diff --git a/types/three/examples/jsm/nodes/Nodes.d.ts b/types/three/examples/jsm/nodes/Nodes.d.ts
index d194de5ab..6ccf790b4 100644
--- a/types/three/examples/jsm/nodes/Nodes.d.ts
+++ b/types/three/examples/jsm/nodes/Nodes.d.ts
@@ -7,7 +7,7 @@ import ConstNode from './core/ConstNode';
import ContextNode from './core/ContextNode';
import ExpressionNode from './core/ExpressionNode';
import FunctionCallNode from './core/FunctionCallNode';
-import FunctionNode from './core/FunctionNode';
+import FunctionNode, { FunctionNodeParameters } from './core/FunctionNode';
import InstanceIndexNode from './core/InstanceIndexNode';
import Node from './core/Node';
import NodeAttribute from './core/NodeAttribute';
@@ -118,6 +118,7 @@ export {
ExpressionNode,
FunctionCallNode,
FunctionNode,
+ FunctionNodeParameters,
InstanceIndexNode,
Node,
NodeAttribute,
diff --git a/types/three/examples/jsm/nodes/core/CodeNode.d.ts b/types/three/examples/jsm/nodes/core/CodeNode.d.ts
index c24c0e805..7ac8b841b 100644
--- a/types/three/examples/jsm/nodes/core/CodeNode.d.ts
+++ b/types/three/examples/jsm/nodes/core/CodeNode.d.ts
@@ -3,13 +3,13 @@ import Node from './Node';
import NodeBuilder from './NodeBuilder';
export interface CodeNodeInclude {
- build(): void;
+ build(builder: NodeBuilder): void;
}
export default class CodeNode extends Node {
isCodeNode: true;
code: string;
- constructor(code: string, nodeType?: NodeTypeOption);
+ constructor(code?: string, includes?: CodeNodeInclude[]);
setIncludes(includes: CodeNodeInclude[]): this;
getIncludes(builder: NodeBuilder): CodeNodeInclude[];
diff --git a/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts b/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts
index 4712e2dc9..6e62e28aa 100644
--- a/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts
+++ b/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts
@@ -2,12 +2,12 @@ import FunctionNode from './FunctionNode';
import TempNode from './TempNode';
import Node from './Node';
-export default class FunctionCallNode extends TempNode {
- functionNode: FunctionNode;
+export default class FunctionCallNode
extends TempNode {
+ functionNode: FunctionNode
;
parameters: { [name: string]: Node };
- constructor(functionNode?: FunctionNode, parameters?: { [name: string]: Node });
+ constructor(functionNode?: FunctionNode
, parameters?: P);
- setParameters(parameters: { [name: string]: Node }): this;
- getParameters(): { [name: string]: Node };
+ setParameters(parameters: P): this;
+ getParameters(): P;
}
diff --git a/types/three/examples/jsm/nodes/core/FunctionNode.d.ts b/types/three/examples/jsm/nodes/core/FunctionNode.d.ts
index 33ed738e2..e312df8af 100644
--- a/types/three/examples/jsm/nodes/core/FunctionNode.d.ts
+++ b/types/three/examples/jsm/nodes/core/FunctionNode.d.ts
@@ -1,15 +1,17 @@
-import CodeNode from './CodeNode';
+import CodeNode, { CodeNodeInclude } from './CodeNode';
import FunctionCallNode from './FunctionCallNode';
import NodeBuilder from './NodeBuilder';
import NodeFunction from './NodeFunction';
import NodeFunctionInput from './NodeFunctionInput';
import Node from './Node';
-export default class FunctionNode extends CodeNode {
+export type FunctionNodeParameters = Node[] | { [name: string]: Node };
+
+export default class FunctionNode
extends CodeNode {
keywords: { [key: string]: Node };
- constructor(code?: string);
+ constructor(code?: string, includes?: CodeNodeInclude[]);
getInputs(builder: NodeBuilder): NodeFunctionInput[];
getNodeFunction(builder: NodeBuilder): NodeFunction;
- call(parameters: { [name: string]: Node }): FunctionCallNode;
+ call(parameters: P): FunctionCallNode
;
}
diff --git a/types/three/examples/jsm/nodes/materialx/functions/lib/mx_hsv.d.ts b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_hsv.d.ts
new file mode 100644
index 000000000..5dd4b8dab
--- /dev/null
+++ b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_hsv.d.ts
@@ -0,0 +1,4 @@
+import { FnParameters, Node, Swizzable } from '../../../Nodes';
+
+export function mx_hsvtorgb(...params: FnParameters<[Node]>): Swizzable;
+export function mx_rgbtohsv(...params: FnParameters<[Node]>): Swizzable;
diff --git a/types/three/examples/jsm/nodes/materialx/functions/lib/mx_noise.d.ts b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_noise.d.ts
new file mode 100644
index 000000000..28187b33b
--- /dev/null
+++ b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_noise.d.ts
@@ -0,0 +1,6 @@
+import { FnParameters, Node, Swizzable } from '../../../Nodes';
+
+export function mx_perlin_noise_float(...params: FnParameters<[Node]>): Swizzable;
+export function mx_cell_noise_float(...params: FnParameters<[Node]>): Swizzable;
+export function mx_worley_noise_float(...params: FnParameters<[Node]>): Swizzable;
+export function mx_fractal_noise_float(...params: FnParameters<[Node, Node, Node, Node]>): Swizzable;
diff --git a/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts b/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts
index 900a3b3e5..849744a47 100644
--- a/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts
+++ b/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts
@@ -7,17 +7,19 @@ export type Swizzable = T &
};
/** anything that can be passed to {@link nodeObject} and returns a proxy */
-export type NodeRepresentation = number | boolean | Node | Swizzable;
+export type NodeRepresentation = number | boolean | Node | Swizzable;
/** anything that can be passed to {@link nodeObject} */
export type NodeObjectOption = NodeRepresentation | string;
-// same logic as in ShaderNodeObject
+// same logic as in ShaderNodeObject: number,boolean,node->swizzable, otherwise do nothing
export type NodeObject = T extends Node ? Swizzable : T extends number | boolean ? Swizzable : T;
-type MakeObjectOption = T extends Node ? NodeRepresentation : T;
+// opposite of NodeObject: node -> node|swizzable|boolean|number, otherwise do nothing
+type Proxied = T extends Node ? NodeRepresentation : T;
// https://github.com/microsoft/TypeScript/issues/42435#issuecomment-765557874
-type MakeObjectOptions = [...{ [index in keyof T]: MakeObjectOption }];
+export type ProxiedTuple = [...{ [index in keyof T]: Proxied }];
+export type ProxiedObject = { [index in keyof T]: Proxied };
type RemoveTail = T extends [unknown, ...infer X] ? X : [];
type RemoveHeadAndTail = T extends [unknown, ...infer X, unknown] ? X : [];
@@ -121,22 +123,22 @@ export function nodeArray(obj: readonly [...T]): N
export function nodeProxy(
nodeClass: T,
-): (...params: MakeObjectOptions>) => Swizzable>;
+): (...params: ProxiedTuple>) => Swizzable>;
export function nodeProxy>(
nodeClass: T,
scope: S,
-): (...params: MakeObjectOptions>>) => Swizzable>;
+): (...params: ProxiedTuple>>) => Swizzable>;
export function nodeProxy>(
nodeClass: T,
scope: S,
factor: NodeObjectOption,
-): (...params: MakeObjectOptions>>) => Swizzable>;
+): (...params: ProxiedTuple>>) => Swizzable>;
export function nodeImmutable(
nodeClass: T,
- ...params: MakeObjectOptions>
+ ...params: ProxiedTuple>
): Swizzable>;
export class ShaderNode {
diff --git a/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts b/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts
index 3b74fe54e..3c499844e 100644
--- a/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts
+++ b/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts
@@ -13,6 +13,9 @@ import {
Swizzable,
NodeRepresentation,
NodeOrType,
+ NodeObjects,
+ ProxiedObject,
+ ProxiedTuple,
} from './ShaderNode';
import { Material, Texture } from '../../../../src/Three';
import { NodeTypeOption, NodeUserData, NodeValueOption } from '../core/constants';
@@ -22,13 +25,14 @@ import {
BypassNode,
CameraNode,
CodeNode,
+ CodeNodeInclude,
ComputeNode,
ContextNode,
- ConvertNode,
ExpressionNode,
FrontFacingNode,
FunctionCallNode,
FunctionNode,
+ FunctionNodeParameters,
InstanceIndexNode,
MaterialNode,
MaterialReferenceNode,
@@ -83,8 +87,6 @@ export const imat4: ConvertType;
export const umat4: ConvertType;
export const bmat4: ConvertType;
-export function func(code: string): ShaderNode;
-
export function uniform(nodeOrType: Node | Swizzable | NodeValueOption): Swizzable;
export function attribute(attributeName: string, nodeType: NodeTypeOption): Swizzable;
@@ -95,10 +97,27 @@ export function code(code: string, nodeType?: NodeTypeOption): Swizzable;
export function expression(snipped?: string, nodeType?: NodeTypeOption): Swizzable;
-export function call(
- functionNode?: NodeRepresentation,
- parameters?: { [name: string]: Node },
-): Swizzable;
+// definition: const call = nodeProxy(FunctionCallNode);
+export function call(
+ functionNode?: FunctionNode
,
+ parameters?: ProxiedObject
,
+): Swizzable>;
+
+export type FnParameters = P extends readonly [...unknown[]]
+ ? ProxiedTuple
+ : readonly [ProxiedObject
];
+
+// tslint:disable:no-unnecessary-generics
+export function func
(
+ code: string,
+ includes?: CodeNodeInclude[],
+): { call: (...params: FnParameters
) => Swizzable };
+
+export function fn
(
+ code: string,
+ includes?: CodeNodeInclude[],
+): (...params: FnParameters
) => Swizzable;
+// tslint:enable:no-unnecessary-generics
export const instanceIndex: Swizzable;
export function label(node: NodeRepresentation, name?: string): Swizzable;
diff --git a/types/three/test/nodes/nodes-FunctionNode.ts b/types/three/test/nodes/nodes-FunctionNode.ts
new file mode 100644
index 000000000..ea8e67a07
--- /dev/null
+++ b/types/three/test/nodes/nodes-FunctionNode.ts
@@ -0,0 +1,57 @@
+/**
+ * Various tests of func, fn and call
+ */
+
+import {
+ code,
+ fn,
+ uv,
+ func,
+ Node,
+ FunctionNode,
+ call,
+ Swizzable,
+ FunctionCallNode,
+} from 'three/examples/jsm/nodes/Nodes';
+
+import { ProxiedObject } from 'three/examples/jsm/nodes/shadernode/ShaderNode';
+
+export const mx_noise = code('whatever');
+const includes = [mx_noise];
+
+const someFunc1 = new FunctionNode<[a: Node]>();
+const someFunc2 = new FunctionNode<{ a: Node }>();
+
+// tslint:disable-next-line:no-unnecessary-generics
+function assertSwizzable(_s: Swizzable) {}
+
+type a = ProxiedObject;
+
+assertSwizzable>(call(someFunc1, [1]));
+assertSwizzable>(call(someFunc1, [uv()]));
+assertSwizzable>(call(someFunc1, [uv().xy]));
+assertSwizzable>(call(someFunc2, { a: 1 }));
+assertSwizzable>(call(someFunc2, { a: uv() }));
+assertSwizzable>(call(someFunc2, { a: uv().xy }));
+
+export const mx_cell_noise_float_call = func<[Node]>('float mx_cell_noise_float( vec3 p )', includes);
+export const mx_worley_noise_float_call = func<[Node, Node, Node]>(
+ 'float mx_worley_noise_float( vec3 p, float jitter, int metric )',
+ includes,
+);
+export const ab_call = func<{ a: Node; b: Node }>('float mx_cell_noise_float( vec3 p )', includes);
+
+assertSwizzable(mx_cell_noise_float_call.call(uv()));
+assertSwizzable(mx_worley_noise_float_call.call(uv(), 1, 1));
+assertSwizzable(ab_call.call({ a: 1, b: uv() }));
+
+export const mx_cell_noise_float = fn<[Node]>('float mx_cell_noise_float( vec3 p )', includes);
+export const mx_worley_noise_float = fn<[Node, Node, Node]>(
+ 'float mx_worley_noise_float( vec3 p, float jitter, int metric )',
+ includes,
+);
+export const ab = fn<{ a: Node; b: Node }>('float mx_cell_noise_float( vec3 p )', includes);
+
+assertSwizzable(mx_cell_noise_float(uv()));
+assertSwizzable(mx_worley_noise_float(uv(), 1, 1));
+assertSwizzable(ab({ a: 1, b: uv() }));
diff --git a/types/three/test/nodes/nodes-ShaderNode.ts b/types/three/test/nodes/nodes-ShaderNode.ts
index 47ea44467..0bb5fb9b5 100644
--- a/types/three/test/nodes/nodes-ShaderNode.ts
+++ b/types/three/test/nodes/nodes-ShaderNode.ts
@@ -22,7 +22,6 @@ import { ConvertType, Swizzable } from 'three/examples/jsm/nodes/shadernode/Shad
// just to type check
// tslint:disable-next-line:no-unnecessary-generics
function assertSwizzable(_s: Swizzable) {}
-function assertNode(_s: Node) {}
export const color = new ConvertType('color');
const s = color(1);
diff --git a/types/three/test/nodes/nodes-materialx.ts b/types/three/test/nodes/nodes-materialx.ts
new file mode 100644
index 000000000..a1e6a87af
--- /dev/null
+++ b/types/three/test/nodes/nodes-materialx.ts
@@ -0,0 +1,15 @@
+import {
+ mx_perlin_noise_float,
+ mx_cell_noise_float,
+ mx_worley_noise_float,
+ mx_fractal_noise_float,
+} from 'three/examples/jsm/nodes/materialx/functions/lib/mx_noise';
+
+import { mx_hsvtorgb, mx_rgbtohsv } from 'three/examples/jsm/nodes/materialx/functions/lib/mx_hsv';
+
+mx_perlin_noise_float(1);
+mx_cell_noise_float(1);
+mx_worley_noise_float(1);
+mx_fractal_noise_float(1, 1, 1, 1);
+mx_hsvtorgb(1);
+mx_rgbtohsv(1);
diff --git a/types/three/tsconfig.json b/types/three/tsconfig.json
index dac57dc63..4f63754b3 100644
--- a/types/three/tsconfig.json
+++ b/types/three/tsconfig.json
@@ -63,6 +63,8 @@
"test/misc/misc-gpucomputationrender.ts",
"test/nodes/nodes-ColorAdjustmentNode.ts",
"test/nodes/nodes-Iridescence.ts",
+ "test/nodes/nodes-FunctionNode.ts",
+ "test/nodes/nodes-materialx.ts",
"test/nodes/nodes-ShaderNode.ts",
"test/nodes/nodes-ShaderNodeBaseElements.ts",
"test/nodes/nodes-ShaderNodeElements.ts",