forked from Orillusion/orillusion
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Graphic3D): add wireframe graphics to draw (Orillusion#42)
add Graphic3D add Graphics3DShape add Graphic3DBatchRenderer add Graphic3DFillRenderer add Graphic3DLineBatchRenderer
- Loading branch information
1 parent
3f46e1b
commit 0fdc1e9
Showing
7 changed files
with
961 additions
and
0 deletions.
There are no files selected for viewing
118 changes: 118 additions & 0 deletions
118
src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DBatchRenderer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import { RenderNode } from "../../../../components/renderer/RenderNode"; | ||
import { BoundingBox } from "../../../../core/bound/BoundingBox"; | ||
import { View3D } from "../../../../core/View3D"; | ||
import { Color } from "../../../../math/Color"; | ||
import { Vector3 } from "../../../../math/Vector3"; | ||
import { ClusterLightingRender } from "../cluster/ClusterLightingRender"; | ||
import { RendererMask } from "../state/RendererMask"; | ||
import { RendererPassState } from "../state/RendererPassState"; | ||
import { RendererType } from "../state/RendererType"; | ||
import { Graphic3DFixedRenderPipeline } from "./Graphic3DFixedRenderPipeline"; | ||
import { GraphicConfig } from "./GraphicConfig"; | ||
import { Graphics3DShape } from "./Graphics3DShape"; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export class Graphic3DBatchRenderer extends RenderNode { | ||
public shapes: Map<string, Graphics3DShape>; | ||
protected mDirtyData: boolean = false; | ||
protected mMinIndexCount: number; | ||
protected mGPUPrimitiveTopology: GPUPrimitiveTopology; | ||
protected mRenderPipeline: Graphic3DFixedRenderPipeline; | ||
|
||
constructor(minIndexCount: number, topology: GPUPrimitiveTopology) { | ||
super(); | ||
this.alwaysRender = true; | ||
this.mMinIndexCount = minIndexCount; | ||
this.mGPUPrimitiveTopology = topology; | ||
this.shapes = new Map<string, Graphics3DShape>(); | ||
this.addRendererMask(RendererMask.Particle); | ||
} | ||
|
||
public fillShapData(uuid: string, type: string, color: Color, points: Vector3[]) { | ||
this.mDirtyData = true; | ||
var data: Graphics3DShape; | ||
|
||
if (this.shapes.has(uuid)) { | ||
data = this.shapes.get(uuid); | ||
if (data.shapeData.length < GraphicConfig.ShapeVertexSize * points.length) { | ||
data.shapeData = new Float32Array(GraphicConfig.ShapeVertexSize * points.length); | ||
} | ||
} else { | ||
data = new Graphics3DShape(this.transform._worldMatrix.index); | ||
data.type = type; | ||
data.color = color; | ||
data.shapeData = new Float32Array(GraphicConfig.ShapeVertexSize * points.length); | ||
} | ||
|
||
const shapeData = data.shapeData; | ||
const transformIndex = this.transform._worldMatrix.index; | ||
for (let i = 0, index = 0; i < points.length; ++i) { | ||
const point = points[i]; | ||
shapeData[index++] = point.x; | ||
shapeData[index++] = point.y; | ||
shapeData[index++] = point.z; | ||
shapeData[index++] = transformIndex; | ||
shapeData[index++] = color.r; | ||
shapeData[index++] = color.g; | ||
shapeData[index++] = color.b; | ||
shapeData[index++] = color.a; | ||
} | ||
this.shapes.set(uuid, data); | ||
} | ||
|
||
protected init() { | ||
super.init(); | ||
this.castGI = false; | ||
this.castShadow = false; | ||
this.mRenderPipeline = new Graphic3DFixedRenderPipeline(this.mMinIndexCount, this.mGPUPrimitiveTopology); | ||
} | ||
|
||
public removeShape(uuid: string) { | ||
if (this.shapes.has(uuid)) { | ||
this.mDirtyData = true; | ||
this.shapes.delete(uuid); | ||
} | ||
} | ||
|
||
protected initPipeline() { | ||
this.object3D.bound = new BoundingBox(Vector3.ZERO, Vector3.MAX); | ||
this._readyPipeline = true; | ||
} | ||
|
||
public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingRender?: ClusterLightingRender) { | ||
// if(!this.enable || passType != RendererType.COLOR ) return ; | ||
if (this.mDirtyData) { | ||
this.mRenderPipeline.reset(); | ||
this.shapes.forEach((shape, uuid) => { | ||
this.mRenderPipeline.addShapeData(shape); | ||
}); | ||
this.mDirtyData = false; | ||
} | ||
return; | ||
} | ||
|
||
public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingRender: ClusterLightingRender, encoder: GPURenderPassEncoder, useBundle: boolean = false) { | ||
// if(!this.enable || passType != RendererType.COLOR ) return ; | ||
this.mRenderPipeline.render(rendererPassState, encoder); | ||
} | ||
|
||
public allocGraphics3DShape(uuid: string, transformIndex: number) { | ||
let shape: Graphics3DShape; | ||
|
||
if (this.shapes.has(uuid)) { | ||
shape = this.shapes.get(uuid); | ||
shape.reset(); | ||
} else { | ||
shape = new Graphics3DShape(transformIndex); | ||
shape.uuid = uuid; | ||
shape.type = 'line'; | ||
shape.color = Color.COLOR_WHITE; | ||
this.shapes.set(shape.uuid, shape); | ||
} | ||
|
||
this.mDirtyData = true; | ||
return shape; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFillRenderer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { GPUPrimitiveTopology } from "../../../../.."; | ||
import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer"; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export class Graphic3DFillRenderer extends Graphic3DBatchRenderer { | ||
constructor() { | ||
super(3, GPUPrimitiveTopology.triangle_list); | ||
} | ||
} |
203 changes: 203 additions & 0 deletions
203
src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DFixedRenderPipeline.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
import { GPUContext, Preprocessor } from "../../../../.."; | ||
import { BlendFactor, BlendMode } from "../../../../materials/BlendMode"; | ||
import { GlobalBindGroupLayout } from "../../../graphics/webGpu/core/bindGroups/GlobalBindGroupLayout"; | ||
import { GPUCullMode, GPUCompareFunction } from "../../../graphics/webGpu/WebGPUConst"; | ||
import { webGPUContext } from "../../../graphics/webGpu/Context3D"; | ||
import { RendererPassState } from "../state/RendererPassState"; | ||
import { Graphics3DShape } from "./Graphics3DShape"; | ||
import Graphic3DShader_vs from "../../../../assets/shader/graphic/Graphic3DShader_vs.wgsl?raw" | ||
import Graphic3DShader_fs from "../../../../assets/shader/graphic/Graphic3DShader_fs.wgsl?raw" | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export class Graphic3DFixedRenderPipeline { | ||
|
||
protected mCount: number; | ||
protected mBatchSize: number; | ||
protected mBatchCount: number; | ||
protected mMinIndexCount: number; | ||
protected mOffset: number; | ||
protected mIndexBuffer: GPUBuffer; | ||
protected mDataBuffer: Float32Array; | ||
protected mBatchBuffers: GPUBuffer[]; | ||
protected mVertexShader: GPUShaderModule; | ||
protected mFragmentShader: GPUShaderModule; | ||
protected mRenderPipeline: GPURenderPipeline; | ||
protected mRenderPipelineLayout: GPUPipelineLayout; | ||
protected mVertexBufferLayout: GPUVertexBufferLayout; | ||
protected mGPUPrimitiveTopology: GPUPrimitiveTopology; | ||
|
||
constructor(minIndexCount: number, topology: GPUPrimitiveTopology) { | ||
this.mMinIndexCount = minIndexCount; | ||
this.mGPUPrimitiveTopology = topology; | ||
this.mBatchSize = Math.trunc(65536 / this.mMinIndexCount); | ||
this.init(); | ||
} | ||
|
||
public reset() { | ||
this.mCount = 0; | ||
this.mOffset = 0; | ||
this.mBatchCount = 0; | ||
} | ||
|
||
public addShapeData(shape: Graphics3DShape) { | ||
let data = shape.shapeData; | ||
while (data.length > 0) { | ||
if (this.mOffset >= this.mDataBuffer.length) { | ||
this.flush(); | ||
} | ||
|
||
if (this.mOffset + data.length <= this.mDataBuffer.length) { | ||
this.mDataBuffer.set(data, this.mOffset); | ||
this.mOffset += data.length; | ||
break; | ||
} | ||
|
||
let remainLength = this.mDataBuffer.length - this.mOffset; | ||
this.mDataBuffer.set(data.slice(0, remainLength), this.mOffset); | ||
this.mOffset += remainLength; | ||
data = data.slice(remainLength); | ||
} | ||
} | ||
|
||
protected flush() { | ||
if (this.mOffset > 0) { | ||
let vertexBuffer: GPUBuffer; | ||
if (this.mBatchCount < this.mBatchBuffers.length) { | ||
vertexBuffer = this.mBatchBuffers[this.mBatchCount]; | ||
} else { | ||
vertexBuffer = webGPUContext.device.createBuffer({ | ||
size: this.mDataBuffer.byteLength, | ||
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, | ||
}) | ||
this.mBatchBuffers.push(vertexBuffer); | ||
} | ||
// console.log(`writeBuffer(${this.mBatchCount}, ${this.mOffset})`); | ||
webGPUContext.device.queue.writeBuffer(vertexBuffer, 0, this.mDataBuffer, 0, this.mOffset); | ||
this.mCount += this.mOffset / 8; | ||
this.mBatchCount++; | ||
this.mOffset = 0; | ||
} | ||
} | ||
|
||
public render(rendererPassState: RendererPassState, encoder: GPURenderPassEncoder) { | ||
const device = webGPUContext.device; | ||
|
||
if (!this.mRenderPipeline) { | ||
let targets = rendererPassState.outAttachments; | ||
if (rendererPassState.outColor != -1) { | ||
let target = targets[rendererPassState.outColor]; | ||
target.blend = BlendFactor.getBlend(BlendMode.NONE); | ||
} | ||
|
||
this.mRenderPipelineLayout = device.createPipelineLayout({ | ||
bindGroupLayouts: [GlobalBindGroupLayout.getGlobalDataBindGroupLayout()], | ||
}); | ||
|
||
let descriptor: GPURenderPipelineDescriptor = { | ||
label: 'Graphic3DFixedRenderPipeline', | ||
layout: this.mRenderPipelineLayout, | ||
vertex: { | ||
module: this.mVertexShader, | ||
entryPoint: 'main', | ||
buffers: [this.mVertexBufferLayout], | ||
}, | ||
fragment: { | ||
module: this.mFragmentShader, | ||
entryPoint: 'main', | ||
targets: targets, | ||
}, | ||
primitive: { | ||
topology: this.mGPUPrimitiveTopology, | ||
cullMode: GPUCullMode.back, | ||
frontFace: 'ccw', | ||
}, | ||
}; | ||
|
||
if (rendererPassState.depthTexture) { | ||
descriptor.depthStencil = { | ||
depthWriteEnabled: true, | ||
depthCompare: GPUCompareFunction.less_equal, | ||
format: rendererPassState.depthTexture.format, | ||
}; | ||
} | ||
|
||
this.mRenderPipeline = GPUContext.createPipeline(descriptor); | ||
} | ||
|
||
this.flush(); | ||
if (this.mBatchCount > 0) { | ||
// console.log(`[${this.mCount} / ${this.mBatchBuffers.length}]`); | ||
encoder.setPipeline(this.mRenderPipeline); | ||
encoder.setIndexBuffer(this.mIndexBuffer, `uint16`); | ||
|
||
let count = this.mCount / this.mMinIndexCount; | ||
for (let i = Math.trunc(count / this.mBatchSize) - 1; i >= 0; i--) { | ||
encoder.setVertexBuffer(0, this.mBatchBuffers[i]); | ||
encoder.drawIndexed(this.mMinIndexCount * this.mBatchSize, 1, 0, 0, 0); | ||
} | ||
|
||
count = count % this.mBatchSize; | ||
if (count != 0) { | ||
encoder.setVertexBuffer(0, this.mBatchBuffers[this.mBatchCount - 1]); | ||
encoder.drawIndexed(this.mMinIndexCount * count, 1, 0, 0, 0); | ||
} | ||
} | ||
} | ||
|
||
protected init() { | ||
const device = webGPUContext.device; | ||
|
||
let indexData = new Uint16Array((Math.trunc(this.mMinIndexCount * this.mBatchSize / 4) + 1) * 4); | ||
for (let i = 0; i < indexData.length; i++) { | ||
indexData[i] = i; | ||
} | ||
this.mIndexBuffer = device.createBuffer({ | ||
size: indexData.byteLength, | ||
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST, | ||
}); | ||
device.queue.writeBuffer(this.mIndexBuffer, 0, indexData); | ||
|
||
this.mVertexBufferLayout = { | ||
arrayStride: (4 + 4) * 4, | ||
stepMode: 'vertex', | ||
attributes: [ | ||
{ shaderLocation: 0, offset: 0, format: 'float32x4' }, | ||
{ shaderLocation: 1, offset: 16, format: 'float32x4' }, | ||
], | ||
}; | ||
|
||
this.mBatchBuffers = []; | ||
this.mDataBuffer = new Float32Array((4 + 4) * indexData.length); | ||
this.mBatchBuffers.push(device.createBuffer({ | ||
size: this.mDataBuffer.byteLength, | ||
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, | ||
})); | ||
|
||
this.mVertexShader = this.createShaderModule( | ||
'Graphic3DFixedRenderPipeline.vs', | ||
Preprocessor.parse(Graphic3DShader_vs, {}) | ||
); | ||
this.mFragmentShader = this.createShaderModule( | ||
'Graphic3DFixedRenderPipeline.fs', | ||
Preprocessor.parse(Graphic3DShader_fs, {}) | ||
); | ||
|
||
this.reset(); | ||
} | ||
|
||
protected createShaderModule(label: string, code: string): GPUShaderModule { | ||
let shaderModule = webGPUContext.device.createShaderModule({ | ||
label: label, | ||
code: code, | ||
}); | ||
shaderModule.getCompilationInfo().then((e) => { | ||
if (e.messages.length > 0) { | ||
console.log(code); | ||
console.log(e); | ||
} | ||
}); | ||
return shaderModule; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/engine/gfx/renderJob/passRenderer/graphic/Graphic3DLineBatchRenderer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { GPUPrimitiveTopology } from "../../../../.."; | ||
import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer"; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export class Graphic3DLineBatchRenderer extends Graphic3DBatchRenderer { | ||
constructor() { | ||
super(2, GPUPrimitiveTopology.line_list); | ||
} | ||
} |
Oops, something went wrong.