当前示例源码github地址:
https://github.com/vilyLei/voxwebgpu/blob/main/src/voxgpu/sample/SimpleLightTest.ts
此示例渲染系统实现的特性:
1. 用户态与系统态隔离。
细节请见:引擎系统设计思路 - 用户态与系统态隔离-CSDN博客
2. 高频调用与低频调用隔离。
3. 面向用户的易用性封装。
4. 渲染数据和渲染机制分离。
5. 用户操作和渲染系统调度并行机制。
当前示例运行效果:
顶点shader:
@group(0) @binding(0) var<uniform> objMat : mat4x4<f32>;
@group(0) @binding(1) var<uniform> viewMat : mat4x4<f32>;
@group(0) @binding(2) var<uniform> projMat : mat4x4<f32>;
struct VertexOutput {
@builtin(position) Position : vec4<f32>,
@location(0) pos: vec4<f32>,
@location(1) uv : vec2<f32>,
@location(2) normal : vec3<f32>
}
fn inverseM33(m: mat3x3<f32>)-> mat3x3<f32> {
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<f32>(
vec3<f32>(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11)) / det,
vec3<f32>(b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10)) / det,
vec3<f32>(b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det);
}
fn m44ToM33(m: mat4x4<f32>) -> mat3x3<f32> {
return mat3x3(m[0].xyz, m[1].xyz, m[2].xyz);
}
@vertex
fn main(
@location(0) position : vec3<f32>,
@location(1) uv : vec2<f32>,
@location(2) normal : vec3<f32>
) -> VertexOutput {
var output : VertexOutput;
output.Position = projMat * viewMat * objMat * vec4(position.xyz, 1.0);
output.uv = uv;
let invMat33 = inverseM33( m44ToM33( objMat ) );
output.normal = normalize( normal * invMat33 );
var pv: vec4<f32>;
pv = vec4<f32>(position, 1.0);
output.pos = pv;
return output;
}
片段shader:
@group(0) @binding(3) var<storage> param: vec4f;
@group(0) @binding(4) var sampler0: sampler;
@group(0) @binding(5) var texture0: texture_2d<f32>;
const lightDirec = vec3<f32>(0.3,0.6,0.9);
@fragment
fn main(
@location(0) pos: vec4<f32>,
@location(1) uv: vec2<f32>,
@location(2) normal: vec3<f32>
) -> @location(0) vec4<f32> {
let nDotL = max(dot(normal, lightDirec), 0.0);
var color4 = textureSample(texture0, sampler0, uv) * param;
color4 = vec4(color4.xyz * (vec3<f32>(1.0 - param.w) + vec3<f32>((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() ...");
this.initEvent();
const shdSrc = {
vertShaderSrc: { code: vertWGSL, uuid: "vertShdCode" },
fragShaderSrc: { code: fragWGSL, uuid: "fragShdCode" }
};
let geom = this.createGeom(this.geomData.createCube(100), true);
let texList = [new WGImage2DTextureData("static/assets/white.jpg")];
let tot = 4;
const size = new Vector3(150, 150, 150);
const pos = new Vector3().copyFrom(size).scaleBy(-0.5 * (tot - 1));
for (let i = 0; i < tot; ++i) {
for (let j = 0; j < tot; ++j) {
for (let k = 0; k < tot; ++k) {
let material = this.createMaterial(shdSrc, texList, new Color4().randomRGB(1.0, 0.2));
let scale = Math.random() * 0.2 + 0.3;
const entity = this.createEntity(geom, [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.position.setXYZ(i * size.x, j * size.y, k * size.z).addBy(pos);
this.mObjs.push(obj);
}
}
}
}
private initEvent(): void {
const rc = this.mRscene;
rc.addEventListener(MouseEvent.MOUSE_DOWN, 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, normalEnabled = false): WGGeometry {
const geometry = new WGGeometry()
.addAttribute({ position: rgd.vs })
.addAttribute({ uv: rgd.uvs })
.setIndices(rgd.ivs);
if (normalEnabled) {
geometry.addAttribute({ normal: rgd.nvs });
}
return geometry;
}
private createEntity(geometry: WGGeometry, materials: WGMaterial[], pv?: Vector3): Entity3D {
const rc = this.mRscene;
const entity = new Entity3D();
entity.materials = materials;
entity.geometry = geometry;
if (pv) entity.transform.setPosition(pv);
rc.addEntity(entity);
return entity;
}
run(): void {
for (let i = 0; i < this.mObjs.length; ++i) {
this.mObjs[i].run();
}
this.mRscene.run();
}
}