@triforge/shader-core 0.1.2 → 0.2.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/bundle.js +55 -27
- package/dist/core/CompileContext.d.ts.map +1 -1
- package/dist/core/CompileContext.js +17 -1
- package/dist/nodes/process/ImageTexture.js +1 -1
- package/dist/nodes/process/Mapping.d.ts +0 -3
- package/dist/nodes/process/Mapping.d.ts.map +1 -1
- package/dist/nodes/process/Mapping.js +28 -25
- package/dist/nodes/process/NormalMap.d.ts +11 -7
- package/dist/nodes/process/NormalMap.d.ts.map +1 -1
- package/dist/nodes/process/NormalMap.js +34 -21
- package/dist/nodes/process/ShaderScript.d.ts.map +1 -1
- package/dist/nodes/process/ShaderScript.js +5 -0
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -308,7 +308,14 @@ var CompileContext = class _CompileContext {
|
|
|
308
308
|
*/
|
|
309
309
|
resolveInput(socket) {
|
|
310
310
|
if (socket.connection) {
|
|
311
|
-
|
|
311
|
+
const varName = this.outputVar(socket.connection.node, socket.connection.name);
|
|
312
|
+
if (socket.type === "vector" && socket.connection.type !== "vector") {
|
|
313
|
+
return `(${varName}).xy`;
|
|
314
|
+
}
|
|
315
|
+
if (socket.type === "color" && socket.connection.type === "vector") {
|
|
316
|
+
return `vec3(${varName}, 0.0)`;
|
|
317
|
+
}
|
|
318
|
+
return varName;
|
|
312
319
|
}
|
|
313
320
|
if (socket.uniformName !== null) {
|
|
314
321
|
if (!(socket.uniformName in this._uniforms)) {
|
|
@@ -421,6 +428,8 @@ var CompileContext = class _CompileContext {
|
|
|
421
428
|
typesCompatible(from, to) {
|
|
422
429
|
if (from === to) return true;
|
|
423
430
|
if ((from === "shader" || from === "color") && (to === "shader" || to === "color")) return true;
|
|
431
|
+
if ((from === "color" || from === "shader") && to === "vector") return true;
|
|
432
|
+
if (from === "vector" && to === "color") return true;
|
|
424
433
|
return false;
|
|
425
434
|
}
|
|
426
435
|
// ── GLSL builders ─────────────────────────────────────────────────
|
|
@@ -2033,7 +2042,7 @@ var ImageTexture = class extends ProcessNode {
|
|
|
2033
2042
|
return `uniform sampler2D ${this.uniformName};`;
|
|
2034
2043
|
}
|
|
2035
2044
|
compileCall(ctx) {
|
|
2036
|
-
const uv = this._inputs.vector.isConnected() ? ctx.
|
|
2045
|
+
const uv = this._inputs.vector.isConnected() ? ctx.resolveInput(this._inputs.vector) : "vUv";
|
|
2037
2046
|
const cv = ctx.outputVar(this, "Color");
|
|
2038
2047
|
const av = ctx.outputVar(this, "Alpha");
|
|
2039
2048
|
return [
|
|
@@ -2644,7 +2653,7 @@ vec3 _st_wavelength(float w) {
|
|
|
2644
2653
|
};
|
|
2645
2654
|
|
|
2646
2655
|
// src/nodes/process/NormalMap.ts
|
|
2647
|
-
var NormalMap = class extends ProcessNode {
|
|
2656
|
+
var NormalMap = class _NormalMap extends ProcessNode {
|
|
2648
2657
|
get nodeType() {
|
|
2649
2658
|
return "NormalMap";
|
|
2650
2659
|
}
|
|
@@ -2657,19 +2666,35 @@ var NormalMap = class extends ProcessNode {
|
|
|
2657
2666
|
category: "Vector",
|
|
2658
2667
|
color: "#4a3a8a",
|
|
2659
2668
|
cost: "medium",
|
|
2660
|
-
costNote: "
|
|
2669
|
+
costNote: "Builds a derivative-based TBN frame per fragment."
|
|
2661
2670
|
};
|
|
2662
2671
|
}
|
|
2663
2672
|
static {
|
|
2664
2673
|
this.glslFunction = `
|
|
2665
|
-
vec3 _st_normalMap(
|
|
2666
|
-
|
|
2674
|
+
vec3 _st_normalMap(vec3 sampledColor, float strength, vec3 N, vec3 P, vec2 uv) {
|
|
2675
|
+
vec3 n = sampledColor * 2.0 - 1.0;
|
|
2676
|
+
n.xy *= strength;
|
|
2677
|
+
|
|
2678
|
+
// Derivative-based cotangent frame (Sch\xFCler) \u2014 no vertex tangent attribute needed.
|
|
2679
|
+
vec3 dp1 = dFdx(P);
|
|
2680
|
+
vec3 dp2 = dFdy(P);
|
|
2681
|
+
vec2 duv1 = dFdx(uv);
|
|
2682
|
+
vec2 duv2 = dFdy(uv);
|
|
2683
|
+
|
|
2684
|
+
vec3 dp2perp = cross(dp2, N);
|
|
2685
|
+
vec3 dp1perp = cross(N, dp1);
|
|
2686
|
+
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
|
|
2687
|
+
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
|
|
2688
|
+
|
|
2689
|
+
float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
|
|
2690
|
+
mat3 TBN = mat3(T * invmax, B * invmax, N);
|
|
2691
|
+
return normalize(TBN * n);
|
|
2667
2692
|
}`;
|
|
2668
2693
|
}
|
|
2669
2694
|
constructor(inputs = {}) {
|
|
2670
2695
|
super("NormalMap");
|
|
2671
2696
|
this._inputs = this.createInputs(inputs, {
|
|
2672
|
-
|
|
2697
|
+
color: ["color", [0.5, 0.5, 1]],
|
|
2673
2698
|
strength: ["float", inputs.strength ?? 1]
|
|
2674
2699
|
});
|
|
2675
2700
|
this._outputs = this.createOutputs({ Normal: "color" });
|
|
@@ -2681,17 +2706,13 @@ vec3 _st_normalMap(float fac, float strength) {
|
|
|
2681
2706
|
return this._outputs;
|
|
2682
2707
|
}
|
|
2683
2708
|
compileDefs() {
|
|
2684
|
-
return
|
|
2709
|
+
return _NormalMap.glslFunction;
|
|
2685
2710
|
}
|
|
2686
2711
|
compileCall(ctx) {
|
|
2687
|
-
const
|
|
2712
|
+
const color = ctx.resolveInput(this._inputs.color);
|
|
2688
2713
|
const strength = ctx.resolveInput(this._inputs.strength);
|
|
2689
2714
|
const normalVar = ctx.outputVar(this, "Normal");
|
|
2690
|
-
return
|
|
2691
|
-
`float _nm_nx_${this.id} = dFdx(${facVar});`,
|
|
2692
|
-
`float _nm_ny_${this.id} = dFdy(${facVar});`,
|
|
2693
|
-
`vec3 ${normalVar} = normalize(vec3(-_nm_nx_${this.id} * ${strength}, 1.0, -_nm_ny_${this.id} * ${strength}));`
|
|
2694
|
-
].join("\n ");
|
|
2715
|
+
return `vec3 ${normalVar} = _st_normalMap(${color}, ${strength}, normalize(vNormal), vPosition, vUv);`;
|
|
2695
2716
|
}
|
|
2696
2717
|
};
|
|
2697
2718
|
|
|
@@ -2793,10 +2814,12 @@ vec3 _st_rotateZ(vec3 v, float a) {
|
|
|
2793
2814
|
constructor(inputs = {}) {
|
|
2794
2815
|
super("Mapping");
|
|
2795
2816
|
this.mode = inputs.mode ?? "TEXTURE";
|
|
2796
|
-
this.
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2817
|
+
this._inputs = this.createInputs(inputs, {
|
|
2818
|
+
vector: ["color", null],
|
|
2819
|
+
location: ["color", inputs.location ?? [0, 0, 0]],
|
|
2820
|
+
rotation: ["color", inputs.rotation ?? [0, 0, 0]],
|
|
2821
|
+
scale: ["color", inputs.scale ?? [1, 1, 1]]
|
|
2822
|
+
});
|
|
2800
2823
|
this._outputs = this.createOutputs({ Vector: "color" });
|
|
2801
2824
|
}
|
|
2802
2825
|
getInputSockets() {
|
|
@@ -2810,18 +2833,19 @@ vec3 _st_rotateZ(vec3 v, float a) {
|
|
|
2810
2833
|
}
|
|
2811
2834
|
compileCall(ctx) {
|
|
2812
2835
|
const v = ctx.resolveInput(this._inputs.vector);
|
|
2836
|
+
const loc = ctx.resolveInput(this._inputs.location);
|
|
2837
|
+
const rot = ctx.resolveInput(this._inputs.rotation);
|
|
2838
|
+
const scl = ctx.resolveInput(this._inputs.scale);
|
|
2813
2839
|
const out = ctx.outputVar(this, "Vector");
|
|
2814
|
-
const toRad = (
|
|
2815
|
-
const [lx, ly, lz] = this.loc;
|
|
2816
|
-
const [rx, ry, rz] = this.rot.map(Number);
|
|
2817
|
-
const [sx, sy, sz] = this.scl;
|
|
2840
|
+
const toRad = (Math.PI / 180).toFixed(6);
|
|
2818
2841
|
return [
|
|
2819
2842
|
`vec3 _mp_v_${this.id} = ${v};`,
|
|
2820
|
-
`
|
|
2821
|
-
`_mp_v_${this.id} =
|
|
2822
|
-
`_mp_v_${this.id} =
|
|
2823
|
-
`_mp_v_${this.id} =
|
|
2824
|
-
`_mp_v_${this.id} = _mp_v_${this.id}
|
|
2843
|
+
`vec3 _mp_r_${this.id} = ${rot} * ${toRad};`,
|
|
2844
|
+
`_mp_v_${this.id} = _mp_v_${this.id} - ${loc};`,
|
|
2845
|
+
`_mp_v_${this.id} = _st_rotateX(_mp_v_${this.id}, _mp_r_${this.id}.x);`,
|
|
2846
|
+
`_mp_v_${this.id} = _st_rotateY(_mp_v_${this.id}, _mp_r_${this.id}.y);`,
|
|
2847
|
+
`_mp_v_${this.id} = _st_rotateZ(_mp_v_${this.id}, _mp_r_${this.id}.z);`,
|
|
2848
|
+
`_mp_v_${this.id} = _mp_v_${this.id} * ${scl};`,
|
|
2825
2849
|
`vec3 ${out} = _mp_v_${this.id};`
|
|
2826
2850
|
].join("\n ");
|
|
2827
2851
|
}
|
|
@@ -4859,6 +4883,7 @@ var ShaderScript = class extends ProcessNode {
|
|
|
4859
4883
|
const defs = {};
|
|
4860
4884
|
const supplied = {};
|
|
4861
4885
|
for (const [name, spec] of Object.entries(config.inputs ?? {})) {
|
|
4886
|
+
assertGlslIdentifier(name, "ShaderScript input name");
|
|
4862
4887
|
if (Array.isArray(spec)) {
|
|
4863
4888
|
const [type, defaultVal] = spec;
|
|
4864
4889
|
defs[name] = [type, defaultVal];
|
|
@@ -4868,6 +4893,9 @@ var ShaderScript = class extends ProcessNode {
|
|
|
4868
4893
|
supplied[name] = sock;
|
|
4869
4894
|
}
|
|
4870
4895
|
}
|
|
4896
|
+
for (const name of Object.keys(this._outputDecl)) {
|
|
4897
|
+
assertGlslIdentifier(name, "ShaderScript output name");
|
|
4898
|
+
}
|
|
4871
4899
|
this._inputs = this.createInputs(supplied, defs);
|
|
4872
4900
|
this._outputs = this.createOutputs(this._outputDecl);
|
|
4873
4901
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompileContext.d.ts","sourceRoot":"","sources":["../../src/core/CompileContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAI,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAQ,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAClD,KAAK,EAAW,UAAU,EAAE,CAAA;CAC7B;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,WAAW,CAAiD;IACpE,OAAO,CAAC,IAAI,CAAiD;IAC7D,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,SAAS,CAAuD;IACxE,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB,CAAiE;IAI1F,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB;IAcjD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAKvD;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"CompileContext.d.ts","sourceRoot":"","sources":["../../src/core/CompileContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAI,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAQ,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAClD,KAAK,EAAW,UAAU,EAAE,CAAA;CAC7B;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,WAAW,CAAiD;IACpE,OAAO,CAAC,IAAI,CAAiD;IAC7D,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,SAAS,CAAuD;IACxE,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB,CAAiE;IAI1F,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB;IAcjD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAKvD;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,MAAM;IAgClD,OAAO,CAAC,KAAK;IA8Bb,OAAO,CAAC,IAAI;IAyBZ,OAAO,CAAC,QAAQ;IA0BhB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,YAAY;IAsCpB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,SAAS;IAqBjB,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAS3D,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAQrC,OAAO,CAAC,SAAS;CAGlB"}
|
|
@@ -53,7 +53,16 @@ export class CompileContext {
|
|
|
53
53
|
*/
|
|
54
54
|
resolveInput(socket) {
|
|
55
55
|
if (socket.connection) {
|
|
56
|
-
|
|
56
|
+
const varName = this.outputVar(socket.connection.node, socket.connection.name);
|
|
57
|
+
// vec3 (color/shader) → vec2 (vector) implicit conversion, e.g. Mapping.Vector → ImageTexture.vector
|
|
58
|
+
if (socket.type === 'vector' && socket.connection.type !== 'vector') {
|
|
59
|
+
return `(${varName}).xy`;
|
|
60
|
+
}
|
|
61
|
+
// vec2 (vector) → vec3 (color) implicit conversion, e.g. TextureCoordinate.UV → Mapping.vector
|
|
62
|
+
if (socket.type === 'color' && socket.connection.type === 'vector') {
|
|
63
|
+
return `vec3(${varName}, 0.0)`;
|
|
64
|
+
}
|
|
65
|
+
return varName;
|
|
57
66
|
}
|
|
58
67
|
if (socket.uniformName !== null) {
|
|
59
68
|
if (!(socket.uniformName in this._uniforms)) {
|
|
@@ -192,6 +201,13 @@ export class CompileContext {
|
|
|
192
201
|
// shader and color are both vec3 — compatible
|
|
193
202
|
if ((from === 'shader' || from === 'color') && (to === 'shader' || to === 'color'))
|
|
194
203
|
return true;
|
|
204
|
+
// vec3 (color/shader) implicitly narrows to vec2 (vector) via .xy, mirroring Blender's
|
|
205
|
+
// Mapping (vector output) → Image Texture Vector panning graph
|
|
206
|
+
if ((from === 'color' || from === 'shader') && to === 'vector')
|
|
207
|
+
return true;
|
|
208
|
+
// vec2 (vector) implicitly widens to vec3 (color), e.g. Texture Coordinate UV → Mapping.vector
|
|
209
|
+
if (from === 'vector' && to === 'color')
|
|
210
|
+
return true;
|
|
195
211
|
return false;
|
|
196
212
|
}
|
|
197
213
|
// ── GLSL builders ─────────────────────────────────────────────────
|
|
@@ -41,7 +41,7 @@ export class ImageTexture extends ProcessNode {
|
|
|
41
41
|
}
|
|
42
42
|
compileCall(ctx) {
|
|
43
43
|
const uv = this._inputs.vector.isConnected()
|
|
44
|
-
? ctx.
|
|
44
|
+
? ctx.resolveInput(this._inputs.vector)
|
|
45
45
|
: 'vUv';
|
|
46
46
|
const cv = ctx.outputVar(this, 'Color');
|
|
47
47
|
const av = ctx.outputVar(this, 'Alpha');
|
|
@@ -22,9 +22,6 @@ export declare class Mapping extends ProcessNode {
|
|
|
22
22
|
static instanceSpecificDef: boolean;
|
|
23
23
|
get metadata(): NodeMetadata;
|
|
24
24
|
static glslFunction: string;
|
|
25
|
-
private readonly loc;
|
|
26
|
-
private readonly rot;
|
|
27
|
-
private readonly scl;
|
|
28
25
|
private readonly mode;
|
|
29
26
|
private readonly _inputs;
|
|
30
27
|
private readonly _outputs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Mapping.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/Mapping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEnE,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAM,WAAW,CAAA;IACtB,MAAM,CAAC,EAAI,YAAY,CAAA;IACvB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,KAAK,CAAC,EAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC;AAED;;;;;;GAMG;AACH,qBAAa,OAAQ,SAAQ,WAAW;IACtC,IAAI,QAAQ,WAAuB;IACnC,MAAM,CAAC,mBAAmB,UAAQ;IAElC,IAAI,QAAQ,IAAI,YAAY,CAE3B;IAED,MAAM,CAAC,YAAY,SAYnB;IAEA,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"Mapping.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/Mapping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEnE,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAM,WAAW,CAAA;IACtB,MAAM,CAAC,EAAI,YAAY,CAAA;IACvB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,KAAK,CAAC,EAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACpC;AAED;;;;;;GAMG;AACH,qBAAa,OAAQ,SAAQ,WAAW;IACtC,IAAI,QAAQ,WAAuB;IACnC,MAAM,CAAC,mBAAmB,UAAQ;IAElC,IAAI,QAAQ,IAAI,YAAY,CAE3B;IAED,MAAM,CAAC,YAAY,SAYnB;IAEA,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmE;gBAEhF,MAAM,GAAE,aAAkB;IAYtC,eAAe;IACf,gBAAgB;IAChB,WAAW;IAEX,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM;CAmBzC"}
|
|
@@ -14,10 +14,12 @@ export class Mapping extends ProcessNode {
|
|
|
14
14
|
constructor(inputs = {}) {
|
|
15
15
|
super('Mapping');
|
|
16
16
|
this.mode = inputs.mode ?? 'TEXTURE';
|
|
17
|
-
this.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
this._inputs = this.createInputs(inputs, {
|
|
18
|
+
vector: ['color', null],
|
|
19
|
+
location: ['color', inputs.location ?? [0, 0, 0]],
|
|
20
|
+
rotation: ['color', inputs.rotation ?? [0, 0, 0]],
|
|
21
|
+
scale: ['color', inputs.scale ?? [1, 1, 1]],
|
|
22
|
+
});
|
|
21
23
|
this._outputs = this.createOutputs({ Vector: 'color' });
|
|
22
24
|
}
|
|
23
25
|
getInputSockets() { return this._inputs; }
|
|
@@ -25,33 +27,34 @@ export class Mapping extends ProcessNode {
|
|
|
25
27
|
compileDefs() { return Mapping.glslFunction; }
|
|
26
28
|
compileCall(ctx) {
|
|
27
29
|
const v = ctx.resolveInput(this._inputs.vector);
|
|
30
|
+
const loc = ctx.resolveInput(this._inputs.location);
|
|
31
|
+
const rot = ctx.resolveInput(this._inputs.rotation);
|
|
32
|
+
const scl = ctx.resolveInput(this._inputs.scale);
|
|
28
33
|
const out = ctx.outputVar(this, 'Vector');
|
|
29
|
-
const toRad = (
|
|
30
|
-
const [lx, ly, lz] = this.loc;
|
|
31
|
-
const [rx, ry, rz] = this.rot.map(Number);
|
|
32
|
-
const [sx, sy, sz] = this.scl;
|
|
34
|
+
const toRad = (Math.PI / 180).toFixed(6);
|
|
33
35
|
return [
|
|
34
36
|
`vec3 _mp_v_${this.id} = ${v};`,
|
|
35
|
-
`
|
|
36
|
-
`_mp_v_${this.id} =
|
|
37
|
-
`_mp_v_${this.id} =
|
|
38
|
-
`_mp_v_${this.id} =
|
|
39
|
-
`_mp_v_${this.id} = _mp_v_${this.id}
|
|
37
|
+
`vec3 _mp_r_${this.id} = ${rot} * ${toRad};`,
|
|
38
|
+
`_mp_v_${this.id} = _mp_v_${this.id} - ${loc};`,
|
|
39
|
+
`_mp_v_${this.id} = _st_rotateX(_mp_v_${this.id}, _mp_r_${this.id}.x);`,
|
|
40
|
+
`_mp_v_${this.id} = _st_rotateY(_mp_v_${this.id}, _mp_r_${this.id}.y);`,
|
|
41
|
+
`_mp_v_${this.id} = _st_rotateZ(_mp_v_${this.id}, _mp_r_${this.id}.z);`,
|
|
42
|
+
`_mp_v_${this.id} = _mp_v_${this.id} * ${scl};`,
|
|
40
43
|
`vec3 ${out} = _mp_v_${this.id};`,
|
|
41
44
|
].join('\n ');
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
Mapping.instanceSpecificDef = false;
|
|
45
|
-
Mapping.glslFunction = `
|
|
46
|
-
vec3 _st_rotateX(vec3 v, float a) {
|
|
47
|
-
float c = cos(a), s = sin(a);
|
|
48
|
-
return vec3(v.x, c * v.y - s * v.z, s * v.y + c * v.z);
|
|
49
|
-
}
|
|
50
|
-
vec3 _st_rotateY(vec3 v, float a) {
|
|
51
|
-
float c = cos(a), s = sin(a);
|
|
52
|
-
return vec3(c * v.x + s * v.z, v.y, -s * v.x + c * v.z);
|
|
53
|
-
}
|
|
54
|
-
vec3 _st_rotateZ(vec3 v, float a) {
|
|
55
|
-
float c = cos(a), s = sin(a);
|
|
56
|
-
return vec3(c * v.x - s * v.y, s * v.x + c * v.y, v.z);
|
|
48
|
+
Mapping.glslFunction = `
|
|
49
|
+
vec3 _st_rotateX(vec3 v, float a) {
|
|
50
|
+
float c = cos(a), s = sin(a);
|
|
51
|
+
return vec3(v.x, c * v.y - s * v.z, s * v.y + c * v.z);
|
|
52
|
+
}
|
|
53
|
+
vec3 _st_rotateY(vec3 v, float a) {
|
|
54
|
+
float c = cos(a), s = sin(a);
|
|
55
|
+
return vec3(c * v.x + s * v.z, v.y, -s * v.x + c * v.z);
|
|
56
|
+
}
|
|
57
|
+
vec3 _st_rotateZ(vec3 v, float a) {
|
|
58
|
+
float c = cos(a), s = sin(a);
|
|
59
|
+
return vec3(c * v.x - s * v.y, s * v.x + c * v.y, v.z);
|
|
57
60
|
}`;
|
|
@@ -3,20 +3,24 @@ import type { NodeMetadata } from '../../core/ShaderNode.js';
|
|
|
3
3
|
import type { CompileContext } from '../../core/CompileContext.js';
|
|
4
4
|
import type { OutputSocket } from '../../core/OutputSocket.js';
|
|
5
5
|
export interface NormalMapInputs {
|
|
6
|
-
|
|
6
|
+
color?: OutputSocket;
|
|
7
7
|
strength?: number | OutputSocket;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* Normal Map —
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Normal Map — Blender "Normal Map" node equivalent.
|
|
11
|
+
* Decodes a tangent-space normal texture (RGB → vector, [0,1] → [-1,1]) and
|
|
12
|
+
* rotates it into world space using a derivative-based cotangent frame, so no
|
|
13
|
+
* explicit vertex tangent attribute is required.
|
|
14
|
+
*
|
|
15
|
+
* Connect ImageTexture.Color (sampling a non-color / linear normal map texture)
|
|
16
|
+
* to `color`. Connect the result to PrincipledBSDF.normal.
|
|
13
17
|
*
|
|
14
18
|
* Inputs:
|
|
15
|
-
*
|
|
16
|
-
* strength (float)
|
|
19
|
+
* color (color) — sampled RGB normal texture, still in [0,1] range
|
|
20
|
+
* strength (float) — normal intensity, default: 1.0
|
|
17
21
|
*
|
|
18
22
|
* Outputs:
|
|
19
|
-
* Normal (
|
|
23
|
+
* Normal (color) — world-space perturbed normal, ready for PrincipledBSDF.normal
|
|
20
24
|
*/
|
|
21
25
|
export declare class NormalMap extends ProcessNode {
|
|
22
26
|
get nodeType(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NormalMap.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/NormalMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,eAAe;IAC9B,
|
|
1
|
+
{"version":3,"file":"NormalMap.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/NormalMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAK,YAAY,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAAA;CACjC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,SAAU,SAAQ,WAAW;IACxC,IAAI,QAAQ,WAAyB;IACrC,MAAM,CAAC,mBAAmB,UAAQ;IAElC,IAAI,QAAQ,IAAI,YAAY,CAQ3B;IAED,MAAM,CAAC,YAAY,SAmBnB;IAEA,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmE;gBAEhF,MAAM,GAAE,eAAoB;IASxC,eAAe;IACf,gBAAgB;IAChB,WAAW;IAEX,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM;CAOzC"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { ProcessNode } from '../../core/ProcessNode.js';
|
|
2
2
|
/**
|
|
3
|
-
* Normal Map —
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Normal Map — Blender "Normal Map" node equivalent.
|
|
4
|
+
* Decodes a tangent-space normal texture (RGB → vector, [0,1] → [-1,1]) and
|
|
5
|
+
* rotates it into world space using a derivative-based cotangent frame, so no
|
|
6
|
+
* explicit vertex tangent attribute is required.
|
|
7
|
+
*
|
|
8
|
+
* Connect ImageTexture.Color (sampling a non-color / linear normal map texture)
|
|
9
|
+
* to `color`. Connect the result to PrincipledBSDF.normal.
|
|
6
10
|
*
|
|
7
11
|
* Inputs:
|
|
8
|
-
*
|
|
9
|
-
* strength (float)
|
|
12
|
+
* color (color) — sampled RGB normal texture, still in [0,1] range
|
|
13
|
+
* strength (float) — normal intensity, default: 1.0
|
|
10
14
|
*
|
|
11
15
|
* Outputs:
|
|
12
|
-
* Normal (
|
|
16
|
+
* Normal (color) — world-space perturbed normal, ready for PrincipledBSDF.normal
|
|
13
17
|
*/
|
|
14
18
|
export class NormalMap extends ProcessNode {
|
|
15
19
|
get nodeType() { return 'NormalMap'; }
|
|
@@ -19,36 +23,45 @@ export class NormalMap extends ProcessNode {
|
|
|
19
23
|
category: 'Vector',
|
|
20
24
|
color: '#4a3a8a',
|
|
21
25
|
cost: 'medium',
|
|
22
|
-
costNote: '
|
|
26
|
+
costNote: 'Builds a derivative-based TBN frame per fragment.',
|
|
23
27
|
};
|
|
24
28
|
}
|
|
25
29
|
constructor(inputs = {}) {
|
|
26
30
|
super('NormalMap');
|
|
27
31
|
this._inputs = this.createInputs(inputs, {
|
|
28
|
-
|
|
32
|
+
color: ['color', [0.5, 0.5, 1.0]],
|
|
29
33
|
strength: ['float', inputs.strength ?? 1.0],
|
|
30
34
|
});
|
|
31
35
|
this._outputs = this.createOutputs({ Normal: 'color' });
|
|
32
36
|
}
|
|
33
37
|
getInputSockets() { return this._inputs; }
|
|
34
38
|
getOutputSockets() { return this._outputs; }
|
|
35
|
-
compileDefs() { return
|
|
39
|
+
compileDefs() { return NormalMap.glslFunction; }
|
|
36
40
|
compileCall(ctx) {
|
|
37
|
-
const
|
|
38
|
-
? ctx.outputVar(this._inputs.fac.connection.node, this._inputs.fac.connection.name)
|
|
39
|
-
: ctx.resolveInput(this._inputs.fac);
|
|
41
|
+
const color = ctx.resolveInput(this._inputs.color);
|
|
40
42
|
const strength = ctx.resolveInput(this._inputs.strength);
|
|
41
43
|
const normalVar = ctx.outputVar(this, 'Normal');
|
|
42
|
-
|
|
43
|
-
return [
|
|
44
|
-
`float _nm_nx_${this.id} = dFdx(${facVar});`,
|
|
45
|
-
`float _nm_ny_${this.id} = dFdy(${facVar});`,
|
|
46
|
-
`vec3 ${normalVar} = normalize(vec3(-_nm_nx_${this.id} * ${strength}, 1.0, -_nm_ny_${this.id} * ${strength}));`,
|
|
47
|
-
].join('\n ');
|
|
44
|
+
return `vec3 ${normalVar} = _st_normalMap(${color}, ${strength}, normalize(vNormal), vPosition, vUv);`;
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
NormalMap.instanceSpecificDef = false;
|
|
51
|
-
NormalMap.glslFunction = `
|
|
52
|
-
vec3 _st_normalMap(
|
|
53
|
-
|
|
48
|
+
NormalMap.glslFunction = `
|
|
49
|
+
vec3 _st_normalMap(vec3 sampledColor, float strength, vec3 N, vec3 P, vec2 uv) {
|
|
50
|
+
vec3 n = sampledColor * 2.0 - 1.0;
|
|
51
|
+
n.xy *= strength;
|
|
52
|
+
|
|
53
|
+
// Derivative-based cotangent frame (Schüler) — no vertex tangent attribute needed.
|
|
54
|
+
vec3 dp1 = dFdx(P);
|
|
55
|
+
vec3 dp2 = dFdy(P);
|
|
56
|
+
vec2 duv1 = dFdx(uv);
|
|
57
|
+
vec2 duv2 = dFdy(uv);
|
|
58
|
+
|
|
59
|
+
vec3 dp2perp = cross(dp2, N);
|
|
60
|
+
vec3 dp1perp = cross(N, dp1);
|
|
61
|
+
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
|
|
62
|
+
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
|
|
63
|
+
|
|
64
|
+
float invmax = inversesqrt(max(dot(T, T), dot(B, B)));
|
|
65
|
+
mat3 TBN = mat3(T * invmax, B * invmax, N);
|
|
66
|
+
return normalize(TBN * n);
|
|
54
67
|
}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShaderScript.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/ShaderScript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;
|
|
1
|
+
{"version":3,"file":"ShaderScript.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/ShaderScript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAK9D;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAA;AAEhF,oDAAoD;AACpD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAA;AAEtF,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAG,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,YAAY,CAAC,CAAA;IAExD,2CAA2C;IAC3C,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAE1B;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAID;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAC3C,IAAI,QAAQ,WAA4B;IACxC,MAAM,CAAC,mBAAmB,UAAO;IAEjC,IAAI,QAAQ,IAAI,YAAY,CAQ3B;IAED,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+E;IACvG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;gBAE/C,MAAM,EAAE,kBAAkB;IAmCtC,eAAe;IACf,gBAAgB;IAEhB,mDAAmD;IACnD,WAAW,IAAI,MAAM;IAErB;;;;;;OAMG;IACH,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM;IAkCxC,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;CAKtB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ProcessNode } from '../../core/ProcessNode.js';
|
|
2
|
+
import { assertGlslIdentifier } from '../../core/glslIdentifier.js';
|
|
2
3
|
// ── ShaderScript node ─────────────────────────────────────────────────────────
|
|
3
4
|
/**
|
|
4
5
|
* ShaderScript — Blender "Script Node (OSL)" equivalent for st-shader-core.
|
|
@@ -47,6 +48,7 @@ export class ShaderScript extends ProcessNode {
|
|
|
47
48
|
const defs = {};
|
|
48
49
|
const supplied = {};
|
|
49
50
|
for (const [name, spec] of Object.entries(config.inputs ?? {})) {
|
|
51
|
+
assertGlslIdentifier(name, 'ShaderScript input name');
|
|
50
52
|
if (Array.isArray(spec)) {
|
|
51
53
|
// ['float'|'color'|'vector'|'shader', defaultValue]
|
|
52
54
|
const [type, defaultVal] = spec;
|
|
@@ -60,6 +62,9 @@ export class ShaderScript extends ProcessNode {
|
|
|
60
62
|
supplied[name] = sock;
|
|
61
63
|
}
|
|
62
64
|
}
|
|
65
|
+
for (const name of Object.keys(this._outputDecl)) {
|
|
66
|
+
assertGlslIdentifier(name, 'ShaderScript output name');
|
|
67
|
+
}
|
|
63
68
|
this._inputs = this.createInputs(supplied, defs);
|
|
64
69
|
this._outputs = this.createOutputs(this._outputDecl);
|
|
65
70
|
}
|