Work on public APIs

This commit is contained in:
Szymon Nowakowski 2023-07-30 21:28:48 +02:00 committed by Szymon Nowakowski
parent ef3a32420d
commit e794cbc172
8 changed files with 538 additions and 48 deletions

View File

@ -52,7 +52,33 @@ export class CameraOrthographic {
this._node = null; this._node = null;
} }
detach(): Camera { set name(value: string) { this._name = value; }
get name(): string { return this._name; }
set verticalSize(value: number) { this._verticalSize = value; }
get verticalSize(): number { return this._verticalSize; }
set nearPlane(value: number) { this._nearPlane = value; }
get nearPlane(): number { return this._nearPlane; }
set farPlane(value: number) { this._farPlane = value; }
get farPlane(): number { return this._farPlane; }
attach(node: Node): CameraOrthographic {
if (this._node !== null) {
this._node._camera = null;
}
if (node._camera !== null) {
node._camera._node = null;
}
node._camera = this;
this._node = node;
return this;
}
detach(): CameraOrthographic {
if (this._node === null) { if (this._node === null) {
return this; return this;
} }
@ -93,7 +119,30 @@ export class CameraPerspective {
this._node = null; this._node = null;
} }
detach(): Camera { set name(value: string) { this._name = value; }
get name(): string { return this._name; }
set nearPlane(value: number) { this._nearPlane = value; }
get nearPlane(): number { return this._nearPlane; }
set farPlane(value: number) { this._farPlane = value; }
get farPlane(): number { return this._farPlane; }
attach(node: Node): CameraPerspective {
if (this._node !== null) {
this._node._camera = null;
}
if (node._camera !== null) {
node._camera._node = null;
}
node._camera = this;
this._node = node;
return this;
}
detach(): CameraPerspective {
if (this._node === null) { if (this._node === null) {
return this; return this;
} }

View File

@ -90,6 +90,15 @@ export class Matrix4x4 {
return new Matrix4x4(...tuple); return new Matrix4x4(...tuple);
} }
static identity(): Matrix4x4 {
return new Matrix4x4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
)
}
static fromTranslation(translation: Vector3Object): Matrix4x4 { static fromTranslation(translation: Vector3Object): Matrix4x4 {
return new Matrix4x4( return new Matrix4x4(
1, 0, 0, 0, 1, 0, 0, 0,
@ -127,22 +136,22 @@ export class Matrix4x4 {
); );
} }
static fromTRS(t: Vector3Object, r: QuaternionObject, s: Vector3Object): Matrix4x4 { static fromTranslationRotationScale(translation: Vector3Object, rotation: QuaternionObject, scale: Vector3Object): Matrix4x4 {
const xx = r.x * r.x; const xx = rotation.x * rotation.x;
const xy = r.x * r.y; const xy = rotation.x * rotation.y;
const xz = r.x * r.z; const xz = rotation.x * rotation.z;
const xw = r.x * r.w; const xw = rotation.x * rotation.w;
const yy = r.y * r.y; const yy = rotation.y * rotation.y;
const yz = r.y * r.z; const yz = rotation.y * rotation.z;
const yw = r.y * r.w; const yw = rotation.y * rotation.w;
const zz = r.z * r.z; const zz = rotation.z * rotation.z;
const zw = r.z * r.w; const zw = rotation.z * rotation.w;
return new Matrix4x4( return new Matrix4x4(
s.x * (1 - 2 * (yy + zz)), s.x * 2 * (xy + zw), s.x * 2 * (xz - yw), 0, scale.x * (1 - 2 * (yy + zz)), scale.x * 2 * (xy + zw), scale.x * 2 * (xz - yw), 0,
s.y * 2 * (xy - zw), s.y * (1 - 2 * (xx + zz)), s.y * 2 * (yz + xw), 0, scale.y * 2 * (xy - zw), scale.y * (1 - 2 * (xx + zz)), scale.y * 2 * (yz + xw), 0,
s.z * 2 * (xz + yw), s.z * 2 * (yz - xw), s.z * (1 - 2 * (xx + yy)), 0, scale.z * 2 * (xz + yw), scale.z * 2 * (yz - xw), scale.z * (1 - 2 * (xx + yy)), 0,
t.x, t.y, t.z, 1, translation.x, translation.y, translation.z, 1,
); );
} }
@ -186,6 +195,26 @@ export class Matrix4x4 {
return this; return this;
} }
setIdentity(): Matrix4x4 {
this.ix = 1;
this.iy = 0;
this.iz = 0;
this.iw = 0;
this.jx = 0;
this.jy = 1;
this.jz = 0;
this.jw = 0;
this.kx = 0;
this.ky = 0;
this.kz = 1;
this.kw = 0;
this.tx = 0;
this.ty = 0;
this.tz = 0;
this.tw = 1;
return this;
}
setTranslation(translation: Vector3Object): Matrix4x4 { setTranslation(translation: Vector3Object): Matrix4x4 {
this.ix = 1; this.ix = 1;
this.iy = 0; this.iy = 0;
@ -256,58 +285,225 @@ export class Matrix4x4 {
return this; return this;
} }
setTRS(t: Vector3Object, r: QuaternionObject, s: Vector3Object): Matrix4x4 { setTranslationRotationScale(translation: Vector3Object, rotation: QuaternionObject, scale: Vector3Object): Matrix4x4 {
const xx = r.x * r.x; const xx = rotation.x * rotation.x;
const xy = r.x * r.y; const xy = rotation.x * rotation.y;
const xz = r.x * r.z; const xz = rotation.x * rotation.z;
const xw = r.x * r.w; const xw = rotation.x * rotation.w;
const yy = r.y * r.y; const yy = rotation.y * rotation.y;
const yz = r.y * r.z; const yz = rotation.y * rotation.z;
const yw = r.y * r.w; const yw = rotation.y * rotation.w;
const zz = r.z * r.z; const zz = rotation.z * rotation.z;
const zw = r.z * r.w; const zw = rotation.z * rotation.w;
this.ix = s.x * (1 - 2 * (yy + zz)); this.ix = scale.x * (1 - 2 * (yy + zz));
this.iy = s.x * 2 * (xy + zw); this.iy = scale.x * 2 * (xy + zw);
this.iz = s.x * 2 * (xz - yw); this.iz = scale.x * 2 * (xz - yw);
this.iw = 0; this.iw = 0;
this.jx = s.y * 2 * (xy - zw); this.jx = scale.y * 2 * (xy - zw);
this.jy = s.y * (1 - 2 * (xx + zz)); this.jy = scale.y * (1 - 2 * (xx + zz));
this.jz = s.y * 2 * (yz + xw); this.jz = scale.y * 2 * (yz + xw);
this.jw = 0; this.jw = 0;
this.kx = s.z * 2 * (xz + yw); this.kx = scale.z * 2 * (xz + yw);
this.ky = s.z * 2 * (yz - xw); this.ky = scale.z * 2 * (yz - xw);
this.kz = s.z * (1 - 2 * (xx + yy)); this.kz = scale.z * (1 - 2 * (xx + yy));
this.kw = 0; this.kw = 0;
this.tx = t.x; this.tx = translation.x;
this.ty = t.y; this.ty = translation.y;
this.tz = t.z; this.tz = translation.z;
this.tw = 1; this.tw = 1;
return this; return this;
} }
add(m: Matrix4x4): Matrix4x4 { addMatrix(m: Matrix4x4): Matrix4x4 {
throw new Error("TODO"); this.ix += m.ix;
this.iy += m.iy;
this.iz += m.iz;
this.iw += m.iw;
this.jx += m.jx;
this.jy += m.jy;
this.jz += m.jz;
this.jw += m.jw;
this.kx += m.kx;
this.ky += m.ky;
this.kz += m.kz;
this.kw += m.kw;
this.tx += m.tx;
this.ty += m.ty;
this.tz += m.tz;
this.tw += m.tw;
return this; return this;
} }
sub(m: Matrix4x4): Matrix4x4 { addMatrices(a: Matrix4x4, b: Matrix4x4): Matrix4x4 {
throw new Error("TODO"); this.ix = a.ix + b.ix;
this.iy = a.iy + b.iy;
this.iz = a.iz + b.iz;
this.iw = a.iw + b.iw;
this.jx = a.jx + b.jx;
this.jy = a.jy + b.jy;
this.jz = a.jz + b.jz;
this.jw = a.jw + b.jw;
this.kx = a.kx + b.kx;
this.ky = a.ky + b.ky;
this.kz = a.kz + b.kz;
this.kw = a.kw + b.kw;
this.tx = a.tx + b.tx;
this.ty = a.ty + b.ty;
this.tz = a.tz + b.tz;
this.tw = a.tw + b.tw;
return this;
}
subMatrix(m: Matrix4x4): Matrix4x4 {
this.ix -= m.ix;
this.iy -= m.iy;
this.iz -= m.iz;
this.iw -= m.iw;
this.jx -= m.jx;
this.jy -= m.jy;
this.jz -= m.jz;
this.jw -= m.jw;
this.kx -= m.kx;
this.ky -= m.ky;
this.kz -= m.kz;
this.kw -= m.kw;
this.tx -= m.tx;
this.ty -= m.ty;
this.tz -= m.tz;
this.tw -= m.tw;
return this;
}
subMatrices(a: Matrix4x4, b: Matrix4x4): Matrix4x4 {
this.ix = a.ix - b.ix;
this.iy = a.iy - b.iy;
this.iz = a.iz - b.iz;
this.iw = a.iw - b.iw;
this.jx = a.jx - b.jx;
this.jy = a.jy - b.jy;
this.jz = a.jz - b.jz;
this.jw = a.jw - b.jw;
this.kx = a.kx - b.kx;
this.ky = a.ky - b.ky;
this.kz = a.kz - b.kz;
this.kw = a.kw - b.kw;
this.tx = a.tx - b.tx;
this.ty = a.ty - b.ty;
this.tz = a.tz - b.tz;
this.tw = a.tw - b.tw;
return this;
}
negate(): Matrix4x4 {
this.ix = -this.ix;
this.iy = -this.iy;
this.iz = -this.iz;
this.iw = -this.iw;
this.jx = -this.jx;
this.jy = -this.jy;
this.jz = -this.jz;
this.jw = -this.jw;
this.kx = -this.kx;
this.ky = -this.ky;
this.kz = -this.kz;
this.kw = -this.kw;
this.tx = -this.tx;
this.ty = -this.ty;
this.tz = -this.tz;
this.tw = -this.tw;
return this; return this;
} }
mulScalar(k: number): Matrix4x4 { mulScalar(k: number): Matrix4x4 {
throw new Error("TODO"); this.ix *= k;
this.iy *= k;
this.iz *= k;
this.iw *= k;
this.jx *= k;
this.jy *= k;
this.jz *= k;
this.jw *= k;
this.kx *= k;
this.ky *= k;
this.kz *= k;
this.kw *= k;
this.tx *= k;
this.ty *= k;
this.tz *= k;
this.tw *= k;
return this; return this;
} }
mulMatrix(m: Matrix4x4): Matrix4x4 { mulMatrix(m: Matrix4x4): Matrix4x4 {
throw new Error("TODO"); const ix = this.ix * m.ix + this.jx * m.iy + this.kx * m.iz + this.tx * m.iw;
const iy = this.iy * m.ix + this.jy * m.iy + this.ky * m.iz + this.ty * m.iw;
const iz = this.iz * m.ix + this.jz * m.iy + this.kz * m.iz + this.tz * m.iw;
const iw = this.iw * m.ix + this.jw * m.iy + this.kw * m.iz + this.tw * m.iw;
const jx = this.ix * m.jx + this.jx * m.jy + this.kx * m.jz + this.tx * m.jw;
const jy = this.iy * m.jx + this.jy * m.jy + this.ky * m.jz + this.ty * m.jw;
const jz = this.iz * m.jx + this.jz * m.jy + this.kz * m.jz + this.tz * m.jw;
const jw = this.iw * m.jx + this.jw * m.jy + this.kw * m.jz + this.tw * m.jw;
const kx = this.ix * m.kx + this.jx * m.ky + this.kx * m.kz + this.tx * m.kw;
const ky = this.iy * m.kx + this.jy * m.ky + this.ky * m.kz + this.ty * m.kw;
const kz = this.iz * m.kx + this.jz * m.ky + this.kz * m.kz + this.tz * m.kw;
const kw = this.iw * m.kx + this.jw * m.ky + this.kw * m.kz + this.tw * m.kw;
const tx = this.ix * m.tx + this.jx * m.ty + this.kx * m.tz + this.tx * m.tw;
const ty = this.iy * m.tx + this.jy * m.ty + this.ky * m.tz + this.ty * m.tw;
const tz = this.iz * m.tx + this.jz * m.ty + this.kz * m.tz + this.tz * m.tw;
const tw = this.iw * m.tx + this.jw * m.ty + this.kw * m.tz + this.tw * m.tw;
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; return this;
} }
premulMatrix(m: Matrix4x4): Matrix4x4 { premulMatrix(m: Matrix4x4): Matrix4x4 {
throw new Error("TODO"); const ix = m.ix * this.ix + m.jx * this.iy + m.kx * this.iz + m.tx * this.iw;
const iy = m.iy * this.ix + m.jy * this.iy + m.ky * this.iz + m.ty * this.iw;
const iz = m.iz * this.ix + m.jz * this.iy + m.kz * this.iz + m.tz * this.iw;
const iw = m.iw * this.ix + m.jw * this.iy + m.kw * this.iz + m.tw * this.iw;
const jx = m.ix * this.jx + m.jx * this.jy + m.kx * this.jz + m.tx * this.jw;
const jy = m.iy * this.jx + m.jy * this.jy + m.ky * this.jz + m.ty * this.jw;
const jz = m.iz * this.jx + m.jz * this.jy + m.kz * this.jz + m.tz * this.jw;
const jw = m.iw * this.jx + m.jw * this.jy + m.kw * this.jz + m.tw * this.jw;
const kx = m.ix * this.kx + m.jx * this.ky + m.kx * this.kz + m.tx * this.kw;
const ky = m.iy * this.kx + m.jy * this.ky + m.ky * this.kz + m.ty * this.kw;
const kz = m.iz * this.kx + m.jz * this.ky + m.kz * this.kz + m.tz * this.kw;
const kw = m.iw * this.kx + m.jw * this.ky + m.kw * this.kz + m.tw * this.kw;
const tx = m.ix * this.tx + m.jx * this.ty + m.kx * this.tz + m.tx * this.tw;
const ty = m.iy * this.tx + m.jy * this.ty + m.ky * this.tz + m.ty * this.tw;
const tz = m.iz * this.tx + m.jz * this.ty + m.kz * this.tz + m.tz * this.tw;
const tw = m.iw * this.tx + m.jw * this.ty + m.kw * this.tz + m.tw * this.tw;
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; return this;
} }
} }

