@woosh/meep-engine 2.43.7 → 2.43.9
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/geom/3d/SurfacePoint3.js +8 -0
- package/core/geom/3d/aabb/compute_aabb_from_points.js +1 -1
- package/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +10 -4
- package/core/geom/3d/topology/samples/sampleFloodFill.js +275 -0
- package/core/geom/3d/topology/simplify/prototypeMeshSimplification.js +5 -6
- package/core/geom/3d/topology/struct/TopoMesh.js +17 -0
- package/core/geom/3d/topology/three_buffer_geometry_to_topo_mesh.js +30 -0
- package/core/geom/3d/topology/{topoMeshToBufferGeometry.js → topo_mesh_to_three_buffer_geometry.js} +1 -1
- package/core/geom/3d/topology/util/mesh_flood_fill.js +61 -0
- package/engine/Engine.js +1 -1
- package/engine/EngineHarness.js +5 -5
- package/engine/ecs/parent/EntityNode.js +1 -2
- package/engine/graphics/GraphicsEngine.js +5 -2
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +1 -1
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +10 -0
- package/engine/graphics/geometry/buffered/makeGeometryIndexed.js +5 -4
- package/engine/graphics/geometry/buffered/query/RaycastNearestHitComputingVisitor.js +6 -5
- package/engine/graphics/impostors/octahedral/README.md +4 -0
- package/engine/graphics/impostors/octahedral/prototypeBaker.js +6 -5
- package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +194 -20
- package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +5 -3
- package/engine/graphics/micron/plugin/MicronRenderPlugin.js +1 -42
- package/engine/graphics/micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js +8 -3
- package/engine/graphics/micron/simplifyGeometry.js +4 -2
- package/engine/graphics/sh3/LightProbeVolume.js +28 -5
- package/engine/graphics/sh3/README.md +3 -0
- package/engine/graphics/sh3/SH3VisualisationMaterial.js +1 -0
- package/engine/graphics/sh3/prototypeSH3Probe.js +26 -21
- package/engine/graphics/shadows/README.md +6 -0
- package/engine/input/devices/PointerDevice.js +28 -0
- package/package.json +1 -1
- package/samples/terrain/from_image_2.js +1 -45
- package/view/elements/navigation/ViewStack.js +4 -2
|
@@ -8,6 +8,13 @@ export class SurfacePoint3 {
|
|
|
8
8
|
constructor() {
|
|
9
9
|
this.normal = new Vector3(0, 1, 0);
|
|
10
10
|
this.position = new Vector3(0, 0, 0);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Primitive index, such as triangle/point/line from the source geometry
|
|
14
|
+
* optional
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
this.index = -1;
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
/**
|
|
@@ -70,6 +77,7 @@ export class SurfacePoint3 {
|
|
|
70
77
|
copy(other) {
|
|
71
78
|
this.position.copy(other.position);
|
|
72
79
|
this.normal.copy(other.normal);
|
|
80
|
+
this.index = other.index;
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
/**
|
|
@@ -19,7 +19,7 @@ export function compute_aabb_from_points(result, input, input_count, d) {
|
|
|
19
19
|
|
|
20
20
|
for (i = 0; i < input_count; i++) {
|
|
21
21
|
for (j = 0; j < d; j++) {
|
|
22
|
-
const v = input[j];
|
|
22
|
+
const v = input[i*d + j];
|
|
23
23
|
|
|
24
24
|
result[j] = min2(result[j], v);
|
|
25
25
|
result[j + d] = max2(result[j + d], v);
|
|
@@ -71,8 +71,8 @@ function Kml(m, l) {
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* compute Index of spherical harmonics coefficient
|
|
74
|
-
* @param {number} m
|
|
75
|
-
* @param {number} l
|
|
74
|
+
* @param {number} m signed offset from zonal harmonic
|
|
75
|
+
* @param {number} l band
|
|
76
76
|
* @return {number}
|
|
77
77
|
*/
|
|
78
78
|
function SHindex(m, l) {
|
|
@@ -239,7 +239,7 @@ function rotateShericalHarmonicBand1(band1, M) {
|
|
|
239
239
|
mat3.scale(invA1TimesK, invA1TimesK, band1);
|
|
240
240
|
|
|
241
241
|
|
|
242
|
-
mat3.multiply(R1OverK, R1OverK, invA1TimesK
|
|
242
|
+
mat3.multiply(R1OverK, R1OverK, invA1TimesK);
|
|
243
243
|
|
|
244
244
|
return R1OverK;
|
|
245
245
|
}
|
|
@@ -568,6 +568,7 @@ function windowSH(output, output_offset, input, input_offset, numBands, channel_
|
|
|
568
568
|
for (let channel = 0; channel < channel_count; channel++) {
|
|
569
569
|
|
|
570
570
|
for (let i = 0; i < numBands * numBands; i++) {
|
|
571
|
+
// copy this channel
|
|
571
572
|
SH[i] = output[output_offset + i * channel_count + channel];
|
|
572
573
|
}
|
|
573
574
|
|
|
@@ -583,19 +584,24 @@ function windowSH(output, output_offset, input, input_offset, numBands, channel_
|
|
|
583
584
|
}
|
|
584
585
|
}
|
|
585
586
|
|
|
587
|
+
// record minimum cutoff
|
|
586
588
|
cutoff = min2(cutoff, l);
|
|
587
589
|
}
|
|
588
590
|
}
|
|
589
591
|
|
|
590
592
|
array_copy(input, input_offset, output, output_offset, numBands * numBands * channel_count);
|
|
591
593
|
|
|
594
|
+
|
|
592
595
|
for (let l = 0; l < numBands; l++) {
|
|
596
|
+
// scale each band individually
|
|
593
597
|
let w = sincWindow(l, cutoff);
|
|
594
598
|
|
|
599
|
+
// write zonal harmonic
|
|
595
600
|
for (let i = 0; i < channel_count; i++) {
|
|
596
|
-
output[output_offset + SHindex(0, l) * channel_count + i]
|
|
601
|
+
output[output_offset + SHindex(0, l) * channel_count + i] *= w;
|
|
597
602
|
}
|
|
598
603
|
|
|
604
|
+
// write the rest of the band
|
|
599
605
|
for (let m = 1; m <= l; m++) {
|
|
600
606
|
for (let i = 0; i < channel_count; i++) {
|
|
601
607
|
output[output_offset + SHindex(-m, l) * channel_count + i] *= w;
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { EngineHarness } from "../../../../../engine/EngineHarness.js";
|
|
2
|
+
import { MeshBasicMaterial, MeshStandardMaterial, OctahedronBufferGeometry } from "three";
|
|
3
|
+
import EntityBuilder from "../../../../../engine/ecs/EntityBuilder.js";
|
|
4
|
+
import { ShadedGeometry } from "../../../../../engine/graphics/ecs/mesh-v2/ShadedGeometry.js";
|
|
5
|
+
import { Transform } from "../../../../../engine/ecs/transform/Transform.js";
|
|
6
|
+
import Vector3 from "../../../Vector3.js";
|
|
7
|
+
import { ShadedGeometrySystem } from "../../../../../engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
|
|
8
|
+
import { SurfacePoint3 } from "../../SurfacePoint3.js";
|
|
9
|
+
import { topo_mesh_to_three_buffer_geometry } from "../topo_mesh_to_three_buffer_geometry.js";
|
|
10
|
+
import { three_buffer_geometry_to_topo_mesh } from "../three_buffer_geometry_to_topo_mesh.js";
|
|
11
|
+
import { mesh_flood_fill } from "../util/mesh_flood_fill.js";
|
|
12
|
+
import { compute_aabb_from_points } from "../../aabb/compute_aabb_from_points.js";
|
|
13
|
+
import { AABB3 } from "../../../../bvh2/aabb3/AABB3.js";
|
|
14
|
+
import { mergeVertices } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
15
|
+
import { makeGeometryIndexed } from "../../../../../engine/graphics/geometry/buffered/makeGeometryIndexed.js";
|
|
16
|
+
import { v3_dot } from "../../../v3_dot.js";
|
|
17
|
+
import { TopoMesh } from "../struct/TopoMesh.js";
|
|
18
|
+
import { SGMeshSystem } from "../../../../../engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js";
|
|
19
|
+
import { SGMesh } from "../../../../../engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js";
|
|
20
|
+
import { GameAssetType } from "../../../../../engine/asset/GameAssetType.js";
|
|
21
|
+
import { GLTFAssetLoader } from "../../../../../engine/asset/loaders/GLTFAssetLoader.js";
|
|
22
|
+
import { computeTriangleSurfaceArea } from "../../../../../engine/graphics/geometry/computeMeshSurfaceArea.js";
|
|
23
|
+
import { SGMeshEvents } from "../../../../../engine/graphics/ecs/mesh-v2/aggregate/SGMeshEvents.js";
|
|
24
|
+
import { Color } from "../../../../color/Color.js";
|
|
25
|
+
import { seededRandom } from "../../../../math/random/seededRandom.js";
|
|
26
|
+
import { expandConnectivityByLocality } from "../expandConnectivityByLocality.js";
|
|
27
|
+
import { buildCubeURLs } from "../../../../../engine/graphics/texture/cubemap/buildCubeURLs.js";
|
|
28
|
+
import { EntityNode } from "../../../../../engine/ecs/parent/EntityNode.js";
|
|
29
|
+
import { TransformAttachmentSystem } from "../../../../../engine/ecs/transform-attachment/TransformAttachmentSystem.js";
|
|
30
|
+
|
|
31
|
+
const harness = new EngineHarness();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
*
|
|
35
|
+
* @param {TopoMesh} mesh
|
|
36
|
+
* @param {TopoTriangle[]} faces
|
|
37
|
+
* @param {EntityNode} entity
|
|
38
|
+
*/
|
|
39
|
+
function set_highlight({
|
|
40
|
+
mesh,
|
|
41
|
+
faces,
|
|
42
|
+
entity
|
|
43
|
+
}) {
|
|
44
|
+
|
|
45
|
+
entity.children.slice().forEach(e => {
|
|
46
|
+
entity.removeChild(e);
|
|
47
|
+
|
|
48
|
+
e.destroy();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
const m = new TopoMesh();
|
|
53
|
+
|
|
54
|
+
const vertex_map = new Map();
|
|
55
|
+
|
|
56
|
+
faces.forEach(f => {
|
|
57
|
+
m.addFaceCopy(f, vertex_map);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const selected_geo = topo_mesh_to_three_buffer_geometry(m);
|
|
61
|
+
|
|
62
|
+
entity.addChild(EntityNode.fromComponents(
|
|
63
|
+
new Transform(),
|
|
64
|
+
ShadedGeometry.from(selected_geo, new MeshBasicMaterial({
|
|
65
|
+
transparent: true,
|
|
66
|
+
opacity: 0.7,
|
|
67
|
+
color: '#00c4ff',
|
|
68
|
+
depthTest: true
|
|
69
|
+
}))
|
|
70
|
+
));
|
|
71
|
+
|
|
72
|
+
entity.addChild(EntityNode.fromComponents(
|
|
73
|
+
new Transform(),
|
|
74
|
+
ShadedGeometry.from(selected_geo,new MeshBasicMaterial({
|
|
75
|
+
wireframe: true,
|
|
76
|
+
transparent: true,
|
|
77
|
+
opacity: 0.7,
|
|
78
|
+
color: '#ffffff',
|
|
79
|
+
depthTest: false
|
|
80
|
+
}))
|
|
81
|
+
))
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @param {Engine} engine
|
|
88
|
+
* @return {Promise<void>}
|
|
89
|
+
*/
|
|
90
|
+
async function main(engine) {
|
|
91
|
+
await EngineHarness.buildBasics({
|
|
92
|
+
engine,
|
|
93
|
+
focus: { x: -10.283977088703375, y: 1.7301942199921359, z: -0.3232510720362 },
|
|
94
|
+
pitch: 0.2700000000000029,
|
|
95
|
+
distance: 17,
|
|
96
|
+
yaw: -Math.PI / 2,
|
|
97
|
+
cameraFarDistance: 100,
|
|
98
|
+
enableTerrain: false
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
engine.graphics.loadEnvironmentMap(buildCubeURLs('data/textures/cubemaps/hip_miramar/32/', '.png'));
|
|
102
|
+
|
|
103
|
+
const path = 'data/models/sponza-pbr/gltf/sponza.glb';
|
|
104
|
+
|
|
105
|
+
const ecd = engine.entityManager.dataset;
|
|
106
|
+
|
|
107
|
+
const entityBuilder = new EntityBuilder();
|
|
108
|
+
entityBuilder
|
|
109
|
+
.add(SGMesh.fromURL(path))
|
|
110
|
+
.add(Transform.fromJSON({}))
|
|
111
|
+
.build(ecd);
|
|
112
|
+
|
|
113
|
+
const random = seededRandom();
|
|
114
|
+
|
|
115
|
+
entityBuilder.addEventListener(SGMeshEvents.AssetLoaded, () => {
|
|
116
|
+
/**
|
|
117
|
+
*
|
|
118
|
+
* @type {EntityNode}
|
|
119
|
+
*/
|
|
120
|
+
const node = entityBuilder.getComponent(SGMesh).__node;
|
|
121
|
+
|
|
122
|
+
node.traverse(n => {
|
|
123
|
+
|
|
124
|
+
const sg = n.entity.getComponent(ShadedGeometry);
|
|
125
|
+
|
|
126
|
+
if (sg === null) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
n.entity.removeComponent(ShadedGeometry);
|
|
131
|
+
|
|
132
|
+
let hue =0;
|
|
133
|
+
|
|
134
|
+
do {
|
|
135
|
+
hue = random();
|
|
136
|
+
|
|
137
|
+
}while(Math.abs(hue - 0.53855555555) < 0.11); // shift away from hue of selection mask
|
|
138
|
+
|
|
139
|
+
sg.material = new MeshStandardMaterial({
|
|
140
|
+
color: Color.fromHSV(hue, 0.9, 0.9).toHex()
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
n.entity.add(sg);
|
|
144
|
+
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// create a mesh
|
|
149
|
+
let source_geo = new OctahedronBufferGeometry(5, 3);
|
|
150
|
+
|
|
151
|
+
makeGeometryIndexed(source_geo);
|
|
152
|
+
source_geo = mergeVertices(source_geo, 0.002);
|
|
153
|
+
|
|
154
|
+
const entity_source = new EntityBuilder();
|
|
155
|
+
entity_source
|
|
156
|
+
.add(ShadedGeometry.from(source_geo, new MeshStandardMaterial({
|
|
157
|
+
color: '#b60000'
|
|
158
|
+
})))
|
|
159
|
+
.add(Transform.fromJSON({
|
|
160
|
+
position: {
|
|
161
|
+
x: 10, y: 6, z: 15
|
|
162
|
+
}
|
|
163
|
+
}))
|
|
164
|
+
.build(ecd);
|
|
165
|
+
|
|
166
|
+
const highlight = new EntityNode();
|
|
167
|
+
highlight.entity.add(new Transform());
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
engine.devices.pointer.on.tap.add(
|
|
171
|
+
/**
|
|
172
|
+
*
|
|
173
|
+
* @param {Vector2} position
|
|
174
|
+
* @param {MouseEvent|TouchEvent} event
|
|
175
|
+
*/
|
|
176
|
+
(position, event) => {
|
|
177
|
+
if (event instanceof MouseEvent) {
|
|
178
|
+
if ((event.buttons & (1)) !== 0) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
*
|
|
185
|
+
* @type {ShadedGeometrySystem}
|
|
186
|
+
*/
|
|
187
|
+
const sgs = engine.entityManager.getSystem(ShadedGeometrySystem);
|
|
188
|
+
|
|
189
|
+
const contact = new SurfacePoint3();
|
|
190
|
+
|
|
191
|
+
const ray_origin = new Vector3();
|
|
192
|
+
const ray_direction = new Vector3();
|
|
193
|
+
|
|
194
|
+
engine.graphics.normalizeViewportPoint(position, position);
|
|
195
|
+
engine.graphics.viewportProjectionRay(position.x, position.y, ray_origin, ray_direction);
|
|
196
|
+
|
|
197
|
+
highlight.destroy();
|
|
198
|
+
|
|
199
|
+
const raycast_result = sgs.raycastNearest(contact, ray_origin.x, ray_origin.y, ray_origin.z, ray_direction.x, ray_direction.y, ray_direction.z);
|
|
200
|
+
|
|
201
|
+
if (raycast_result !== undefined) {
|
|
202
|
+
//got a hit
|
|
203
|
+
|
|
204
|
+
const sg = raycast_result.mesh;
|
|
205
|
+
makeGeometryIndexed(sg.geometry);
|
|
206
|
+
const geometry = mergeVertices(sg.geometry);
|
|
207
|
+
// console.warn(raycast_result, contact, geometry);
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
const topo = three_buffer_geometry_to_topo_mesh(geometry);
|
|
211
|
+
|
|
212
|
+
const aabb_array = [];
|
|
213
|
+
const position_attribute = geometry.getAttribute('position');
|
|
214
|
+
compute_aabb_from_points(aabb_array, position_attribute.array, position_attribute.count, 3);
|
|
215
|
+
const aabb3 = new AABB3(...aabb_array);
|
|
216
|
+
//
|
|
217
|
+
// weld_duplicate_vertices(topo, aabb3);
|
|
218
|
+
expandConnectivityByLocality(topo, aabb3);
|
|
219
|
+
|
|
220
|
+
// identify triangle that was clicked
|
|
221
|
+
const face = topo.getFaceByIndex(contact.index);
|
|
222
|
+
|
|
223
|
+
const selection = mesh_flood_fill({
|
|
224
|
+
mesh: topo,
|
|
225
|
+
initial_set: [face],
|
|
226
|
+
filter(current, prev) {
|
|
227
|
+
current.computeNormal();
|
|
228
|
+
|
|
229
|
+
const area = computeTriangleSurfaceArea(
|
|
230
|
+
current.vertices[0].x,
|
|
231
|
+
current.vertices[0].z,
|
|
232
|
+
current.vertices[0].y,
|
|
233
|
+
|
|
234
|
+
current.vertices[1].x,
|
|
235
|
+
current.vertices[1].z,
|
|
236
|
+
current.vertices[1].y,
|
|
237
|
+
|
|
238
|
+
current.vertices[2].x,
|
|
239
|
+
current.vertices[2].z,
|
|
240
|
+
current.vertices[2].y,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (area < 0.0003) {
|
|
244
|
+
// area very small, allow jumping across
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return v3_dot(current.normal[0], current.normal[1], current.normal[2], contact.normal.x, contact.normal.y, contact.normal.z) >= 0.8;
|
|
249
|
+
// return true;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// console.log(`selection: ${selection.length}`, selection);
|
|
254
|
+
|
|
255
|
+
highlight.transform.copy(ecd.getComponent(raycast_result.entity, Transform));
|
|
256
|
+
set_highlight({
|
|
257
|
+
mesh: topo, faces: selection, entity: highlight
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
highlight.build(ecd);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
harness.initialize({
|
|
266
|
+
configuration(config, engine) {
|
|
267
|
+
config.addSystem(new ShadedGeometrySystem(engine));
|
|
268
|
+
config.addSystem(new TransformAttachmentSystem());
|
|
269
|
+
config.addSystem(new SGMeshSystem(engine));
|
|
270
|
+
|
|
271
|
+
const loader = new GLTFAssetLoader();
|
|
272
|
+
config.addLoader(GameAssetType.ModelGLTF_JSON, loader)
|
|
273
|
+
config.addLoader(GameAssetType.ModelGLTF, loader)
|
|
274
|
+
}
|
|
275
|
+
}).then(main);
|
|
@@ -24,7 +24,7 @@ import { mergeVertices } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
|
24
24
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
25
25
|
import Stats from "three/examples/jsm/libs/stats.module.js";
|
|
26
26
|
import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
|
|
27
|
-
import {
|
|
27
|
+
import { topo_mesh_to_three_buffer_geometry } from "../topo_mesh_to_three_buffer_geometry.js";
|
|
28
28
|
import { TopoMesh } from "../struct/TopoMesh.js";
|
|
29
29
|
import {
|
|
30
30
|
deinterleaveBufferGeometry
|
|
@@ -36,6 +36,7 @@ import { computeTopoMeshBoundiningBox } from "../bounds/computeTopoMeshBoundinin
|
|
|
36
36
|
import { AABB3 } from "../../../../bvh2/aabb3/AABB3.js";
|
|
37
37
|
import { Color } from "../../../../color/Color.js";
|
|
38
38
|
import { clamp } from "../../../../math/clamp.js";
|
|
39
|
+
import { three_buffer_geometry_to_topo_mesh } from "../three_buffer_geometry_to_topo_mesh.js";
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -290,15 +291,13 @@ function init() {
|
|
|
290
291
|
label_steps = true
|
|
291
292
|
}) {
|
|
292
293
|
|
|
293
|
-
const topology =
|
|
294
|
-
const faces_array = geo.getIndex().array;
|
|
295
|
-
topology.build(geo.getAttribute('position').array, faces_array);
|
|
294
|
+
const topology = three_buffer_geometry_to_topo_mesh(geo);
|
|
296
295
|
|
|
297
296
|
for (let i = 0; i < steps; i++) {
|
|
298
297
|
if (i === 11) debugger;
|
|
299
298
|
simplifyTopoMesh2(topology, 1);
|
|
300
299
|
|
|
301
|
-
const simplified_bg =
|
|
300
|
+
const simplified_bg = topo_mesh_to_three_buffer_geometry(topology);
|
|
302
301
|
simplified_bg.computeVertexNormals();
|
|
303
302
|
|
|
304
303
|
const proxy = build_preview_object({ geometry: simplified_bg, color: 'rgb(255,90,90)' });
|
|
@@ -372,7 +371,7 @@ function init() {
|
|
|
372
371
|
console.timeEnd('simplification');
|
|
373
372
|
|
|
374
373
|
console.time('topo -> buffer geo');
|
|
375
|
-
const simplified_bg =
|
|
374
|
+
const simplified_bg = topo_mesh_to_three_buffer_geometry(mesh);
|
|
376
375
|
console.timeEnd('topo -> buffer geo');
|
|
377
376
|
|
|
378
377
|
simplified_bg.computeVertexNormals();
|
|
@@ -51,6 +51,23 @@ export class TopoMesh {
|
|
|
51
51
|
return this.__faces;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
* @param {number} index
|
|
57
|
+
* @return {undefined|TopoTriangle}
|
|
58
|
+
*/
|
|
59
|
+
getFaceByIndex(index) {
|
|
60
|
+
assert.isNonNegativeInteger(index, 'index');
|
|
61
|
+
|
|
62
|
+
for (const face of this.__faces) {
|
|
63
|
+
if (face.index === index) {
|
|
64
|
+
return face;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
/**
|
|
55
72
|
*
|
|
56
73
|
* @param {function(reason:string)} error_consumer
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { TopoMesh } from "./struct/TopoMesh.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {THREE.BufferGeometry} geo
|
|
6
|
+
* @return {TopoMesh}
|
|
7
|
+
*/
|
|
8
|
+
export function three_buffer_geometry_to_topo_mesh(geo) {
|
|
9
|
+
const topology = new TopoMesh();
|
|
10
|
+
let faces_array;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const position_attribute = geo.getAttribute('position');
|
|
14
|
+
|
|
15
|
+
const geo_index = geo.getIndex();
|
|
16
|
+
|
|
17
|
+
if (geo_index !== null) {
|
|
18
|
+
faces_array = geo_index.array;
|
|
19
|
+
} else {
|
|
20
|
+
faces_array = new Uint32Array(position_attribute.count );
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < faces_array.length; i++) {
|
|
23
|
+
faces_array[i] = i;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
topology.build(position_attribute.array, faces_array);
|
|
28
|
+
|
|
29
|
+
return topology;
|
|
30
|
+
}
|
package/core/geom/3d/topology/{topoMeshToBufferGeometry.js → topo_mesh_to_three_buffer_geometry.js}
RENAMED
|
@@ -5,7 +5,7 @@ import { BufferAttribute, BufferGeometry } from "three";
|
|
|
5
5
|
* @param {TopoMesh} mesh
|
|
6
6
|
* @returns {THREE.BufferGeometry}
|
|
7
7
|
*/
|
|
8
|
-
export function
|
|
8
|
+
export function topo_mesh_to_three_buffer_geometry(mesh) {
|
|
9
9
|
const vertices_lookup = new Map();
|
|
10
10
|
|
|
11
11
|
// build vertices array
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { BitSet } from "../../../../binary/BitSet.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @type {TopoTriangle[]}
|
|
6
|
+
*/
|
|
7
|
+
const neighbours = [];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param {TopoMesh} mesh
|
|
12
|
+
* @param {TopoTriangle[]} initial_set indices of triangles that make up initial set, these are triangles that we start from, they will also be included in the resulting set
|
|
13
|
+
* @param {function(tri:TopoTriangle, prev:TopoTriangle):boolean} filter decides whether a triangle should be included or not
|
|
14
|
+
* @returns {TopoTriangle[]} set of selected triangles, will include initial set as well
|
|
15
|
+
*/
|
|
16
|
+
export function mesh_flood_fill({
|
|
17
|
+
mesh,
|
|
18
|
+
initial_set,
|
|
19
|
+
filter
|
|
20
|
+
}) {
|
|
21
|
+
|
|
22
|
+
const closed = new BitSet();
|
|
23
|
+
const open = [...initial_set];
|
|
24
|
+
|
|
25
|
+
const result_set = [];
|
|
26
|
+
|
|
27
|
+
while (open.length > 0) {
|
|
28
|
+
const current = open.pop();
|
|
29
|
+
|
|
30
|
+
closed.set(current.index, true);
|
|
31
|
+
|
|
32
|
+
result_set.push(current);
|
|
33
|
+
|
|
34
|
+
// get neighbours
|
|
35
|
+
|
|
36
|
+
const neighbour_count = current.getEdgeNeighbours(neighbours, 0);
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < neighbour_count; i++) {
|
|
39
|
+
const neighbour_face = neighbours[i];
|
|
40
|
+
|
|
41
|
+
if (closed.get(neighbour_face.index)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!filter(neighbour_face, current)) {
|
|
46
|
+
// rejected by filter
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (open.includes(neighbour_face)) {
|
|
51
|
+
// already included
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
open.push(neighbour_face);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return result_set;
|
|
61
|
+
}
|
package/engine/Engine.js
CHANGED
|
@@ -305,7 +305,7 @@ class Engine {
|
|
|
305
305
|
gameView.addChild(viewport);
|
|
306
306
|
|
|
307
307
|
this.viewStack = new ViewStack();
|
|
308
|
-
this.viewStack.push(gameView);
|
|
308
|
+
this.viewStack.push(gameView,'game-view');
|
|
309
309
|
|
|
310
310
|
//bind size of renderer viewport to game view
|
|
311
311
|
viewport.bindSignal(gameView.size.onChanged, viewport.size.set.bind(viewport.size));
|
package/engine/EngineHarness.js
CHANGED
|
@@ -260,7 +260,7 @@ export class EngineHarness {
|
|
|
260
260
|
}) {
|
|
261
261
|
|
|
262
262
|
if (enableLights) {
|
|
263
|
-
EngineHarness.buildLights({ engine: engine, shadowmapResolution });
|
|
263
|
+
await EngineHarness.buildLights({ engine: engine, shadowmapResolution });
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
const camera = EngineHarness.buildCamera({
|
|
@@ -307,11 +307,11 @@ export class EngineHarness {
|
|
|
307
307
|
* @param {EntityComponentDataset} ecd
|
|
308
308
|
* @param shadowmapResolution
|
|
309
309
|
*/
|
|
310
|
-
static buildLights({ engine, ecd = engine.entityManager.dataset, shadowmapResolution = 1024 }) {
|
|
310
|
+
static async buildLights({ engine, ecd = engine.entityManager.dataset, shadowmapResolution = 1024 }) {
|
|
311
311
|
const em = engine.entityManager;
|
|
312
312
|
|
|
313
|
-
if (em.
|
|
314
|
-
em.addSystem(new LightSystem(engine, {
|
|
313
|
+
if (!em.hasSystem(LightSystem)) {
|
|
314
|
+
await em.addSystem(new LightSystem(engine, {
|
|
315
315
|
shadowResolution: shadowmapResolution
|
|
316
316
|
}));
|
|
317
317
|
}
|
|
@@ -345,7 +345,7 @@ export class EngineHarness {
|
|
|
345
345
|
const fill = new Light();
|
|
346
346
|
fill.type.set(Light.Type.AMBIENT);
|
|
347
347
|
fill.color.setRGB(1, 1, 1);
|
|
348
|
-
fill.intensity.set(0.
|
|
348
|
+
fill.intensity.set(0.1);
|
|
349
349
|
|
|
350
350
|
|
|
351
351
|
new EntityBuilder()
|
|
@@ -233,7 +233,7 @@ export class EntityNode {
|
|
|
233
233
|
|
|
234
234
|
// live mode
|
|
235
235
|
if (this.__entity.isBuilt) {
|
|
236
|
-
|
|
236
|
+
node.build(this.__entity.dataset);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
return true;
|
|
@@ -256,7 +256,6 @@ export class EntityNode {
|
|
|
256
256
|
|
|
257
257
|
node.parent = null;
|
|
258
258
|
|
|
259
|
-
|
|
260
259
|
return true;
|
|
261
260
|
}
|
|
262
261
|
|
|
@@ -486,8 +486,11 @@ GraphicsEngine.prototype.normalizeViewportPoint = function (input, result) {
|
|
|
486
486
|
|
|
487
487
|
const viewportSize = this.viewport.size;
|
|
488
488
|
|
|
489
|
-
|
|
490
|
-
|
|
489
|
+
const _x = input.x;
|
|
490
|
+
const _y = input.y;
|
|
491
|
+
|
|
492
|
+
result.x = (_x / viewportSize.x) * 2 - 1;
|
|
493
|
+
result.y = -(_y / viewportSize.y) * 2 + 1;
|
|
491
494
|
};
|
|
492
495
|
|
|
493
496
|
/**
|
|
@@ -324,7 +324,7 @@ export class ShadedGeometry {
|
|
|
324
324
|
*
|
|
325
325
|
* @param {SurfacePoint3} contact if found, contact is written here
|
|
326
326
|
* @param {ArrayLike<number>|number[]|Float32Array} ray 6-tuple: [origin_x, origin_y, origin_z, direction_x, direction_y, direction_z]
|
|
327
|
-
* @param {ArrayLike<number>|number[]|Float32Array} transform_matrix4
|
|
327
|
+
* @param {ArrayLike<number>|number[]|Float32Array} transform_matrix4 transform applied to the geometry
|
|
328
328
|
* @returns {boolean}
|
|
329
329
|
*/
|
|
330
330
|
query_raycast_nearest(contact, ray, transform_matrix4) {
|
|
@@ -9,6 +9,7 @@ import { SGMeshEvents } from "./SGMeshEvents.js";
|
|
|
9
9
|
import { ParentEntity } from "../../../../ecs/parent/ParentEntity.js";
|
|
10
10
|
import { EntityNode } from "../../../../ecs/parent/EntityNode.js";
|
|
11
11
|
import { min2 } from "../../../../../core/math/min2.js";
|
|
12
|
+
import { TransformAttachmentSystem } from "../../../../ecs/transform-attachment/TransformAttachmentSystem.js";
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -69,6 +70,15 @@ export class SGMeshSystem extends System {
|
|
|
69
70
|
this.__asset_object_cache = new Map();
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
async startup(em, ready_callback, error_callback) {
|
|
74
|
+
|
|
75
|
+
if (!em.hasSystem(TransformAttachmentSystem)) {
|
|
76
|
+
await em.addSystem(new TransformAttachmentSystem());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
super.startup(em, ready_callback, error_callback);
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
/**
|
|
73
83
|
*
|
|
74
84
|
* @param {number} entity
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Uint32BufferAttribute } from "three";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
@@ -10,13 +10,14 @@ export function makeGeometryIndexed(geometry) {
|
|
|
10
10
|
if (index_attribute === null || index_attribute === undefined) {
|
|
11
11
|
const position_attribute = geometry.getAttribute('position');
|
|
12
12
|
// non-indexed geometry, build index
|
|
13
|
-
const
|
|
13
|
+
const size = position_attribute.count;
|
|
14
|
+
const array = new Uint32Array(size);
|
|
14
15
|
|
|
15
|
-
for (let i = 0; i <
|
|
16
|
+
for (let i = 0; i < size; i++) {
|
|
16
17
|
array[i] = i;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
index_attribute = new
|
|
20
|
+
index_attribute = new Uint32BufferAttribute(array, 1, false);
|
|
20
21
|
|
|
21
22
|
geometry.setIndex(index_attribute);
|
|
22
23
|
}
|