@woosh/meep-engine 2.35.8 → 2.35.12
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/core/binary/BinaryBuffer.js +65 -18
- 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/mesh-v2/ShadedGeometrySystem.js +8 -2
- package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +19 -4
- 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/build/buildMicronGeometryFromBufferGeometry.js +1 -1
- package/engine/graphics/micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js +45 -76
- package/engine/graphics/micron/render/VirtualGeometryBuilder.js +19 -24
- package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +1 -1
- package/engine/graphics/micron/render/v1/MaterialContext.js +1 -11
- package/engine/graphics/micron/render/v1/MaterialVertexSpec.js +55 -2
- package/engine/graphics/micron/render/v1/MicronRenderContext.js +151 -0
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +24 -117
- 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,32 @@
|
|
|
1
|
+
import { CatmullRomCurve3 } from "three";
|
|
2
|
+
import { computeFrenetFrames } from "./computeFrenetFrames.js";
|
|
3
|
+
import { makeTubeGeometry } from "./makeTubeGeometry.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {THREE.Vector3[]} points
|
|
8
|
+
* @param {number} point_count
|
|
9
|
+
* @param {TubePathStyle} style
|
|
10
|
+
* @return {THREE.BufferGeometry}
|
|
11
|
+
*/
|
|
12
|
+
export function build_geometry_catmullrom(points, point_count, style) {
|
|
13
|
+
|
|
14
|
+
const path = new CatmullRomCurve3(points, false, "centripetal");
|
|
15
|
+
|
|
16
|
+
const sample_points = [];
|
|
17
|
+
|
|
18
|
+
// resample curve
|
|
19
|
+
const total_points = Math.ceil(point_count * style.resolution);
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < total_points; i++) {
|
|
22
|
+
const t = i / (total_points - 1);
|
|
23
|
+
|
|
24
|
+
const point = path.getPoint(t);
|
|
25
|
+
|
|
26
|
+
sample_points.push(point);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const frames = computeFrenetFrames(sample_points, false);
|
|
30
|
+
|
|
31
|
+
return makeTubeGeometry(sample_points, frames.normals, frames.binormals, style.width, style.radial_resolution, false);
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { computeFrenetFrames } from "./computeFrenetFrames.js";
|
|
2
|
+
import { makeTubeGeometry } from "./makeTubeGeometry.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {THREE.Vector3[]} points
|
|
7
|
+
* @param {number} point_count
|
|
8
|
+
* @param {TubePathStyle} style
|
|
9
|
+
* @return {THREE.BufferGeometry}
|
|
10
|
+
*/
|
|
11
|
+
export function build_geometry_linear(points, point_count, style) {
|
|
12
|
+
|
|
13
|
+
const frames = computeFrenetFrames(points, false);
|
|
14
|
+
|
|
15
|
+
return makeTubeGeometry(points, frames.normals, frames.binormals, style.width, style.radial_resolution, false);
|
|
16
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Vector3 } from "three";
|
|
2
|
+
import { Matrix4 } from "three/src/math/Matrix4.js";
|
|
3
|
+
import { max2 } from "../../../../../../core/math/max2.js";
|
|
4
|
+
import { min2 } from "../../../../../../core/math/min2.js";
|
|
5
|
+
import * as MathUtils from "three/src/math/MathUtils.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @see https://github.com/mrdoob/three.js/blob/c12c9a166a1369cdd58622fff2aff7e3a84305d7/src/extras/core/Curve.js#L260
|
|
9
|
+
* @param {Vector3[]} points
|
|
10
|
+
* @param {boolean} [closed]
|
|
11
|
+
*/
|
|
12
|
+
export function computeFrenetFrames(points, closed = false) {
|
|
13
|
+
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
|
|
14
|
+
|
|
15
|
+
const normal = new Vector3();
|
|
16
|
+
|
|
17
|
+
const tangents = [];
|
|
18
|
+
const normals = [];
|
|
19
|
+
const binormals = [];
|
|
20
|
+
|
|
21
|
+
const vec = new Vector3();
|
|
22
|
+
const mat = new Matrix4();
|
|
23
|
+
|
|
24
|
+
const segments = points.length - 1;
|
|
25
|
+
|
|
26
|
+
const v3_0 = new Vector3();
|
|
27
|
+
const v3_1 = new Vector3();
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @param {number} i
|
|
32
|
+
* @param {Vector3} destination
|
|
33
|
+
*/
|
|
34
|
+
function getTangent(i, destination) {
|
|
35
|
+
// get points on either side
|
|
36
|
+
const i0 = max2(i - 1, 0);
|
|
37
|
+
const i1 = min2(i + 1, segments);
|
|
38
|
+
|
|
39
|
+
const p0 = points[i0];
|
|
40
|
+
const pR = points[i];
|
|
41
|
+
const p1 = points[i1];
|
|
42
|
+
|
|
43
|
+
// get points along the lines close to the reference
|
|
44
|
+
v3_0.subVectors(p0, pR);
|
|
45
|
+
v3_0.normalize();
|
|
46
|
+
|
|
47
|
+
v3_1.subVectors(p1, pR);
|
|
48
|
+
v3_1.normalize();
|
|
49
|
+
|
|
50
|
+
destination.subVectors(v3_1, v3_0);
|
|
51
|
+
destination.normalize();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// compute the tangent vectors for each segment on the curve
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i <= segments; i++) {
|
|
57
|
+
|
|
58
|
+
const tangent = new Vector3();
|
|
59
|
+
getTangent(i, tangent);
|
|
60
|
+
|
|
61
|
+
tangents[i] = tangent;
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// select an initial normal vector perpendicular to the first tangent vector,
|
|
66
|
+
// and in the direction of the minimum tangent xyz component
|
|
67
|
+
|
|
68
|
+
normals[0] = new Vector3();
|
|
69
|
+
binormals[0] = new Vector3();
|
|
70
|
+
let min = Number.MAX_VALUE;
|
|
71
|
+
const tx = Math.abs(tangents[0].x);
|
|
72
|
+
const ty = Math.abs(tangents[0].y);
|
|
73
|
+
const tz = Math.abs(tangents[0].z);
|
|
74
|
+
|
|
75
|
+
if (tx <= min) {
|
|
76
|
+
|
|
77
|
+
min = tx;
|
|
78
|
+
normal.set(1, 0, 0);
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (ty <= min) {
|
|
83
|
+
|
|
84
|
+
min = ty;
|
|
85
|
+
normal.set(0, 1, 0);
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (tz <= min) {
|
|
90
|
+
|
|
91
|
+
normal.set(0, 0, 1);
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
vec.crossVectors(tangents[0], normal).normalize();
|
|
96
|
+
|
|
97
|
+
normals[0].crossVectors(tangents[0], vec);
|
|
98
|
+
binormals[0].crossVectors(tangents[0], normals[0]);
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
// compute the slowly-varying normal and binormal vectors for each segment on the curve
|
|
102
|
+
|
|
103
|
+
for (let i = 1; i <= segments; i++) {
|
|
104
|
+
|
|
105
|
+
normals[i] = normals[i - 1].clone();
|
|
106
|
+
|
|
107
|
+
binormals[i] = binormals[i - 1].clone();
|
|
108
|
+
|
|
109
|
+
vec.crossVectors(tangents[i - 1], tangents[i]);
|
|
110
|
+
|
|
111
|
+
if (vec.length() > Number.EPSILON) {
|
|
112
|
+
|
|
113
|
+
vec.normalize();
|
|
114
|
+
|
|
115
|
+
const theta = Math.acos(MathUtils.clamp(tangents[i - 1].dot(tangents[i]), -1, 1)); // clamp for floating pt errors
|
|
116
|
+
|
|
117
|
+
normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta));
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
binormals[i].crossVectors(tangents[i], normals[i]);
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
|
|
126
|
+
|
|
127
|
+
if (closed === true) {
|
|
128
|
+
|
|
129
|
+
let theta = Math.acos(MathUtils.clamp(normals[0].dot(normals[segments]), -1, 1));
|
|
130
|
+
theta /= segments;
|
|
131
|
+
|
|
132
|
+
if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
|
|
133
|
+
|
|
134
|
+
theta = -theta;
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for (let i = 1; i <= segments; i++) {
|
|
139
|
+
|
|
140
|
+
// twist a little...
|
|
141
|
+
normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i));
|
|
142
|
+
binormals[i].crossVectors(tangents[i], normals[i]);
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
tangents: tangents,
|
|
150
|
+
normals: normals,
|
|
151
|
+
binormals: binormals
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { InterpolationType } from "../../../../../navigation/ecs/components/InterpolationType.js";
|
|
2
|
+
import { estimatePathViaIterativeIntegral } from "./estimatePathViaIterativeIntegral.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {Path} path
|
|
7
|
+
* @returns {number}
|
|
8
|
+
*/
|
|
9
|
+
function estimatePathLength(path) {
|
|
10
|
+
|
|
11
|
+
if (path.interpolation === InterpolationType.Linear) {
|
|
12
|
+
return path.getLength();
|
|
13
|
+
} else {
|
|
14
|
+
return estimatePathViaIterativeIntegral(path, 0.01);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Vector3 } from "three";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* some useful references:
|
|
5
|
+
* https://stackoverflow.com/questions/29438398/cheap-way-of-calculating-cubic-bezier-length
|
|
6
|
+
* https://stackoverflow.com/questions/1147249/connecting-catmull-rom-splines-together-and-calculating-its-length
|
|
7
|
+
* @param {Path} path
|
|
8
|
+
* @param {number} epsilon
|
|
9
|
+
*/
|
|
10
|
+
export function estimatePathViaIterativeIntegral(path, epsilon) {
|
|
11
|
+
let sum = 0;
|
|
12
|
+
|
|
13
|
+
let p0 = new Vector3();
|
|
14
|
+
let p1 = new Vector3();
|
|
15
|
+
|
|
16
|
+
if (!path.sample(p0, 0)) {
|
|
17
|
+
// path has 0 length
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (let p = epsilon; ; i += epsilon) {
|
|
22
|
+
const ended = path.sample(p1, p);
|
|
23
|
+
|
|
24
|
+
if (ended) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
sum += p0.distanceTo(p1);
|
|
29
|
+
|
|
30
|
+
const swap = p1;
|
|
31
|
+
|
|
32
|
+
p1 = p0;
|
|
33
|
+
p0 = swap;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return sum;
|
|
37
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -121,7 +121,7 @@ const PRINT_VERBOSE_STATS = false;
|
|
|
121
121
|
/**
|
|
122
122
|
*
|
|
123
123
|
* @param {THREE.BufferGeometry} input
|
|
124
|
-
* @returns {MicronGeometry}
|
|
124
|
+
* @returns {Promise<MicronGeometry>}
|
|
125
125
|
*/
|
|
126
126
|
export async function buildMicronGeometryFromBufferGeometry(input) {
|
|
127
127
|
const source_geometry = deinterleaveBufferGeometry(input);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AbstractRenderAdapter } from "../../../ecs/mesh-v2/render/adapters/AbstractRenderAdapter.js";
|
|
2
2
|
import Vector2 from "../../../../../core/geom/Vector2.js";
|
|
3
|
-
import {
|
|
3
|
+
import { buildMicronGeometryFromBufferGeometry } from "../../build/buildMicronGeometryFromBufferGeometry.js";
|
|
4
|
+
import { ShadedGeometryFlags } from "../../../ecs/mesh-v2/ShadedGeometryFlags.js";
|
|
5
|
+
import { MaterialVertexSpec, MaterialVertexSpecFlags } from "../../render/v1/MaterialVertexSpec.js";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
*
|
|
@@ -8,35 +10,16 @@ import { MaterialVertexSpec } from "../../render/v1/MaterialVertexSpec.js";
|
|
|
8
10
|
*/
|
|
9
11
|
const scratch_mvc = new MaterialVertexSpec();
|
|
10
12
|
|
|
11
|
-
class MicronRenderContext {
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
13
|
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
14
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* @type {VirtualGeometry|null}
|
|
30
|
-
* @private
|
|
31
|
-
*/
|
|
32
|
-
this.__vg = null;
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
33
17
|
|
|
34
18
|
/**
|
|
35
19
|
*
|
|
36
|
-
* @type {
|
|
37
|
-
* @private
|
|
20
|
+
* @type {MicronRenderContext|null}
|
|
38
21
|
*/
|
|
39
|
-
this.
|
|
22
|
+
this.ctx = null;
|
|
40
23
|
|
|
41
24
|
/**
|
|
42
25
|
*
|
|
@@ -47,18 +30,41 @@ export class MicronShadedGeometryRenderAdapter extends AbstractRenderAdapter {
|
|
|
47
30
|
|
|
48
31
|
/**
|
|
49
32
|
*
|
|
50
|
-
* @type {
|
|
33
|
+
* @type {Map<number, Promise>}
|
|
51
34
|
* @private
|
|
52
35
|
*/
|
|
53
|
-
this.
|
|
36
|
+
this.__geometry_building_promises = new Map();
|
|
54
37
|
}
|
|
55
38
|
|
|
56
39
|
add(sg) {
|
|
57
40
|
|
|
58
|
-
const
|
|
41
|
+
const geometry_id = sg.geometry.id;
|
|
42
|
+
|
|
43
|
+
const micron_geometry = this.__geometry_map.get(geometry_id);
|
|
44
|
+
|
|
45
|
+
if (micron_geometry === undefined) {
|
|
46
|
+
// no micron geometry
|
|
47
|
+
if (!this.__geometry_building_promises.has(geometry_id)) {
|
|
48
|
+
const p = buildMicronGeometryFromBufferGeometry(sg.geometry);
|
|
49
|
+
|
|
50
|
+
this.__geometry_building_promises.set(geometry_id, p);
|
|
51
|
+
|
|
52
|
+
p.then(mg => this.__geometry_map.set(geometry_id, mg));
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
59
56
|
|
|
60
57
|
// populate virtual geometry for this instance
|
|
61
|
-
this.
|
|
58
|
+
this.ctx.builder.buildForMesh(sg.entity, micron_geometry, sg.transform);
|
|
59
|
+
|
|
60
|
+
scratch_mvc.material = sg.material;
|
|
61
|
+
scratch_mvc.spec = micron_geometry.vertex_spec;
|
|
62
|
+
scratch_mvc.writeFlag(MaterialVertexSpecFlags.CastShadow, sg.getFlag(ShadedGeometryFlags.CastShadow));
|
|
63
|
+
scratch_mvc.writeFlag(MaterialVertexSpecFlags.ReceiveShadow, sg.getFlag(ShadedGeometryFlags.ReceiveShadow));
|
|
64
|
+
|
|
65
|
+
const material_context = this.ctx.obtain_material(scratch_mvc);
|
|
66
|
+
|
|
67
|
+
material_context.instances.add(sg.entity);
|
|
62
68
|
|
|
63
69
|
}
|
|
64
70
|
|
|
@@ -84,67 +90,30 @@ export class MicronShadedGeometryRenderAdapter extends AbstractRenderAdapter {
|
|
|
84
90
|
pixelRatio = renderer.getPixelRatio();
|
|
85
91
|
}
|
|
86
92
|
|
|
87
|
-
const vg_builder = this.
|
|
93
|
+
const vg_builder = this.ctx.builder;
|
|
88
94
|
|
|
89
95
|
vg_builder.resolution.set(resolution.x * pixelRatio, resolution.y * pixelRatio);
|
|
90
96
|
vg_builder.setMatricesFromCamera(view.camera);
|
|
91
|
-
vg_builder.setOutput(this.
|
|
97
|
+
vg_builder.setOutput(this.ctx.geometry);
|
|
92
98
|
|
|
93
|
-
vg_builder.
|
|
99
|
+
vg_builder.initialize_build();
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
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();
|
|
103
|
+
this.ctx.render();
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
const material_contexts = this.ctx.contexts_array;
|
|
106
|
+
const contexts_count = material_contexts.length;
|
|
107
|
+
for (let i = 0; i < contexts_count; i++) {
|
|
108
|
+
const mc = material_contexts[i];
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
if (mc.instances.size > 0) {
|
|
111
|
+
this.__objects[this.__object_count++] = mc.mesh;
|
|
112
112
|
}
|
|
113
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
|
-
}
|
|
145
114
|
}
|
|
146
115
|
|
|
147
116
|
dispose() {
|
|
148
|
-
|
|
117
|
+
// rendering context is not owned, do nothing
|
|
149
118
|
}
|
|
150
119
|
}
|