Light classes, gathering materials
This commit is contained in:
parent
7fef3c90d8
commit
94ad52397c
@ -1,4 +1,10 @@
|
|||||||
import { Matrix4x4Object, Vector2Object, Vector3Object, Vector4Object } from "./data";
|
/*!
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ColorObject, Matrix4x4Object, Vector2Object, Vector3Object, Vector4Object } from "./data";
|
||||||
|
|
||||||
export class _BinaryWriter {
|
export class _BinaryWriter {
|
||||||
|
|
||||||
@ -103,6 +109,13 @@ export class _BinaryWriter {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeColorF32(value: ColorObject): _BinaryWriter {
|
||||||
|
this.writeF32(value.r);
|
||||||
|
this.writeF32(value.g);
|
||||||
|
this.writeF32(value.b);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
alloc(byteLength: number): DataView {
|
alloc(byteLength: number): DataView {
|
||||||
this.ensureUnusedCapacity(byteLength);
|
this.ensureUnusedCapacity(byteLength);
|
||||||
const dataView = new DataView(this._buffer, this._length, byteLength);
|
const dataView = new DataView(this._buffer, this._length, byteLength);
|
||||||
|
29
src/_Mapping.ts
Normal file
29
src/_Mapping.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*!
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class _Mapping<T> {
|
||||||
|
table: T[];
|
||||||
|
map: Map<T, number>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.table = [];
|
||||||
|
this.map = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
add(item: T) {
|
||||||
|
if (this.map.has(item)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = this.table.length;
|
||||||
|
this.table.push(item);
|
||||||
|
this.map.set(item, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(item: T): number | undefined {
|
||||||
|
return this.map.get(item);
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
import { Node } from ".";
|
import { Node } from ".";
|
||||||
|
|
||||||
export type Camera = CameraOrthographic | CameraPerspective;
|
export type Camera = OrthographicCamera | PerspectiveCamera;
|
||||||
|
|
||||||
export interface CameraOrthographicProps {
|
export interface OrthographicCameraProps {
|
||||||
readonly name?: string;
|
readonly name?: string;
|
||||||
|
|
||||||
readonly verticalSize: number;
|
readonly verticalSize: number;
|
||||||
@ -16,7 +16,7 @@ export interface CameraOrthographicProps {
|
|||||||
readonly farPlane: number;
|
readonly farPlane: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CameraPerspectiveProps {
|
export interface PerspectiveCameraProps {
|
||||||
readonly name?: string;
|
readonly name?: string;
|
||||||
|
|
||||||
readonly verticalFovRad: number;
|
readonly verticalFovRad: number;
|
||||||
@ -24,9 +24,9 @@ export interface CameraPerspectiveProps {
|
|||||||
readonly farPlane: number;
|
readonly farPlane: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CameraOrthographic {
|
export class OrthographicCamera {
|
||||||
|
|
||||||
readonly type!: "CameraOrthographic";
|
readonly type!: "OrthographicCamera";
|
||||||
|
|
||||||
_name: string;
|
_name: string;
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export class CameraOrthographic {
|
|||||||
verticalSize,
|
verticalSize,
|
||||||
nearPlane,
|
nearPlane,
|
||||||
farPlane,
|
farPlane,
|
||||||
}: CameraOrthographicProps) {
|
}: OrthographicCameraProps) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
|
|
||||||
this._verticalSize = verticalSize;
|
this._verticalSize = verticalSize;
|
||||||
@ -64,7 +64,7 @@ export class CameraOrthographic {
|
|||||||
set farPlane(value: number) { this._farPlane = value; }
|
set farPlane(value: number) { this._farPlane = value; }
|
||||||
get farPlane(): number { return this._farPlane; }
|
get farPlane(): number { return this._farPlane; }
|
||||||
|
|
||||||
attach(node: Node): CameraOrthographic {
|
attach(node: Node): OrthographicCamera {
|
||||||
if (this._node !== null) {
|
if (this._node !== null) {
|
||||||
this._node._camera = null;
|
this._node._camera = null;
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ export class CameraOrthographic {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
detach(): CameraOrthographic {
|
detach(): OrthographicCamera {
|
||||||
if (this._node === null) {
|
if (this._node === null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -89,11 +89,9 @@ export class CameraOrthographic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(CameraOrthographic.prototype, "type", { value: "CameraOrthographic" });
|
export class PerspectiveCamera {
|
||||||
|
|
||||||
export class CameraPerspective {
|
readonly type!: "PerspectiveCamera";
|
||||||
|
|
||||||
readonly type!: "CameraPerspective";
|
|
||||||
|
|
||||||
_name: string;
|
_name: string;
|
||||||
|
|
||||||
@ -109,7 +107,7 @@ export class CameraPerspective {
|
|||||||
verticalFovRad,
|
verticalFovRad,
|
||||||
nearPlane,
|
nearPlane,
|
||||||
farPlane,
|
farPlane,
|
||||||
}: CameraPerspectiveProps) {
|
}: PerspectiveCameraProps) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
|
|
||||||
this._verticalFovRad = verticalFovRad;
|
this._verticalFovRad = verticalFovRad;
|
||||||
@ -128,7 +126,7 @@ export class CameraPerspective {
|
|||||||
set farPlane(value: number) { this._farPlane = value; }
|
set farPlane(value: number) { this._farPlane = value; }
|
||||||
get farPlane(): number { return this._farPlane; }
|
get farPlane(): number { return this._farPlane; }
|
||||||
|
|
||||||
attach(node: Node): CameraPerspective {
|
attach(node: Node): PerspectiveCamera {
|
||||||
if (this._node !== null) {
|
if (this._node !== null) {
|
||||||
this._node._camera = null;
|
this._node._camera = null;
|
||||||
}
|
}
|
||||||
@ -142,7 +140,7 @@ export class CameraPerspective {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
detach(): CameraPerspective {
|
detach(): PerspectiveCamera {
|
||||||
if (this._node === null) {
|
if (this._node === null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -153,12 +151,14 @@ export class CameraPerspective {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(CameraPerspective.prototype, "type", { value: "CameraPerspective" });
|
Object.defineProperty(OrthographicCamera.prototype, "type", { value: "OrthographicCamera" });
|
||||||
|
|
||||||
export function isCameraOrthographic(value: unknown): value is CameraOrthographic {
|
Object.defineProperty(PerspectiveCamera.prototype, "type", { value: "PerspectiveCamera" });
|
||||||
return Boolean(value) && (value as CameraOrthographic).type === "CameraOrthographic";
|
|
||||||
|
export function isOrthographicCamera(value: unknown): value is OrthographicCamera {
|
||||||
|
return Boolean(value) && (value as OrthographicCamera).type === "OrthographicCamera";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCameraPerspective(value: unknown): value is CameraPerspective {
|
export function isPerspectiveCamera(value: unknown): value is PerspectiveCamera {
|
||||||
return Boolean(value) && (value as CameraPerspective).type === "CameraPerspective";
|
return Boolean(value) && (value as PerspectiveCamera).type === "PerspectiveCamera";
|
||||||
}
|
}
|
||||||
|
151
src/data/Light.ts
Normal file
151
src/data/Light.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*!
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Color, ColorObject, Node } from ".";
|
||||||
|
|
||||||
|
export type Light = DirectionalLight | PointLight;
|
||||||
|
|
||||||
|
export interface DirectionalLightProps {
|
||||||
|
readonly name?: string;
|
||||||
|
|
||||||
|
readonly color: ColorObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PointLightProps {
|
||||||
|
readonly name?: string;
|
||||||
|
|
||||||
|
readonly color: ColorObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DirectionalLight {
|
||||||
|
|
||||||
|
readonly type!: "DirectionalLight";
|
||||||
|
|
||||||
|
_name: string;
|
||||||
|
|
||||||
|
_color: Color;
|
||||||
|
|
||||||
|
/** backreference */
|
||||||
|
_node: Node | null;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
name = "",
|
||||||
|
color,
|
||||||
|
}: DirectionalLightProps) {
|
||||||
|
this._name = name;
|
||||||
|
|
||||||
|
this._color = Color.fromObject(color);
|
||||||
|
|
||||||
|
this._node = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set name(value: string) { this._name = value; }
|
||||||
|
get name(): string { return this._name; }
|
||||||
|
|
||||||
|
setColor(value: ColorObject): DirectionalLight {
|
||||||
|
this._color.setObject(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getColor(res: Color): Color {
|
||||||
|
return res.setObject(this._color);
|
||||||
|
}
|
||||||
|
|
||||||
|
attach(node: Node): DirectionalLight {
|
||||||
|
if (this._node !== null) {
|
||||||
|
this._node._light = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node._light !== null) {
|
||||||
|
node._light._node = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
node._light = this;
|
||||||
|
this._node = node;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
detach(): DirectionalLight {
|
||||||
|
if (this._node === null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._node._light = null;
|
||||||
|
this._node = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PointLight {
|
||||||
|
|
||||||
|
readonly type!: "PointLight";
|
||||||
|
|
||||||
|
_name: string;
|
||||||
|
|
||||||
|
_color: Color;
|
||||||
|
|
||||||
|
/** backreference */
|
||||||
|
_node: Node | null;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
name = "",
|
||||||
|
color,
|
||||||
|
}: PointLightProps) {
|
||||||
|
this._name = name;
|
||||||
|
|
||||||
|
this._color = Color.fromObject(color);
|
||||||
|
|
||||||
|
this._node = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set name(value: string) { this._name = value; }
|
||||||
|
get name(): string { return this._name; }
|
||||||
|
|
||||||
|
setColor(value: ColorObject): PointLight {
|
||||||
|
this._color.setObject(value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getColor(res: Color): Color {
|
||||||
|
return res.setObject(this._color);
|
||||||
|
}
|
||||||
|
|
||||||
|
attach(node: Node): PointLight {
|
||||||
|
if (this._node !== null) {
|
||||||
|
this._node._light = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node._light !== null) {
|
||||||
|
node._light._node = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
node._light = this;
|
||||||
|
this._node = node;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
detach(): PointLight {
|
||||||
|
if (this._node === null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._node._light = null;
|
||||||
|
this._node = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(DirectionalLight.prototype, "type", { value: "DirectionalLight" });
|
||||||
|
|
||||||
|
Object.defineProperty(PointLight.prototype, "type", { value: "PointLight" });
|
||||||
|
|
||||||
|
export function isDirectionalLight(value: unknown): value is DirectionalLight {
|
||||||
|
return Boolean(value) && (value as DirectionalLight).type === "DirectionalLight";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPointLight(value: unknown): value is PointLight {
|
||||||
|
return Boolean(value) && (value as PointLight).type === "PointLight";
|
||||||
|
}
|
@ -4,9 +4,8 @@
|
|||||||
* obtain one at http://mozilla.org/MPL/2.0/.
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Texture2D } from ".";
|
import { Color, ColorObject } from ".";
|
||||||
import { Color, ColorObject } from "../data";
|
import { Texture2D } from "../resources";
|
||||||
import { Renderer } from "../oktaeder";
|
|
||||||
|
|
||||||
export const UNIFORM_BUFFER_SIZE = 64;
|
export const UNIFORM_BUFFER_SIZE = 64;
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ export interface MaterialProps {
|
|||||||
|
|
||||||
baseColorPartialCoverageTexture?: Texture2D | null;
|
baseColorPartialCoverageTexture?: Texture2D | null;
|
||||||
occlusionTexture?: Texture2D | null;
|
occlusionTexture?: Texture2D | null;
|
||||||
metallicRoughnessTexture?: Texture2D | null;
|
roughnessMetallicTexture?: Texture2D | null;
|
||||||
normalTexture?: Texture2D | null;
|
normalTexture?: Texture2D | null;
|
||||||
emissiveTexture?: Texture2D | null;
|
emissiveTexture?: Texture2D | null;
|
||||||
transmissionCollimationTexture?: Texture2D | null;
|
transmissionCollimationTexture?: Texture2D | null;
|
||||||
@ -38,7 +37,6 @@ export interface MaterialProps {
|
|||||||
export class Material {
|
export class Material {
|
||||||
|
|
||||||
readonly type!: "Material";
|
readonly type!: "Material";
|
||||||
_renderer: Renderer;
|
|
||||||
|
|
||||||
_name: string;
|
_name: string;
|
||||||
|
|
||||||
@ -55,7 +53,7 @@ export class Material {
|
|||||||
|
|
||||||
_baseColorPartialCoverageTexture: Texture2D | null;
|
_baseColorPartialCoverageTexture: Texture2D | null;
|
||||||
_occlusionTexture: Texture2D | null;
|
_occlusionTexture: Texture2D | null;
|
||||||
_metallicRoughnessTexture: Texture2D | null;
|
_roughnessMetallicTexture: Texture2D | null;
|
||||||
_normalTexture: Texture2D | null;
|
_normalTexture: Texture2D | null;
|
||||||
_emissiveTexture: Texture2D | null;
|
_emissiveTexture: Texture2D | null;
|
||||||
_transmissionCollimationTexture: Texture2D | null;
|
_transmissionCollimationTexture: Texture2D | null;
|
||||||
@ -63,7 +61,7 @@ export class Material {
|
|||||||
_transparent: boolean;
|
_transparent: boolean;
|
||||||
_doubleSided: boolean;
|
_doubleSided: boolean;
|
||||||
|
|
||||||
constructor(renderer: Renderer, {
|
constructor({
|
||||||
name = "",
|
name = "",
|
||||||
baseColor,
|
baseColor,
|
||||||
partialCoverage = 1,
|
partialCoverage = 1,
|
||||||
@ -77,15 +75,13 @@ export class Material {
|
|||||||
ior = 1.45,
|
ior = 1.45,
|
||||||
baseColorPartialCoverageTexture = null,
|
baseColorPartialCoverageTexture = null,
|
||||||
occlusionTexture = null,
|
occlusionTexture = null,
|
||||||
metallicRoughnessTexture = null,
|
roughnessMetallicTexture = null,
|
||||||
normalTexture = null,
|
normalTexture = null,
|
||||||
emissiveTexture = null,
|
emissiveTexture = null,
|
||||||
transmissionCollimationTexture = null,
|
transmissionCollimationTexture = null,
|
||||||
transparent = false,
|
transparent = false,
|
||||||
doubleSided = false,
|
doubleSided = false,
|
||||||
}: MaterialProps) {
|
}: MaterialProps) {
|
||||||
this._renderer = renderer;
|
|
||||||
|
|
||||||
this._name = name;
|
this._name = name;
|
||||||
|
|
||||||
this._baseColor = baseColor !== undefined ? Color.fromObject(baseColor) : Color.white();
|
this._baseColor = baseColor !== undefined ? Color.fromObject(baseColor) : Color.white();
|
||||||
@ -101,7 +97,7 @@ export class Material {
|
|||||||
|
|
||||||
this._baseColorPartialCoverageTexture = baseColorPartialCoverageTexture;
|
this._baseColorPartialCoverageTexture = baseColorPartialCoverageTexture;
|
||||||
this._occlusionTexture = occlusionTexture;
|
this._occlusionTexture = occlusionTexture;
|
||||||
this._metallicRoughnessTexture = metallicRoughnessTexture;
|
this._roughnessMetallicTexture = roughnessMetallicTexture;
|
||||||
this._normalTexture = normalTexture;
|
this._normalTexture = normalTexture;
|
||||||
this._emissiveTexture = emissiveTexture;
|
this._emissiveTexture = emissiveTexture;
|
||||||
this._transmissionCollimationTexture = transmissionCollimationTexture;
|
this._transmissionCollimationTexture = transmissionCollimationTexture;
|
||||||
@ -109,15 +105,6 @@ export class Material {
|
|||||||
this._transparent = transparent;
|
this._transparent = transparent;
|
||||||
this._doubleSided = doubleSided;
|
this._doubleSided = doubleSided;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys owned GPU resources. The material should not be used after
|
|
||||||
* calling this method.
|
|
||||||
* @returns `this` for chaining
|
|
||||||
*/
|
|
||||||
dispose(): Material {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(Material.prototype, "type", { value: "Material" });
|
Object.defineProperty(Material.prototype, "type", { value: "Material" });
|
@ -4,8 +4,7 @@
|
|||||||
* obtain one at http://mozilla.org/MPL/2.0/.
|
* obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Camera, Matrix4x4, Mesh, Quaternion, QuaternionObject, Vector3, Vector3Object } from ".";
|
import { Camera, Light, Material, Matrix4x4, Mesh, Quaternion, QuaternionObject, Vector3, Vector3Object } from ".";
|
||||||
import { Material } from "../resources";
|
|
||||||
|
|
||||||
export interface NodeProps {
|
export interface NodeProps {
|
||||||
readonly name?: string;
|
readonly name?: string;
|
||||||
@ -15,6 +14,7 @@ export interface NodeProps {
|
|||||||
readonly scale?: Vector3Object;
|
readonly scale?: Vector3Object;
|
||||||
|
|
||||||
readonly camera?: Camera | null;
|
readonly camera?: Camera | null;
|
||||||
|
readonly light?: Light | null;
|
||||||
readonly mesh?: Mesh | null;
|
readonly mesh?: Mesh | null;
|
||||||
readonly materials?: Material[];
|
readonly materials?: Material[];
|
||||||
|
|
||||||
@ -33,6 +33,8 @@ export class Node {
|
|||||||
|
|
||||||
/** unique */
|
/** unique */
|
||||||
_camera: Camera | null;
|
_camera: Camera | null;
|
||||||
|
/** unique */
|
||||||
|
_light: Light | null;
|
||||||
/** shared */
|
/** shared */
|
||||||
_mesh: Mesh | null;
|
_mesh: Mesh | null;
|
||||||
/** shared */
|
/** shared */
|
||||||
@ -56,6 +58,7 @@ export class Node {
|
|||||||
rotation,
|
rotation,
|
||||||
scale,
|
scale,
|
||||||
camera = null,
|
camera = null,
|
||||||
|
light = null,
|
||||||
mesh = null,
|
mesh = null,
|
||||||
materials = [],
|
materials = [],
|
||||||
children = [],
|
children = [],
|
||||||
@ -67,6 +70,7 @@ export class Node {
|
|||||||
this._scale = scale !== undefined ? Vector3.fromObject(scale) : Vector3.one();
|
this._scale = scale !== undefined ? Vector3.fromObject(scale) : Vector3.one();
|
||||||
|
|
||||||
this._camera = camera;
|
this._camera = camera;
|
||||||
|
this._light = light;
|
||||||
this._mesh = mesh;
|
this._mesh = mesh;
|
||||||
this._materials = materials;
|
this._materials = materials;
|
||||||
|
|
||||||
@ -94,6 +98,10 @@ export class Node {
|
|||||||
this._camera._node = this;
|
this._camera._node = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._light !== null) {
|
||||||
|
this._light._node = this;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._children !== null) {
|
if (this._children !== null) {
|
||||||
for (const child of this._children) {
|
for (const child of this._children) {
|
||||||
child._parent = this;
|
child._parent = this;
|
||||||
@ -101,6 +109,9 @@ export class Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set name(value: string) { this._name = value; }
|
||||||
|
get name(): string { return this._name; }
|
||||||
|
|
||||||
setTranslation(value: Vector3Object): Node {
|
setTranslation(value: Vector3Object): Node {
|
||||||
this._translation.setObject(value);
|
this._translation.setObject(value);
|
||||||
this._localMatrixNeedsUpdate = true;
|
this._localMatrixNeedsUpdate = true;
|
||||||
@ -109,8 +120,7 @@ export class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTranslation(res: Vector3): Vector3 {
|
getTranslation(res: Vector3): Vector3 {
|
||||||
res.setObject(this._translation);
|
return res.setObject(this._translation);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setRotation(value: QuaternionObject): Node {
|
setRotation(value: QuaternionObject): Node {
|
||||||
@ -121,8 +131,7 @@ export class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getRotation(res: Quaternion): Quaternion {
|
getRotation(res: Quaternion): Quaternion {
|
||||||
res.setObject(this._rotation);
|
return res.setObject(this._rotation);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setScale(value: Vector3Object): Node {
|
setScale(value: Vector3Object): Node {
|
||||||
@ -133,8 +142,7 @@ export class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getScale(res: Vector3): Vector3 {
|
getScale(res: Vector3): Vector3 {
|
||||||
res.setObject(this._scale);
|
return res.setObject(this._scale);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set camera(value: Camera | null) {
|
set camera(value: Camera | null) {
|
||||||
@ -172,6 +180,41 @@ export class Node {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set light(value: Light | null) {
|
||||||
|
if (value !== null) {
|
||||||
|
this.attachLight(value);
|
||||||
|
} else {
|
||||||
|
this.detachLight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get light(): Light | null { return this._light; }
|
||||||
|
|
||||||
|
attachLight(light: Light): Node {
|
||||||
|
if (this._light !== null) {
|
||||||
|
this._light._node = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._light = light;
|
||||||
|
|
||||||
|
if (light._node !== null) {
|
||||||
|
light._node._light = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
light._node = this;
|
||||||
|
this._light = light;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
detachLight(): Node {
|
||||||
|
if (this._light === null) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._light._node = null;
|
||||||
|
this._light = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
set mesh(value: Mesh | null) { this._mesh = value; }
|
set mesh(value: Mesh | null) { this._mesh = value; }
|
||||||
get mesh(): Mesh | null { return this._mesh; }
|
get mesh(): Mesh | null { return this._mesh; }
|
||||||
|
|
||||||
@ -269,3 +312,10 @@ Object.defineProperty(Node.prototype, "type", { value: "Node" });
|
|||||||
export function isNode(value: unknown): value is Node {
|
export function isNode(value: unknown): value is Node {
|
||||||
return Boolean(value) && (value as Node).type === "Node";
|
return Boolean(value) && (value as Node).type === "Node";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* preOrder(nodes: Iterable<Node>): Generator<Node, void, undefined> {
|
||||||
|
for (const node of nodes) {
|
||||||
|
yield node;
|
||||||
|
yield* node._children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
export * from "./Camera";
|
export * from "./Camera";
|
||||||
export * from "./Color";
|
export * from "./Color";
|
||||||
|
export * from "./Light";
|
||||||
|
export * from "./Material";
|
||||||
export * from "./Matrix4x4";
|
export * from "./Matrix4x4";
|
||||||
export * from "./Mesh";
|
export * from "./Mesh";
|
||||||
export * from "./Node";
|
export * from "./Node";
|
||||||
|
112
src/oktaeder.ts
112
src/oktaeder.ts
@ -8,8 +8,9 @@ export * from "./_BinaryWriter";
|
|||||||
export * from "./shader";
|
export * from "./shader";
|
||||||
|
|
||||||
import { _BinaryWriter as BinaryWriter } from "./_BinaryWriter";
|
import { _BinaryWriter as BinaryWriter } from "./_BinaryWriter";
|
||||||
import { Camera, Scene } from "./data";
|
import { _Mapping as Mapping } from "./_Mapping";
|
||||||
import { IndexBuffer, IndexBufferProps, Material, MaterialProps, Texture2D, Texture2DProps, VertexBuffer, VertexBufferProps } from "./resources";
|
import { Camera, Material, Node, Scene, preOrder } from "./data";
|
||||||
|
import { IndexBuffer, IndexBufferProps, Texture2D, Texture2DProps, VertexBuffer, VertexBufferProps } from "./resources";
|
||||||
import { ShaderFlagKey, ShaderFlags, createPipeline, shaderFlagsKey } from "./shader";
|
import { ShaderFlagKey, ShaderFlags, createPipeline, shaderFlagsKey } from "./shader";
|
||||||
|
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
@ -36,6 +37,13 @@ export class Renderer {
|
|||||||
_pipelineCache: Map<ShaderFlagKey, GPURenderPipeline>;
|
_pipelineCache: Map<ShaderFlagKey, GPURenderPipeline>;
|
||||||
|
|
||||||
_uniformWriter: BinaryWriter;
|
_uniformWriter: BinaryWriter;
|
||||||
|
_uniformBuffer: GPUBuffer;
|
||||||
|
_directionalLightBuffer: GPUBuffer;
|
||||||
|
_pointLightBuffer: GPUBuffer;
|
||||||
|
|
||||||
|
_sampler: GPUSampler;
|
||||||
|
|
||||||
|
_objectBindGroup: GPUBindGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor is intended primarily for internal use. Consider using
|
* This constructor is intended primarily for internal use. Consider using
|
||||||
@ -204,6 +212,37 @@ export class Renderer {
|
|||||||
this._pipelineCache = new Map();
|
this._pipelineCache = new Map();
|
||||||
|
|
||||||
this._uniformWriter = new BinaryWriter();
|
this._uniformWriter = new BinaryWriter();
|
||||||
|
this._uniformBuffer = device.createBuffer({
|
||||||
|
size: 4 * 1024 * 1024,
|
||||||
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,
|
||||||
|
label: "Uniform",
|
||||||
|
});
|
||||||
|
this._directionalLightBuffer = device.createBuffer({
|
||||||
|
size: 1024 * 32,
|
||||||
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
||||||
|
});
|
||||||
|
this._pointLightBuffer = device.createBuffer({
|
||||||
|
size: 1024 * 32,
|
||||||
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._sampler = device.createSampler({
|
||||||
|
addressModeU: "repeat",
|
||||||
|
addressModeV: "repeat",
|
||||||
|
addressModeW: "repeat",
|
||||||
|
magFilter: "linear",
|
||||||
|
minFilter: "linear",
|
||||||
|
mipmapFilter: "linear",
|
||||||
|
maxAnisotropy: 16,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._objectBindGroup = device.createBindGroup({
|
||||||
|
layout: this._objectBindGroupLayout,
|
||||||
|
entries: [
|
||||||
|
{ binding: 0, resource: { buffer: this._uniformBuffer } },
|
||||||
|
],
|
||||||
|
label: "Object",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static async init(canvas: HTMLCanvasElement): Promise<Renderer> {
|
static async init(canvas: HTMLCanvasElement): Promise<Renderer> {
|
||||||
@ -242,6 +281,9 @@ export class Renderer {
|
|||||||
this._textureBlack.dispose();
|
this._textureBlack.dispose();
|
||||||
this._textureNormal.dispose();
|
this._textureNormal.dispose();
|
||||||
this._depthBuffer.dispose();
|
this._depthBuffer.dispose();
|
||||||
|
this._uniformBuffer.destroy();
|
||||||
|
this._directionalLightBuffer.destroy();
|
||||||
|
this._pointLightBuffer.destroy();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,10 +291,6 @@ export class Renderer {
|
|||||||
return new IndexBuffer(this, props);
|
return new IndexBuffer(this, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
createMaterial(props: MaterialProps): Material {
|
|
||||||
return new Material(this, props);
|
|
||||||
}
|
|
||||||
|
|
||||||
createTexture(props: Texture2DProps): Texture2D {
|
createTexture(props: Texture2DProps): Texture2D {
|
||||||
return new Texture2D(this, props);
|
return new Texture2D(this, props);
|
||||||
}
|
}
|
||||||
@ -299,8 +337,66 @@ export class Renderer {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
void scene;
|
this._uniformWriter.clear();
|
||||||
void camera;
|
|
||||||
|
// material gather
|
||||||
|
|
||||||
|
const materialMapping = new Mapping<Material>();
|
||||||
|
for (const node of preOrder(scene._nodes)) {
|
||||||
|
for (const material of node._materials) {
|
||||||
|
materialMapping.add(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const materialBindGroups = materialMapping.table.map((material) => {
|
||||||
|
const offset = this._uniformWriter._length;
|
||||||
|
this._uniformWriter.writeColorF32(material._baseColor);
|
||||||
|
this._uniformWriter.writeF32(material._partialCoverage);
|
||||||
|
this._uniformWriter.writeColorF32(material._transmission);
|
||||||
|
this._uniformWriter.writeF32(material._collimation);
|
||||||
|
this._uniformWriter.writeF32(material._occlusionTextureStrength);
|
||||||
|
this._uniformWriter.writeF32(material._roughness);
|
||||||
|
this._uniformWriter.writeF32(material._metallic);
|
||||||
|
this._uniformWriter.writeF32(material._normalScale);
|
||||||
|
this._uniformWriter.writeColorF32(material._emissive);
|
||||||
|
this._uniformWriter.writeF32(material._ior);
|
||||||
|
|
||||||
|
const bindGroup = this._device.createBindGroup({
|
||||||
|
layout: this._materialBindGroupLayout,
|
||||||
|
entries: [
|
||||||
|
{ binding: 0, resource: { buffer: this._uniformBuffer } },
|
||||||
|
{ binding: 1, resource: this._sampler },
|
||||||
|
{ binding: 2, resource: material._baseColorPartialCoverageTexture?._textureView ?? this._textureWhite._textureView },
|
||||||
|
{ binding: 3, resource: material._occlusionTexture?._textureView ?? this._textureWhite._textureView },
|
||||||
|
{ binding: 4, resource: material._roughnessMetallicTexture?._textureView ?? this._textureWhite._textureView },
|
||||||
|
{ binding: 5, resource: material._normalTexture?._textureView ?? this._textureNormal._textureView },
|
||||||
|
{ binding: 6, resource: material._emissiveTexture?._textureView ?? this._textureWhite._textureView },
|
||||||
|
{ binding: 7, resource: material._transmissionCollimationTexture?._textureView ?? this._textureBlack._textureView },
|
||||||
|
],
|
||||||
|
label: material._name,
|
||||||
|
});
|
||||||
|
return { offset, bindGroup };
|
||||||
|
});
|
||||||
|
|
||||||
|
// object gather
|
||||||
|
|
||||||
|
const objectMapping = new Mapping<Node>();
|
||||||
|
for (const node of preOrder(scene._nodes)) {
|
||||||
|
if (node._mesh !== null) {
|
||||||
|
objectMapping.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectOffsets = objectMapping.table.map((object) => {
|
||||||
|
const offset = this._uniformWriter._length;
|
||||||
|
object._updateWorldMatrix();
|
||||||
|
this._uniformWriter.writeMatrix4x4(object._worldMatrix);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
});
|
||||||
|
|
||||||
|
void materialBindGroups;
|
||||||
|
void objectOffsets;
|
||||||
|
|
||||||
pass.end();
|
pass.end();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user