View File

@ -44,7 +44,10 @@ export class Node {
/** backreference */ /** backreference */
_parent: Node | null; _parent: Node | null;
_localMatrixNeedsUpdate: boolean;
_localMatrix: Matrix4x4; _localMatrix: Matrix4x4;
_worldMatrixNeedsUpdate: boolean;
_worldMatrix: Matrix4x4; _worldMatrix: Matrix4x4;
constructor({ constructor({
@ -71,8 +74,21 @@ export class Node {
this._parent = null; this._parent = null;
this._localMatrix = Matrix4x4.fromTRS(this._translation, this._rotation, this._scale); this._localMatrixNeedsUpdate = true;
this._worldMatrix = Matrix4x4.fromObject(this._localMatrix); this._localMatrix = new Matrix4x4(
NaN, NaN, NaN, NaN,
NaN, NaN, NaN, NaN,
NaN, NaN, NaN, NaN,
NaN, NaN, NaN, NaN,
);
this._worldMatrixNeedsUpdate = true;
this._worldMatrix = new Matrix4x4(
NaN, NaN, NaN, NaN,
NaN, NaN, NaN, NaN,
NaN, NaN, NaN, NaN,
NaN, NaN, NaN, NaN,
);
if (this._camera !== null) { if (this._camera !== null) {
this._camera._node = this; this._camera._node = this;
@ -84,6 +100,168 @@ export class Node {
} }
} }
} }
setTranslation(value: Vector3Object): Node {
this._translation.setObject(value);
this._localMatrixNeedsUpdate = true;
this._setWorldMatrixNeedsUpdateRecursive(true);
return this;
}
getTranslation(res: Vector3): Vector3 {
res.setObject(this._translation);
return res;
}
setRotation(value: QuaternionObject): Node {
this._rotation.setObject(value);
this._localMatrixNeedsUpdate = true;
this._setWorldMatrixNeedsUpdateRecursive(true);
return this;
}
getRotation(res: Quaternion): Quaternion {
res.setObject(this._rotation);
return res;
}
setScale(value: Vector3Object): Node {
this._scale.setObject(value);
this._localMatrixNeedsUpdate = true;
this._setWorldMatrixNeedsUpdateRecursive(true);
return this;
}
getScale(res: Vector3): Vector3 {
res.setObject(this._scale);
return res;
}
set camera(value: Camera | null) {
if (value !== null) {
this.attachCamera(value);
} else {
this.detachCamera();
}
}
get camera(): Camera | null { return this._camera; }
attachCamera(camera: Camera): Node {
if (this._camera !== null) {
this._camera._node = null;
}
this._camera = camera;
if (camera._node !== null) {
camera._node._camera = null;
}
camera._node = this;
this._camera = camera;
return this;
}
detachCamera(): Node {
if (this._camera === null) {
return this;
}
this._camera._node = null;
this._camera = null;
return this;
}
set mesh(value: Mesh | null) { this._mesh = value; }
get mesh(): Mesh | null { return this._mesh; }
setMaterials(value: readonly Material[]): Node {
this._materials.length = 0;
this._materials.push(...value);
return this;
}
getMaterials(res: Material[]): Material[] {
res.length = 0;
res.push(...this._materials);
return res;
}
// TODO children
set parent(value: Node | null) {
if (value !== null) {
this.attach(value);
} else {
this.detach();
}
}
get parent(): Node | null { return this._parent; }
attach(node: Node): Node {
if (this._parent !== null) {
this._parent._children.splice(this._parent._children.indexOf(this), 1);
}
node._children.push(this);
this._parent = node;
this._setWorldMatrixNeedsUpdateRecursive(true);
return this;
}
detach(): Node {
if (this._parent === null) {
return this;
}
this._parent._children.splice(this._parent._children.indexOf(this), 1);
this._parent = null;
this._setWorldMatrixNeedsUpdateRecursive(true);
return this;
}
getLocalMatrix(res: Matrix4x4): Matrix4x4 {
this._updateLocalMatrix();
res.setObject(this._localMatrix);
return res;
}
getWorldMatrix(res: Matrix4x4): Matrix4x4 {
this._updateWorldMatrix();
res.setObject(this._worldMatrix);
return res;
}
_updateLocalMatrix(): Node {
if (!this._localMatrixNeedsUpdate) {
return this;
}
this._localMatrix.setTranslationRotationScale(this._translation, this._rotation, this._scale);
this._localMatrixNeedsUpdate = false;
return this;
}
_updateWorldMatrix(): Node {
if (!this._worldMatrixNeedsUpdate) {
return this;
}
this._updateLocalMatrix();
if (this._parent !== null) {
this._parent.getWorldMatrix(this._worldMatrix);
this._worldMatrix.premulMatrix(this._localMatrix);
} else {
this._worldMatrix.setObject(this._localMatrix);
}
return this;
}
_setWorldMatrixNeedsUpdateRecursive(value: boolean): Node {
this._localMatrixNeedsUpdate = true;
for (const child of this._children) {
child._setWorldMatrixNeedsUpdateRecursive(value);
}
return this;
}
} }
Object.defineProperty(Node.prototype, "type", { value: "Node" }); Object.defineProperty(Node.prototype, "type", { value: "Node" });

View File

@ -28,6 +28,9 @@ export class Scene {
this._nodes = nodes; this._nodes = nodes;
} }
set name(value: string) { this._name = value; }
get name(): string { return this._name; }
} }
Object.defineProperty(Scene.prototype, "type", { value: "Scene" }); Object.defineProperty(Scene.prototype, "type", { value: "Scene" });

