@selvajs/visualization 1.7.0-beta.0 → 1.7.1-beta.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/dist/parse.cjs +60 -15
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +3 -2
- package/dist/parse.d.ts +3 -2
- package/dist/parse.js +60 -15
- package/dist/parse.js.map +1 -1
- package/package.json +1 -1
package/dist/parse.d.cts
CHANGED
|
@@ -4,6 +4,7 @@ import * as THREE from "three";
|
|
|
4
4
|
export declare const meshPolicy: {
|
|
5
5
|
clone(meshes: THREE.Object3D[]): THREE.Object3D[];
|
|
6
6
|
release(meshes: THREE.Object3D[]): void;
|
|
7
|
+
byteSize(meshes: THREE.Object3D[]): number;
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
10
|
* Declared structurally rather than imported from `@selvajs/compute` — this package converts
|
|
@@ -93,11 +94,11 @@ interface SerializableMaterial {
|
|
|
93
94
|
clearcoat?: number;
|
|
94
95
|
clearcoatRoughness?: number;
|
|
95
96
|
/**
|
|
96
|
-
* Stretches highlights
|
|
97
|
+
* Stretches highlights across texture U, the grain of brushed or rolled sheet. Ignored when the
|
|
97
98
|
* batch carries no UVs: the tangent is built from them.
|
|
98
99
|
*/
|
|
99
100
|
anisotropy?: number;
|
|
100
|
-
/**
|
|
101
|
+
/** The grain's direction in radians, counter-clockwise from texture U. */
|
|
101
102
|
anisotropyRotation?: number;
|
|
102
103
|
/**
|
|
103
104
|
* Millimetres one repeat of every map covers across U; V follows each image's aspect. Set only
|
package/dist/parse.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as THREE from "three";
|
|
|
4
4
|
export declare const meshPolicy: {
|
|
5
5
|
clone(meshes: THREE.Object3D[]): THREE.Object3D[];
|
|
6
6
|
release(meshes: THREE.Object3D[]): void;
|
|
7
|
+
byteSize(meshes: THREE.Object3D[]): number;
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
10
|
* Declared structurally rather than imported from `@selvajs/compute` — this package converts
|
|
@@ -93,11 +94,11 @@ interface SerializableMaterial {
|
|
|
93
94
|
clearcoat?: number;
|
|
94
95
|
clearcoatRoughness?: number;
|
|
95
96
|
/**
|
|
96
|
-
* Stretches highlights
|
|
97
|
+
* Stretches highlights across texture U, the grain of brushed or rolled sheet. Ignored when the
|
|
97
98
|
* batch carries no UVs: the tangent is built from them.
|
|
98
99
|
*/
|
|
99
100
|
anisotropy?: number;
|
|
100
|
-
/**
|
|
101
|
+
/** The grain's direction in radians, counter-clockwise from texture U. */
|
|
101
102
|
anisotropyRotation?: number;
|
|
102
103
|
/**
|
|
103
104
|
* Millimetres one repeat of every map covers across U; V follows each image's aspect. Set only
|
package/dist/parse.js
CHANGED
|
@@ -73,10 +73,24 @@ function cloneSceneObjects(meshes) {
|
|
|
73
73
|
function releaseSceneObjects(meshes) {
|
|
74
74
|
meshes.forEach((root) => disposeObjectTree(root, { materials: false }));
|
|
75
75
|
}
|
|
76
|
+
/** Geometry bytes only: the memo's copies share materials and textures with the live scene. */
|
|
77
|
+
function sceneObjectsByteSize(meshes) {
|
|
78
|
+
let bytes = 0;
|
|
79
|
+
const seen = /* @__PURE__ */ new Set();
|
|
80
|
+
for (const root of meshes) root.traverse((child) => {
|
|
81
|
+
const geometry = child.geometry;
|
|
82
|
+
if (!geometry || seen.has(geometry)) return;
|
|
83
|
+
seen.add(geometry);
|
|
84
|
+
for (const attribute of Object.values(geometry.attributes)) bytes += attribute.array.byteLength;
|
|
85
|
+
if (geometry.index) bytes += geometry.index.array.byteLength;
|
|
86
|
+
});
|
|
87
|
+
return bytes;
|
|
88
|
+
}
|
|
76
89
|
/** Structurally, not nominally, typed as `@selvajs/solve/client`'s `MeshPolicy<THREE.Object3D>` — avoids a dependency on solve. */
|
|
77
90
|
const meshPolicy = {
|
|
78
91
|
clone: cloneSceneObjects,
|
|
79
|
-
release: releaseSceneObjects
|
|
92
|
+
release: releaseSceneObjects,
|
|
93
|
+
byteSize: sceneObjectsByteSize
|
|
80
94
|
};
|
|
81
95
|
/** Opacity < 1 flips `transparent` on. */
|
|
82
96
|
function materialParams(color, opacity) {
|
|
@@ -1682,29 +1696,58 @@ function applyTexture(material, url, slot, mapSize) {
|
|
|
1682
1696
|
const f$1 = (n) => n.toFixed(4);
|
|
1683
1697
|
const PITH = 120;
|
|
1684
1698
|
const PITH_SPREAD = 120;
|
|
1685
|
-
const PLANK =
|
|
1699
|
+
const PLANK = 160;
|
|
1700
|
+
const SEAM_JITTER = .7;
|
|
1686
1701
|
const LEAN = .0105;
|
|
1702
|
+
const BOARD_SHADE = .14;
|
|
1703
|
+
const PORE_ROW = .35;
|
|
1704
|
+
const PORE_FILL = .3;
|
|
1705
|
+
const PORE_DARK = .4;
|
|
1706
|
+
const PORE_MEAN = PORE_FILL * .7 * .42;
|
|
1707
|
+
const seam = (k) => `( ( ${k} ) + ( selvaHash( vec2( ${k}, 6.0 ) ) - 0.5 ) * ${f$1(SEAM_JITTER)} ) * ${f$1(PLANK)}`;
|
|
1687
1708
|
const wood = ({ ring, latewood, band, pores, streaks }) => `
|
|
1688
|
-
float
|
|
1689
|
-
float
|
|
1709
|
+
float cell = floor( uv.y / ${f$1(PLANK)} );
|
|
1710
|
+
float plank = cell + ( uv.y < ${seam("cell")} ? -1.0 : ( uv.y >= ${seam("cell + 1.0")} ? 1.0 : 0.0 ) );
|
|
1711
|
+
float lo = ${seam("plank")};
|
|
1712
|
+
float hi = ${seam("plank + 1.0")};
|
|
1713
|
+
// Each plank starts somewhere else along its log.
|
|
1714
|
+
float along = uv.x + selvaHash( vec2( plank, 9.0 ) ) * 5000.0;
|
|
1715
|
+
// The pith lies anywhere under the plank, sometimes past its edge, which leaves straight
|
|
1716
|
+
// rift grain on that side.
|
|
1717
|
+
float heart = mix( lo, hi, selvaHash( vec2( plank, 3.0 ) ) * 1.6 - 0.3 );
|
|
1718
|
+
heart += ( selvaNoise( vec2( along * 0.0006, plank * 7.0 ) ) - 0.5 ) * 50.0;
|
|
1719
|
+
float s = uv.y - heart;
|
|
1690
1720
|
float pith = ${f$1(PITH)} + selvaHash( vec2( plank, 2.0 ) ) * ${f$1(PITH_SPREAD)};
|
|
1721
|
+
pith += ( selvaFbm( vec2( along * 0.0004, plank * 5.0 + 1.0 ) ) - 0.5 ) * ${f$1(50)};
|
|
1722
|
+
float lean = ${f$1(LEAN)} * ( 0.5 + selvaHash( vec2( plank, 8.0 ) ) );
|
|
1691
1723
|
// Rings wander a few mm and vary in spacing, as growth does from year to year.
|
|
1692
|
-
float wander = ( selvaFbm(
|
|
1693
|
-
float r = sqrt( pith * pith + s * s ) +
|
|
1724
|
+
float wander = ( selvaFbm( vec2( along * 0.003, uv.y * 0.008 ) ) - 0.5 ) * ${f$1(ring * 2)};
|
|
1725
|
+
float r = sqrt( pith * pith + s * s ) + along * lean + wander;
|
|
1694
1726
|
r += selvaFbm( vec2( r * 0.02, plank ) ) * ${f$1(ring * 3)} + selvaHash( vec2( plank, 1.0 ) ) * ${f$1(ring * 20)};
|
|
1695
1727
|
float year = fract( r / ${f$1(ring)} );
|
|
1696
1728
|
float late = smoothstep( ${f$1(1 - band)}, ${f$1(1 - band * .4)}, year ) * ( 1.0 - smoothstep( 0.95, 1.0, year ) );
|
|
1697
1729
|
// Open-pored wood shows its rings as a broken band of pores, not a clean line.
|
|
1698
|
-
|
|
1730
|
+
float broken = 1.0 - smoothstep( 0.3, 0.7, selvaNoise( uv * vec2( 0.25, 2.0 ) ) );
|
|
1731
|
+
late *= 1.0 - ${f$1(pores * .45)} * mix( 0.5, broken, selvaDetail( 0.5 ) );
|
|
1699
1732
|
late *= selvaDetail( ${f$1(ring)} );
|
|
1700
1733
|
float fibre = ( selvaNoise( uv * vec2( 0.04, 1.6 ) ) - 0.5 ) * selvaDetail( 1.0 );
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
float
|
|
1704
|
-
float
|
|
1705
|
-
|
|
1734
|
+
// Pores: thin dashes along the grain, most of each row empty. Smaller than a pixel they
|
|
1735
|
+
// show as their average shade, or they would be static.
|
|
1736
|
+
float poreRow = floor( uv.y / ${f$1(PORE_ROW)} );
|
|
1737
|
+
float poreAlong = uv.x / mix( 1.5, 5.0, selvaHash( vec2( poreRow, 11.0 ) ) ) + selvaHash( vec2( poreRow, 12.0 ) );
|
|
1738
|
+
float poreT = fract( poreAlong );
|
|
1739
|
+
float pore = step( ${f$1(.7)}, selvaHash( vec2( poreRow, 13.0 + 1.618 * floor( poreAlong ) ) ) );
|
|
1740
|
+
pore *= smoothstep( 0.0, 0.3, poreT ) * smoothstep( 1.0, 0.7, poreT );
|
|
1741
|
+
pore *= 1.0 - smoothstep( 0.12, 0.3, abs( fract( uv.y / ${f$1(PORE_ROW)} ) - 0.5 ) );
|
|
1742
|
+
pore = mix( ${f$1(PORE_MEAN)}, pore, selvaDetail( ${f$1(PORE_ROW)} ) ) * ${f$1(pores)} * ( 1.0 - 0.6 * late );
|
|
1743
|
+
float streak = ( selvaFbm( vec2( along * 0.0015, uv.y * 0.012 ) ) - 0.5 ) * ${f$1(streaks)};
|
|
1744
|
+
float shade = 1.0 + ${f$1(latewood * band)} - late * ${f$1(latewood)} + fibre * 0.1 - pore * ${f$1(PORE_DARK)} + streak * 0.6;
|
|
1745
|
+
float board = ( selvaHash( vec2( plank, 4.0 ) ) - 0.5 ) * selvaDetail( ${f$1(PLANK * .5)} );
|
|
1746
|
+
float warmth = ( selvaHash( vec2( plank, 5.0 ) ) - 0.5 ) * selvaDetail( ${f$1(PLANK * .5)} );
|
|
1747
|
+
tone = vec3( shade ) * ( 1.0 + board * ${f$1(BOARD_SHADE)} ) * vec3( 1.0 + warmth * 0.06, 1.0, 1.0 - warmth * 0.06 );
|
|
1706
1748
|
gloss = 1.0 + late * 0.08 + pore * 0.4 - fibre * 0.2;
|
|
1707
|
-
|
|
1749
|
+
// No relief from pores: a bump from screen derivatives beads any dash under a few pixels wide.
|
|
1750
|
+
height = fibre * 0.00008 * selvaDetail( 0.6 );`;
|
|
1708
1751
|
/**
|
|
1709
1752
|
* Procedural surfaces, so a preset looks like its material with no texture files to ship or upload.
|
|
1710
1753
|
* UVs are millimetres, so a brick is brick-sized at any model scale. Each recipe sets `tone` (albedo
|
|
@@ -2014,6 +2057,7 @@ const RECIPES = {
|
|
|
2014
2057
|
};
|
|
2015
2058
|
const TILT = .6;
|
|
2016
2059
|
const FIBRE_FADE = .35;
|
|
2060
|
+
const FIBRE_ASPECT = 16;
|
|
2017
2061
|
const f = (n) => n.toFixed(4);
|
|
2018
2062
|
/** The shader patch for a finish, or null when it would draw nothing. `key` extends the program cache key. */
|
|
2019
2063
|
function finishPatch(finish, strength) {
|
|
@@ -2045,7 +2089,8 @@ function finishPatch(finish, strength) {
|
|
|
2045
2089
|
// of the part. depth * |depth| keeps most fibres faint and a few deep.
|
|
2046
2090
|
float selvaFibreRow( vec2 uv, float pitch, vec2 len, float seed ) {
|
|
2047
2091
|
float row = floor( uv.y / pitch );
|
|
2048
|
-
|
|
2092
|
+
// A coarse cell stays a streak: as wide as it is long it reads as speckle, not grain.
|
|
2093
|
+
float l = max( mix( len.x, len.y, selvaHash( vec2( row, seed + 1.0 ) ) ), pitch * ${f(FIBRE_ASPECT)} );
|
|
2049
2094
|
float along = uv.x / l + selvaHash( vec2( row, seed + 2.0 ) );
|
|
2050
2095
|
float seg = floor( along );
|
|
2051
2096
|
float depth = selvaHash( vec2( row, seed + 3.0 + 1.618 * seg ) ) * 2.0 - 1.0;
|
|
@@ -2157,7 +2202,7 @@ function createMaterial(matData, options) {
|
|
|
2157
2202
|
}
|
|
2158
2203
|
if (matData.anisotropy != null && matData.anisotropy > 0 && options?.hasUvs) {
|
|
2159
2204
|
material.anisotropy = matData.anisotropy;
|
|
2160
|
-
material.anisotropyRotation = matData.anisotropyRotation ?? 0;
|
|
2205
|
+
material.anisotropyRotation = (matData.anisotropyRotation ?? 0) + Math.PI / 2;
|
|
2161
2206
|
}
|
|
2162
2207
|
if (matData.ior != null) material.ior = matData.ior;
|
|
2163
2208
|
if (matData.transmission != null && matData.transmission > 0) applyGlass(material, matData);
|