Camera projection, upload lights and global uniforms, issue draw calls
This commit is contained in:
parent
be350c5f4f
commit
23309903e8
@ -4,7 +4,7 @@
|
|||||||
* obtain one at http://mozilla.org/MPL/2.0/.
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Node } from ".";
|
import { Matrix4x4, Node } from ".";
|
||||||
|
|
||||||
export type Camera = OrthographicCamera | PerspectiveCamera;
|
export type Camera = OrthographicCamera | PerspectiveCamera;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export class OrthographicCamera {
|
|||||||
|
|
||||||
_name: string;
|
_name: string;
|
||||||
|
|
||||||
_verticalSize: number;
|
_halfVerticalSize: number;
|
||||||
_nearPlane: number;
|
_nearPlane: number;
|
||||||
_farPlane: number;
|
_farPlane: number;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ export class OrthographicCamera {
|
|||||||
}: OrthographicCameraProps) {
|
}: OrthographicCameraProps) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
|
|
||||||
this._verticalSize = verticalSize;
|
this._halfVerticalSize = verticalSize;
|
||||||
this._nearPlane = nearPlane;
|
this._nearPlane = nearPlane;
|
||||||
this._farPlane = farPlane;
|
this._farPlane = farPlane;
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ export class OrthographicCamera {
|
|||||||
set name(value: string) { this._name = value; }
|
set name(value: string) { this._name = value; }
|
||||||
get name(): string { return this._name; }
|
get name(): string { return this._name; }
|
||||||
|
|
||||||
set verticalSize(value: number) { this._verticalSize = value; }
|
set halfVerticalSize(value: number) { this._halfVerticalSize = value; }
|
||||||
get verticalSize(): number { return this._verticalSize; }
|
get halfVerticalSize(): number { return this._halfVerticalSize; }
|
||||||
|
|
||||||
set nearPlane(value: number) { this._nearPlane = value; }
|
set nearPlane(value: number) { this._nearPlane = value; }
|
||||||
get nearPlane(): number { return this._nearPlane; }
|
get nearPlane(): number { return this._nearPlane; }
|
||||||
@ -87,6 +87,16 @@ export class OrthographicCamera {
|
|||||||
this._node = null;
|
this._node = null;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computeProjectionMatrix(aspectRatio: number, res: Matrix4x4): Matrix4x4 {
|
||||||
|
const halfHorizontalSize = this._halfVerticalSize / aspectRatio;
|
||||||
|
return res.set(
|
||||||
|
1 / halfHorizontalSize, 0, 0, 0,
|
||||||
|
0, 1 / this._halfVerticalSize, 0, 0,
|
||||||
|
0, 0, 1 / (this._nearPlane - this._farPlane), 0,
|
||||||
|
0, 0, this._farPlane / (this._farPlane - this._nearPlane), 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PerspectiveCamera {
|
export class PerspectiveCamera {
|
||||||
@ -149,6 +159,25 @@ export class PerspectiveCamera {
|
|||||||
this._node = null;
|
this._node = null;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computeProjectionMatrix(aspectRatio: number, res: Matrix4x4): Matrix4x4 {
|
||||||
|
const halfVerticalCotangent = 1 / Math.tan(0.5 * this._verticalFovRad);
|
||||||
|
if (this._farPlane === Infinity) {
|
||||||
|
return res.set(
|
||||||
|
halfVerticalCotangent / aspectRatio, 0, 0, 0,
|
||||||
|
0, halfVerticalCotangent, 0, 0,
|
||||||
|
0, 0, 0, 1,
|
||||||
|
0, 0, this._nearPlane, 0,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return res.set(
|
||||||
|
halfVerticalCotangent / aspectRatio, 0, 0, 0,
|
||||||
|
0, halfVerticalCotangent, 0, 0,
|
||||||
|
0, 0, this._nearPlane / (this._nearPlane - this._farPlane), 1,
|
||||||
|
0, 0, this._nearPlane * this._farPlane / (this._farPlane - this._nearPlane), 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(OrthographicCamera.prototype, "type", { value: "OrthographicCamera" });
|
Object.defineProperty(OrthographicCamera.prototype, "type", { value: "OrthographicCamera" });
|
||||||
|
@ -155,6 +155,31 @@ export class Matrix4x4 {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set(
|
||||||
|
ix: number, iy: number, iz: number, iw: number,
|
||||||
|
jx: number, jy: number, jz: number, jw: number,
|
||||||
|
kx: number, ky: number, kz: number, kw: number,
|
||||||
|
tx: number, ty: number, tz: number, tw: number,
|
||||||
|
): Matrix4x4 {
|
||||||
|
this.ix = ix;
|
||||||
|
this.iy = iy;
|
||||||
|
this.iz = iz;
|
||||||
|
this.iw = iw;
|
||||||
|
this.jx = jx;
|
||||||
|
this.jy = jy;
|
||||||
|
this.jz = jz;
|
||||||
|
this.jw = jw;
|
||||||
|
this.kx = kx;
|
||||||
|
this.ky = ky;
|
||||||
|
this.kz = kz;
|
||||||
|
this.kw = kw;
|
||||||
|
this.tx = tx;
|
||||||
|
this.ty = ty;
|
||||||
|
this.tz = tz;
|
||||||
|
this.tw = tw;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
setObject(object: Matrix4x4Object): Matrix4x4 {
|
setObject(object: Matrix4x4Object): Matrix4x4 {
|
||||||
this.ix = object.ix;
|
this.ix = object.ix;
|
||||||
this.iy = object.iy;
|
this.iy = object.iy;
|
||||||
@ -507,6 +532,40 @@ export class Matrix4x4 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inverseAffine(): Matrix4x4 {
|
||||||
|
const ix = this.ix;
|
||||||
|
const iy = this.iy;
|
||||||
|
const iz = this.iz;
|
||||||
|
const jx = this.jx;
|
||||||
|
const jy = this.jy;
|
||||||
|
const jz = this.jz;
|
||||||
|
const kx = this.kx;
|
||||||
|
const ky = this.ky;
|
||||||
|
const kz = this.kz;
|
||||||
|
const tx = this.tx;
|
||||||
|
const ty = this.ty;
|
||||||
|
const tz = this.tz;
|
||||||
|
|
||||||
|
const det = ix * jy * kz + iy * jz * kx + iz * jx * ky
|
||||||
|
- ix * jz * ky - iy * jx * kz - iz * jy * kx;
|
||||||
|
const invDet = 1 / det;
|
||||||
|
|
||||||
|
this.ix = invDet * (jy * kz - jz * ky);
|
||||||
|
this.iy = invDet * (iz * ky - iy * kz);
|
||||||
|
this.iz = invDet * (iy * jz - iz * jy);
|
||||||
|
this.jx = invDet * (jz * kx - jx * kz);
|
||||||
|
this.jy = invDet * (ix * kz - iz * kx);
|
||||||
|
this.jz = invDet * (iz * jx - ix * jz);
|
||||||
|
this.kx = invDet * (jx * ky - jy * kx);
|
||||||
|
this.ky = invDet * (iy * kx - ix * ky);
|
||||||
|
this.kz = invDet * (ix * jy - iy * jx);
|
||||||
|
this.tx = -(this.ix * tx + this.jx * ty + this.kx * tz);
|
||||||
|
this.ty = -(this.iy * tx + this.jy * ty + this.ky * tz);
|
||||||
|
this.tz = -(this.iz * tx + this.jz * ty + this.kz * tz);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
inverseTransposeAffine(): Matrix4x4 {
|
inverseTransposeAffine(): Matrix4x4 {
|
||||||
const ix = this.ix;
|
const ix = this.ix;
|
||||||
const iy = this.iy;
|
const iy = this.iy;
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
* obtain one at http://mozilla.org/MPL/2.0/.
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Node } from ".";
|
import { Color, ColorObject, Node } from ".";
|
||||||
|
|
||||||
export interface SceneProps {
|
export interface SceneProps {
|
||||||
readonly name?: string;
|
readonly name?: string;
|
||||||
|
|
||||||
readonly nodes?: Node[];
|
readonly nodes?: Node[];
|
||||||
|
|
||||||
|
readonly ambientLight?: ColorObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Scene {
|
export class Scene {
|
||||||
@ -20,17 +22,31 @@ export class Scene {
|
|||||||
|
|
||||||
_nodes: Node[];
|
_nodes: Node[];
|
||||||
|
|
||||||
|
_ambientLight: Color;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
name = "",
|
name = "",
|
||||||
nodes = [],
|
nodes = [],
|
||||||
|
ambientLight,
|
||||||
}: SceneProps) {
|
}: SceneProps) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
|
|
||||||
this._nodes = nodes;
|
this._nodes = nodes;
|
||||||
|
|
||||||
|
this._ambientLight = ambientLight !== undefined ? Color.fromObject(ambientLight) : Color.black();
|
||||||
}
|
}
|
||||||
|
|
||||||
set name(value: string) { this._name = value; }
|
set name(value: string) { this._name = value; }
|
||||||
get name(): string { return this._name; }
|
get name(): string { return this._name; }
|
||||||
|
|
||||||
|
setAmbientLight(value: ColorObject): Scene {
|
||||||
|
this._ambientLight.setObject(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAmbientLight(res: Color): Color {
|
||||||
|
return res.setObject(this._ambientLight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(Scene.prototype, "type", { value: "Scene" });
|
Object.defineProperty(Scene.prototype, "type", { value: "Scene" });
|
||||||
|
@ -78,6 +78,13 @@ export class Vector2 {
|
|||||||
this.y = y;
|
this.y = y;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
normalize(): Vector2 {
|
||||||
|
const l = Math.sqrt(this.x * this.x + this.y * this.y);
|
||||||
|
this.x /= l;
|
||||||
|
this.y /= l;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(Vector2.prototype, "type", { value: "Vector2" });
|
Object.defineProperty(Vector2.prototype, "type", { value: "Vector2" });
|
||||||
|
@ -91,6 +91,14 @@ export class Vector3 {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
normalize(): Vector3 {
|
||||||
|
const l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||||
|
this.x /= l;
|
||||||
|
this.y /= l;
|
||||||
|
this.z /= l;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(Vector3.prototype, "type", { value: "Vector3" });
|
Object.defineProperty(Vector3.prototype, "type", { value: "Vector3" });
|
||||||
|
@ -104,6 +104,15 @@ export class Vector4 {
|
|||||||
this.w = w;
|
this.w = w;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
normalize(): Vector4 {
|
||||||
|
const l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
|
||||||
|
this.x /= l;
|
||||||
|
this.y /= l;
|
||||||
|
this.z /= l;
|
||||||
|
this.w /= l;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(Vector4.prototype, "type", { value: "Vector4" });
|
Object.defineProperty(Vector4.prototype, "type", { value: "Vector4" });
|
||||||
|
158
src/oktaeder.ts
158
src/oktaeder.ts
@ -9,17 +9,34 @@ export * from "./shader";
|
|||||||
|
|
||||||
import { _BinaryWriter as BinaryWriter } from "./_BinaryWriter";
|
import { _BinaryWriter as BinaryWriter } from "./_BinaryWriter";
|
||||||
import { _Mapping as Mapping } from "./_Mapping";
|
import { _Mapping as Mapping } from "./_Mapping";
|
||||||
import { Camera, Material, Matrix4x4, Node, Scene, preOrder } from "./data";
|
import { Camera, Material, Matrix4x4, Node, Scene, Vector3, isDirectionalLight, isPointLight, preOrder } from "./data";
|
||||||
import { IndexBuffer, IndexBufferProps, Texture2D, Texture2DProps, VertexBuffer, VertexBufferProps } from "./resources";
|
import { IndexBuffer, IndexBufferProps, Texture2D, Texture2DProps, VertexBuffer, VertexBufferProps } from "./resources";
|
||||||
import { ShaderFlagKey, ShaderFlags, createPipeline, shaderFlagsKey } from "./shader";
|
import { ShaderFlagKey, ShaderFlags, createPipeline, shaderFlagsKey } from "./shader";
|
||||||
|
|
||||||
const _normalMatrix = new Matrix4x4(
|
const _matrixOStoWSNormal = new Matrix4x4(
|
||||||
NaN, NaN, NaN, NaN,
|
NaN, NaN, NaN, NaN,
|
||||||
NaN, NaN, NaN, NaN,
|
NaN, NaN, NaN, NaN,
|
||||||
NaN, NaN, NaN, NaN,
|
NaN, NaN, NaN, NaN,
|
||||||
NaN, NaN, NaN, NaN,
|
NaN, NaN, NaN, NaN,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const _matrixWStoVS = new Matrix4x4(
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
);
|
||||||
|
|
||||||
|
const _matrixVStoCS = new Matrix4x4(
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
NaN, NaN, NaN, NaN,
|
||||||
|
);
|
||||||
|
|
||||||
|
const _directionWS = new Vector3(NaN, NaN, NaN);
|
||||||
|
const _positionWS = new Vector3(NaN, NaN, NaN);
|
||||||
|
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
|
|
||||||
_adapter: GPUAdapter;
|
_adapter: GPUAdapter;
|
||||||
@ -45,11 +62,14 @@ export class Renderer {
|
|||||||
|
|
||||||
_uniformWriter: BinaryWriter;
|
_uniformWriter: BinaryWriter;
|
||||||
_uniformBuffer: GPUBuffer;
|
_uniformBuffer: GPUBuffer;
|
||||||
_directionalLightBuffer: GPUBuffer;
|
|
||||||
|
_lightWriter: BinaryWriter;
|
||||||
_pointLightBuffer: GPUBuffer;
|
_pointLightBuffer: GPUBuffer;
|
||||||
|
_directionalLightBuffer: GPUBuffer;
|
||||||
|
|
||||||
_sampler: GPUSampler;
|
_sampler: GPUSampler;
|
||||||
|
|
||||||
|
_globalBindGroup: GPUBindGroup;
|
||||||
_objectBindGroup: GPUBindGroup;
|
_objectBindGroup: GPUBindGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,7 +133,6 @@ export class Renderer {
|
|||||||
binding: 1,
|
binding: 1,
|
||||||
visibility: GPUShaderStage.FRAGMENT,
|
visibility: GPUShaderStage.FRAGMENT,
|
||||||
buffer: {
|
buffer: {
|
||||||
hasDynamicOffset: true,
|
|
||||||
type: "read-only-storage",
|
type: "read-only-storage",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -121,7 +140,6 @@ export class Renderer {
|
|||||||
binding: 2,
|
binding: 2,
|
||||||
visibility: GPUShaderStage.FRAGMENT,
|
visibility: GPUShaderStage.FRAGMENT,
|
||||||
buffer: {
|
buffer: {
|
||||||
hasDynamicOffset: true,
|
|
||||||
type: "read-only-storage",
|
type: "read-only-storage",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -224,11 +242,13 @@ export class Renderer {
|
|||||||
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,
|
||||||
label: "Uniform",
|
label: "Uniform",
|
||||||
});
|
});
|
||||||
this._directionalLightBuffer = device.createBuffer({
|
|
||||||
|
this._lightWriter = new BinaryWriter();
|
||||||
|
this._pointLightBuffer = device.createBuffer({
|
||||||
size: 1024 * 32,
|
size: 1024 * 32,
|
||||||
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
||||||
});
|
});
|
||||||
this._pointLightBuffer = device.createBuffer({
|
this._directionalLightBuffer = device.createBuffer({
|
||||||
size: 1024 * 32,
|
size: 1024 * 32,
|
||||||
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
||||||
});
|
});
|
||||||
@ -243,6 +263,15 @@ export class Renderer {
|
|||||||
maxAnisotropy: 16,
|
maxAnisotropy: 16,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._globalBindGroup = device.createBindGroup({
|
||||||
|
layout: this._globalBindGroupLayout,
|
||||||
|
entries: [
|
||||||
|
{ binding: 0, resource: { buffer: this._uniformBuffer } },
|
||||||
|
{ binding: 1, resource: { buffer: this._pointLightBuffer } },
|
||||||
|
{ binding: 2, resource: { buffer: this._directionalLightBuffer } },
|
||||||
|
],
|
||||||
|
label: "Global",
|
||||||
|
});
|
||||||
this._objectBindGroup = device.createBindGroup({
|
this._objectBindGroup = device.createBindGroup({
|
||||||
layout: this._objectBindGroupLayout,
|
layout: this._objectBindGroupLayout,
|
||||||
entries: [
|
entries: [
|
||||||
@ -320,6 +349,11 @@ export class Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(scene: Scene, camera: Camera): Renderer {
|
render(scene: Scene, camera: Camera): Renderer {
|
||||||
|
const cameraNode = camera._node;
|
||||||
|
if (cameraNode === null) {
|
||||||
|
throw new Error(`Cannot render with a detached camera. Camera [${camera._name}] is not attached to a node.`);
|
||||||
|
}
|
||||||
|
|
||||||
const { width, height } = this._context.getCurrentTexture();
|
const { width, height } = this._context.getCurrentTexture();
|
||||||
if (this._depthBuffer.width !== width || this._depthBuffer.height !== height) {
|
if (this._depthBuffer.width !== width || this._depthBuffer.height !== height) {
|
||||||
this._depthBuffer.resizeDiscard({
|
this._depthBuffer.resizeDiscard({
|
||||||
@ -346,7 +380,7 @@ export class Renderer {
|
|||||||
|
|
||||||
this._uniformWriter.clear();
|
this._uniformWriter.clear();
|
||||||
|
|
||||||
// material gather
|
// gather materials
|
||||||
|
|
||||||
const materialMapping = new Mapping<Material>();
|
const materialMapping = new Mapping<Material>();
|
||||||
for (const node of preOrder(scene._nodes)) {
|
for (const node of preOrder(scene._nodes)) {
|
||||||
@ -385,7 +419,7 @@ export class Renderer {
|
|||||||
return { offset, bindGroup };
|
return { offset, bindGroup };
|
||||||
});
|
});
|
||||||
|
|
||||||
// object gather
|
// gather objects
|
||||||
|
|
||||||
const objectMapping = new Mapping<Node>();
|
const objectMapping = new Mapping<Node>();
|
||||||
for (const node of preOrder(scene._nodes)) {
|
for (const node of preOrder(scene._nodes)) {
|
||||||
@ -398,20 +432,112 @@ export class Renderer {
|
|||||||
const offset = this._uniformWriter._length;
|
const offset = this._uniformWriter._length;
|
||||||
object._updateWorldMatrix();
|
object._updateWorldMatrix();
|
||||||
this._uniformWriter.writeMatrix4x4(object._worldMatrix);
|
this._uniformWriter.writeMatrix4x4(object._worldMatrix);
|
||||||
this._uniformWriter.writeMatrix4x4(_normalMatrix.setObject(object._worldMatrix).inverseTransposeAffine());
|
this._uniformWriter.writeMatrix4x4(_matrixOStoWSNormal.setObject(object._worldMatrix).inverseTransposeAffine());
|
||||||
return offset;
|
return offset;
|
||||||
});
|
});
|
||||||
|
|
||||||
// directional lights gather
|
// gather point lights
|
||||||
|
|
||||||
// TODO
|
this._lightWriter.clear();
|
||||||
|
let pointLightCount = 0;
|
||||||
|
for (const node of preOrder(scene._nodes)) {
|
||||||
|
const light = node._light;
|
||||||
|
if (!isPointLight(light)) continue;
|
||||||
|
|
||||||
// point lights gather
|
node._updateWorldMatrix();
|
||||||
|
_positionWS.set(node._worldMatrix.tx, node._worldMatrix.ty, node._worldMatrix.tz);
|
||||||
|
|
||||||
// TODO
|
this._lightWriter.writeVector3(_positionWS);
|
||||||
|
this._lightWriter.writeU32(0);
|
||||||
|
this._lightWriter.writeColorF32(light._color);
|
||||||
|
this._lightWriter.writeU32(0);
|
||||||
|
|
||||||
void materialBindGroups;
|
pointLightCount += 1;
|
||||||
void objectOffsets;
|
}
|
||||||
|
|
||||||
|
this._device.queue.writeBuffer(this._pointLightBuffer, 0, this._lightWriter.subarray);
|
||||||
|
|
||||||
|
// gather directional lights
|
||||||
|
|
||||||
|
this._lightWriter.clear();
|
||||||
|
let directionalLightCount = 0;
|
||||||
|
for (const node of preOrder(scene._nodes)) {
|
||||||
|
const light = node._light;
|
||||||
|
if (!isDirectionalLight(light)) continue;
|
||||||
|
|
||||||
|
node._updateWorldMatrix();
|
||||||
|
_directionWS.set(-node._worldMatrix.kx, -node._worldMatrix.ky, -node._worldMatrix.kz);
|
||||||
|
_directionWS.normalize();
|
||||||
|
|
||||||
|
this._lightWriter.writeVector3(_directionWS);
|
||||||
|
this._lightWriter.writeU32(0);
|
||||||
|
this._lightWriter.writeColorF32(light._color);
|
||||||
|
this._lightWriter.writeU32(0);
|
||||||
|
|
||||||
|
directionalLightCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._device.queue.writeBuffer(this._directionalLightBuffer, 0, this._lightWriter.subarray);
|
||||||
|
|
||||||
|
// global uniforms
|
||||||
|
|
||||||
|
const globalUniformsOffset = this._uniformWriter._length;
|
||||||
|
cameraNode._updateWorldMatrix();
|
||||||
|
_matrixWStoVS.setObject(cameraNode._worldMatrix).inverseAffine();
|
||||||
|
camera.computeProjectionMatrix(width / height, _matrixVStoCS);
|
||||||
|
|
||||||
|
this._uniformWriter.writeMatrix4x4(_matrixWStoVS);
|
||||||
|
this._uniformWriter.writeMatrix4x4(_matrixVStoCS);
|
||||||
|
this._uniformWriter.writeColorF32(scene._ambientLight);
|
||||||
|
this._uniformWriter.writeU32(pointLightCount);
|
||||||
|
this._uniformWriter.writeU32(directionalLightCount);
|
||||||
|
this._uniformWriter.writeU32(0);
|
||||||
|
this._uniformWriter.writeU32(0);
|
||||||
|
this._uniformWriter.writeU32(0);
|
||||||
|
|
||||||
|
// upload uniforms
|
||||||
|
|
||||||
|
this._device.queue.writeBuffer(this._uniformBuffer, 0, this._uniformWriter.subarray);
|
||||||
|
|
||||||
|
// render
|
||||||
|
|
||||||
|
pass.setBindGroup(0, this._globalBindGroup, [globalUniformsOffset]);
|
||||||
|
|
||||||
|
for (let oi = 0; oi < objectMapping.table.length; ++oi) {
|
||||||
|
const object = objectMapping.table[oi]!;
|
||||||
|
const objectOffset = objectOffsets[oi]!;
|
||||||
|
const mesh = object.mesh!;
|
||||||
|
const { _vertexBuffer: vertexBuffer, _indexBuffer: indexBuffer } = mesh;
|
||||||
|
|
||||||
|
const flags: ShaderFlags = {
|
||||||
|
texCoord: vertexBuffer._texCoordBuffer !== null,
|
||||||
|
lightTexCoord: vertexBuffer._lightTexCoordBuffer !== null,
|
||||||
|
normal: vertexBuffer._normalBuffer !== null,
|
||||||
|
tangent: vertexBuffer._tangentBuffer !== null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderPipeline = this._getOrCreatePipeline(flags);
|
||||||
|
|
||||||
|
pass.setPipeline(renderPipeline);
|
||||||
|
|
||||||
|
pass.setVertexBuffer(0, vertexBuffer._positionBuffer);
|
||||||
|
pass.setVertexBuffer(1, vertexBuffer._texCoordBuffer);
|
||||||
|
pass.setVertexBuffer(2, vertexBuffer._lightTexCoordBuffer);
|
||||||
|
pass.setVertexBuffer(3, vertexBuffer._normalBuffer);
|
||||||
|
pass.setVertexBuffer(4, vertexBuffer._tangentBuffer);
|
||||||
|
pass.setIndexBuffer(indexBuffer._buffer, indexBuffer._indexFormat);
|
||||||
|
|
||||||
|
pass.setBindGroup(2, this._objectBindGroup, [objectOffset]);
|
||||||
|
|
||||||
|
for (let si = 0; si < mesh._submeshes.length; ++si) {
|
||||||
|
const submesh = mesh._submeshes[si]!;
|
||||||
|
const material = object._materials[si]!;
|
||||||
|
const { bindGroup: materialBindGroup, offset: materialOffset } = materialBindGroups[materialMapping.get(material)!]!;
|
||||||
|
|
||||||
|
pass.setBindGroup(1, materialBindGroup, [materialOffset]);
|
||||||
|
pass.drawIndexed(submesh.length, 1, submesh.start, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pass.end();
|
pass.end();
|
||||||
|
|
||||||
|
@ -116,6 +116,9 @@ export class IndexBuffer {
|
|||||||
indexCount,
|
indexCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get indexFormat(): "uint16" | "uint32" { return this._indexFormat; }
|
||||||
|
get indexSize(): number { return indexSize(this._indexFormat); }
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(IndexBuffer.prototype, "type", { value: "IndexBuffer" });
|
Object.defineProperty(IndexBuffer.prototype, "type", { value: "IndexBuffer" });
|
||||||
|
@ -136,16 +136,15 @@ export function createShaderCode({
|
|||||||
normal,
|
normal,
|
||||||
tangent,
|
tangent,
|
||||||
}: ShaderFlags): string {
|
}: ShaderFlags): string {
|
||||||
let vertexLocation = 0;
|
|
||||||
let varyingLocation = 0;
|
let varyingLocation = 0;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@location(${vertexLocation++}) positionOS: vec3<f32>,
|
@location(0) positionOS: vec3<f32>,
|
||||||
${texCoord ? `@location(${vertexLocation++}) texCoord: vec2<f32>,` : ""}
|
${texCoord ? `@location(1) texCoord: vec2<f32>,` : ""}
|
||||||
${lightTexCoord ? `@location(${vertexLocation++}) lightTexCoord: vec2<f32>,` : ""}
|
${lightTexCoord ? `@location(2) lightTexCoord: vec2<f32>,` : ""}
|
||||||
${normal ? `@location(${vertexLocation++}) normalOS: vec3<f32>,` : ""}
|
${normal ? `@location(3) normalOS: vec3<f32>,` : ""}
|
||||||
${normal && tangent ? `@location(${vertexLocation++}) tangentOS: vec4<f32>,` : ""}
|
${normal && tangent ? `@location(4) tangentOS: vec4<f32>,` : ""}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Varyings {
|
struct Varyings {
|
||||||
|
Loading…
Reference in New Issue
Block a user