@woosh/meep-engine 2.41.0 → 2.42.0
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/apply_mat4_transform_to_v3_array.js +2 -4
- package/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +28 -0
- package/core/geom/Quaternion.js +14 -0
- package/engine/EngineHarness.js +9 -3
- package/engine/ecs/transform/Transform.js +23 -3
- package/engine/graphics/ecs/decal/v2/Decal.d.ts +11 -0
- package/engine/graphics/ecs/decal/v2/Decal.js +50 -0
- package/engine/graphics/ecs/decal/v2/FPDecalSystem.d.ts +8 -0
- package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +213 -0
- package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +237 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +8 -1
- package/engine/graphics/ecs/mesh-v2/build_three_object.js +4 -0
- package/engine/graphics/geometry/MikkT/MikkTSpace.js +466 -305
- package/engine/graphics/geometry/buffered/computeGeometryEquality.js +1 -1
- package/engine/graphics/geometry/buffered/computeGeometryHash.js +1 -1
- package/engine/graphics/impostors/octahedral/ImpostorBaker.js +27 -14
- package/engine/graphics/impostors/octahedral/ImpostorDescription.js +6 -0
- package/engine/graphics/impostors/octahedral/README.md +1 -0
- package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere.js +25 -22
- package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere_radius_only.js +37 -0
- package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +30 -1
- package/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +1 -1
- package/engine/graphics/impostors/octahedral/prototypeBaker.js +121 -22
- package/engine/graphics/impostors/octahedral/shader/BakeShaderStandard.js +46 -7
- package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +349 -0
- package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV1.js +74 -0
- package/engine/graphics/impostors/octahedral/shader/glsl/v1/common.glsl +209 -0
- package/engine/graphics/impostors/octahedral/shader/glsl/v1/flagment.glsl +80 -0
- package/engine/graphics/impostors/octahedral/shader/glsl/v1/vertex.glsl +350 -0
- package/engine/graphics/micron/render/v1/getTransformedPositionsCached.js +1 -1
- package/engine/graphics/render/forward_plus/LightManager.js +1 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +1 -3
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +2 -1
- package/engine/graphics/render/forward_plus/model/Decal.js +19 -2
- package/engine/graphics/texture/sampler/Sampler2D.js +10 -10
- package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +117 -11
- package/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +66 -0
- package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +2 -2
- package/package.json +1 -1
|
@@ -2,30 +2,36 @@ import { assert } from "../../../../core/assert.js";
|
|
|
2
2
|
import { EPSILON } from "../../../../core/math/MathUtils.js";
|
|
3
3
|
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
4
4
|
import { fabsf } from "../../../../core/math/fabsf.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
5
|
+
import { v3_distance_sqr } from "../../../../core/geom/v3_distance_sqr.js";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the
|
|
10
|
+
normal map sampler must use the exact inverse of the pixel shader transformation.
|
|
11
|
+
The most efficient transformation we can possibly do in the pixel shader is
|
|
12
|
+
achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN.
|
|
13
|
+
pixel shader (fast transform out)
|
|
14
|
+
vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
|
15
|
+
where vNt is the tangent space normal. The normal map sampler must likewise use the
|
|
16
|
+
interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader.
|
|
17
|
+
sampler does (exact inverse of pixel shader):
|
|
18
|
+
float3 row0 = cross(vB, vN);
|
|
19
|
+
float3 row1 = cross(vN, vT);
|
|
20
|
+
float3 row2 = cross(vT, vB);
|
|
21
|
+
float fSign = dot(vT, row0)<0 ? -1 : 1;
|
|
22
|
+
vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) );
|
|
23
|
+
where vNout is the sampled normal in some chosen 3D space.
|
|
24
|
+
|
|
25
|
+
Should you choose to reconstruct the bitangent in the pixel shader instead
|
|
26
|
+
of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also.
|
|
27
|
+
Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of
|
|
28
|
+
quads as your renderer then problems will occur since the interpolated tangent spaces will differ
|
|
29
|
+
eventhough the vertex level tangent spaces match. This can be solved either by triangulating before
|
|
30
|
+
sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier.
|
|
31
|
+
However, this must be used both by the sampler and your tools/rendering pipeline.
|
|
32
|
+
|
|
33
|
+
@see https://github.com/mmikk/MikkTSpace/blob/master/mikktspace.c
|
|
34
|
+
*/
|
|
29
35
|
|
|
30
36
|
|
|
31
37
|
/**
|
|
@@ -63,6 +69,12 @@ class SVec3 {
|
|
|
63
69
|
this.z = v;
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
copy(other) {
|
|
73
|
+
this.x = other.x;
|
|
74
|
+
this.y = other.y;
|
|
75
|
+
this.z = other.z;
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
}
|
|
67
79
|
|
|
68
80
|
class SEdge {
|
|
@@ -124,9 +136,9 @@ class STSpace {
|
|
|
124
136
|
* @param {STSpace} other
|
|
125
137
|
*/
|
|
126
138
|
copy(other) {
|
|
127
|
-
this.vOs
|
|
139
|
+
this.vOs.copy(other.vOs);
|
|
128
140
|
this.fMagS = other.fMagS;
|
|
129
|
-
this.vOt
|
|
141
|
+
this.vOt.copy(other.vOt);
|
|
130
142
|
this.fMagT = other.fMagT;
|
|
131
143
|
this.iCounter = other.iCounter;
|
|
132
144
|
this.bOrient = other.bOrient;
|
|
@@ -143,7 +155,7 @@ class SSubGroup {
|
|
|
143
155
|
|
|
144
156
|
/**
|
|
145
157
|
* *int
|
|
146
|
-
* @type {null}
|
|
158
|
+
* @type {Int32Array|null}
|
|
147
159
|
*/
|
|
148
160
|
this.pTriMembers = null;
|
|
149
161
|
}
|
|
@@ -210,130 +222,6 @@ class STriInfo {
|
|
|
210
222
|
}
|
|
211
223
|
}
|
|
212
224
|
|
|
213
|
-
class SMikkTSpaceInterface {
|
|
214
|
-
constructor() {
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Returns the number of faces (triangles/quads) on the mesh to be processed.
|
|
220
|
-
* @param {SMikkTSpaceContext} pContext
|
|
221
|
-
* @returns {number}
|
|
222
|
-
*/
|
|
223
|
-
m_getNumFaces(pContext) {
|
|
224
|
-
return pContext.geometry_buffer_index.length / 3;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Returns the number of vertices on face number iFace
|
|
229
|
-
* iFace is a number in the range {0, 1, ..., getNumFaces()-1}
|
|
230
|
-
* @param {SMikkTSpaceContext} pContext
|
|
231
|
-
* @param {number} iFace
|
|
232
|
-
* @returns {number}
|
|
233
|
-
*/
|
|
234
|
-
m_getNumVerticesOfFace(pContext, iFace) {
|
|
235
|
-
// only support triangles
|
|
236
|
-
return 3;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// returns the position/normal/texcoord of the referenced face of vertex number iVert.
|
|
240
|
-
// iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
*
|
|
244
|
-
* @param {SMikkTSpaceContext} pContext
|
|
245
|
-
* @param {number[]|{0:number,1:number,2:number}} fvPosOut
|
|
246
|
-
* @param {number} iFace
|
|
247
|
-
* @param {number} iVert
|
|
248
|
-
* @returns {void}
|
|
249
|
-
*/
|
|
250
|
-
m_getPosition(pContext, fvPosOut, iFace, iVert) {
|
|
251
|
-
// figure out which vertex it is
|
|
252
|
-
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
253
|
-
|
|
254
|
-
array_copy(pContext.geometry_buffer_vertex_position, vertex_index * 3, fvPosOut, 0, 3);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
*
|
|
259
|
-
* @param {SMikkTSpaceContext} pContext
|
|
260
|
-
* @param {number[]|{0:number,1:number,2:number}} fvNormOut
|
|
261
|
-
* @param {number} iFace
|
|
262
|
-
* @param {number} iVert
|
|
263
|
-
* @returns {void}
|
|
264
|
-
*/
|
|
265
|
-
m_getNormal(pContext, fvNormOut, iFace, iVert) {
|
|
266
|
-
// figure out which vertex it is
|
|
267
|
-
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
268
|
-
|
|
269
|
-
array_copy(pContext.geometry_buffer_vertex_normal, vertex_index * 3, fvNormOut, 0, 3);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
*
|
|
274
|
-
* @param {SMikkTSpaceContext} pContext
|
|
275
|
-
* @param {number[]|{0:number,1:number}} fvTexcOut
|
|
276
|
-
* @param {number} iFace
|
|
277
|
-
* @param {number} iVert
|
|
278
|
-
* @returns {void}
|
|
279
|
-
*/
|
|
280
|
-
m_getTexCoord(pContext, fvTexcOut, iFace, iVert) {
|
|
281
|
-
// figure out which vertex it is
|
|
282
|
-
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
283
|
-
|
|
284
|
-
array_copy(pContext.geometry_buffer_vertex_uv, vertex_index * 2, fvTexcOut, 0, 3);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* either (or both) of the two setTSpace callbacks can be set.
|
|
289
|
-
* The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
|
|
290
|
-
*
|
|
291
|
-
* This function is used to return the tangent and fSign to the application.
|
|
292
|
-
* fvTangent is a unit length vector.
|
|
293
|
-
* For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
|
|
294
|
-
* bitangent = fSign * cross(vN, tangent);
|
|
295
|
-
* Note that the results are returned unindexed. It is possible to generate a new index list
|
|
296
|
-
* But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
|
|
297
|
-
* DO NOT! use an already existing index list.
|
|
298
|
-
*
|
|
299
|
-
* @param {SMikkTSpaceContext} pContext
|
|
300
|
-
* @param {number[]} fvTangent
|
|
301
|
-
* @param {number} fSign
|
|
302
|
-
* @param {number} iFace
|
|
303
|
-
* @param {number} iVert
|
|
304
|
-
* @returns {void}
|
|
305
|
-
*/
|
|
306
|
-
m_setTSpaceBasic(pContext, fvTangent, fSign, iFace, iVert) {
|
|
307
|
-
throw new Error('Not supported');
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
*
|
|
312
|
-
* @param {SMikkTSpaceContext} pContext
|
|
313
|
-
* @param {number[]} fvTangent
|
|
314
|
-
* @param {number[]} fvBiTangent
|
|
315
|
-
* @param {number} fMagS
|
|
316
|
-
* @param {number} fMagT
|
|
317
|
-
* @param {boolean} bIsOrientationPreserving
|
|
318
|
-
* @param {number} iFace
|
|
319
|
-
* @param {number} iVert
|
|
320
|
-
* @returns {void}
|
|
321
|
-
*/
|
|
322
|
-
m_setTSpace(pContext, fvTangent, fvBiTangent, fMagS, fMagT, bIsOrientationPreserving, iFace, iVert) {
|
|
323
|
-
// figure out which vertex it is
|
|
324
|
-
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
325
|
-
|
|
326
|
-
const tangent_destination = pContext.geometry_buffer_vertex_tangent;
|
|
327
|
-
const tangent_address = vertex_index * 4;
|
|
328
|
-
|
|
329
|
-
// for logic explanation, see https://github.com/gltf-rs/mikktspace/blob/6275cc4f15cff8be29819fb34ae8be3b9129dae1/src/lib.rs#L33
|
|
330
|
-
tangent_destination[tangent_address] = fvTangent[0];
|
|
331
|
-
tangent_destination[tangent_address + 1] = fvTangent[1];
|
|
332
|
-
tangent_destination[tangent_address + 2] = fvTangent[2];
|
|
333
|
-
tangent_destination[tangent_address + 3] = bIsOrientationPreserving ? 1 : -1;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
225
|
export class SMikkTSpaceContext {
|
|
338
226
|
constructor() {
|
|
339
227
|
/**
|
|
@@ -367,15 +255,127 @@ export class SMikkTSpaceContext {
|
|
|
367
255
|
* @type {number[]}
|
|
368
256
|
*/
|
|
369
257
|
this.geometry_buffer_vertex_bitangent = [];
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
*
|
|
373
|
-
* @type {SMikkTSpaceInterface|null}
|
|
374
|
-
*/
|
|
375
|
-
this.m_pInterface = new SMikkTSpaceInterface();
|
|
376
258
|
}
|
|
377
259
|
}
|
|
378
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Returns the number of faces (triangles/quads) on the mesh to be processed.
|
|
263
|
+
* @param {SMikkTSpaceContext} pContext
|
|
264
|
+
* @returns {number}
|
|
265
|
+
*/
|
|
266
|
+
function m_getNumFaces(pContext) {
|
|
267
|
+
return pContext.geometry_buffer_index.length / 3;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Returns the number of vertices on face number iFace
|
|
272
|
+
* iFace is a number in the range {0, 1, ..., getNumFaces()-1}
|
|
273
|
+
* @param {SMikkTSpaceContext} pContext
|
|
274
|
+
* @param {number} iFace
|
|
275
|
+
* @returns {number}
|
|
276
|
+
*/
|
|
277
|
+
function m_getNumVerticesOfFace(pContext, iFace) {
|
|
278
|
+
// only support triangles
|
|
279
|
+
return 3;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// returns the position/normal/texcoord of the referenced face of vertex number iVert.
|
|
283
|
+
// iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
*
|
|
287
|
+
* @param {SMikkTSpaceContext} pContext
|
|
288
|
+
* @param {number[]|{0:number,1:number,2:number}} fvPosOut
|
|
289
|
+
* @param {number} iFace
|
|
290
|
+
* @param {number} iVert
|
|
291
|
+
* @returns {void}
|
|
292
|
+
*/
|
|
293
|
+
function m_getPosition(pContext, fvPosOut, iFace, iVert) {
|
|
294
|
+
// figure out which vertex it is
|
|
295
|
+
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
296
|
+
|
|
297
|
+
array_copy(pContext.geometry_buffer_vertex_position, vertex_index * 3, fvPosOut, 0, 3);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
*
|
|
302
|
+
* @param {SMikkTSpaceContext} pContext
|
|
303
|
+
* @param {number[]|{0:number,1:number,2:number}} fvNormOut
|
|
304
|
+
* @param {number} iFace
|
|
305
|
+
* @param {number} iVert
|
|
306
|
+
* @returns {void}
|
|
307
|
+
*/
|
|
308
|
+
function m_getNormal(pContext, fvNormOut, iFace, iVert) {
|
|
309
|
+
// figure out which vertex it is
|
|
310
|
+
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
311
|
+
|
|
312
|
+
array_copy(pContext.geometry_buffer_vertex_normal, vertex_index * 3, fvNormOut, 0, 3);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
*
|
|
317
|
+
* @param {SMikkTSpaceContext} pContext
|
|
318
|
+
* @param {number[]|{0:number,1:number}} fvTexcOut
|
|
319
|
+
* @param {number} iFace
|
|
320
|
+
* @param {number} iVert
|
|
321
|
+
* @returns {void}
|
|
322
|
+
*/
|
|
323
|
+
function m_getTexCoord(pContext, fvTexcOut, iFace, iVert) {
|
|
324
|
+
// figure out which vertex it is
|
|
325
|
+
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
326
|
+
|
|
327
|
+
array_copy(pContext.geometry_buffer_vertex_uv, vertex_index * 2, fvTexcOut, 0, 3);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* either (or both) of the two setTSpace callbacks can be set.
|
|
332
|
+
* The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
|
|
333
|
+
*
|
|
334
|
+
* This function is used to return the tangent and fSign to the application.
|
|
335
|
+
* fvTangent is a unit length vector.
|
|
336
|
+
* For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
|
|
337
|
+
* bitangent = fSign * cross(vN, tangent);
|
|
338
|
+
* Note that the results are returned unindexed. It is possible to generate a new index list
|
|
339
|
+
* But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
|
|
340
|
+
* DO NOT! use an already existing index list.
|
|
341
|
+
*
|
|
342
|
+
* @param {SMikkTSpaceContext} pContext
|
|
343
|
+
* @param {number[]} fvTangent
|
|
344
|
+
* @param {number} fSign
|
|
345
|
+
* @param {number} iFace
|
|
346
|
+
* @param {number} iVert
|
|
347
|
+
* @returns {void}
|
|
348
|
+
*/
|
|
349
|
+
function m_setTSpaceBasic(pContext, fvTangent, fSign, iFace, iVert) {
|
|
350
|
+
throw new Error('Not supported');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
*
|
|
355
|
+
* @param {SMikkTSpaceContext} pContext
|
|
356
|
+
* @param {number[]} fvTangent
|
|
357
|
+
* @param {number[]} fvBiTangent
|
|
358
|
+
* @param {number} fMagS
|
|
359
|
+
* @param {number} fMagT
|
|
360
|
+
* @param {boolean} bIsOrientationPreserving
|
|
361
|
+
* @param {number} iFace
|
|
362
|
+
* @param {number} iVert
|
|
363
|
+
* @returns {void}
|
|
364
|
+
*/
|
|
365
|
+
function m_setTSpace(pContext, fvTangent, fvBiTangent, fMagS, fMagT, bIsOrientationPreserving, iFace, iVert) {
|
|
366
|
+
// figure out which vertex it is
|
|
367
|
+
const vertex_index = pContext.geometry_buffer_index[iFace * 3 + iVert];
|
|
368
|
+
|
|
369
|
+
const tangent_destination = pContext.geometry_buffer_vertex_tangent;
|
|
370
|
+
const tangent_address = vertex_index * 4;
|
|
371
|
+
|
|
372
|
+
// for logic explanation, see https://github.com/gltf-rs/mikktspace/blob/6275cc4f15cff8be29819fb34ae8be3b9129dae1/src/lib.rs#L33
|
|
373
|
+
tangent_destination[tangent_address] = fvTangent[0];
|
|
374
|
+
tangent_destination[tangent_address + 1] = fvTangent[1];
|
|
375
|
+
tangent_destination[tangent_address + 2] = fvTangent[2];
|
|
376
|
+
tangent_destination[tangent_address + 3] = bIsOrientationPreserving ? 1 : -1;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
379
|
const MARK_DEGENERATE = 1;
|
|
380
380
|
const QUAD_ONE_DEGEN_TRI = 2;
|
|
381
381
|
const GROUP_WITH_ANY = 4;
|
|
@@ -395,34 +395,38 @@ function veq(v1, v2) {
|
|
|
395
395
|
|
|
396
396
|
/**
|
|
397
397
|
*
|
|
398
|
+
* @param {SVec3} res
|
|
398
399
|
* @param {SVec3} v1
|
|
399
400
|
* @param {SVec3} v2
|
|
400
|
-
* @returns {SVec3}
|
|
401
401
|
*/
|
|
402
|
-
function vadd(v1, v2) {
|
|
403
|
-
const res = new SVec3();
|
|
402
|
+
function vadd(res, v1, v2) {
|
|
404
403
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
404
|
+
const x = v1.x + v2.x;
|
|
405
|
+
const y = v1.y + v2.y;
|
|
406
|
+
const z = v1.z + v2.z;
|
|
407
|
+
|
|
408
|
+
res.x = x;
|
|
409
|
+
res.y = y;
|
|
410
|
+
res.z = z;
|
|
408
411
|
|
|
409
|
-
return res;
|
|
410
412
|
}
|
|
411
413
|
|
|
412
414
|
/**
|
|
413
415
|
*
|
|
416
|
+
* @param {SVec3} res
|
|
414
417
|
* @param {SVec3} v1
|
|
415
418
|
* @param {SVec3} v2
|
|
416
|
-
* @returns {SVec3}
|
|
417
419
|
*/
|
|
418
|
-
function vsub(v1, v2) {
|
|
419
|
-
const res = new SVec3();
|
|
420
|
+
function vsub(res, v1, v2) {
|
|
420
421
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
const x = v1.x - v2.x;
|
|
423
|
+
const y = v1.y - v2.y;
|
|
424
|
+
const z = v1.z - v2.z;
|
|
425
|
+
|
|
426
|
+
res.x = x;
|
|
427
|
+
res.y = y;
|
|
428
|
+
res.z = z;
|
|
424
429
|
|
|
425
|
-
return res;
|
|
426
430
|
}
|
|
427
431
|
|
|
428
432
|
/**
|
|
@@ -450,6 +454,16 @@ function LengthSquared(v) {
|
|
|
450
454
|
return v.x * v.x + v.y * v.y + v.z * v.z;
|
|
451
455
|
}
|
|
452
456
|
|
|
457
|
+
/**
|
|
458
|
+
*
|
|
459
|
+
* @param {SVec3} v0
|
|
460
|
+
* @param {SVec3} v1
|
|
461
|
+
* @returns {number}
|
|
462
|
+
*/
|
|
463
|
+
function DistanceSquared(v0, v1) {
|
|
464
|
+
return v3_distance_sqr(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z);
|
|
465
|
+
}
|
|
466
|
+
|
|
453
467
|
/**
|
|
454
468
|
*
|
|
455
469
|
* @param {SVec3} v
|
|
@@ -462,11 +476,22 @@ function Length(v) {
|
|
|
462
476
|
|
|
463
477
|
/**
|
|
464
478
|
*
|
|
465
|
-
* @param {SVec3}
|
|
466
|
-
* @
|
|
479
|
+
* @param {SVec3} out
|
|
480
|
+
* @param {SVec3} input
|
|
467
481
|
*/
|
|
468
|
-
function
|
|
469
|
-
|
|
482
|
+
function NormalizeSafe(out, input) {
|
|
483
|
+
|
|
484
|
+
const len = Length(input);
|
|
485
|
+
|
|
486
|
+
if (len !== 0) {
|
|
487
|
+
const m = 1 / len;
|
|
488
|
+
|
|
489
|
+
out.x = input.x * m;
|
|
490
|
+
out.y = input.y * m;
|
|
491
|
+
out.z = input.z * m;
|
|
492
|
+
} else {
|
|
493
|
+
out.copy(input);
|
|
494
|
+
}
|
|
470
495
|
}
|
|
471
496
|
|
|
472
497
|
/**
|
|
@@ -481,11 +506,11 @@ function vdot(v1, v2) {
|
|
|
481
506
|
|
|
482
507
|
/**
|
|
483
508
|
*
|
|
484
|
-
* @param {number}
|
|
509
|
+
* @param {number} v
|
|
485
510
|
* @returns {boolean}
|
|
486
511
|
*/
|
|
487
|
-
function NotZero(
|
|
488
|
-
return Math.abs(
|
|
512
|
+
function NotZero(v) {
|
|
513
|
+
return Math.abs(v) > EPSILON;
|
|
489
514
|
}
|
|
490
515
|
|
|
491
516
|
/**
|
|
@@ -519,19 +544,25 @@ function AvgTSpace(ts_res, pTS0, pTS1) {
|
|
|
519
544
|
// this if is important. Due to floating point precision
|
|
520
545
|
// averaging when ts0==ts1 will cause a slight difference
|
|
521
546
|
// which results in tangent space splits later on
|
|
522
|
-
if (
|
|
523
|
-
|
|
547
|
+
if (
|
|
548
|
+
pTS0.fMagS === pTS1.fMagS && pTS0.fMagT === pTS1.fMagT &&
|
|
549
|
+
veq(pTS0.vOs, pTS1.vOs) && veq(pTS0.vOt, pTS1.vOt)
|
|
550
|
+
) {
|
|
551
|
+
|
|
524
552
|
ts_res.fMagS = pTS0.fMagS;
|
|
525
553
|
ts_res.fMagT = pTS0.fMagT;
|
|
526
554
|
ts_res.vOs = pTS0.vOs;
|
|
527
555
|
ts_res.vOt = pTS0.vOt;
|
|
556
|
+
|
|
528
557
|
} else {
|
|
529
558
|
ts_res.fMagS = 0.5 * (pTS0.fMagS + pTS1.fMagS);
|
|
530
559
|
ts_res.fMagT = 0.5 * (pTS0.fMagT + pTS1.fMagT);
|
|
531
|
-
|
|
532
|
-
ts_res.
|
|
533
|
-
|
|
534
|
-
|
|
560
|
+
|
|
561
|
+
vadd(ts_res.vOs, pTS0.vOs, pTS1.vOs);
|
|
562
|
+
vadd(ts_res.vOt, pTS0.vOt, pTS1.vOt);
|
|
563
|
+
|
|
564
|
+
NormalizeSafe(ts_res.vOs, ts_res.vOs);
|
|
565
|
+
NormalizeSafe(ts_res.vOt, ts_res.vOt);
|
|
535
566
|
}
|
|
536
567
|
|
|
537
568
|
}
|
|
@@ -550,7 +581,7 @@ function GetPosition(pContext, index) {
|
|
|
550
581
|
const iF = index & 0x3;
|
|
551
582
|
const iI = index >> 2;
|
|
552
583
|
|
|
553
|
-
|
|
584
|
+
m_getPosition(pContext, res, iF, iI);
|
|
554
585
|
|
|
555
586
|
return res;
|
|
556
587
|
}
|
|
@@ -568,26 +599,25 @@ function GetNormal(pContext, index) {
|
|
|
568
599
|
const iF = index & 0x3;
|
|
569
600
|
const iI = index >> 2;
|
|
570
601
|
|
|
571
|
-
|
|
602
|
+
m_getNormal(pContext, res, iF, iI);
|
|
572
603
|
|
|
573
604
|
return res;
|
|
574
605
|
}
|
|
575
606
|
|
|
576
607
|
/**
|
|
577
608
|
* TODO doesn't need to be V3, can save memory
|
|
609
|
+
* @param {SVec3} res
|
|
578
610
|
* @param {SMikkTSpaceContext} pContext
|
|
579
611
|
* @param {number} index
|
|
580
612
|
* @returns {SVec3}
|
|
581
613
|
*/
|
|
582
|
-
function GetTexCoord(pContext, index) {
|
|
583
|
-
|
|
584
|
-
const res = new SVec3();
|
|
614
|
+
function GetTexCoord(res, pContext, index) {
|
|
585
615
|
|
|
586
616
|
// inlined : IndexToData(&iF, &iI, index);
|
|
587
617
|
const iF = index & 0x3;
|
|
588
618
|
const iI = index >> 2;
|
|
589
619
|
|
|
590
|
-
|
|
620
|
+
m_getTexCoord(pContext, res, iF, iI);
|
|
591
621
|
|
|
592
622
|
res.z = 1;
|
|
593
623
|
|
|
@@ -702,9 +732,13 @@ function GetEdge(out, indices, indices_offset, i0_in, i1_in) {
|
|
|
702
732
|
*/
|
|
703
733
|
function CalcTexArea(pContext, indices, indices_offset) {
|
|
704
734
|
|
|
705
|
-
const t1 =
|
|
706
|
-
const t2 =
|
|
707
|
-
const t3 =
|
|
735
|
+
const t1 = new SVec3();
|
|
736
|
+
const t2 = new SVec3();
|
|
737
|
+
const t3 = new SVec3();
|
|
738
|
+
|
|
739
|
+
GetTexCoord(t1, pContext, indices[indices_offset + 0]);
|
|
740
|
+
GetTexCoord(t2, pContext, indices[indices_offset + 1]);
|
|
741
|
+
GetTexCoord(t3, pContext, indices[indices_offset + 2]);
|
|
708
742
|
|
|
709
743
|
const t21x = t2.x - t1.x;
|
|
710
744
|
const t21y = t2.y - t1.y;
|
|
@@ -745,71 +779,94 @@ function malloc(Klass, count) {
|
|
|
745
779
|
*/
|
|
746
780
|
function EvalTspace(face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVertexRepresentitive) {
|
|
747
781
|
const res = new STSpace();
|
|
782
|
+
|
|
748
783
|
let fAngleSum = 0;
|
|
749
784
|
let face = 0;
|
|
785
|
+
|
|
750
786
|
res.vOs.x = 0.0;
|
|
751
787
|
res.vOs.y = 0.0;
|
|
752
788
|
res.vOs.z = 0.0;
|
|
789
|
+
|
|
753
790
|
res.vOt.x = 0.0;
|
|
754
791
|
res.vOt.y = 0.0;
|
|
755
792
|
res.vOt.z = 0.0;
|
|
793
|
+
|
|
756
794
|
res.fMagS = 0;
|
|
757
795
|
res.fMagT = 0;
|
|
758
796
|
|
|
797
|
+
const vOs = new SVec3();
|
|
798
|
+
const vOt = new SVec3();
|
|
799
|
+
|
|
759
800
|
for (face = 0; face < iFaces; face++) {
|
|
760
801
|
const f = face_indices[face];
|
|
802
|
+
const tri_info = pTriInfos[f];
|
|
761
803
|
|
|
762
804
|
// only valid triangles get to add their contribution
|
|
763
|
-
if ((
|
|
805
|
+
if ((tri_info.iFlag & GROUP_WITH_ANY) === 0) {
|
|
764
806
|
/**
|
|
765
807
|
* @type {SVec3}
|
|
766
808
|
*/
|
|
767
|
-
let n,
|
|
809
|
+
let n, p0, p1, p2, v1, v2;
|
|
768
810
|
/**
|
|
769
811
|
* @type {number}
|
|
770
812
|
*/
|
|
771
813
|
let fCos, fAngle, fMagS, fMagT;
|
|
772
814
|
let i = -1, index = -1, i0 = -1, i1 = -1, i2 = -1;
|
|
773
815
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
816
|
+
const f3 = 3 * f;
|
|
817
|
+
|
|
818
|
+
if (piTriListIn[f3] === iVertexRepresentitive) {
|
|
819
|
+
i = 0;
|
|
820
|
+
} else if (piTriListIn[f3 + 1] === iVertexRepresentitive) {
|
|
821
|
+
i = 1;
|
|
822
|
+
} else if (piTriListIn[f3 + 2] === iVertexRepresentitive) {
|
|
823
|
+
i = 2;
|
|
824
|
+
}
|
|
825
|
+
|
|
777
826
|
assert(i >= 0 && i < 3);
|
|
778
827
|
|
|
779
828
|
// project
|
|
780
|
-
index = piTriListIn[
|
|
829
|
+
index = piTriListIn[f3 + i];
|
|
781
830
|
n = GetNormal(pContext, index);
|
|
782
|
-
vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n));
|
|
783
|
-
vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n));
|
|
784
|
-
if (VNotZero(vOs)) vOs = Normalize(vOs);
|
|
785
|
-
if (VNotZero(vOt)) vOt = Normalize(vOt);
|
|
786
831
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
832
|
+
vsub(vOs, tri_info.vOs, vscale(vdot(n, tri_info.vOs), n));
|
|
833
|
+
|
|
834
|
+
vsub(vOt, tri_info.vOt, vscale(vdot(n, tri_info.vOt), n));
|
|
835
|
+
|
|
836
|
+
NormalizeSafe(vOs, vOs);
|
|
837
|
+
NormalizeSafe(vOt, vOt);
|
|
838
|
+
|
|
839
|
+
i2 = piTriListIn[f3 + (i < 2 ? (i + 1) : 0)];
|
|
840
|
+
i1 = piTriListIn[f3 + i];
|
|
841
|
+
i0 = piTriListIn[f3 + (i > 0 ? (i - 1) : 2)];
|
|
790
842
|
|
|
791
843
|
p0 = GetPosition(pContext, i0);
|
|
792
844
|
p1 = GetPosition(pContext, i1);
|
|
793
845
|
p2 = GetPosition(pContext, i2);
|
|
794
|
-
|
|
795
|
-
|
|
846
|
+
|
|
847
|
+
v1 = new SVec3();
|
|
848
|
+
vsub(v1, p0, p1);
|
|
849
|
+
v2 = new SVec3();
|
|
850
|
+
vsub(v2, p2, p1);
|
|
796
851
|
|
|
797
852
|
// project
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
853
|
+
vsub(v1, v1, vscale(vdot(n, v1), n));
|
|
854
|
+
NormalizeSafe(v1, v1);
|
|
855
|
+
|
|
856
|
+
vsub(v2, v2, vscale(vdot(n, v2), n));
|
|
857
|
+
NormalizeSafe(v2, v2);
|
|
802
858
|
|
|
803
859
|
// weight contribution by the angle
|
|
804
860
|
// between the two edge vectors
|
|
805
861
|
fCos = vdot(v1, v2);
|
|
806
862
|
fCos = fCos > 1 ? 1 : (fCos < (-1) ? (-1) : fCos);
|
|
807
863
|
fAngle = Math.acos(fCos);
|
|
808
|
-
fMagS =
|
|
809
|
-
fMagT =
|
|
864
|
+
fMagS = tri_info.fMagS;
|
|
865
|
+
fMagT = tri_info.fMagT;
|
|
866
|
+
|
|
867
|
+
vadd(res.vOs, res.vOs, vscale(fAngle, vOs));
|
|
868
|
+
vadd(res.vOt, res.vOt, vscale(fAngle, vOt));
|
|
810
869
|
|
|
811
|
-
res.vOs = vadd(res.vOs, vscale(fAngle, vOs));
|
|
812
|
-
res.vOt = vadd(res.vOt, vscale(fAngle, vOt));
|
|
813
870
|
res.fMagS += (fAngle * fMagS);
|
|
814
871
|
res.fMagT += (fAngle * fMagT);
|
|
815
872
|
fAngleSum += fAngle;
|
|
@@ -817,8 +874,9 @@ function EvalTspace(face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVer
|
|
|
817
874
|
}
|
|
818
875
|
|
|
819
876
|
// normalize
|
|
820
|
-
|
|
821
|
-
|
|
877
|
+
NormalizeSafe(res.vOs, res.vOs);
|
|
878
|
+
NormalizeSafe(res.vOt, res.vOt);
|
|
879
|
+
|
|
822
880
|
if (fAngleSum > 0) {
|
|
823
881
|
res.fMagS /= fAngleSum;
|
|
824
882
|
res.fMagT /= fAngleSum;
|
|
@@ -836,11 +894,21 @@ function EvalTspace(face_indices, iFaces, piTriListIn, pTriInfos, pContext, iVer
|
|
|
836
894
|
function CompareSubGroups(pg1, pg2) {
|
|
837
895
|
let bStillSame = true;
|
|
838
896
|
let i = 0;
|
|
839
|
-
|
|
897
|
+
|
|
898
|
+
if (pg1.iNrFaces !== pg2.iNrFaces) {
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
901
|
+
|
|
840
902
|
while (i < pg1.iNrFaces && bStillSame) {
|
|
903
|
+
|
|
841
904
|
bStillSame = pg1.pTriMembers[i] === pg2.pTriMembers[i];
|
|
842
|
-
|
|
905
|
+
|
|
906
|
+
if (bStillSame) {
|
|
907
|
+
++i;
|
|
908
|
+
}
|
|
909
|
+
|
|
843
910
|
}
|
|
911
|
+
|
|
844
912
|
return bStillSame;
|
|
845
913
|
}
|
|
846
914
|
|
|
@@ -906,13 +974,18 @@ function BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn) {
|
|
|
906
974
|
// build array of edges
|
|
907
975
|
const uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
|
|
908
976
|
let iEntries = 0, iCurStartIndex = -1, f = 0, i = 0;
|
|
977
|
+
|
|
909
978
|
for (f = 0; f < iNrTrianglesIn; f++)
|
|
979
|
+
|
|
910
980
|
for (i = 0; i < 3; i++) {
|
|
911
981
|
const i0 = piTriListIn[f * 3 + i];
|
|
912
982
|
const i1 = piTriListIn[f * 3 + (i < 2 ? (i + 1) : 0)];
|
|
913
|
-
|
|
914
|
-
pEdges[f * 3 + i]
|
|
915
|
-
|
|
983
|
+
|
|
984
|
+
const edge = pEdges[f * 3 + i];
|
|
985
|
+
|
|
986
|
+
edge.i0 = i0 < i1 ? i0 : i1; // put minimum index in i0
|
|
987
|
+
edge.i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1
|
|
988
|
+
edge.f = f; // record face number
|
|
916
989
|
}
|
|
917
990
|
|
|
918
991
|
// sort over all edges by i0, this is the pricy one.
|
|
@@ -923,6 +996,7 @@ function BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn) {
|
|
|
923
996
|
// with i0 as msb in the quicksort call above.
|
|
924
997
|
iEntries = iNrTrianglesIn * 3;
|
|
925
998
|
iCurStartIndex = 0;
|
|
999
|
+
|
|
926
1000
|
for (i = 1; i < iEntries; i++) {
|
|
927
1001
|
if (pEdges[iCurStartIndex].i0 !== pEdges[i].i0) {
|
|
928
1002
|
const iL = iCurStartIndex;
|
|
@@ -1061,45 +1135,66 @@ function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
|
|
|
1061
1135
|
// pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function.
|
|
1062
1136
|
|
|
1063
1137
|
// generate neighbor info list
|
|
1064
|
-
for (f = 0; f < iNrTrianglesIn; f++)
|
|
1138
|
+
for (f = 0; f < iNrTrianglesIn; f++) {
|
|
1065
1139
|
for (i = 0; i < 3; i++) {
|
|
1066
|
-
pTriInfos[f]
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1140
|
+
const tri = pTriInfos[f];
|
|
1141
|
+
|
|
1142
|
+
tri.FaceNeighbors[i] = -1;
|
|
1143
|
+
tri.AssignedGroup[i] = null;
|
|
1144
|
+
|
|
1145
|
+
tri.vOs.x = 0.0;
|
|
1146
|
+
tri.vOs.y = 0.0;
|
|
1147
|
+
tri.vOs.z = 0.0;
|
|
1148
|
+
|
|
1149
|
+
tri.vOt.x = 0.0;
|
|
1150
|
+
tri.vOt.y = 0.0;
|
|
1151
|
+
tri.vOt.z = 0.0;
|
|
1152
|
+
|
|
1153
|
+
tri.fMagS = 0;
|
|
1154
|
+
tri.fMagT = 0;
|
|
1077
1155
|
|
|
1078
1156
|
// assumed bad
|
|
1079
|
-
|
|
1157
|
+
tri.iFlag |= GROUP_WITH_ANY;
|
|
1080
1158
|
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
const t1 = new SVec3();
|
|
1162
|
+
const t2 = new SVec3();
|
|
1163
|
+
const t3 = new SVec3();
|
|
1164
|
+
|
|
1165
|
+
const d1 = new SVec3();
|
|
1166
|
+
const d2 = new SVec3();
|
|
1167
|
+
|
|
1168
|
+
const vOs = new SVec3();
|
|
1169
|
+
const vOt = new SVec3();
|
|
1081
1170
|
|
|
1082
1171
|
// evaluate first order derivatives
|
|
1083
1172
|
for (f = 0; f < iNrTrianglesIn; f++) {
|
|
1084
1173
|
// initial values
|
|
1085
|
-
const
|
|
1086
|
-
|
|
1087
|
-
const
|
|
1088
|
-
const
|
|
1089
|
-
const
|
|
1090
|
-
|
|
1174
|
+
const f3 = f * 3;
|
|
1175
|
+
|
|
1176
|
+
const v1 = GetPosition(pContext, piTriListIn[f3 + 0]);
|
|
1177
|
+
const v2 = GetPosition(pContext, piTriListIn[f3 + 1]);
|
|
1178
|
+
const v3 = GetPosition(pContext, piTriListIn[f3 + 2]);
|
|
1179
|
+
|
|
1180
|
+
GetTexCoord(t1, pContext, piTriListIn[f3 + 0]);
|
|
1181
|
+
GetTexCoord(t2, pContext, piTriListIn[f3 + 1]);
|
|
1182
|
+
GetTexCoord(t3, pContext, piTriListIn[f3 + 2]);
|
|
1091
1183
|
|
|
1092
1184
|
const t21x = t2.x - t1.x;
|
|
1093
1185
|
const t21y = t2.y - t1.y;
|
|
1186
|
+
|
|
1094
1187
|
const t31x = t3.x - t1.x;
|
|
1095
1188
|
const t31y = t3.y - t1.y;
|
|
1096
|
-
|
|
1097
|
-
|
|
1189
|
+
|
|
1190
|
+
vsub(d1, v2, v1);
|
|
1191
|
+
vsub(d2, v3, v1);
|
|
1098
1192
|
|
|
1099
1193
|
const fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
|
|
1100
1194
|
//assert(fSignedAreaSTx2!=0);
|
|
1101
|
-
|
|
1102
|
-
|
|
1195
|
+
vsub(vOs, vscale(t31y, d1), vscale(t21y, d2)); // eq 18
|
|
1196
|
+
|
|
1197
|
+
vadd(vOt, vscale(-t31x, d1), vscale(t21x, d2)); // eq 19
|
|
1103
1198
|
|
|
1104
1199
|
pTriInfos[f].iFlag |= (fSignedAreaSTx2 > 0 ? ORIENT_PRESERVING : 0);
|
|
1105
1200
|
|
|
@@ -1108,16 +1203,21 @@ function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
|
|
|
1108
1203
|
const fLenOs = Length(vOs);
|
|
1109
1204
|
const fLenOt = Length(vOt);
|
|
1110
1205
|
const fS = (pTriInfos[f].iFlag & ORIENT_PRESERVING) === 0 ? (-1.0) : 1.0;
|
|
1111
|
-
if (NotZero(fLenOs))
|
|
1112
|
-
|
|
1206
|
+
if (NotZero(fLenOs)) {
|
|
1207
|
+
pTriInfos[f].vOs = vscale(fS / fLenOs, vOs);
|
|
1208
|
+
}
|
|
1209
|
+
if (NotZero(fLenOt)) {
|
|
1210
|
+
pTriInfos[f].vOt = vscale(fS / fLenOt, vOt);
|
|
1211
|
+
}
|
|
1113
1212
|
|
|
1114
1213
|
// evaluate magnitudes prior to normalization of vOs and vOt
|
|
1115
1214
|
pTriInfos[f].fMagS = fLenOs / fAbsArea;
|
|
1116
1215
|
pTriInfos[f].fMagT = fLenOt / fAbsArea;
|
|
1117
1216
|
|
|
1118
1217
|
// if this is a good triangle
|
|
1119
|
-
if (NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT))
|
|
1218
|
+
if (NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) {
|
|
1120
1219
|
pTriInfos[f].iFlag &= (~GROUP_WITH_ANY);
|
|
1220
|
+
}
|
|
1121
1221
|
}
|
|
1122
1222
|
}
|
|
1123
1223
|
|
|
@@ -1140,7 +1240,7 @@ function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
|
|
|
1140
1240
|
//printf("found quad with bad mapping\n");
|
|
1141
1241
|
let bChooseOrientFirstTri = false;
|
|
1142
1242
|
if ((pTriInfos[t + 1].iFlag & GROUP_WITH_ANY) !== 0) bChooseOrientFirstTri = true;
|
|
1143
|
-
else if (CalcTexArea(pContext, piTriListIn, t * 3
|
|
1243
|
+
else if (CalcTexArea(pContext, piTriListIn, t * 3) >= CalcTexArea(pContext, piTriListIn, (t + 1) * 3 + 0))
|
|
1144
1244
|
bChooseOrientFirstTri = true;
|
|
1145
1245
|
|
|
1146
1246
|
// force match
|
|
@@ -1176,21 +1276,14 @@ export function genTangSpace(pContext, fAngularThreshold = 180) {
|
|
|
1176
1276
|
let iNrTrianglesIn = 0, f = 0, t = 0, i = 0;
|
|
1177
1277
|
let iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0;
|
|
1178
1278
|
let iNrActiveGroups = 0, index = 0;
|
|
1179
|
-
const iNrFaces =
|
|
1279
|
+
const iNrFaces = m_getNumFaces(pContext);
|
|
1180
1280
|
let bRes = false;
|
|
1181
1281
|
const fThresCos = Math.cos((fAngularThreshold * Math.PI) / 180.0);
|
|
1182
1282
|
|
|
1183
|
-
// verify all call-backs have been set
|
|
1184
|
-
if (pContext.m_pInterface.m_getNumFaces === null ||
|
|
1185
|
-
pContext.m_pInterface.m_getNumVerticesOfFace === null ||
|
|
1186
|
-
pContext.m_pInterface.m_getPosition === null ||
|
|
1187
|
-
pContext.m_pInterface.m_getNormal === null ||
|
|
1188
|
-
pContext.m_pInterface.m_getTexCoord === null)
|
|
1189
|
-
return false;
|
|
1190
1283
|
|
|
1191
1284
|
// count triangles on supported faces
|
|
1192
1285
|
for (f = 0; f < iNrFaces; f++) {
|
|
1193
|
-
const verts =
|
|
1286
|
+
const verts = m_getNumVerticesOfFace(pContext, f);
|
|
1194
1287
|
if (verts === 3) ++iNrTrianglesIn;
|
|
1195
1288
|
else if (verts === 4) iNrTrianglesIn += 2;
|
|
1196
1289
|
}
|
|
@@ -1294,7 +1387,7 @@ export function genTangSpace(pContext, fAngularThreshold = 180) {
|
|
|
1294
1387
|
|
|
1295
1388
|
index = 0;
|
|
1296
1389
|
for (f = 0; f < iNrFaces; f++) {
|
|
1297
|
-
const verts =
|
|
1390
|
+
const verts = m_getNumVerticesOfFace(pContext, f);
|
|
1298
1391
|
if (verts !== 3 && verts !== 4) continue;
|
|
1299
1392
|
|
|
1300
1393
|
|
|
@@ -1325,7 +1418,7 @@ export function genTangSpace(pContext, fAngularThreshold = 180) {
|
|
|
1325
1418
|
const tang = [pTSpace.vOs.x, pTSpace.vOs.y, pTSpace.vOs.z];
|
|
1326
1419
|
const bitang = [pTSpace.vOt.x, pTSpace.vOt.y, pTSpace.vOt.z];
|
|
1327
1420
|
|
|
1328
|
-
|
|
1421
|
+
m_setTSpace(pContext, tang, bitang, pTSpace.fMagS, pTSpace.fMagT, pTSpace.bOrient, f, i);
|
|
1329
1422
|
|
|
1330
1423
|
++index;
|
|
1331
1424
|
}
|
|
@@ -1390,7 +1483,10 @@ function GenerateSharedVerticesIndexList(piTriList_in_and_out, pContext, iNrTria
|
|
|
1390
1483
|
else if (vMax.z < vP.z) vMax.z = vP.z;
|
|
1391
1484
|
}
|
|
1392
1485
|
|
|
1393
|
-
vDim =
|
|
1486
|
+
vDim = new SVec3();
|
|
1487
|
+
|
|
1488
|
+
vsub(vDim, vMax, vMin);
|
|
1489
|
+
|
|
1394
1490
|
iChannel = 0;
|
|
1395
1491
|
fMin = vMin.x;
|
|
1396
1492
|
fMax = vMax.x;
|
|
@@ -1485,14 +1581,25 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
|
|
|
1485
1581
|
let c = 0, l = 0, channel = 0;
|
|
1486
1582
|
let fvMin = [], fvMax = [];
|
|
1487
1583
|
let dx = 0, dy = 0, dz = 0, fSep = 0;
|
|
1584
|
+
|
|
1488
1585
|
for (c = 0; c < 3; c++) {
|
|
1489
1586
|
fvMin[c] = pTmpVert[iL_in].vert[c];
|
|
1490
1587
|
fvMax[c] = fvMin[c];
|
|
1491
1588
|
}
|
|
1589
|
+
|
|
1492
1590
|
for (l = (iL_in + 1); l <= iR_in; l++) {
|
|
1591
|
+
const temp_vert = pTmpVert[l];
|
|
1592
|
+
|
|
1493
1593
|
for (c = 0; c < 3; c++) {
|
|
1494
|
-
|
|
1495
|
-
|
|
1594
|
+
const coordinate = temp_vert.vert[c];
|
|
1595
|
+
|
|
1596
|
+
if (fvMin[c] > coordinate) {
|
|
1597
|
+
fvMin[c] = coordinate;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
if (fvMax[c] < coordinate) {
|
|
1601
|
+
fvMax[c] = coordinate;
|
|
1602
|
+
}
|
|
1496
1603
|
}
|
|
1497
1604
|
}
|
|
1498
1605
|
|
|
@@ -1507,8 +1614,9 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
|
|
|
1507
1614
|
fSep = 0.5 * (fvMax[channel] + fvMin[channel]);
|
|
1508
1615
|
|
|
1509
1616
|
// stop if all vertices are NaNs
|
|
1510
|
-
if (!Number.isFinite(fSep))
|
|
1617
|
+
if (!Number.isFinite(fSep)) {
|
|
1511
1618
|
return;
|
|
1619
|
+
}
|
|
1512
1620
|
|
|
1513
1621
|
// terminate recursion when the separation/average value
|
|
1514
1622
|
// is no longer strictly between fMin and fMax values.
|
|
@@ -1519,7 +1627,8 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
|
|
|
1519
1627
|
const index = piTriList_in_and_out[i];
|
|
1520
1628
|
const vP = GetPosition(pContext, index);
|
|
1521
1629
|
const vN = GetNormal(pContext, index);
|
|
1522
|
-
const vT =
|
|
1630
|
+
const vT = new SVec3();
|
|
1631
|
+
GetTexCoord(vT, pContext, index);
|
|
1523
1632
|
|
|
1524
1633
|
let bNotFound = true;
|
|
1525
1634
|
let l2 = iL_in, i2rec = -1;
|
|
@@ -1528,16 +1637,22 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
|
|
|
1528
1637
|
const index2 = piTriList_in_and_out[i2];
|
|
1529
1638
|
const vP2 = GetPosition(pContext, index2);
|
|
1530
1639
|
const vN2 = GetNormal(pContext, index2);
|
|
1531
|
-
|
|
1640
|
+
|
|
1641
|
+
const vT2 = new SVec3();
|
|
1642
|
+
GetTexCoord(vT2, pContext, index2);
|
|
1643
|
+
|
|
1532
1644
|
i2rec = i2;
|
|
1533
1645
|
|
|
1534
1646
|
//if (vP==vP2 && vN==vN2 && vT==vT2)
|
|
1535
|
-
if (
|
|
1647
|
+
if (
|
|
1648
|
+
vP.x === vP2.x && vP.y === vP2.y && vP.z === vP2.z &&
|
|
1536
1649
|
vN.x === vN2.x && vN.y === vN2.y && vN.z === vN2.z &&
|
|
1537
|
-
vT.x === vT2.x && vT.y === vT2.y && vT.z === vT2.z
|
|
1650
|
+
vT.x === vT2.x && vT.y === vT2.y && vT.z === vT2.z
|
|
1651
|
+
) {
|
|
1538
1652
|
bNotFound = false;
|
|
1539
|
-
else
|
|
1653
|
+
} else {
|
|
1540
1654
|
++l2;
|
|
1655
|
+
}
|
|
1541
1656
|
}
|
|
1542
1657
|
|
|
1543
1658
|
// merge if previously found
|
|
@@ -1599,8 +1714,8 @@ function MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR_in)
|
|
|
1599
1714
|
function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iNrTrianglesIn) {
|
|
1600
1715
|
let iTSpacesOffs = 0, f = 0, t = 0;
|
|
1601
1716
|
let iDstTriIndex = 0;
|
|
1602
|
-
for (f = 0; f <
|
|
1603
|
-
const verts =
|
|
1717
|
+
for (f = 0; f < m_getNumFaces(pContext); f++) {
|
|
1718
|
+
const verts = m_getNumVerticesOfFace(pContext, f);
|
|
1604
1719
|
if (verts !== 3 && verts !== 4) continue;
|
|
1605
1720
|
|
|
1606
1721
|
pTriInfos[iDstTriIndex].iOrgFaceNumber = f;
|
|
@@ -1629,12 +1744,19 @@ function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iN
|
|
|
1629
1744
|
const i1 = MakeIndex(f, 1);
|
|
1630
1745
|
const i2 = MakeIndex(f, 2);
|
|
1631
1746
|
const i3 = MakeIndex(f, 3);
|
|
1632
|
-
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
const
|
|
1747
|
+
|
|
1748
|
+
const T0 = new SVec3();
|
|
1749
|
+
GetTexCoord(T0, pContext, i0);
|
|
1750
|
+
const T1 = new SVec3();
|
|
1751
|
+
GetTexCoord(T1, pContext, i1);
|
|
1752
|
+
const T2 = new SVec3();
|
|
1753
|
+
GetTexCoord(T2, pContext, i2);
|
|
1754
|
+
const T3 = new SVec3();
|
|
1755
|
+
GetTexCoord(T3, pContext, i3);
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
const distSQ_02 = DistanceSquared(T2, T0);
|
|
1759
|
+
const distSQ_13 = DistanceSquared(T3, T1);
|
|
1638
1760
|
let bQuadDiagIs_02 = false;
|
|
1639
1761
|
if (distSQ_02 < distSQ_13)
|
|
1640
1762
|
bQuadDiagIs_02 = true;
|
|
@@ -1645,8 +1767,8 @@ function GenerateInitialVerticesIndexList(pTriInfos, piTriList_out, pContext, iN
|
|
|
1645
1767
|
const P1 = GetPosition(pContext, i1);
|
|
1646
1768
|
const P2 = GetPosition(pContext, i2);
|
|
1647
1769
|
const P3 = GetPosition(pContext, i3);
|
|
1648
|
-
const distSQ_02 =
|
|
1649
|
-
const distSQ_13 =
|
|
1770
|
+
const distSQ_02 = DistanceSquared(P2, P0);
|
|
1771
|
+
const distSQ_13 = DistanceSquared(P3, P1);
|
|
1650
1772
|
|
|
1651
1773
|
bQuadDiagIs_02 = distSQ_13 >= distSQ_02;
|
|
1652
1774
|
}
|
|
@@ -1909,6 +2031,9 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
|
|
|
1909
2031
|
|
|
1910
2032
|
iUniqueTspaces = 0;
|
|
1911
2033
|
|
|
2034
|
+
const vOs = new SVec3();
|
|
2035
|
+
const vOt = new SVec3();
|
|
2036
|
+
|
|
1912
2037
|
for (g = 0; g < iNrActiveGroups; g++) {
|
|
1913
2038
|
const pGroup = pGroups[g];
|
|
1914
2039
|
let iUniqueSubGroups = 0, s = 0;
|
|
@@ -1925,7 +2050,7 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
|
|
|
1925
2050
|
/**
|
|
1926
2051
|
* @type {SVec3}
|
|
1927
2052
|
*/
|
|
1928
|
-
let n
|
|
2053
|
+
let n;
|
|
1929
2054
|
|
|
1930
2055
|
if (pTriInfos[f].AssignedGroup[0] === pGroup) index = 0;
|
|
1931
2056
|
else if (pTriInfos[f].AssignedGroup[1] === pGroup) index = 1;
|
|
@@ -1939,10 +2064,12 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
|
|
|
1939
2064
|
n = GetNormal(pContext, iVertIndex);
|
|
1940
2065
|
|
|
1941
2066
|
// project
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2067
|
+
|
|
2068
|
+
vsub(vOs, pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n));
|
|
2069
|
+
vsub(vOt, pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n));
|
|
2070
|
+
|
|
2071
|
+
NormalizeSafe(vOs, vOs);
|
|
2072
|
+
NormalizeSafe(vOt, vOt);
|
|
1946
2073
|
|
|
1947
2074
|
// original face number
|
|
1948
2075
|
iOF_1 = pTriInfos[f].iOrgFaceNumber;
|
|
@@ -1953,10 +2080,14 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
|
|
|
1953
2080
|
const iOF_2 = pTriInfos[t].iOrgFaceNumber;
|
|
1954
2081
|
|
|
1955
2082
|
// project
|
|
1956
|
-
let vOs2 =
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2083
|
+
let vOs2 = new SVec3();
|
|
2084
|
+
vsub(vOs2, pTriInfos[t].vOs, vscale(vdot(n, pTriInfos[t].vOs), n));
|
|
2085
|
+
|
|
2086
|
+
let vOt2 = new SVec3();
|
|
2087
|
+
vsub(vOt2, pTriInfos[t].vOt, vscale(vdot(n, pTriInfos[t].vOt), n));
|
|
2088
|
+
|
|
2089
|
+
NormalizeSafe(vOs2, vOs2);
|
|
2090
|
+
NormalizeSafe(vOt2, vOt2);
|
|
1960
2091
|
|
|
1961
2092
|
{
|
|
1962
2093
|
const bAny = ((pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY) !== 0;
|
|
@@ -1975,6 +2106,7 @@ function GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriLis
|
|
|
1975
2106
|
// sort pTmpMembers
|
|
1976
2107
|
tmp_group.iNrFaces = iMembers;
|
|
1977
2108
|
tmp_group.pTriMembers = pTmpMembers;
|
|
2109
|
+
|
|
1978
2110
|
if (iMembers > 1) {
|
|
1979
2111
|
const uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
|
|
1980
2112
|
QuickSort(pTmpMembers, 0, iMembers - 1, uSeed);
|
|
@@ -2140,30 +2272,43 @@ function DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesI
|
|
|
2140
2272
|
|
|
2141
2273
|
// deal with degenerate triangles
|
|
2142
2274
|
// punishment for degenerate triangles is O(N^2)
|
|
2275
|
+
|
|
2143
2276
|
for (t = iNrTrianglesIn; t < iTotTris; t++) {
|
|
2277
|
+
const tri0 = pTriInfos[t];
|
|
2278
|
+
|
|
2144
2279
|
// degenerate triangles on a quad with one good triangle are skipped
|
|
2145
2280
|
// here but processed in the next loop
|
|
2146
|
-
const bSkip = (
|
|
2281
|
+
const bSkip = (tri0.iFlag & QUAD_ONE_DEGEN_TRI) !== 0;
|
|
2147
2282
|
|
|
2148
2283
|
if (!bSkip) {
|
|
2149
2284
|
for (i = 0; i < 3; i++) {
|
|
2285
|
+
|
|
2150
2286
|
const index1 = piTriListIn[t * 3 + i];
|
|
2151
2287
|
// search through the good triangles
|
|
2152
2288
|
let bNotFound = true;
|
|
2153
2289
|
let j = 0;
|
|
2290
|
+
|
|
2154
2291
|
while (bNotFound && j < (3 * iNrTrianglesIn)) {
|
|
2155
2292
|
const index2 = piTriListIn[j];
|
|
2156
|
-
|
|
2157
|
-
|
|
2293
|
+
|
|
2294
|
+
if (index1 === index2) {
|
|
2295
|
+
bNotFound = false;
|
|
2296
|
+
} else {
|
|
2297
|
+
++j;
|
|
2298
|
+
}
|
|
2158
2299
|
}
|
|
2159
2300
|
|
|
2160
2301
|
if (!bNotFound) {
|
|
2161
2302
|
const iTri = j / 3;
|
|
2162
2303
|
const iVert = j % 3;
|
|
2163
|
-
|
|
2164
|
-
const
|
|
2165
|
-
|
|
2166
|
-
const
|
|
2304
|
+
|
|
2305
|
+
const tri1 = pTriInfos[iTri];
|
|
2306
|
+
|
|
2307
|
+
const iSrcVert = tri1.vert_num[iVert];
|
|
2308
|
+
const iSrcOffs = tri1.iTSpacesOffs;
|
|
2309
|
+
|
|
2310
|
+
const iDstVert = tri0.vert_num[i];
|
|
2311
|
+
const iDstOffs = tri0.iTSpacesOffs;
|
|
2167
2312
|
|
|
2168
2313
|
// copy tspace
|
|
2169
2314
|
psTspace[iDstOffs + iDstVert] = psTspace[iSrcOffs + iSrcVert];
|
|
@@ -2176,33 +2321,49 @@ function DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesI
|
|
|
2176
2321
|
for (t = 0; t < iNrTrianglesIn; t++) {
|
|
2177
2322
|
// this triangle belongs to a quad where the
|
|
2178
2323
|
// other triangle is degenerate
|
|
2179
|
-
|
|
2324
|
+
const tri = pTriInfos[t];
|
|
2325
|
+
|
|
2326
|
+
if ((tri.iFlag & QUAD_ONE_DEGEN_TRI) !== 0) {
|
|
2327
|
+
|
|
2180
2328
|
/**
|
|
2181
2329
|
* @type {SVec3}
|
|
2182
2330
|
*/
|
|
2183
2331
|
let vDstP;
|
|
2184
2332
|
let iOrgF = -1, i = 0;
|
|
2185
2333
|
let bNotFound;
|
|
2186
|
-
|
|
2334
|
+
|
|
2335
|
+
const pV = tri.vert_num;
|
|
2187
2336
|
const iFlag = (1 << pV[0]) | (1 << pV[1]) | (1 << pV[2]);
|
|
2337
|
+
|
|
2188
2338
|
let iMissingIndex = 0;
|
|
2189
|
-
if ((iFlag & 2) === 0) iMissingIndex = 1;
|
|
2190
|
-
else if ((iFlag & 4) === 0) iMissingIndex = 2;
|
|
2191
|
-
else if ((iFlag & 8) === 0) iMissingIndex = 3;
|
|
2192
2339
|
|
|
2193
|
-
|
|
2340
|
+
if ((iFlag & 2) === 0) {
|
|
2341
|
+
iMissingIndex = 1;
|
|
2342
|
+
} else if ((iFlag & 4) === 0) {
|
|
2343
|
+
iMissingIndex = 2;
|
|
2344
|
+
} else if ((iFlag & 8) === 0) {
|
|
2345
|
+
iMissingIndex = 3;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
iOrgF = tri.iOrgFaceNumber;
|
|
2194
2349
|
vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex));
|
|
2195
2350
|
bNotFound = true;
|
|
2351
|
+
|
|
2196
2352
|
i = 0;
|
|
2353
|
+
|
|
2197
2354
|
while (bNotFound && i < 3) {
|
|
2355
|
+
|
|
2198
2356
|
const iVert = pV[i];
|
|
2199
2357
|
const vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert));
|
|
2200
|
-
|
|
2201
|
-
|
|
2358
|
+
|
|
2359
|
+
if (veq(vSrcP, vDstP)) {
|
|
2360
|
+
const iOffs = tri.iTSpacesOffs;
|
|
2202
2361
|
psTspace[iOffs + iMissingIndex] = psTspace[iOffs + iVert];
|
|
2203
2362
|
bNotFound = false;
|
|
2204
|
-
} else
|
|
2363
|
+
} else {
|
|
2205
2364
|
++i;
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2206
2367
|
}
|
|
2207
2368
|
assert(!bNotFound);
|
|
2208
2369
|
}
|