@woosh/meep-engine 2.35.7 → 2.35.10
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/engine/graphics/ecs/camera/Camera.d.ts +3 -0
- package/engine/graphics/ecs/camera/Camera.js +39 -1
- package/engine/graphics/ecs/camera/CameraSystem.js +25 -6
- package/engine/graphics/ecs/path/PathDisplaySystem.js +1 -1
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +13 -12
- package/engine/graphics/ecs/path/tube/TubePathStyle.d.ts +2 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.js +43 -1
- package/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +138 -0
- package/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.js +32 -0
- package/engine/graphics/ecs/path/tube/build/build_geometry_linear.js +16 -0
- package/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +153 -0
- package/engine/graphics/ecs/path/tube/build/estimatePathLength.js +17 -0
- package/engine/graphics/ecs/path/tube/build/estimatePathViaIterativeIntegral.js +37 -0
- package/engine/graphics/ecs/path/tube/build/makeTubeGeometry.js +156 -0
- package/engine/graphics/micron/format/MicronGeometry.d.ts +2 -1
- package/engine/graphics/micron/format/MicronGeometry.js +8 -10
- package/engine/graphics/micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js +10 -83
- package/engine/graphics/micron/render/VirtualGeometryBuilder.js +19 -24
- package/engine/graphics/micron/render/v1/MicronRenderContext.js +139 -0
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +18 -123
- package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +1 -0
- package/package.json +1 -1
- package/engine/graphics/ecs/path/tube/TubePathBuilder.js +0 -522
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BufferGeometry, Float32BufferAttribute, Vector3 } from "three";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @see https://github.com/mrdoob/three.js/blob/master/src/geometries/TubeGeometry.js
|
|
5
|
+
* @param {Vector3[]} points
|
|
6
|
+
* @param {Vector3[]} _normals
|
|
7
|
+
* @param {Vector3[]} binormals
|
|
8
|
+
* @param {number} radius
|
|
9
|
+
* @param {number} radialSegments
|
|
10
|
+
* @param {boolean} [closed]
|
|
11
|
+
* @returns {BufferGeometry}
|
|
12
|
+
*/
|
|
13
|
+
export function makeTubeGeometry(points, _normals, binormals, radius, radialSegments, closed = false) {
|
|
14
|
+
const geometry = new BufferGeometry();
|
|
15
|
+
// helper variables
|
|
16
|
+
|
|
17
|
+
const vertex = new Vector3();
|
|
18
|
+
const normal = new Vector3();
|
|
19
|
+
|
|
20
|
+
// buffer
|
|
21
|
+
|
|
22
|
+
const vertices = [];
|
|
23
|
+
const normals = [];
|
|
24
|
+
const uvs = [];
|
|
25
|
+
const indices = [];
|
|
26
|
+
|
|
27
|
+
const tubularSegments = points.length - 1;
|
|
28
|
+
|
|
29
|
+
// create buffer data
|
|
30
|
+
|
|
31
|
+
generateBufferData();
|
|
32
|
+
|
|
33
|
+
// build geometry
|
|
34
|
+
|
|
35
|
+
geometry.setIndex(indices);
|
|
36
|
+
geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
|
|
37
|
+
geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3));
|
|
38
|
+
geometry.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
|
|
39
|
+
|
|
40
|
+
// functions
|
|
41
|
+
|
|
42
|
+
function generateBufferData() {
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < tubularSegments; i++) {
|
|
45
|
+
|
|
46
|
+
generateSegment(i);
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// if the geometry is not closed, generate the last row of vertices and normals
|
|
51
|
+
// at the regular position on the given path
|
|
52
|
+
//
|
|
53
|
+
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
|
|
54
|
+
|
|
55
|
+
generateSegment((closed === false) ? tubularSegments : 0);
|
|
56
|
+
|
|
57
|
+
// uvs are generated in a separate function.
|
|
58
|
+
// this makes it easy compute correct values for closed geometries
|
|
59
|
+
|
|
60
|
+
generateUVs();
|
|
61
|
+
|
|
62
|
+
// finally create faces
|
|
63
|
+
|
|
64
|
+
generateIndices();
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function generateSegment(i) {
|
|
69
|
+
|
|
70
|
+
// we use getPointAt to sample evenly distributed points from the given path
|
|
71
|
+
|
|
72
|
+
const P = points[i];
|
|
73
|
+
|
|
74
|
+
// retrieve corresponding normal and binormal
|
|
75
|
+
|
|
76
|
+
const N = _normals[i];
|
|
77
|
+
const B = binormals[i];
|
|
78
|
+
|
|
79
|
+
// generate normals and vertices for the current segment
|
|
80
|
+
|
|
81
|
+
const angular_step = (Math.PI * 2) / radialSegments;
|
|
82
|
+
|
|
83
|
+
for (let j = 0; j <= radialSegments; j++) {
|
|
84
|
+
const v = j * angular_step;
|
|
85
|
+
|
|
86
|
+
const sin = Math.sin(v);
|
|
87
|
+
const cos = -Math.cos(v);
|
|
88
|
+
|
|
89
|
+
// normal
|
|
90
|
+
|
|
91
|
+
normal.x = (cos * N.x + sin * B.x);
|
|
92
|
+
normal.y = (cos * N.y + sin * B.y);
|
|
93
|
+
normal.z = (cos * N.z + sin * B.z);
|
|
94
|
+
normal.normalize();
|
|
95
|
+
|
|
96
|
+
normals.push(normal.x, normal.y, normal.z);
|
|
97
|
+
|
|
98
|
+
// vertex
|
|
99
|
+
|
|
100
|
+
vertex.x = P.x + radius * normal.x;
|
|
101
|
+
vertex.y = P.y + radius * normal.y;
|
|
102
|
+
vertex.z = P.z + radius * normal.z;
|
|
103
|
+
|
|
104
|
+
vertices.push(vertex.x, vertex.y, vertex.z);
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function generateIndices() {
|
|
111
|
+
let i = 0, j = 0;
|
|
112
|
+
|
|
113
|
+
for (j = 1; j <= tubularSegments; j++) {
|
|
114
|
+
|
|
115
|
+
for (i = 1; i <= radialSegments; i++) {
|
|
116
|
+
|
|
117
|
+
const s_1 = radialSegments + 1;
|
|
118
|
+
|
|
119
|
+
const a = s_1 * (j - 1) + (i - 1);
|
|
120
|
+
const b = s_1 * j + (i - 1);
|
|
121
|
+
const c = s_1 * j + i;
|
|
122
|
+
const d = s_1 * (j - 1) + i;
|
|
123
|
+
|
|
124
|
+
// faces
|
|
125
|
+
|
|
126
|
+
indices.push(a, b, d);
|
|
127
|
+
indices.push(b, c, d);
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function generateUVs() {
|
|
136
|
+
let i = 0, j = 0;
|
|
137
|
+
|
|
138
|
+
for (i = 0; i <= tubularSegments; i++) {
|
|
139
|
+
|
|
140
|
+
const u = i / tubularSegments;
|
|
141
|
+
|
|
142
|
+
for (j = 0; j <= radialSegments; j++) {
|
|
143
|
+
|
|
144
|
+
const v = j / radialSegments;
|
|
145
|
+
|
|
146
|
+
uvs.push(u, v);
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
return geometry;
|
|
156
|
+
}
|
|
@@ -10,9 +10,10 @@ export class MicronGeometry {
|
|
|
10
10
|
initialize(): void
|
|
11
11
|
|
|
12
12
|
raycast(
|
|
13
|
+
destination: SurfacePoint3[], destination_offset: number,
|
|
13
14
|
origin_x: number, origin_y: number, origin_z: number,
|
|
14
15
|
direction_x: number, direction_y: number, direction_z: number
|
|
15
|
-
):
|
|
16
|
+
): number
|
|
16
17
|
|
|
17
18
|
readonly isMicronGeometry: boolean
|
|
18
19
|
|
|
@@ -75,28 +75,26 @@ export class MicronGeometry {
|
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
*
|
|
78
|
+
* @param {SurfacePoint3[]} destination
|
|
79
|
+
* @param {number} destination_offset
|
|
78
80
|
* @param {number} origin_x
|
|
79
81
|
* @param {number} origin_y
|
|
80
82
|
* @param {number} origin_z
|
|
81
83
|
* @param {number} direction_x
|
|
82
84
|
* @param {number} direction_y
|
|
83
85
|
* @param {number} direction_z
|
|
84
|
-
* @returns {
|
|
86
|
+
* @returns {number}
|
|
85
87
|
*/
|
|
86
88
|
raycast(
|
|
89
|
+
destination,
|
|
90
|
+
destination_offset,
|
|
87
91
|
origin_x, origin_y, origin_z,
|
|
88
92
|
direction_x, direction_y, direction_z
|
|
89
93
|
) {
|
|
90
|
-
|
|
94
|
+
let destination_address = destination_offset;
|
|
91
95
|
let i;
|
|
92
96
|
let stack_cursor = 1;
|
|
93
97
|
|
|
94
|
-
/**
|
|
95
|
-
*
|
|
96
|
-
* @type {SurfacePoint3[]}
|
|
97
|
-
*/
|
|
98
|
-
const hits = [];
|
|
99
|
-
|
|
100
98
|
// initialize stack
|
|
101
99
|
const stack = scratch_traversal_stack;
|
|
102
100
|
stack[0] = this.root;
|
|
@@ -185,7 +183,7 @@ export class MicronGeometry {
|
|
|
185
183
|
|
|
186
184
|
contact.copy(temp_hit);
|
|
187
185
|
|
|
188
|
-
|
|
186
|
+
destination[destination_address++] = contact;
|
|
189
187
|
|
|
190
188
|
}
|
|
191
189
|
}
|
|
@@ -233,7 +231,7 @@ export class MicronGeometry {
|
|
|
233
231
|
}
|
|
234
232
|
}
|
|
235
233
|
|
|
236
|
-
return
|
|
234
|
+
return destination_address - destination_offset;
|
|
237
235
|
}
|
|
238
236
|
|
|
239
237
|
/**
|
|
@@ -1,42 +1,16 @@
|
|
|
1
1
|
import { AbstractRenderAdapter } from "../../../ecs/mesh-v2/render/adapters/AbstractRenderAdapter.js";
|
|
2
2
|
import Vector2 from "../../../../../core/geom/Vector2.js";
|
|
3
|
-
import { MaterialVertexSpec } from "../../render/v1/MaterialVertexSpec.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
* @type {MaterialVertexSpec}
|
|
8
|
-
*/
|
|
9
|
-
const scratch_mvc = new MaterialVertexSpec();
|
|
10
|
-
|
|
11
|
-
class MicronRenderContext {
|
|
12
|
-
|
|
13
|
-
}
|
|
14
3
|
|
|
15
4
|
export class MicronShadedGeometryRenderAdapter extends AbstractRenderAdapter {
|
|
16
|
-
constructor({
|
|
17
|
-
vgtr
|
|
18
|
-
}) {
|
|
19
|
-
super();
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @type {VGThreeRenderer}
|
|
23
|
-
* @private
|
|
24
|
-
*/
|
|
25
|
-
this.__vgtr = vgtr;
|
|
26
5
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* @type {VirtualGeometry|null}
|
|
30
|
-
* @private
|
|
31
|
-
*/
|
|
32
|
-
this.__vg = null;
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
33
8
|
|
|
34
9
|
/**
|
|
35
10
|
*
|
|
36
|
-
* @type {
|
|
37
|
-
* @private
|
|
11
|
+
* @type {MicronRenderContext|null}
|
|
38
12
|
*/
|
|
39
|
-
this.
|
|
13
|
+
this.ctx = null;
|
|
40
14
|
|
|
41
15
|
/**
|
|
42
16
|
*
|
|
@@ -58,7 +32,7 @@ export class MicronShadedGeometryRenderAdapter extends AbstractRenderAdapter {
|
|
|
58
32
|
const micron_geometry = this.__geometry_map.get(sg.geometry.id);
|
|
59
33
|
|
|
60
34
|
// populate virtual geometry for this instance
|
|
61
|
-
this.
|
|
35
|
+
this.ctx.builder.buildForMesh(sg.entity, micron_geometry, sg.transform);
|
|
62
36
|
|
|
63
37
|
}
|
|
64
38
|
|
|
@@ -84,67 +58,20 @@ export class MicronShadedGeometryRenderAdapter extends AbstractRenderAdapter {
|
|
|
84
58
|
pixelRatio = renderer.getPixelRatio();
|
|
85
59
|
}
|
|
86
60
|
|
|
87
|
-
const vg_builder = this.
|
|
61
|
+
const vg_builder = this.ctx.builder;
|
|
88
62
|
|
|
89
63
|
vg_builder.resolution.set(resolution.x * pixelRatio, resolution.y * pixelRatio);
|
|
90
64
|
vg_builder.setMatricesFromCamera(view.camera);
|
|
91
|
-
vg_builder.setOutput(this.
|
|
65
|
+
vg_builder.setOutput(this.ctx.geometry);
|
|
92
66
|
|
|
93
|
-
vg_builder.
|
|
67
|
+
vg_builder.initialize_build();
|
|
94
68
|
}
|
|
95
69
|
|
|
96
70
|
build_end() {
|
|
97
|
-
|
|
98
|
-
const context_count = contexts.length;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
*
|
|
102
|
-
* @type {Map<number, MaterialContext>}
|
|
103
|
-
*/
|
|
104
|
-
const instance_to_ctx = new Map();
|
|
105
|
-
|
|
106
|
-
for (let i = 0; i < context_count; i++) {
|
|
107
|
-
const ctx = contexts[i];
|
|
108
|
-
ctx.__patch_count = 0;
|
|
109
|
-
|
|
110
|
-
for (const instance of ctx.instances) {
|
|
111
|
-
instance_to_ctx.set(instance, ctx);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// sort patches into relevant contexts
|
|
116
|
-
const geometry = this.geometry;
|
|
117
|
-
const patch_count = geometry.patch_count;
|
|
118
|
-
const patches = geometry.patches;
|
|
119
|
-
|
|
120
|
-
for (let i = 0; i < patch_count; i++) {
|
|
121
|
-
const i3 = i * 3;
|
|
122
|
-
|
|
123
|
-
const instance_id = patches[i3];
|
|
124
|
-
const geometry_id = patches[i3 + 1];
|
|
125
|
-
const patch_id = patches[i3 + 2];
|
|
126
|
-
|
|
127
|
-
const ctx = instance_to_ctx.get(instance_id);
|
|
128
|
-
|
|
129
|
-
const target_address = ctx.__patch_count * 3;
|
|
130
|
-
ctx.__patch_count++;
|
|
131
|
-
|
|
132
|
-
const ctx_patches = ctx.__patches;
|
|
133
|
-
|
|
134
|
-
ctx_patches[target_address] = instance_id;
|
|
135
|
-
ctx_patches[target_address + 1] = geometry_id;
|
|
136
|
-
ctx_patches[target_address + 2] = patch_id;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// build each context
|
|
140
|
-
for (let i = 0; i < context_count; i++) {
|
|
141
|
-
const ctx = contexts[i];
|
|
142
|
-
|
|
143
|
-
ctx.build(this.geometry);
|
|
144
|
-
}
|
|
71
|
+
this.ctx.render();
|
|
145
72
|
}
|
|
146
73
|
|
|
147
74
|
dispose() {
|
|
148
|
-
|
|
75
|
+
// rendering context is not owned, do nothing
|
|
149
76
|
}
|
|
150
77
|
}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
2
2
|
import Vector2 from "../../../../core/geom/Vector2.js";
|
|
3
3
|
import { RefinementSpec } from "./refinement/RefinementSpec.js";
|
|
4
|
-
import { ActivePatchList } from "./refinement/ActivePatchList.js";
|
|
5
4
|
import { mat4 } from "gl-matrix";
|
|
6
5
|
import { get_geometry_patch_cut } from "./refinement/get_geometry_patch_cut.js";
|
|
7
6
|
import { traverseThreeObject } from "../../ecs/highlight/renderer/traverseThreeObject.js";
|
|
8
7
|
|
|
9
|
-
/**
|
|
10
|
-
* @readonly
|
|
11
|
-
* @type {RefinementSpec}
|
|
12
|
-
*/
|
|
13
|
-
const refinement_spec = new RefinementSpec();
|
|
14
|
-
|
|
15
8
|
export class VirtualGeometryBuilder {
|
|
16
9
|
constructor() {
|
|
17
10
|
|
|
@@ -60,13 +53,6 @@ export class VirtualGeometryBuilder {
|
|
|
60
53
|
*/
|
|
61
54
|
this.resolution = new Vector2();
|
|
62
55
|
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
* @type {ActivePatchList}
|
|
66
|
-
* @private
|
|
67
|
-
*/
|
|
68
|
-
this.__acl = new ActivePatchList();
|
|
69
|
-
|
|
70
56
|
/**
|
|
71
57
|
* How much error to accept when deciding to subdivide a cluster
|
|
72
58
|
* Measured in pixels
|
|
@@ -74,10 +60,15 @@ export class VirtualGeometryBuilder {
|
|
|
74
60
|
* @type {number}
|
|
75
61
|
*/
|
|
76
62
|
this.error_bias = 2;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
* @type {RefinementSpec}
|
|
67
|
+
*/
|
|
68
|
+
this.refinement_spec = new RefinementSpec();
|
|
77
69
|
}
|
|
78
70
|
|
|
79
71
|
dropCache() {
|
|
80
|
-
this.__acl.clear();
|
|
81
72
|
}
|
|
82
73
|
|
|
83
74
|
/**
|
|
@@ -103,7 +94,7 @@ export class VirtualGeometryBuilder {
|
|
|
103
94
|
mat4.multiply(this.view_projection_matrix, this.matrix_projection, this.matrix_world_inverse);
|
|
104
95
|
|
|
105
96
|
//
|
|
106
|
-
refinement_spec.focal_length = camera.fov / 180;
|
|
97
|
+
this.refinement_spec.focal_length = camera.fov / 180;
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
/**
|
|
@@ -121,17 +112,15 @@ export class VirtualGeometryBuilder {
|
|
|
121
112
|
* @type {MicronGeometry|undefined}
|
|
122
113
|
*/
|
|
123
114
|
const micron_geometry = object.geometry;
|
|
124
|
-
if (micron_geometry !== undefined) {
|
|
125
|
-
// get acl
|
|
126
|
-
const acl = this.__acl;
|
|
127
115
|
|
|
116
|
+
if (micron_geometry !== undefined) {
|
|
128
117
|
|
|
129
118
|
this.buildForMesh(
|
|
130
119
|
object.instance_id,
|
|
131
120
|
micron_geometry,
|
|
132
|
-
object.matrixWorld.elements
|
|
133
|
-
acl
|
|
121
|
+
object.matrixWorld.elements
|
|
134
122
|
);
|
|
123
|
+
|
|
135
124
|
}
|
|
136
125
|
}
|
|
137
126
|
}
|
|
@@ -147,6 +136,8 @@ export class VirtualGeometryBuilder {
|
|
|
147
136
|
geometry,
|
|
148
137
|
transform
|
|
149
138
|
) {
|
|
139
|
+
const refinement_spec = this.refinement_spec;
|
|
140
|
+
|
|
150
141
|
refinement_spec.build(transform, this.view_projection_matrix);
|
|
151
142
|
|
|
152
143
|
const output = this.output;
|
|
@@ -183,17 +174,21 @@ export class VirtualGeometryBuilder {
|
|
|
183
174
|
this.input_scene_length += object_count;
|
|
184
175
|
}
|
|
185
176
|
|
|
186
|
-
|
|
177
|
+
initialize_build() {
|
|
187
178
|
|
|
188
179
|
// update refinement spec
|
|
189
|
-
refinement_spec.error_threshold = this.error_bias;
|
|
180
|
+
this.refinement_spec.error_threshold = this.error_bias;
|
|
190
181
|
|
|
191
182
|
const resolution = this.resolution;
|
|
192
183
|
|
|
193
|
-
refinement_spec.setResolution(resolution.x, resolution.y);
|
|
184
|
+
this.refinement_spec.setResolution(resolution.x, resolution.y);
|
|
194
185
|
|
|
195
186
|
// clear output
|
|
196
187
|
this.output.clear();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
build() {
|
|
191
|
+
this.initialize_build();
|
|
197
192
|
|
|
198
193
|
|
|
199
194
|
const n = this.input_scene_length;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { VirtualGeometry } from "../../format/VirtualGeometry.js";
|
|
2
|
+
import { VirtualGeometryBuilder } from "../VirtualGeometryBuilder.js";
|
|
3
|
+
import { HashMap } from "../../../../../core/collection/HashMap.js";
|
|
4
|
+
import Signal from "../../../../../core/events/signal/Signal.js";
|
|
5
|
+
import { MaterialContext } from "./MaterialContext.js";
|
|
6
|
+
import { MaterialVertexSpec } from "./MaterialVertexSpec.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @type {MaterialVertexSpec}
|
|
11
|
+
*/
|
|
12
|
+
const scratch_mvc = new MaterialVertexSpec();
|
|
13
|
+
|
|
14
|
+
export class MicronRenderContext {
|
|
15
|
+
constructor() {
|
|
16
|
+
|
|
17
|
+
this.geometry = new VirtualGeometry();
|
|
18
|
+
|
|
19
|
+
this.builder = new VirtualGeometryBuilder();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @type {Map<MaterialVertexSpec, MaterialContext>}
|
|
24
|
+
*/
|
|
25
|
+
this.material_contexts = new HashMap();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @type {MaterialContext[]}
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
this.__contexts_array = [];
|
|
33
|
+
|
|
34
|
+
this.on = {
|
|
35
|
+
/**
|
|
36
|
+
* @type {Signal<MaterialContext>}
|
|
37
|
+
*/
|
|
38
|
+
contextAdded: new Signal()
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Enable/disable wireframe rendering
|
|
44
|
+
* @param {boolean} x
|
|
45
|
+
*/
|
|
46
|
+
set wireframe(x) {
|
|
47
|
+
this.material_contexts.forEach((ctx, mv) => {
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
ctx.compiled_material.wireframe = x;
|
|
51
|
+
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {VertexDataSpec} spec
|
|
59
|
+
* @param {Material} m
|
|
60
|
+
* @returns {MaterialContext}
|
|
61
|
+
*/
|
|
62
|
+
obtain_material(spec, m) {
|
|
63
|
+
scratch_mvc.material = m;
|
|
64
|
+
scratch_mvc.spec = spec;
|
|
65
|
+
|
|
66
|
+
const existing = this.material_contexts.get(scratch_mvc);
|
|
67
|
+
|
|
68
|
+
if (existing !== undefined) {
|
|
69
|
+
return existing;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// create a separate instance to be stored alongside the context
|
|
73
|
+
const key = scratch_mvc.clone();
|
|
74
|
+
|
|
75
|
+
const ctx = new MaterialContext(spec, m);
|
|
76
|
+
|
|
77
|
+
ctx.init();
|
|
78
|
+
|
|
79
|
+
this.material_contexts.set(key, ctx);
|
|
80
|
+
this.__contexts_array.push(ctx);
|
|
81
|
+
|
|
82
|
+
this.on.contextAdded.send1(ctx);
|
|
83
|
+
|
|
84
|
+
return ctx;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
render() {
|
|
88
|
+
const render_context = this;
|
|
89
|
+
const contexts = render_context.__contexts_array;
|
|
90
|
+
const context_count = contexts.length;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @type {Map<number, MaterialContext>}
|
|
95
|
+
*/
|
|
96
|
+
const instance_to_ctx = new Map();
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < context_count; i++) {
|
|
99
|
+
const ctx = contexts[i];
|
|
100
|
+
ctx.__patch_count = 0;
|
|
101
|
+
|
|
102
|
+
for (const instance of ctx.instances) {
|
|
103
|
+
instance_to_ctx.set(instance, ctx);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// sort patches into relevant contexts
|
|
108
|
+
const geometry = render_context.geometry;
|
|
109
|
+
const patch_count = geometry.patch_count;
|
|
110
|
+
const patches = geometry.patches;
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < patch_count; i++) {
|
|
113
|
+
const i3 = i * 3;
|
|
114
|
+
|
|
115
|
+
const instance_id = patches[i3];
|
|
116
|
+
const geometry_id = patches[i3 + 1];
|
|
117
|
+
const patch_id = patches[i3 + 2];
|
|
118
|
+
|
|
119
|
+
const ctx = instance_to_ctx.get(instance_id);
|
|
120
|
+
|
|
121
|
+
const target_address = ctx.__patch_count * 3;
|
|
122
|
+
ctx.__patch_count++;
|
|
123
|
+
|
|
124
|
+
const ctx_patches = ctx.__patches;
|
|
125
|
+
|
|
126
|
+
ctx_patches[target_address] = instance_id;
|
|
127
|
+
ctx_patches[target_address + 1] = geometry_id;
|
|
128
|
+
ctx_patches[target_address + 2] = patch_id;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// build each context
|
|
132
|
+
for (let i = 0; i < context_count; i++) {
|
|
133
|
+
const ctx = contexts[i];
|
|
134
|
+
|
|
135
|
+
ctx.build(geometry);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
}
|