当前示例源码github地址:
https://github.com/vilyLei/voxwebgpu/blob/main/src/voxgpu/sample/SimpleLightTest.ts
此示例渲染系统实现的特性:
1. 用户态与系统态隔离。
2. 高频调用与低频调用隔离。
3. 面向用户的易用性封装。
4. 渲染数据和渲染机制分离。
5. 用户操作和渲染系统调度并行机制。
当前示例运行效果:
顶点shader:
@group(0) @binding(0) var objMat : mat4x4;
@group(0) @binding(1) var viewMat : mat4x4;
@group(0) @binding(2) var projMat : mat4x4;
struct VertexOutput {
@builtin(position) Position : vec4,
@location(0) pos: vec4,
@location(1) uv : vec2,
@location(2) normal : vec3
}
fn inverseM33(m: mat3x3)-> mat3x3 {
let a00 = m[0][0]; let a01 = m[0][1]; let a02 = m[0][2];
let a10 = m[1][0]; let a11 = m[1][1]; let a12 = m[1][2];
let a20 = m[2][0]; let a21 = m[2][1]; let a22 = m[2][2];
let b01 = a22 * a11 - a12 * a21;
let b11 = -a22 * a10 + a12 * a20;
let b21 = a21 * a10 - a11 * a20;
let det = a00 * b01 + a01 * b11 + a02 * b21;
return mat3x3(
vec3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11)) / det,
vec3(b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10)) / det,
vec3(b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det);
}
@vertex
fn main(
@location(0) position : vec3,
@location(1) uv : vec2,
@location(2) normal : vec3
) -> VertexOutput {
var output : VertexOutput;
output.Position = projMat * viewMat * objMat * vec4(position.xyz, 1.0);
output.uv = uv;
let mat33 = mat3x3(objMat[0].xyz, objMat[1].xyz, objMat[2].xyz);
let invMat33 = inverseM33(mat33);
output.normal = normalize( normal * invMat33 );
var pv: vec4;
pv = vec4(position, 1.0);
output.pos = pv;
return output;
}
片段shader:
@group(0) @binding(3) var param: vec4f;
@group(0) @binding(4) var sampler0: sampler;
@group(0) @binding(5) var texture0: texture_2d;
const lightDirec = vec3(0.3,0.6,0.9);
@fragment
fn main(
@location(0) pos: vec4,
@location(1) uv: vec2,
@location(2) normal: vec3
) -> @location(0) vec4 {
let nDotL = max(dot(normal, lightDirec), 0.0);
var color4 = textureSample(texture0, sampler0, uv) * param;
color4 = vec4(color4.xyz * (vec3(1.0 - param.w) + vec3((param.w) * nDotL) * param.xyz), color4.w);
return color4;
}
此示例基于此渲染系统实现,当前示例TypeScript源码如下:
export class SimpleLightTest {
private mObjs: TransObject[] = [];
private mRscene = new RendererScene();
geomData = new GeomDataBuilder();
initialize(): void {
console.log("SimpleLightTest::initialize() ...");
const rc = this.mRscene;
rc.initialize();
this.initEvent();
const shdSrc = {
vertShaderSrc: { code: vertWGSL, uuid: "vertShdCode" },
fragShaderSrc: { code: fragWGSL, uuid: "fragShdCode" }
};
for (let i = 0; i < 10; ++i) {
let material = this.createMaterial(shdSrc, [new WGImage2DTextureData("static/assets/white.jpg")], new Color4().randomRGB(1.0, 0.2));
let scale = Math.random() * 0.5 + 0.5;
const entity = this.createEntity([material]);
const obj = new TransObject();
obj.entity = entity;
obj.scale.setXYZ(scale, scale, scale);
obj.rotationSpdv.setXYZ(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5);
obj.initialize(800);
this.mObjs.push(obj);
}
}
private initEvent(): void {
const rc = this.mRscene;
rc.addEventListener(MouseEvent.MOUSE_DOWN, this, this.mouseDown);
new MouseInteraction().initialize(rc, 0, false).setAutoRunning(true);
}
private mouseDown(evt: MouseEvent): void {
console.log("mousedown evt call ...");
}
private createMaterial(
shdSrc: WGRShderSrcType,
texDatas?: WGImage2DTextureData[],
color?: Color4,
blendModes: string[] = ["solid"],
faceCullMode = "back"
): WGMaterial {
let pipelineDefParam = {
depthWriteEnabled: true,
faceCullMode,
blendModes: [] as string[]
};
if (!color) color = new Color4(1.0, 1.0, 1.0);
pipelineDefParam.blendModes = blendModes;
const texTotal = texDatas ? texDatas.length : 0;
const material = new WGMaterial({
shadinguuid: "base-material-tex" + texTotal,
shaderCodeSrc: shdSrc,
pipelineDefParam
});
let ufv = new WGRStorageValue(new Float32Array([color.r, color.g, color.b, 0.9]));
material.uniformValues = [ufv];
material.addTextureWithDatas(texDatas);
return material;
}
private createGeom(rgd: GeomRDataType): WGGeometry {
const geometry = new WGGeometry()
.addAttribute({ shdVarName: "position", data: rgd.vs, strides: [3] })
.addAttribute({ shdVarName: "uv", data: rgd.uvs, strides: [2] })
.addAttribute({ shdVarName: "normal", data: rgd.nvs, strides: [3] })
.setIndexBuffer({ name: "geomIndex", data: rgd.ivs });
return geometry;
}
private createEntity(materials: WGMaterial[], pv?: Vector3): Entity3D {
const rc = this.mRscene;
let geometry = this.mObjs.length > 0 ? this.mObjs[0].entity.geometry : null;
geometry = geometry ? geometry : this.createGeom(this.geomData.createCube(200));
const entity = new Entity3D();
entity.materials = materials;
entity.geometry = geometry;
entity.transform.setPosition(pv ? pv : new Vector3());
rc.addEntity(entity);
return entity;
}
run(): void {
for (let i = 0; i < this.mObjs.length; ++i) {
this.mObjs[i].run();
}
this.mRscene.run();
}
}