@configura/web-core 1.3.0-alpha.1 → 1.3.0-alpha.5
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/dist/cm/core3D/ATriMeshF.d.ts +7 -1
- package/dist/cm/core3D/ATriMeshF.js +9 -5
- package/dist/cm/core3D/GMaterial3D.d.ts +4 -0
- package/dist/cm/core3D/GMaterial3D.js +4 -4
- package/dist/cm/core3D/GMaterialPBR.js +25 -13
- package/dist/cm/core3D/{UVMapEnv.d.ts → uvmapper/UVMapEnv.d.ts} +3 -1
- package/dist/cm/core3D/{UVMapEnv.js → uvmapper/UVMapEnv.js} +13 -1
- package/dist/cm/core3D/uvmapper/UVMapper.d.ts +42 -0
- package/dist/cm/core3D/uvmapper/UVMapper.js +94 -0
- package/dist/cm/core3D/uvmapper/UVMapperBox.d.ts +5 -0
- package/dist/cm/core3D/uvmapper/UVMapperBox.js +181 -0
- package/dist/cm/core3D/uvmapper/UVMapperCylinder.d.ts +10 -0
- package/dist/cm/core3D/uvmapper/UVMapperCylinder.js +96 -0
- package/dist/cm/core3D/uvmapper/UVMapperPlane.d.ts +4 -0
- package/dist/cm/core3D/uvmapper/UVMapperPlane.js +84 -0
- package/dist/cm/core3D/uvmapper/UVTransformer.d.ts +6 -0
- package/dist/cm/core3D/{UVTransformer.js → uvmapper/UVTransformer.js} +0 -0
- package/dist/cm/core3D/uvmapper/instantiateUVMapper.d.ts +4 -0
- package/dist/cm/core3D/uvmapper/instantiateUVMapper.js +4 -0
- package/dist/cm/format/cmsym/SymNode.d.ts +8 -0
- package/dist/cm/format/cmsym/SymNode.js +75 -0
- package/dist/cm/format/cmsym/components/SymBox.d.ts +1 -0
- package/dist/cm/format/cmsym/components/SymBox.js +8 -3
- package/dist/cm/format/cmsym/components/SymGMaterialSelector.d.ts +5 -0
- package/dist/cm/format/cmsym/components/SymGMaterialSelector.js +5 -3
- package/dist/cm/format/cmsym/components/SymMeasure.d.ts +3 -4
- package/dist/cm/format/cmsym/components/SymMeasure.js +20 -29
- package/dist/cm/format/cmsym/components/SymMultiSelector.js +7 -8
- package/dist/cm/format/cmsym/components/SymParams.d.ts +12 -0
- package/dist/cm/format/cmsym/components/SymParams.js +51 -0
- package/dist/cm/format/cmsym/components/SymPlane.d.ts +1 -1
- package/dist/cm/format/cmsym/components/SymPlane.js +4 -1
- package/dist/cm/format/cmsym/components/SymProgs.d.ts +28 -0
- package/dist/cm/format/cmsym/components/SymProgs.js +113 -0
- package/dist/cm/format/cmsym/components/SymProps.d.ts +1 -1
- package/dist/cm/format/cmsym/components/SymRep.d.ts +4 -4
- package/dist/cm/format/cmsym/components/SymRep.js +5 -5
- package/dist/cm/format/cmsym/components/SymReps.js +3 -3
- package/dist/cm/format/cmsym/components/SymShape.js +4 -1
- package/dist/cm/format/cmsym/components/SymSphere.d.ts +2 -0
- package/dist/cm/format/cmsym/components/SymSphere.js +6 -3
- package/dist/cm/format/cmsym/components/SymText2D.d.ts +1 -0
- package/dist/cm/format/cmsym/components/SymText2D.js +1 -1
- package/dist/cm/format/cmsym/components/SymText3D.d.ts +1 -0
- package/dist/cm/format/cmsym/components/SymText3D.js +1 -1
- package/dist/cm/format/cmsym/components/SymUVMapper.d.ts +4 -4
- package/dist/cm/format/cmsym/components/SymUVMapper.js +3 -3
- package/dist/cm/format/dex/DexObj.d.ts +1 -1
- package/dist/cm/format/dex/DexObj.js +1 -1
- package/dist/cm/format/dex/DexReader.d.ts +5 -1
- package/dist/cm/format/dex/DexReader.js +40 -0
- package/dist/cm/geometry/Angle.js +2 -2
- package/dist/cm/geometry/DetailMask.d.ts +5 -0
- package/dist/cm/geometry/DetailMask.js +7 -5
- package/dist/cm/geometry/Matrix22.d.ts +1 -0
- package/dist/cm/geometry/Matrix22.js +3 -0
- package/dist/cm/geometry/Plane.d.ts +2 -2
- package/dist/cm/geometry/Point.d.ts +3 -0
- package/dist/cm/geometry/Point.js +9 -0
- package/dist/cm/geometry/Point2D.d.ts +1 -0
- package/dist/cm/geometry/Point2D.js +3 -0
- package/dist/cm/geometry/Transform2D.d.ts +2 -2
- package/dist/cm/io/Semver.d.ts +1 -0
- package/dist/cm/io/Semver.js +4 -1
- package/package.json +4 -4
- package/dist/cm/core3D/DummyUVMapper.d.ts +0 -7
- package/dist/cm/core3D/DummyUVMapper.js +0 -6
- package/dist/cm/core3D/UVTransformer.d.ts +0 -6
- package/dist/cm/core3D/instantiateUVMapper.d.ts +0 -4
- package/dist/cm/core3D/instantiateUVMapper.js +0 -5
|
@@ -50,7 +50,8 @@ export declare class ATriMeshF {
|
|
|
50
50
|
*/
|
|
51
51
|
doubleSided: boolean;
|
|
52
52
|
constructor(data: Uint8Array | undefined, lowerLeftTextureOrigin: boolean, doubleSided: boolean);
|
|
53
|
-
|
|
53
|
+
/** Creates and returns a new ATriMeshF with the mesh data supplied. */
|
|
54
|
+
static createWithArrays(indices: Uint32Array, vertices: Float32Array, normals?: Float32Array, uvs?: Float32Array, colors?: Float32Array, tangents?: Float32Array): ATriMeshF;
|
|
54
55
|
get indices(): Uint32Array;
|
|
55
56
|
get vertices(): Float32Array;
|
|
56
57
|
get normals(): Float32Array;
|
|
@@ -81,6 +82,11 @@ export declare class ATriMeshF {
|
|
|
81
82
|
* public geometry getters.
|
|
82
83
|
*/
|
|
83
84
|
load(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Calculates and sets tangent data if this ATriMeshF has normals but no gradient (constant) UV
|
|
87
|
+
* coordinates. Without this fix, shader calculations that depends on UV gradients can fail.
|
|
88
|
+
* This is only a workaround since a the tangent is not well defined without a UV gradient.
|
|
89
|
+
*/
|
|
84
90
|
private computeTangentsIfNeeded;
|
|
85
91
|
hasNormals(): boolean;
|
|
86
92
|
hasUVCoordinates(): boolean;
|
|
@@ -26,12 +26,14 @@ export class ATriMeshF {
|
|
|
26
26
|
this._colors = new Float32Array(0);
|
|
27
27
|
this._tangents = new Float32Array(0);
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
/** Creates and returns a new ATriMeshF with the mesh data supplied. */
|
|
30
30
|
static createWithArrays(indices, vertices, normals, uvs, colors, tangents) {
|
|
31
31
|
const mesh = new ATriMeshF(undefined, false, false);
|
|
32
32
|
mesh._indices = indices;
|
|
33
33
|
mesh._vertices = vertices;
|
|
34
|
-
|
|
34
|
+
if (normals !== undefined) {
|
|
35
|
+
mesh._normals = normals;
|
|
36
|
+
}
|
|
35
37
|
if (uvs !== undefined) {
|
|
36
38
|
mesh._uvs = uvs;
|
|
37
39
|
}
|
|
@@ -129,9 +131,11 @@ export class ATriMeshF {
|
|
|
129
131
|
// );
|
|
130
132
|
this.computeTangentsIfNeeded();
|
|
131
133
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Calculates and sets tangent data if this ATriMeshF has normals but no gradient (constant) UV
|
|
136
|
+
* coordinates. Without this fix, shader calculations that depends on UV gradients can fail.
|
|
137
|
+
* This is only a workaround since a the tangent is not well defined without a UV gradient.
|
|
138
|
+
*/
|
|
135
139
|
computeTangentsIfNeeded() {
|
|
136
140
|
if (this._uvs.length < 2 || this._normals.length < 3) {
|
|
137
141
|
return;
|
|
@@ -31,6 +31,7 @@ export declare const enum TextureType {
|
|
|
31
31
|
pbrRefraction = "refraction",
|
|
32
32
|
pbrRoughness = "roughness"
|
|
33
33
|
}
|
|
34
|
+
/** Common texture class used both by Classic and PBR GMaterials. */
|
|
34
35
|
export declare class GMaterial3DTexture {
|
|
35
36
|
readonly type: TextureType;
|
|
36
37
|
constructor(type: TextureType);
|
|
@@ -39,13 +40,16 @@ export declare class GMaterial3DTexture {
|
|
|
39
40
|
vScale: number;
|
|
40
41
|
uOffset: number;
|
|
41
42
|
vOffset: number;
|
|
43
|
+
/** Texture rotation in radians. */
|
|
42
44
|
rot: number;
|
|
43
45
|
wrapU: TextureWrap;
|
|
44
46
|
wrapV: TextureWrap;
|
|
45
47
|
minFilter: TextureFilter;
|
|
46
48
|
magFilter: TextureFilter;
|
|
49
|
+
/** mipFilter is tristate. Also not (yet) included in the CmSym PBR specification. */
|
|
47
50
|
mipFilter: TextureFilter | undefined;
|
|
48
51
|
}
|
|
52
|
+
/** Common settings for both Classic and PBR GMaterials. */
|
|
49
53
|
export declare class GMaterial3D {
|
|
50
54
|
materialKey?: string;
|
|
51
55
|
doubleSided: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DexObj } from "../format/dex/DexObj.js";
|
|
2
2
|
import { DexURL } from "../format/dex/DexURL.js";
|
|
3
3
|
import { DexXRef } from "../format/dex/DexXRef.js";
|
|
4
|
-
|
|
4
|
+
/** Common texture class used both by Classic and PBR GMaterials. */
|
|
5
5
|
export class GMaterial3DTexture {
|
|
6
6
|
constructor(type) {
|
|
7
7
|
this.type = type;
|
|
@@ -10,7 +10,7 @@ export class GMaterial3DTexture {
|
|
|
10
10
|
this.vScale = 1;
|
|
11
11
|
this.uOffset = 0;
|
|
12
12
|
this.vOffset = 0;
|
|
13
|
-
|
|
13
|
+
/** Texture rotation in radians. */
|
|
14
14
|
this.rot = 0;
|
|
15
15
|
// Texture wrap modes
|
|
16
16
|
this.wrapU = 0 /* repeat */;
|
|
@@ -18,11 +18,11 @@ export class GMaterial3DTexture {
|
|
|
18
18
|
// Texture filtering. Default to trilinear.
|
|
19
19
|
this.minFilter = 0 /* linear */;
|
|
20
20
|
this.magFilter = 0 /* linear */;
|
|
21
|
-
|
|
21
|
+
/** mipFilter is tristate. Also not (yet) included in the CmSym PBR specification. */
|
|
22
22
|
this.mipFilter = 0 /* linear */;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
/** Common settings for both Classic and PBR GMaterials. */
|
|
26
26
|
export class GMaterial3D {
|
|
27
27
|
constructor(log, obj) {
|
|
28
28
|
this.doubleSided = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ColorF } from "../basic/ColorF.js";
|
|
2
2
|
import { DexObj } from "../format/dex/DexObj.js";
|
|
3
3
|
import { AngleF } from "../geometry/AngleF.js";
|
|
4
|
-
import { GMaterial3D, GMaterial3DTexture, imageUrlFromDex, textureWrapFromDex } from "./GMaterial3D.js";
|
|
4
|
+
import { GMaterial3D, GMaterial3DTexture, imageUrlFromDex, textureWrapFromDex, } from "./GMaterial3D.js";
|
|
5
5
|
// tslint:disable:max-classes-per-file
|
|
6
6
|
export class GMaterialPBR extends GMaterial3D {
|
|
7
7
|
constructor(log, obj) {
|
|
@@ -159,8 +159,10 @@ export class PBRRoughness {
|
|
|
159
159
|
this.channel = channel;
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Loads and returns the specified texture. Returns undefined if the texture was not found (they
|
|
164
|
+
* are optional) or there was an problem loading the texture.
|
|
165
|
+
*/
|
|
164
166
|
function loadTexture(log, type, dex) {
|
|
165
167
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
166
168
|
const scope = type + ".texture";
|
|
@@ -201,8 +203,10 @@ function loadTexture(log, type, dex) {
|
|
|
201
203
|
}
|
|
202
204
|
return txt;
|
|
203
205
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Loads and returns the TextureFilter specified by the name parameter.
|
|
208
|
+
* Returns undefined if the object was not found or not of the correct type.
|
|
209
|
+
*/
|
|
206
210
|
function loadTextureFilter(log, scope, dex, name) {
|
|
207
211
|
const obj = dex.get(name);
|
|
208
212
|
switch (obj) {
|
|
@@ -240,8 +244,10 @@ function loadChannels(log, scope, dex, name = "channels") {
|
|
|
240
244
|
log.warn(`Channels property not valid (${scope}.${name}): ${obj}`);
|
|
241
245
|
return undefined;
|
|
242
246
|
}
|
|
243
|
-
|
|
244
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Loads and returns the number specified by the name parameter.
|
|
249
|
+
* Returns undefined if the object was not found or not of the correct type.
|
|
250
|
+
*/
|
|
245
251
|
function loadNumber(log, scope, dex, name) {
|
|
246
252
|
const obj = dex.get(name);
|
|
247
253
|
if (obj !== undefined && typeof obj !== "number") {
|
|
@@ -250,8 +256,10 @@ function loadNumber(log, scope, dex, name) {
|
|
|
250
256
|
}
|
|
251
257
|
return obj;
|
|
252
258
|
}
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Loads and returns the angle (in radians) specified by the name parameter.
|
|
261
|
+
* Returns undefined if the object was not found or not of the correct type.
|
|
262
|
+
*/
|
|
255
263
|
function loadAngle(log, scope, dex, name) {
|
|
256
264
|
const obj = dex.get(name);
|
|
257
265
|
if (obj !== undefined && !(obj instanceof AngleF)) {
|
|
@@ -260,8 +268,10 @@ function loadAngle(log, scope, dex, name) {
|
|
|
260
268
|
}
|
|
261
269
|
return obj === null || obj === void 0 ? void 0 : obj.radians;
|
|
262
270
|
}
|
|
263
|
-
|
|
264
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Loads and returns the ColorF specified by the name parameter.
|
|
273
|
+
* Returns <1,1,1,1> if the object was not found or not of the correct type.
|
|
274
|
+
*/
|
|
265
275
|
function loadColorF(log, scope, dex, name) {
|
|
266
276
|
const obj = dex.get(name);
|
|
267
277
|
if (!(obj instanceof ColorF)) {
|
|
@@ -272,8 +282,10 @@ function loadColorF(log, scope, dex, name) {
|
|
|
272
282
|
}
|
|
273
283
|
return obj;
|
|
274
284
|
}
|
|
275
|
-
|
|
276
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Loads and returns the PBROpacityMode mode.
|
|
287
|
+
* Returns "opaque" if the object was not found or not of the correct type.
|
|
288
|
+
*/
|
|
277
289
|
function loadOpacityMode(log, scope, dex) {
|
|
278
290
|
const obj = dex.get("mode");
|
|
279
291
|
switch (obj) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Point } from "
|
|
1
|
+
import { Point } from "../../geometry/Point.js";
|
|
2
2
|
import { UVTransformer } from "./UVTransformer.js";
|
|
3
3
|
export declare enum UVMapperType {
|
|
4
4
|
Box = 0,
|
|
@@ -14,5 +14,7 @@ export declare class UVMapEnv {
|
|
|
14
14
|
normal: Point;
|
|
15
15
|
uniform: boolean;
|
|
16
16
|
constructor(type: UVMapperType, transforms?: UVTransformer[] | undefined, normal?: Point, uniform?: boolean);
|
|
17
|
+
private _hash;
|
|
18
|
+
get hash(): number;
|
|
17
19
|
}
|
|
18
20
|
//# sourceMappingURL=UVMapEnv.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hashCode } from "@configura/web-utilities";
|
|
2
|
+
import { Point } from "../../geometry/Point.js";
|
|
2
3
|
export var UVMapperType;
|
|
3
4
|
(function (UVMapperType) {
|
|
4
5
|
UVMapperType[UVMapperType["Box"] = 0] = "Box";
|
|
@@ -32,4 +33,15 @@ export class UVMapEnv {
|
|
|
32
33
|
this.normal = normal;
|
|
33
34
|
this.uniform = uniform;
|
|
34
35
|
}
|
|
36
|
+
get hash() {
|
|
37
|
+
if (this._hash === undefined) {
|
|
38
|
+
this._hash = hashCode(`ty${this.type}-tr${(this.transforms || [])
|
|
39
|
+
.map((t) => {
|
|
40
|
+
const { pos, mapping } = t.transform;
|
|
41
|
+
return `po${pos.toString()}-ma${mapping.toString()}`;
|
|
42
|
+
})
|
|
43
|
+
.join("-")}-no${this.normal.toString()}-un${this.uniform}`);
|
|
44
|
+
}
|
|
45
|
+
return this._hash;
|
|
46
|
+
}
|
|
35
47
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Logger } from "@configura/web-utilities";
|
|
2
|
+
import { UVMapEnv } from "./UVMapEnv.js";
|
|
3
|
+
import { UVTransformer } from "./UVTransformer.js";
|
|
4
|
+
export declare type MinMaxSize = {
|
|
5
|
+
min: number[];
|
|
6
|
+
max: number[];
|
|
7
|
+
size: number[];
|
|
8
|
+
};
|
|
9
|
+
export declare class UVMapper {
|
|
10
|
+
env?: UVMapEnv | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Applies linear transformations to the UV-coordinates. This is essentially rotating, scaling
|
|
13
|
+
* moving the texture before applying it.
|
|
14
|
+
*/
|
|
15
|
+
static applyUvTransform(uv: [number, number], t: UVTransformer): [number, number];
|
|
16
|
+
static calculateLimits(bounds: MinMaxSize, refBounds: MinMaxSize | undefined): {
|
|
17
|
+
refMin: number[];
|
|
18
|
+
refSize: number[];
|
|
19
|
+
textureFixMin: number[];
|
|
20
|
+
textureFixMax: number[];
|
|
21
|
+
};
|
|
22
|
+
static calculateTextureFixLimits(bounds: MinMaxSize, refBounds: MinMaxSize): {
|
|
23
|
+
min: number[];
|
|
24
|
+
max: number[];
|
|
25
|
+
};
|
|
26
|
+
constructor(env?: UVMapEnv | undefined);
|
|
27
|
+
/**
|
|
28
|
+
* Do not use this method if you have prebaked coordinates in the CmSym file generated by CET.
|
|
29
|
+
* It is safer to use the existing ones since CET has already modified the geometry of the
|
|
30
|
+
* mesh by splitting vertices etc.
|
|
31
|
+
*/
|
|
32
|
+
createUVCoordinates(logger: Logger, positions: Float32Array, bounds: MinMaxSize, normals: Float32Array): Float32Array;
|
|
33
|
+
/**
|
|
34
|
+
* @param positions Stretched positions
|
|
35
|
+
* @param normals Used both for stretched and non-stretched. We cheat a bit by always using the same normals
|
|
36
|
+
* @param refPositions Non-stretched positions
|
|
37
|
+
* @param refUvs Non-stretched UV coordinates
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
createUVCoordinatesForStretched(logger: Logger, positions: Float32Array, bounds: MinMaxSize, normals: Float32Array, refPositions: Float32Array, refBounds: MinMaxSize, refUvs: Float32Array): Float32Array;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=UVMapper.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { UVMapperType } from "./UVMapEnv.js";
|
|
2
|
+
import { createUVBoxCoordinates, createUVBoxCoordinatesForStretched } from "./UVMapperBox.js";
|
|
3
|
+
import { createUVCylinderCoordinates, createUVCylinderCoordinatesForStretched, } from "./UVMapperCylinder.js";
|
|
4
|
+
import { createUVPlaneCoordinates, createUVPlaneCoordinatesForStretched } from "./UVMapperPlane.js";
|
|
5
|
+
const xyz = [0, 1, 2];
|
|
6
|
+
export class UVMapper {
|
|
7
|
+
constructor(env) {
|
|
8
|
+
this.env = env;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Applies linear transformations to the UV-coordinates. This is essentially rotating, scaling
|
|
12
|
+
* moving the texture before applying it.
|
|
13
|
+
*/
|
|
14
|
+
static applyUvTransform(uv, t) {
|
|
15
|
+
const { mapping, pos } = t.transform;
|
|
16
|
+
const [u, v] = uv;
|
|
17
|
+
const { x, y } = pos;
|
|
18
|
+
let uNew = u;
|
|
19
|
+
let vNew = v;
|
|
20
|
+
const { c0, c1 } = mapping;
|
|
21
|
+
uNew = c0.x * u + c1.x * v;
|
|
22
|
+
vNew = c0.y * u + c1.y * v;
|
|
23
|
+
uNew += x;
|
|
24
|
+
vNew += y;
|
|
25
|
+
return [uNew, vNew];
|
|
26
|
+
}
|
|
27
|
+
static calculateLimits(bounds, refBounds) {
|
|
28
|
+
const { min: refMin, size: refSize } = refBounds || bounds;
|
|
29
|
+
const { min: textureFixMin, max: textureFixMax } = refBounds === undefined
|
|
30
|
+
? { min: [0, 0, 0], max: [0, 0, 0] }
|
|
31
|
+
: UVMapper.calculateTextureFixLimits(bounds, refBounds);
|
|
32
|
+
return {
|
|
33
|
+
refMin,
|
|
34
|
+
refSize,
|
|
35
|
+
textureFixMin,
|
|
36
|
+
textureFixMax,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
static calculateTextureFixLimits(bounds, refBounds) {
|
|
40
|
+
return {
|
|
41
|
+
min: xyz.map((axis) => (refBounds.min[axis] - bounds.min[axis]) / refBounds.size[axis]),
|
|
42
|
+
max: xyz.map((axis) => (refBounds.max[axis] - bounds.max[axis]) / refBounds.size[axis]),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Do not use this method if you have prebaked coordinates in the CmSym file generated by CET.
|
|
47
|
+
* It is safer to use the existing ones since CET has already modified the geometry of the
|
|
48
|
+
* mesh by splitting vertices etc.
|
|
49
|
+
*/
|
|
50
|
+
createUVCoordinates(logger, positions, bounds, normals) {
|
|
51
|
+
const env = this.env;
|
|
52
|
+
if (env === undefined) {
|
|
53
|
+
throw new Error("No UV mapping env");
|
|
54
|
+
}
|
|
55
|
+
switch (env.type) {
|
|
56
|
+
case UVMapperType.Box:
|
|
57
|
+
return createUVBoxCoordinates(env, positions, bounds, normals);
|
|
58
|
+
case UVMapperType.Planar:
|
|
59
|
+
return createUVPlaneCoordinates(env, positions);
|
|
60
|
+
case UVMapperType.Cylindrical:
|
|
61
|
+
return createUVCylinderCoordinates(env, positions, bounds, normals);
|
|
62
|
+
case UVMapperType.Spherical:
|
|
63
|
+
throw logger.errorAsObject(`Unsupported UV-mapper: ${env.type} (Spherical)`);
|
|
64
|
+
default:
|
|
65
|
+
throw logger.errorAsObject("Unknown UV-mapper: " + env.type);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @param positions Stretched positions
|
|
70
|
+
* @param normals Used both for stretched and non-stretched. We cheat a bit by always using the same normals
|
|
71
|
+
* @param refPositions Non-stretched positions
|
|
72
|
+
* @param refUvs Non-stretched UV coordinates
|
|
73
|
+
* @returns
|
|
74
|
+
*/
|
|
75
|
+
createUVCoordinatesForStretched(logger, positions, bounds, normals, refPositions, refBounds, refUvs) {
|
|
76
|
+
const env = this.env;
|
|
77
|
+
if (env === undefined) {
|
|
78
|
+
throw new Error("No mapping env");
|
|
79
|
+
}
|
|
80
|
+
switch (env.type) {
|
|
81
|
+
case UVMapperType.Box:
|
|
82
|
+
return createUVBoxCoordinatesForStretched(env, positions, bounds, normals, refPositions, refBounds, refUvs);
|
|
83
|
+
case UVMapperType.Planar:
|
|
84
|
+
return createUVPlaneCoordinatesForStretched(env, positions, refPositions);
|
|
85
|
+
case UVMapperType.Cylindrical:
|
|
86
|
+
return createUVCylinderCoordinatesForStretched(env, positions, bounds, normals, refPositions, refBounds, refUvs);
|
|
87
|
+
case UVMapperType.Spherical:
|
|
88
|
+
logger.warn("Spherical mapping is not implemented for stretch. Original UV-coordinates will be used.");
|
|
89
|
+
return refUvs;
|
|
90
|
+
default:
|
|
91
|
+
throw logger.errorAsObject("Unknown UV-mapper");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { UVMapEnv } from "./UVMapEnv.js";
|
|
2
|
+
import { MinMaxSize } from "./UVMapper.js";
|
|
3
|
+
export declare function createUVBoxCoordinates(env: UVMapEnv | undefined, positions: Float32Array, bounds: MinMaxSize, normals: Float32Array): Float32Array;
|
|
4
|
+
export declare function createUVBoxCoordinatesForStretched(env: UVMapEnv | undefined, positions: Float32Array, bounds: MinMaxSize, normals: Float32Array, refPositions: Float32Array, refBounds: MinMaxSize, refUvs: Float32Array): Float32Array;
|
|
5
|
+
//# sourceMappingURL=UVMapperBox.d.ts.map
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { UVMapper } from "./UVMapper.js";
|
|
2
|
+
const XYZ = [0, 1, 2];
|
|
3
|
+
const X = 0, Y = 1, Z = 2;
|
|
4
|
+
const toSide = (axis, negAxis) => axis * 2 + (negAxis ? 1 : 0);
|
|
5
|
+
const toAxisAndIsNeg = (side) => [Math.trunc(side / 2), side % 2 === 1];
|
|
6
|
+
/**
|
|
7
|
+
* This simulates how CET maps xyz-coordinates to uv-coordinates. On certain axis the mapping is
|
|
8
|
+
* flipped, this is handled here.
|
|
9
|
+
*/
|
|
10
|
+
function uvFromXyz(axis, negAxis, xyz) {
|
|
11
|
+
let u = axis === X ? xyz[1] : xyz[0];
|
|
12
|
+
let v = axis === Z ? xyz[1] : xyz[2];
|
|
13
|
+
if ((axis === X && negAxis) || (axis === Y && !negAxis)) {
|
|
14
|
+
u = 1 - u;
|
|
15
|
+
}
|
|
16
|
+
if (axis === Z && negAxis) {
|
|
17
|
+
v = 1 - v;
|
|
18
|
+
}
|
|
19
|
+
return [u, v];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The recommended method for calculating what side vertices belong to. It uses already calculated
|
|
23
|
+
* UVs to and as such is useful when doing stretch. If you do not do stretch you don't need to use
|
|
24
|
+
* this mapper at all. Just use the existing UVs.
|
|
25
|
+
*/
|
|
26
|
+
function calculateSideMapFromRefUvs(transforms, normals, refPositions, refBounds, refUvs) {
|
|
27
|
+
const vertexCount = refPositions.length / 3;
|
|
28
|
+
const { min: refMin, size: refSize } = refBounds;
|
|
29
|
+
const sideMap = new Uint8Array(vertexCount);
|
|
30
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
31
|
+
const xyzOffset = i * 3;
|
|
32
|
+
const uvOffset = i * 2;
|
|
33
|
+
// Texture is applied as if the image texture was stretched to fit each side of the "cube"
|
|
34
|
+
const refNormalized = XYZ.map((axis) => (refPositions[xyzOffset + axis] - refMin[axis]) / refSize[axis]);
|
|
35
|
+
const refU = refUvs[uvOffset];
|
|
36
|
+
const refV = refUvs[uvOffset + 1];
|
|
37
|
+
// We aim at finding what side of the cube this vertex shall be textured from.
|
|
38
|
+
// We do this by in turn testing what UV-values we would get for non-stretched
|
|
39
|
+
// data and selecting the one which is the closest.
|
|
40
|
+
let diffOnLatestCandidate = Number.POSITIVE_INFINITY;
|
|
41
|
+
let normalComponentAbsOnLatestCandidate = 0;
|
|
42
|
+
let selectedSide;
|
|
43
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
44
|
+
const normalComponent = normals[xyzOffset + axis];
|
|
45
|
+
const normalComponentAbs = Math.abs(normalComponent);
|
|
46
|
+
const negAxis = normalComponent < 0;
|
|
47
|
+
let [u, v] = uvFromXyz(axis, negAxis, refNormalized);
|
|
48
|
+
if (transforms !== undefined) {
|
|
49
|
+
[u, v] = UVMapper.applyUvTransform([u, v], transforms[axis]);
|
|
50
|
+
}
|
|
51
|
+
// How far off are we from the reference UV-coordinates?
|
|
52
|
+
const diffOnCandidate = Math.abs(refU - u) + Math.abs(refV - v);
|
|
53
|
+
// Here we need a lite extra care. For highly regular shapes, such as a cube it is very
|
|
54
|
+
// likely we will end up in a situation where the "pick best UV-match" approach does
|
|
55
|
+
// not work. You can imagine this as the same "color" touching the same corner from
|
|
56
|
+
// more than one side. In this case we also need to take the normals into account.
|
|
57
|
+
//
|
|
58
|
+
// For highly irregular shapes it is more unlikely that the texture coordinates will be
|
|
59
|
+
// identical, and if they are the high polygon count on such a model is likely to mask
|
|
60
|
+
// the error.
|
|
61
|
+
//
|
|
62
|
+
// The factors below are a bit arbitrarily chosen. They might need to be tweaked.
|
|
63
|
+
if (diffOnLatestCandidate - diffOnCandidate > 0.01 ||
|
|
64
|
+
normalComponentAbs - normalComponentAbsOnLatestCandidate > 0.9) {
|
|
65
|
+
selectedSide = toSide(axis, negAxis);
|
|
66
|
+
diffOnLatestCandidate = diffOnCandidate;
|
|
67
|
+
normalComponentAbsOnLatestCandidate = normalComponentAbs;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (selectedSide === undefined) {
|
|
71
|
+
throw new Error("Unexpected error when calculating UV side mapping");
|
|
72
|
+
}
|
|
73
|
+
sideMap[i] = selectedSide;
|
|
74
|
+
}
|
|
75
|
+
return sideMap;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Fallback method of calculating what side a vertex belongs to in cases where you have no refUvs.
|
|
79
|
+
* It will give bad results in the boundary areas where mapping from different sides meet.
|
|
80
|
+
*
|
|
81
|
+
* WARNING: Only use it if you have no refUvs.
|
|
82
|
+
*/
|
|
83
|
+
function calculateSideMapFromNormals(normals) {
|
|
84
|
+
const vertexCount = normals.length / 3;
|
|
85
|
+
const sideMap = new Uint8Array(vertexCount);
|
|
86
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
87
|
+
const xyzOffset = i * 3;
|
|
88
|
+
const normalX = normals[xyzOffset];
|
|
89
|
+
const normalY = normals[xyzOffset + 1];
|
|
90
|
+
const normalZ = normals[xyzOffset + 2];
|
|
91
|
+
if (Math.abs(normalY) < Math.abs(normalX) && Math.abs(normalZ) < Math.abs(normalX)) {
|
|
92
|
+
sideMap[i] = toSide(0, normalX < 0);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (Math.abs(normalZ) < Math.abs(normalY)) {
|
|
96
|
+
sideMap[i] = toSide(1, normalY < 0);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
sideMap[i] = toSide(2, normalZ < 0);
|
|
100
|
+
}
|
|
101
|
+
return sideMap;
|
|
102
|
+
}
|
|
103
|
+
export function createUVBoxCoordinates(env, positions, bounds, normals) {
|
|
104
|
+
if (normals.length !== positions.length) {
|
|
105
|
+
throw new Error("Normals are wrong count");
|
|
106
|
+
}
|
|
107
|
+
return createUV(env, positions, bounds, undefined, calculateSideMapFromNormals(normals));
|
|
108
|
+
}
|
|
109
|
+
export function createUVBoxCoordinatesForStretched(env, positions, bounds, normals, refPositions, refBounds, refUvs) {
|
|
110
|
+
const transforms = env === null || env === void 0 ? void 0 : env.transforms;
|
|
111
|
+
const xyzCount = positions.length;
|
|
112
|
+
const vertexCount = xyzCount / 3;
|
|
113
|
+
const uvCount = vertexCount * 2;
|
|
114
|
+
if (refPositions.length !== xyzCount) {
|
|
115
|
+
throw new Error(`Position count differs: ${refPositions.length} vs ${xyzCount}.`);
|
|
116
|
+
}
|
|
117
|
+
if (normals.length !== xyzCount) {
|
|
118
|
+
throw new Error(`Normal count differs: ${normals.length} vs ${xyzCount}.`);
|
|
119
|
+
}
|
|
120
|
+
if (refUvs.length !== uvCount) {
|
|
121
|
+
throw new Error(`UV count differs: ${uvCount} vs ${refUvs.length}.`);
|
|
122
|
+
}
|
|
123
|
+
return createUV(env, positions, bounds, refBounds, calculateSideMapFromRefUvs(transforms, normals, refPositions, refBounds, refUvs));
|
|
124
|
+
}
|
|
125
|
+
function createUV(env, positions, bounds, refBounds, sideMap) {
|
|
126
|
+
const transforms = env === null || env === void 0 ? void 0 : env.transforms;
|
|
127
|
+
const xyzCount = positions.length;
|
|
128
|
+
const vertexCount = xyzCount / 3;
|
|
129
|
+
const uvCount = vertexCount * 2;
|
|
130
|
+
const { refMin, refSize, textureFixMin, textureFixMax } = UVMapper.calculateLimits(bounds, refBounds);
|
|
131
|
+
// This is what this entire method aims at populating
|
|
132
|
+
const newUvs = new Float32Array(uvCount);
|
|
133
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
134
|
+
const xyzOffset = i * 3;
|
|
135
|
+
const uvOffset = i * 2;
|
|
136
|
+
// We normalize using the ref-sizes as we want the texture to tile. Normalizing to the
|
|
137
|
+
// stretched positions would make it just stretch (and defeat the entire purpose)
|
|
138
|
+
const normalized = XYZ.map((axis) => (positions[xyzOffset + axis] - refMin[axis]) / refSize[axis]);
|
|
139
|
+
const [axis, isNegAxis] = toAxisAndIsNeg(sideMap[i]);
|
|
140
|
+
let [u, v] = uvFromXyz(axis, isNegAxis, normalized);
|
|
141
|
+
// CET uses different texture origins for different sides of the cube, which makes it look
|
|
142
|
+
// like the texture "moves with" the stretch direction on some sides and stays in place on
|
|
143
|
+
// some sides.
|
|
144
|
+
//
|
|
145
|
+
// The code below emulates the CET behavior even though it can be argued that it is neither
|
|
146
|
+
// expected nor "correct".
|
|
147
|
+
if (axis === 0) {
|
|
148
|
+
if (isNegAxis) {
|
|
149
|
+
u -= textureFixMax[1];
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
u += textureFixMin[1];
|
|
153
|
+
}
|
|
154
|
+
v += textureFixMin[2];
|
|
155
|
+
}
|
|
156
|
+
else if (axis === 1) {
|
|
157
|
+
if (isNegAxis) {
|
|
158
|
+
u += textureFixMin[0];
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
u -= textureFixMax[0];
|
|
162
|
+
}
|
|
163
|
+
v += textureFixMin[2];
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
u += textureFixMin[0];
|
|
167
|
+
if (isNegAxis) {
|
|
168
|
+
v -= textureFixMax[1];
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
v += textureFixMin[1];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (transforms !== undefined) {
|
|
175
|
+
[u, v] = UVMapper.applyUvTransform([u, v], transforms[axis]);
|
|
176
|
+
}
|
|
177
|
+
newUvs[uvOffset] = u;
|
|
178
|
+
newUvs[uvOffset + 1] = v;
|
|
179
|
+
}
|
|
180
|
+
return newUvs;
|
|
181
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UVMapEnv } from "./UVMapEnv.js";
|
|
2
|
+
import { MinMaxSize } from "./UVMapper.js";
|
|
3
|
+
/**
|
|
4
|
+
* This mapper gives bad results in the "seam" where the wrapped texture meet itself. If you have
|
|
5
|
+
* access to prebaked UVs then use those, and if you do stretch use the for stretched method with
|
|
6
|
+
* the prebaked UVS as a start point
|
|
7
|
+
*/
|
|
8
|
+
export declare function createUVCylinderCoordinates(env: UVMapEnv | undefined, positions: Float32Array, bounds: MinMaxSize, normals: Float32Array): Float32Array;
|
|
9
|
+
export declare function createUVCylinderCoordinatesForStretched(env: UVMapEnv | undefined, positions: Float32Array, bounds: MinMaxSize, normals: Float32Array, refPositions: Float32Array, refBounds: MinMaxSize, refUvs: Float32Array): Float32Array;
|
|
10
|
+
//# sourceMappingURL=UVMapperCylinder.d.ts.map
|