View File

@ -148,6 +148,10 @@ export class Renderer {
depthStoreOp: "store", depthStoreOp: "store",
}, },
}); });
void scene;
void camera;
pass.end(); pass.end();
const commandBuffer = encoder.finish(); const commandBuffer = encoder.finish();

View File

@ -107,7 +107,7 @@ export class IndexBuffer {
ensureSizeDiscard({ ensureSizeDiscard({
indexFormat = this._indexFormat, indexFormat = this._indexFormat,
indexCount = this.indexCount, indexCount = this.indexCount,
}): IndexBuffer { }: IndexBufferResizeProps): IndexBuffer {
if (this.indexCount >= indexCount && indexSize(this._indexFormat) >= indexSize(indexFormat)) { if (this.indexCount >= indexCount && indexSize(this._indexFormat) >= indexSize(indexFormat)) {
return this; return this;
} }

View File

@ -23,6 +23,12 @@ export interface Texture2DProps {
readonly format: Texture2DFormat; readonly format: Texture2DFormat;
} }
export interface Texture2DResizeProps {
readonly width?: number;
readonly height?: number;
readonly format?: Texture2DFormat;
}
export interface Texture2DAdvancedWriteProps { export interface Texture2DAdvancedWriteProps {
readonly origin: Vector2Object | Vector2Tuple, readonly origin: Vector2Object | Vector2Tuple,
readonly data: BufferSource | SharedArrayBuffer, readonly data: BufferSource | SharedArrayBuffer,
@ -69,6 +75,11 @@ export class Texture2D {
this._format = format; this._format = format;
} }
/**
* Destroys owned GPU resources. The texture should not be used after
* calling this method.
* @returns `this` for chaining
*/
dispose(): Texture2D { dispose(): Texture2D {
this._texture.destroy(); this._texture.destroy();
return this; return this;
@ -124,6 +135,36 @@ export class Texture2D {
); );
return this; return this;
} }
/**
* Resize the texture and/or change its format, discarding currently stored
* data.
* @param props Desired texture properties. Any unspecified property will
* stay unchanged.
* @returns `this` for chaining
*/
resizeDiscard({
width = this._texture.width,
height = this._texture.height,
format = this._format,
}: Texture2DResizeProps): Texture2D {
this._texture.destroy();
const gpuFormat = gpuTextureFormat(format);
this._texture = this._renderer._device.createTexture({
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
size: { width, height },
format: gpuFormat,
label: this._name
});
this._textureView = this._texture.createView({
format: gpuFormat,
dimension: "2d",
label: `${this._name}.textureView`,
});
return this;
}
} }
Object.defineProperty(Texture2D.prototype, "type", { value: "Texture2D" }); Object.defineProperty(Texture2D.prototype, "type", { value: "Texture2D" });

View File

@ -132,5 +132,24 @@ fn frag(fragment: Varyings) -> @location(0) vec2<f32> {
let occlusionTexel = texture(_OcclusionTexture, _Sampler, fragment.lightTexCoord); let occlusionTexel = texture(_OcclusionTexture, _Sampler, fragment.lightTexCoord);
occlusion += _Material.occlusionTextureStrength * (occlusionTexel.r - 1.0); occlusion += _Material.occlusionTextureStrength * (occlusionTexel.r - 1.0);
` : ""} ` : ""}
let positionVS = fragment.positionVS;
${normal ? `
let geometricNormalVS = fragment.normalVS;
` : `
let dPositionVSdx = dpdx(positionVS);
let dPositionVSdy = dpdy(positionVS);
let geometricNormalVS = normalize(cross(dPositionVSdx, dPositionVSdy));
let actualNormalVS = geometricNormalVS;
`}
${texCoord ? `
` : `
let actualNormalVS = geometricNormalVS;
`}
${tangent ? `
let tangentVS =
` : `
let actualNormalVS = geometricNormalVS;
`}
}`; }`;
} }