@luma.gl/engine 9.0.0-alpha.3 → 9.0.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -1
- package/dist/animation/key-frames.d.ts +1 -1
- package/dist/animation/key-frames.d.ts.map +1 -1
- package/dist/animation/key-frames.js +0 -20
- package/dist/animation/key-frames.js.map +1 -1
- package/dist/animation/timeline.d.ts +5 -5
- package/dist/animation/timeline.d.ts.map +1 -1
- package/dist/animation/timeline.js +0 -30
- package/dist/animation/timeline.js.map +1 -1
- package/dist/{lib → animation-loop}/animation-loop.d.ts +28 -29
- package/dist/animation-loop/animation-loop.d.ts.map +1 -0
- package/dist/{lib → animation-loop}/animation-loop.js +96 -175
- package/dist/animation-loop/animation-loop.js.map +1 -0
- package/dist/{lib → animation-loop}/animation-props.d.ts +7 -7
- package/dist/animation-loop/animation-props.d.ts.map +1 -0
- package/dist/animation-loop/animation-props.js.map +1 -0
- package/dist/animation-loop/make-animation-loop.d.ts +6 -0
- package/dist/animation-loop/make-animation-loop.d.ts.map +1 -0
- package/dist/animation-loop/make-animation-loop.js +28 -0
- package/dist/animation-loop/make-animation-loop.js.map +1 -0
- package/dist/animation-loop/render-loop.d.ts +23 -0
- package/dist/animation-loop/render-loop.d.ts.map +1 -0
- package/dist/animation-loop/render-loop.js +7 -0
- package/dist/animation-loop/render-loop.js.map +1 -0
- package/dist/dist.dev.js +14887 -0
- package/dist/geometries/cone-geometry.d.ts +1 -1
- package/dist/geometries/cone-geometry.d.ts.map +1 -1
- package/dist/geometries/cone-geometry.js +6 -5
- package/dist/geometries/cone-geometry.js.map +1 -1
- package/dist/geometries/cube-geometry.d.ts +2 -2
- package/dist/geometries/cube-geometry.d.ts.map +1 -1
- package/dist/geometries/cube-geometry.js +15 -8
- package/dist/geometries/cube-geometry.js.map +1 -1
- package/dist/geometries/cylinder-geometry.d.ts +1 -1
- package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
- package/dist/geometries/cylinder-geometry.js +6 -5
- package/dist/geometries/cylinder-geometry.js.map +1 -1
- package/dist/geometries/ico-sphere-geometry.d.ts +2 -2
- package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/ico-sphere-geometry.js +9 -18
- package/dist/geometries/ico-sphere-geometry.js.map +1 -1
- package/dist/geometries/plane-geometry.d.ts +2 -2
- package/dist/geometries/plane-geometry.d.ts.map +1 -1
- package/dist/geometries/plane-geometry.js +10 -19
- package/dist/geometries/plane-geometry.js.map +1 -1
- package/dist/geometries/sphere-geometry.d.ts +2 -2
- package/dist/geometries/sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/sphere-geometry.js +9 -13
- package/dist/geometries/sphere-geometry.js.map +1 -1
- package/dist/geometries/truncated-cone-geometry.d.ts +2 -2
- package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
- package/dist/geometries/truncated-cone-geometry.js +9 -14
- package/dist/geometries/truncated-cone-geometry.js.map +1 -1
- package/dist/geometry/geometry-table.d.ts +2 -2
- package/dist/geometry/geometry-table.d.ts.map +1 -1
- package/dist/geometry/geometry-table.js.map +1 -1
- package/dist/geometry/geometry-utils.d.ts.map +1 -1
- package/dist/geometry/geometry-utils.js +0 -9
- package/dist/geometry/geometry-utils.js.map +1 -1
- package/dist/geometry/geometry.d.ts +35 -58
- package/dist/geometry/geometry.d.ts.map +1 -1
- package/dist/geometry/geometry.js +26 -89
- package/dist/geometry/geometry.js.map +1 -1
- package/dist/geometry/primitive-utils.js.map +1 -1
- package/dist/index.cjs +2574 -0
- package/dist/index.d.ts +18 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/clip-space.d.ts +8 -0
- package/dist/lib/clip-space.d.ts.map +1 -1
- package/dist/lib/clip-space.js +36 -1
- package/dist/lib/clip-space.js.map +1 -1
- package/dist/lib/pipeline-factory.d.ts +19 -14
- package/dist/lib/pipeline-factory.d.ts.map +1 -1
- package/dist/lib/pipeline-factory.js +52 -63
- package/dist/lib/pipeline-factory.js.map +1 -1
- package/dist/{lib → model}/model-utils.d.ts +2 -2
- package/dist/model/model-utils.d.ts.map +1 -0
- package/dist/{lib → model}/model-utils.js +3 -8
- package/dist/model/model-utils.js.map +1 -0
- package/dist/model/model.d.ts +65 -0
- package/dist/model/model.d.ts.map +1 -0
- package/dist/{lib → model}/model.js +56 -75
- package/dist/model/model.js.map +1 -0
- package/dist/scenegraph/group-node.d.ts +21 -0
- package/dist/scenegraph/group-node.d.ts.map +1 -0
- package/dist/scenegraph/group-node.js +95 -0
- package/dist/scenegraph/group-node.js.map +1 -0
- package/dist/scenegraph/model-node.d.ts +18 -0
- package/dist/scenegraph/model-node.d.ts.map +1 -0
- package/dist/scenegraph/model-node.js +29 -0
- package/dist/scenegraph/model-node.js.map +1 -0
- package/dist/scenegraph/scenegraph-node.d.ts +56 -0
- package/dist/scenegraph/scenegraph-node.d.ts.map +1 -0
- package/dist/scenegraph/scenegraph-node.js +142 -0
- package/dist/scenegraph/scenegraph-node.js.map +1 -0
- package/dist/transform/transform.d.ts +98 -0
- package/dist/transform/transform.d.ts.map +1 -0
- package/dist/transform/transform.js +67 -0
- package/dist/transform/transform.js.map +1 -0
- package/dist.min.js +314 -0
- package/package.json +22 -12
- package/src/animation/timeline.ts +2 -2
- package/src/{lib → animation-loop}/animation-loop.ts +115 -97
- package/src/{lib → animation-loop}/animation-props.ts +6 -5
- package/src/animation-loop/make-animation-loop.ts +44 -0
- package/src/animation-loop/render-loop.ts +23 -0
- package/src/geometries/cone-geometry.ts +1 -1
- package/src/geometries/cube-geometry.ts +6 -3
- package/src/geometries/cylinder-geometry.ts +2 -2
- package/src/geometries/ico-sphere-geometry.ts +7 -6
- package/src/geometries/plane-geometry.ts +5 -4
- package/src/geometries/sphere-geometry.ts +4 -3
- package/src/geometries/truncated-cone-geometry.ts +4 -3
- package/src/geometry/geometry-table.ts +1 -1
- package/src/geometry/geometry-utils.ts +3 -3
- package/src/geometry/geometry.ts +72 -115
- package/src/index.ts +28 -12
- package/src/lib/clip-space.ts +17 -15
- package/src/lib/pipeline-factory.ts +60 -51
- package/src/{lib → model}/model-utils.ts +5 -4
- package/src/model/model.ts +226 -0
- package/src/scenegraph/group-node.ts +103 -0
- package/src/scenegraph/model-node.ts +50 -0
- package/src/scenegraph/scenegraph-node.ts +204 -0
- package/src/transform/transform.ts +246 -0
- package/dist/bundle.d.ts +0 -2
- package/dist/bundle.d.ts.map +0 -1
- package/dist/bundle.js +0 -5
- package/dist/bundle.js.map +0 -1
- package/dist/lib/animation-loop.d.ts.map +0 -1
- package/dist/lib/animation-loop.js.map +0 -1
- package/dist/lib/animation-props.d.ts.map +0 -1
- package/dist/lib/animation-props.js.map +0 -1
- package/dist/lib/model-utils.d.ts.map +0 -1
- package/dist/lib/model-utils.js.map +0 -1
- package/dist/lib/model.d.ts +0 -41
- package/dist/lib/model.d.ts.map +0 -1
- package/dist/lib/model.js.map +0 -1
- package/dist/lib/render-loop.d.ts +0 -14
- package/dist/lib/render-loop.d.ts.map +0 -1
- package/dist/lib/render-loop.js +0 -49
- package/dist/lib/render-loop.js.map +0 -1
- package/src/bundle.ts +0 -4
- package/src/lib/model.ts +0 -179
- package/src/lib/render-loop.ts +0 -58
- /package/dist/{lib → animation-loop}/animation-props.js +0 -0
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {Device, RenderPipeline
|
|
1
|
+
import type {RenderPipelineParameters, PrimitiveTopology, ShaderLayout} from '@luma.gl/core';
|
|
2
|
+
import {Device, RenderPipeline} from '@luma.gl/core';
|
|
3
3
|
import type { ShaderModule } from '@luma.gl/shadertools';
|
|
4
4
|
import {assembleShaders} from '@luma.gl/shadertools';
|
|
5
5
|
|
|
6
6
|
export type GetRenderPipelineOptions = {
|
|
7
|
-
vs: string
|
|
8
|
-
fs: string
|
|
9
|
-
topology;
|
|
7
|
+
vs: string;
|
|
8
|
+
fs: string | null;
|
|
9
|
+
topology: PrimitiveTopology;
|
|
10
|
+
layout?: ShaderLayout | null;
|
|
10
11
|
parameters?: RenderPipelineParameters;
|
|
11
12
|
|
|
12
13
|
modules?: ShaderModule[];
|
|
13
|
-
defines?: Record<string, string
|
|
14
|
-
inject?: Record<string, string
|
|
14
|
+
defines?: Record<string, string | number | boolean>;
|
|
15
|
+
inject?: Record<string, string>;
|
|
15
16
|
transpileToGLSL100?: boolean;
|
|
16
17
|
|
|
17
|
-
varyings?: string[]
|
|
18
|
+
varyings?: string[];
|
|
18
19
|
bufferMode?: number,
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export type GetComputePipelineOptions = {
|
|
22
|
-
cs: string
|
|
23
|
-
|
|
23
|
+
cs: string;
|
|
24
|
+
parameters?: RenderPipelineParameters;
|
|
24
25
|
|
|
25
26
|
modules?: ShaderModule[];
|
|
26
|
-
defines?: Record<string, string
|
|
27
|
-
inject?: Record<string, string
|
|
27
|
+
defines?: Record<string, string>;
|
|
28
|
+
inject?: Record<string, string>;
|
|
28
29
|
transpileToGLSL100?: boolean;
|
|
29
30
|
|
|
30
|
-
varyings?: string[]
|
|
31
|
-
bufferMode?: number
|
|
31
|
+
varyings?: string[];
|
|
32
|
+
bufferMode?: number;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
|
|
@@ -38,6 +39,7 @@ const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
|
|
|
38
39
|
defines: {},
|
|
39
40
|
inject: {},
|
|
40
41
|
transpileToGLSL100: false,
|
|
42
|
+
layout: null,
|
|
41
43
|
|
|
42
44
|
varyings: [],
|
|
43
45
|
bufferMode: 0x8c8d, // // varyings/bufferMode for xform feedback, 0x8c8d: SEPARATE_ATTRIBS
|
|
@@ -45,8 +47,10 @@ const DEFAULT_RENDER_PIPELINE_OPTIONS: Required<GetRenderPipelineOptions> = {
|
|
|
45
47
|
parameters: {}
|
|
46
48
|
};
|
|
47
49
|
|
|
50
|
+
type GetUniformsFunc = (props?: Record<string, any>) => Record<string, any>;
|
|
51
|
+
|
|
48
52
|
/** Efficiently create shared pipelines with varying parameters */
|
|
49
|
-
export
|
|
53
|
+
export class PipelineFactory {
|
|
50
54
|
readonly device: Device;
|
|
51
55
|
|
|
52
56
|
stateHash: number = 0; // Used to change hashing if hooks are modified
|
|
@@ -56,7 +60,7 @@ export default class PipelineFactory {
|
|
|
56
60
|
|
|
57
61
|
private readonly _pipelineCache: Record<string, RenderPipeline> = {};
|
|
58
62
|
|
|
59
|
-
private readonly _getUniforms: Record<string,
|
|
63
|
+
private readonly _getUniforms: Record<string, GetUniformsFunc> = {};
|
|
60
64
|
private readonly _hookFunctions: any[] = [];
|
|
61
65
|
private _defaultModules: any[] = [];
|
|
62
66
|
// private readonly _registeredModules = {}; // TODO: Remove? This isn't used anywhere in luma.gl
|
|
@@ -72,20 +76,20 @@ export default class PipelineFactory {
|
|
|
72
76
|
this.device = device;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
addDefaultModule(module: ShaderModule): void {
|
|
80
|
+
if (!this._defaultModules.find((m) => m.name === (typeof module === 'string' ? module : module.name))) {
|
|
81
|
+
this._defaultModules.push(module);
|
|
82
|
+
}
|
|
83
|
+
this.stateHash++;
|
|
84
|
+
}
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
removeDefaultModule(module: ShaderModule): void {
|
|
87
|
+
const moduleName = typeof module === 'string' ? module : module.name;
|
|
88
|
+
this._defaultModules = this._defaultModules.filter((m) => m.name !== moduleName);
|
|
89
|
+
this.stateHash++;
|
|
90
|
+
}
|
|
87
91
|
|
|
88
|
-
addShaderHook(hook, opts
|
|
92
|
+
addShaderHook(hook: string, opts?: any): void {
|
|
89
93
|
if (opts) {
|
|
90
94
|
hook = Object.assign(opts, {hook});
|
|
91
95
|
}
|
|
@@ -94,8 +98,8 @@ export default class PipelineFactory {
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
createRenderPipeline(options: GetRenderPipelineOptions): {
|
|
97
|
-
|
|
98
|
-
getUniforms:
|
|
101
|
+
pipeline: RenderPipeline;
|
|
102
|
+
getUniforms: GetUniformsFunc;
|
|
99
103
|
} {
|
|
100
104
|
const props: Required<GetRenderPipelineOptions> = {...DEFAULT_RENDER_PIPELINE_OPTIONS, ...options};
|
|
101
105
|
|
|
@@ -104,17 +108,17 @@ export default class PipelineFactory {
|
|
|
104
108
|
const hash = this._hashRenderPipeline({...props, modules});
|
|
105
109
|
|
|
106
110
|
if (!this._pipelineCache[hash]) {
|
|
107
|
-
const {
|
|
108
|
-
|
|
109
|
-
this._pipelineCache[hash] =
|
|
110
|
-
this._getUniforms[hash] = getUniforms || ((x
|
|
111
|
+
const {pipeline, getUniforms} = this._createRenderPipeline({...props, modules});
|
|
112
|
+
pipeline.hash = hash;
|
|
113
|
+
this._pipelineCache[hash] = pipeline;
|
|
114
|
+
this._getUniforms[hash] = getUniforms || ((x?: unknown) => ({}));
|
|
111
115
|
this._useCounts[hash] = 0;
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
this._useCounts[hash]++;
|
|
115
119
|
|
|
116
120
|
return {
|
|
117
|
-
|
|
121
|
+
pipeline: this._pipelineCache[hash],
|
|
118
122
|
getUniforms: this._getUniforms[hash]
|
|
119
123
|
};
|
|
120
124
|
}
|
|
@@ -137,50 +141,55 @@ export default class PipelineFactory {
|
|
|
137
141
|
// PRIVATE
|
|
138
142
|
|
|
139
143
|
_createRenderPipeline(props: GetRenderPipelineOptions): {
|
|
140
|
-
|
|
141
|
-
getUniforms:
|
|
144
|
+
pipeline: RenderPipeline,
|
|
145
|
+
getUniforms: GetUniformsFunc
|
|
142
146
|
} {
|
|
143
147
|
const platformInfo = {
|
|
144
148
|
gpu: this.device.info.gpu,
|
|
145
149
|
features: this.device.features
|
|
146
150
|
};
|
|
147
151
|
|
|
148
|
-
|
|
152
|
+
if (!props.fs) {
|
|
153
|
+
throw new Error('fs');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const assembled = assembleShaders(platformInfo, {...props, fs: props.fs, hookFunctions: this._hookFunctions});
|
|
149
157
|
|
|
150
|
-
const
|
|
158
|
+
const pipeline = this.device.createRenderPipeline({
|
|
151
159
|
...props,
|
|
152
160
|
vs: this.device.createShader({stage: 'vertex', source: assembled.vs}),
|
|
153
|
-
fs: assembled.fs
|
|
161
|
+
fs: assembled.fs ? this.device.createShader({stage: 'fragment', source: assembled.fs}) : null,
|
|
154
162
|
});
|
|
155
163
|
|
|
156
|
-
return {
|
|
164
|
+
return {pipeline, getUniforms: assembled.getUniforms};
|
|
157
165
|
}
|
|
158
166
|
|
|
159
167
|
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
160
168
|
_hashRenderPipeline(props: GetRenderPipelineOptions): string {
|
|
169
|
+
const {modules = [], varyings = [], defines = {}, inject = {}, parameters = {}} = props;
|
|
161
170
|
const vsHash = this._getHash(props.vs);
|
|
162
|
-
const fsHash = this._getHash(props.fs);
|
|
171
|
+
const fsHash = props.fs ? this._getHash(props.fs) : 0;
|
|
163
172
|
|
|
164
|
-
const moduleHashes =
|
|
165
|
-
const varyingHashes =
|
|
173
|
+
const moduleHashes = modules.map((m) => this._getHash(typeof m === 'string' ? m : m.name)).sort();
|
|
174
|
+
const varyingHashes = varyings.map((v) => this._getHash(v));
|
|
166
175
|
|
|
167
|
-
const defineKeys = Object.keys(
|
|
168
|
-
const injectKeys = Object.keys(
|
|
169
|
-
const defineHashes = [];
|
|
170
|
-
const injectHashes = [];
|
|
176
|
+
const defineKeys = Object.keys(defines).sort();
|
|
177
|
+
const injectKeys = Object.keys(inject).sort();
|
|
178
|
+
const defineHashes: number[] = [];
|
|
179
|
+
const injectHashes: number[] = [];
|
|
171
180
|
|
|
172
181
|
for (const key of defineKeys) {
|
|
173
182
|
defineHashes.push(this._getHash(key));
|
|
174
|
-
defineHashes.push(this._getHash(
|
|
183
|
+
defineHashes.push(this._getHash(String(defines[key])));
|
|
175
184
|
}
|
|
176
185
|
|
|
177
186
|
for (const key of injectKeys) {
|
|
178
187
|
injectHashes.push(this._getHash(key));
|
|
179
|
-
injectHashes.push(this._getHash(
|
|
188
|
+
injectHashes.push(this._getHash(inject[key]));
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
// TODO - hash parameters!
|
|
183
|
-
const parameterHash = JSON.stringify(
|
|
192
|
+
const parameterHash = JSON.stringify(parameters);
|
|
184
193
|
|
|
185
194
|
return `${vsHash}/${fsHash}D${defineHashes.join('/')}M${moduleHashes.join(
|
|
186
195
|
'/'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {Device, Buffer, assert} from '@luma.gl/
|
|
2
|
-
import type Geometry from '../geometry/geometry';
|
|
1
|
+
import {Device, Buffer, assert} from '@luma.gl/core';
|
|
2
|
+
import type {Geometry} from '../geometry/geometry';
|
|
3
3
|
|
|
4
4
|
// Support for mapping new geometries with glTF attribute names to "classic" luma.gl shader names
|
|
5
5
|
const GLTF_TO_LUMA_ATTRIBUTE_MAP = {
|
|
@@ -72,10 +72,10 @@ export function getAttributeBuffersFromGeometry(device: Device, geometry: Geomet
|
|
|
72
72
|
|
|
73
73
|
for (const [name, attribute] of Object.entries(geometry.attributes)) {
|
|
74
74
|
const remappedName = mapAttributeName(name);
|
|
75
|
-
if (attribute
|
|
75
|
+
if (attribute?.constant) {
|
|
76
76
|
throw new Error('constant attributes not supported');
|
|
77
77
|
} else {
|
|
78
|
-
const typedArray = attribute
|
|
78
|
+
const typedArray = attribute?.value;
|
|
79
79
|
buffers[remappedName] = device.createBuffer({data: typedArray, id: `${remappedName}-buffer`});
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -84,6 +84,7 @@ export function getAttributeBuffersFromGeometry(device: Device, geometry: Geomet
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function mapAttributeName(name: string): string {
|
|
87
|
+
// @ts-ignore-error
|
|
87
88
|
return GLTF_TO_LUMA_ATTRIBUTE_MAP[name] || name;
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// luma.gl, MIT license
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Device,
|
|
5
|
+
Buffer,
|
|
6
|
+
RenderPipelineProps,
|
|
7
|
+
RenderPass,
|
|
8
|
+
Binding,
|
|
9
|
+
PrimitiveTopology,
|
|
10
|
+
log
|
|
11
|
+
} from '@luma.gl/core';
|
|
12
|
+
import {RenderPipeline} from '@luma.gl/core';
|
|
13
|
+
import type {ShaderModule} from '@luma.gl/shadertools';
|
|
14
|
+
import type {Geometry} from '../geometry/geometry';
|
|
15
|
+
import {getAttributeBuffersFromGeometry, getIndexBufferFromGeometry} from './model-utils';
|
|
16
|
+
import {PipelineFactory} from '../lib/pipeline-factory';
|
|
17
|
+
import {TypedArray} from '@math.gl/core';
|
|
18
|
+
|
|
19
|
+
/** @todo import type */
|
|
20
|
+
type UniformValue = unknown;
|
|
21
|
+
|
|
22
|
+
export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs'> & {
|
|
23
|
+
// Model also accepts a string
|
|
24
|
+
vs?: {glsl?: string; wgsl?: string} | string | null;
|
|
25
|
+
fs?: {glsl?: string; wgsl?: string} | string | null;
|
|
26
|
+
defines?: Record<string, string | number | boolean>;
|
|
27
|
+
modules?: ShaderModule[];
|
|
28
|
+
moduleSettings?: Record<string, Record<string, any>>;
|
|
29
|
+
geometry?: Geometry | null;
|
|
30
|
+
/** deprecated pipeline factory to use to create renderpipelines */
|
|
31
|
+
pipelineFactory?: PipelineFactory;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const DEFAULT_MODEL_PROPS: Required<ModelProps> = {
|
|
35
|
+
...RenderPipeline._DEFAULT_PROPS,
|
|
36
|
+
vs: null,
|
|
37
|
+
fs: null,
|
|
38
|
+
id: 'unnamed',
|
|
39
|
+
handle: undefined,
|
|
40
|
+
userData: {},
|
|
41
|
+
defines: {},
|
|
42
|
+
modules: [],
|
|
43
|
+
moduleSettings: {},
|
|
44
|
+
geometry: null,
|
|
45
|
+
pipelineFactory: undefined
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** v9 API */
|
|
49
|
+
export class Model {
|
|
50
|
+
readonly device: Device;
|
|
51
|
+
readonly id: string;
|
|
52
|
+
readonly vs: string;
|
|
53
|
+
readonly fs: string | null = null;
|
|
54
|
+
readonly topology: PrimitiveTopology;
|
|
55
|
+
readonly pipelineFactory: PipelineFactory;
|
|
56
|
+
/** The underlying GPU "program". @note May be recreated if parameters change */
|
|
57
|
+
pipeline: RenderPipeline;
|
|
58
|
+
userData: {[key: string]: any} = {};
|
|
59
|
+
|
|
60
|
+
// readonly props: Required<ModelProps>;
|
|
61
|
+
|
|
62
|
+
/** Vertex count */
|
|
63
|
+
vertexCount: number;
|
|
64
|
+
/** instance count */
|
|
65
|
+
instanceCount: number = 0;
|
|
66
|
+
/** Buffer-valued attributes */
|
|
67
|
+
bufferAttributes: Record<string, Buffer> = {};
|
|
68
|
+
/** Constant-valued attributes */
|
|
69
|
+
constantAttributes: Record<string, TypedArray> = {};
|
|
70
|
+
/** Bindings (textures, samplers, uniform buffers) */
|
|
71
|
+
bindings: Record<string, Binding> = {};
|
|
72
|
+
/** Uniforms */
|
|
73
|
+
uniforms: Record<string, UniformValue> = {};
|
|
74
|
+
|
|
75
|
+
private _getModuleUniforms: (props?: Record<string, Record<string, any>>) => Record<string, any>;
|
|
76
|
+
|
|
77
|
+
constructor(device: Device, props: ModelProps) {
|
|
78
|
+
props = {...DEFAULT_MODEL_PROPS, ...props};
|
|
79
|
+
this.id = props.id;
|
|
80
|
+
this.device = device;
|
|
81
|
+
|
|
82
|
+
Object.assign(this.userData, props.userData);
|
|
83
|
+
|
|
84
|
+
// Create the pipeline
|
|
85
|
+
if (!props.vs) {
|
|
86
|
+
throw new Error('no vertex shader');
|
|
87
|
+
}
|
|
88
|
+
this.vs = getShaderSource(this.device, props.vs);
|
|
89
|
+
if (props.fs) {
|
|
90
|
+
this.fs = getShaderSource(this.device, props.fs);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.vertexCount = props.vertexCount;
|
|
94
|
+
this.instanceCount = props.instanceCount;
|
|
95
|
+
this.topology = props.topology;
|
|
96
|
+
|
|
97
|
+
if (props.geometry) {
|
|
98
|
+
this.vertexCount = props.geometry.vertexCount;
|
|
99
|
+
this.topology = props.geometry.topology || 'triangle-list';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.pipelineFactory =
|
|
103
|
+
props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
104
|
+
const {pipeline, getUniforms} = this.pipelineFactory.createRenderPipeline({
|
|
105
|
+
...props,
|
|
106
|
+
vs: this.vs,
|
|
107
|
+
fs: this.fs,
|
|
108
|
+
topology: this.topology,
|
|
109
|
+
defines: props.defines,
|
|
110
|
+
parameters: props.parameters,
|
|
111
|
+
layout: props.layout
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
this.pipeline = pipeline;
|
|
115
|
+
this._getModuleUniforms = getUniforms;
|
|
116
|
+
|
|
117
|
+
if (props.geometry) {
|
|
118
|
+
this._setGeometry(props.geometry);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.setUniforms(this._getModuleUniforms()); // Get all default module uniforms
|
|
122
|
+
|
|
123
|
+
// Props can update any of the above, so call setProps last.
|
|
124
|
+
this.setProps(props);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
destroy(): void {
|
|
128
|
+
this.pipelineFactory.release(this.pipeline);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
draw(renderPass: RenderPass): void {
|
|
132
|
+
this.pipeline.draw({
|
|
133
|
+
renderPass,
|
|
134
|
+
vertexCount: this.vertexCount,
|
|
135
|
+
instanceCount: this.instanceCount
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
setProps(props: ModelProps): void {
|
|
140
|
+
if (props.indices) {
|
|
141
|
+
this.setIndexBuffer(props.indices);
|
|
142
|
+
}
|
|
143
|
+
if (props.attributes) {
|
|
144
|
+
this.setAttributes(props.attributes);
|
|
145
|
+
}
|
|
146
|
+
if (props.bindings) {
|
|
147
|
+
this.setBindings(props.bindings);
|
|
148
|
+
}
|
|
149
|
+
if (props.uniforms) {
|
|
150
|
+
this.setUniforms(props.uniforms);
|
|
151
|
+
}
|
|
152
|
+
if (props.moduleSettings) {
|
|
153
|
+
this.updateModuleSettings(props.moduleSettings);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
updateModuleSettings(props: Record<string, any>): void {
|
|
158
|
+
const uniforms = this._getModuleUniforms(props);
|
|
159
|
+
this.setUniforms(uniforms);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
setIndexBuffer(indices: Buffer): void {
|
|
163
|
+
this.pipeline.setIndexBuffer(indices);
|
|
164
|
+
// this._indices = indices;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
setAttributes(bufferAttributes: Record<string, Buffer>): void {
|
|
168
|
+
if (bufferAttributes.indices) {
|
|
169
|
+
log.warn(`Model:${this.id} setAttributes() - indices should be set using setIndexBuffer()`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.pipeline.setAttributes(bufferAttributes);
|
|
173
|
+
Object.assign(this.bufferAttributes, bufferAttributes);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setConstantAttributes(constantAttributes: Record<string, TypedArray>): void {
|
|
177
|
+
// TODO - this doesn't work under WebGPU, we'll need to create buffers or inject uniforms
|
|
178
|
+
this.pipeline.setConstantAttributes(constantAttributes);
|
|
179
|
+
Object.assign(this.constantAttributes, constantAttributes);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Set the bindings */
|
|
183
|
+
setBindings(bindings: Record<string, Binding>): void {
|
|
184
|
+
this.pipeline.setBindings(bindings);
|
|
185
|
+
Object.assign(this.bindings, bindings);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
setUniforms(uniforms: Record<string, any>): void {
|
|
189
|
+
this.pipeline.setUniforms(uniforms);
|
|
190
|
+
Object.assign(this.uniforms, uniforms);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
_setGeometry(geometry: Geometry): void {
|
|
194
|
+
// this._deleteGeometryBuffers();
|
|
195
|
+
|
|
196
|
+
const geometryBuffers = getAttributeBuffersFromGeometry(this.device, geometry);
|
|
197
|
+
this.setAttributes(geometryBuffers);
|
|
198
|
+
|
|
199
|
+
const indexBuffer = getIndexBufferFromGeometry(this.device, geometry);
|
|
200
|
+
if (indexBuffer) {
|
|
201
|
+
this.setIndexBuffer(indexBuffer);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Create a shader from the different overloads */
|
|
207
|
+
function getShaderSource(device: Device, shader: string | {glsl?: string; wgsl?: string}): string {
|
|
208
|
+
// TODO - detect WGSL/GLSL and throw an error if not supported
|
|
209
|
+
if (typeof shader === 'string') {
|
|
210
|
+
return shader;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
switch (device.info.type) {
|
|
214
|
+
case 'webgpu':
|
|
215
|
+
if (shader?.wgsl) {
|
|
216
|
+
return shader.wgsl;
|
|
217
|
+
}
|
|
218
|
+
throw new Error('WebGPU does not support GLSL shaders');
|
|
219
|
+
|
|
220
|
+
default:
|
|
221
|
+
if (shader?.glsl) {
|
|
222
|
+
return shader.glsl;
|
|
223
|
+
}
|
|
224
|
+
throw new Error('WebGL does not support WGSL shaders');
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {Matrix4, Vector3} from '@math.gl/core';
|
|
2
|
+
import {log} from '@luma.gl/core';
|
|
3
|
+
import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
|
|
4
|
+
|
|
5
|
+
export type GroupNodeProps = ScenegraphNodeProps & {
|
|
6
|
+
children?: ScenegraphNode[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class GroupNode extends ScenegraphNode {
|
|
10
|
+
children: ScenegraphNode[];
|
|
11
|
+
|
|
12
|
+
constructor(children: ScenegraphNode[]);
|
|
13
|
+
constructor(props?: GroupNodeProps);
|
|
14
|
+
|
|
15
|
+
constructor(props: ScenegraphNode[] | GroupNodeProps = {}) {
|
|
16
|
+
props = Array.isArray(props) ? {children: props} : props;
|
|
17
|
+
const {children = []} = props;
|
|
18
|
+
log.assert(
|
|
19
|
+
children.every((child) => child instanceof ScenegraphNode),
|
|
20
|
+
'every child must an instance of ScenegraphNode'
|
|
21
|
+
);
|
|
22
|
+
super(props);
|
|
23
|
+
this.children = children;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override getBounds(): [number[], number[]] | null {
|
|
27
|
+
const result: [number[], number[]] = [[Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity]];
|
|
28
|
+
|
|
29
|
+
this.traverse((node, {worldMatrix}) => {
|
|
30
|
+
const bounds = node.getBounds();
|
|
31
|
+
if (!bounds) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const [min, max] = bounds;
|
|
35
|
+
const center = new Vector3(min).add(max).divide([2, 2, 2]);
|
|
36
|
+
worldMatrix.transformAsPoint(center, center);
|
|
37
|
+
const halfSize = new Vector3(max).subtract(min).divide([2, 2, 2]);
|
|
38
|
+
worldMatrix.transformAsVector(halfSize, halfSize);
|
|
39
|
+
|
|
40
|
+
for (let v = 0; v < 8; v++) {
|
|
41
|
+
// Test all 8 corners of the box
|
|
42
|
+
const position = new Vector3(
|
|
43
|
+
v & 0b001 ? -1 : 1,
|
|
44
|
+
v & 0b010 ? -1 : 1,
|
|
45
|
+
v & 0b100 ? -1 : 1
|
|
46
|
+
).multiply(halfSize).add(center);
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < 3; i++) {
|
|
49
|
+
result[0][i] = Math.min(result[0][i], position[i]);
|
|
50
|
+
result[1][i] = Math.max(result[1][i], position[i]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
if (!Number.isFinite(result[0][0])) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
override destroy(): void {
|
|
61
|
+
this.children.forEach((child) => child.destroy());
|
|
62
|
+
this.removeAll();
|
|
63
|
+
super.destroy();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Unpacks arrays and nested arrays of children
|
|
67
|
+
add(...children: (ScenegraphNode | ScenegraphNode[])[]): this {
|
|
68
|
+
for (const child of children) {
|
|
69
|
+
if (Array.isArray(child)) {
|
|
70
|
+
this.add(...child);
|
|
71
|
+
} else {
|
|
72
|
+
this.children.push(child);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
remove(child: ScenegraphNode): this {
|
|
79
|
+
const children = this.children;
|
|
80
|
+
const indexOf = children.indexOf(child);
|
|
81
|
+
if (indexOf > -1) {
|
|
82
|
+
children.splice(indexOf, 1);
|
|
83
|
+
}
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
removeAll(): this {
|
|
88
|
+
this.children = [];
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
traverse(visitor: (node: ScenegraphNode, context: {worldMatrix: Matrix4}) => void, {worldMatrix = new Matrix4()} = {}) {
|
|
93
|
+
const modelMatrix = new Matrix4(worldMatrix).multiplyRight(this.matrix);
|
|
94
|
+
|
|
95
|
+
for (const child of this.children) {
|
|
96
|
+
if (child instanceof GroupNode) {
|
|
97
|
+
child.traverse(visitor, {worldMatrix: modelMatrix});
|
|
98
|
+
} else {
|
|
99
|
+
visitor(child, {worldMatrix: modelMatrix});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {RenderPass} from '@luma.gl/core';
|
|
2
|
+
import {ScenegraphNode, ScenegraphNodeProps} from './scenegraph-node';
|
|
3
|
+
import {Model} from '../model/model';
|
|
4
|
+
|
|
5
|
+
export type ModelNodeProps = ScenegraphNodeProps & {
|
|
6
|
+
model: Model;
|
|
7
|
+
managedResources?: any[];
|
|
8
|
+
bounds?: [number[], number[]];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ModelNode extends ScenegraphNode {
|
|
12
|
+
readonly model: Model;
|
|
13
|
+
bounds: [number[], number[]] | null = null;
|
|
14
|
+
managedResources: any[];
|
|
15
|
+
|
|
16
|
+
// TODO - is this used? override callbacks to make sure we call them with this
|
|
17
|
+
// onBeforeRender = null;
|
|
18
|
+
// onAfterRender = null;
|
|
19
|
+
// AfterRender = null;
|
|
20
|
+
|
|
21
|
+
constructor(props: ModelNodeProps) {
|
|
22
|
+
super(props);
|
|
23
|
+
|
|
24
|
+
// Create new Model or used supplied Model
|
|
25
|
+
this.model = props.model;
|
|
26
|
+
this.managedResources = props.managedResources || [];
|
|
27
|
+
this.bounds = props.bounds || null;
|
|
28
|
+
this.setProps(props);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override getBounds(): [number[], number[]] | null {
|
|
32
|
+
return this.bounds;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override destroy(): void {
|
|
36
|
+
if (this.model) {
|
|
37
|
+
this.model.destroy();
|
|
38
|
+
// @ts-expect-error
|
|
39
|
+
this.model = null;
|
|
40
|
+
}
|
|
41
|
+
this.managedResources.forEach((resource) => resource.destroy());
|
|
42
|
+
this.managedResources = [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Expose model methods
|
|
46
|
+
draw(renderPass?: RenderPass) {
|
|
47
|
+
// Return value indicates if something was actually drawn
|
|
48
|
+
return this.model.draw(renderPass);
|
|
49
|
+
}
|
|
50
|
+
}
|