Skip to content

Commit

Permalink
WebGPURenderer: MaterialX (mrdoob#27294)
Browse files Browse the repository at this point in the history
* MathNode: Add `bitcast()`

* WGSLNodeBuilder: Add `greaterThan` for vec3

* WGSLNodeBuilder: XOR

* NodeBuilder: .buildFunctionNode() and getFunctionOperator()

* TSL: Function Overloading

* SplitNode: Fix expected output if used uvec or ivec

* TSL Transpiler: Improvements and fixes

* TSL: Fix expected output if used a.assign( b ), returns a

* FIX & TODO: Check reasons

* Fix clearcoat op sequence

* WebGPURenderer: MaterialX Support

* add webgpu materialx examples

* fix backend name

* unknown diff screenshot problem

* testing e2e response
  • Loading branch information
sunag authored and AdaRoseCannon committed Jan 15, 2024
1 parent 17da335 commit 11f9df5
Show file tree
Hide file tree
Showing 28 changed files with 2,536 additions and 805 deletions.
2 changes: 2 additions & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,10 @@
"webgpu_loader_gltf_compressed",
"webgpu_loader_gltf_iridescence",
"webgpu_loader_gltf_sheen",
"webgpu_loader_materialx",
"webgpu_materials",
"webgpu_materials_video",
"webgpu_materialx_noise",
"webgpu_multiple_rendertargets",
"webgpu_morphtargets",
"webgpu_morphtargets_face",
Expand Down
106 changes: 53 additions & 53 deletions examples/jsm/loaders/MaterialXLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const colorSpaceLib = {
mx_srgb_texture_to_lin_rec709
};

class MtlXElement {
class MXElement {

constructor( name, nodeFunc, params = null ) {

Expand All @@ -39,41 +39,41 @@ class MtlXElement {

// Ref: https://github.com/mrdoob/three.js/issues/24674

const MtlXElements = [
const MXElements = [

// << Math >>
new MtlXElement( 'add', add, [ 'in1', 'in2' ] ),
new MtlXElement( 'subtract', sub, [ 'in1', 'in2' ] ),
new MtlXElement( 'multiply', mul, [ 'in1', 'in2' ] ),
new MtlXElement( 'divide', div, [ 'in1', 'in2' ] ),
new MtlXElement( 'modulo', mod, [ 'in1', 'in2' ] ),
new MtlXElement( 'absval', abs, [ 'in1', 'in2' ] ),
new MtlXElement( 'sign', sign, [ 'in1', 'in2' ] ),
new MtlXElement( 'floor', floor, [ 'in1', 'in2' ] ),
new MtlXElement( 'ceil', ceil, [ 'in1', 'in2' ] ),
new MtlXElement( 'round', round, [ 'in1', 'in2' ] ),
new MtlXElement( 'power', pow, [ 'in1', 'in2' ] ),
new MtlXElement( 'sin', sin, [ 'in' ] ),
new MtlXElement( 'cos', cos, [ 'in' ] ),
new MtlXElement( 'tan', tan, [ 'in' ] ),
new MtlXElement( 'asin', asin, [ 'in' ] ),
new MtlXElement( 'acos', acos, [ 'in' ] ),
new MtlXElement( 'atan2', atan2, [ 'in1', 'in2' ] ),
new MtlXElement( 'sqrt', sqrt, [ 'in' ] ),
new MXElement( 'add', add, [ 'in1', 'in2' ] ),
new MXElement( 'subtract', sub, [ 'in1', 'in2' ] ),
new MXElement( 'multiply', mul, [ 'in1', 'in2' ] ),
new MXElement( 'divide', div, [ 'in1', 'in2' ] ),
new MXElement( 'modulo', mod, [ 'in1', 'in2' ] ),
new MXElement( 'absval', abs, [ 'in1', 'in2' ] ),
new MXElement( 'sign', sign, [ 'in1', 'in2' ] ),
new MXElement( 'floor', floor, [ 'in1', 'in2' ] ),
new MXElement( 'ceil', ceil, [ 'in1', 'in2' ] ),
new MXElement( 'round', round, [ 'in1', 'in2' ] ),
new MXElement( 'power', pow, [ 'in1', 'in2' ] ),
new MXElement( 'sin', sin, [ 'in' ] ),
new MXElement( 'cos', cos, [ 'in' ] ),
new MXElement( 'tan', tan, [ 'in' ] ),
new MXElement( 'asin', asin, [ 'in' ] ),
new MXElement( 'acos', acos, [ 'in' ] ),
new MXElement( 'atan2', atan2, [ 'in1', 'in2' ] ),
new MXElement( 'sqrt', sqrt, [ 'in' ] ),
//new MtlXElement( 'ln', ... ),
new MtlXElement( 'exp', exp, [ 'in' ] ),
new MtlXElement( 'clamp', clamp, [ 'in', 'low', 'high' ] ),
new MtlXElement( 'min', min, [ 'in1', 'in2' ] ),
new MtlXElement( 'max', max, [ 'in1', 'in2' ] ),
new MtlXElement( 'normalize', normalize, [ 'in' ] ),
new MtlXElement( 'magnitude', length, [ 'in1', 'in2' ] ),
new MtlXElement( 'dotproduct', dot, [ 'in1', 'in2' ] ),
new MtlXElement( 'crossproduct', cross, [ 'in' ] ),
new MXElement( 'exp', exp, [ 'in' ] ),
new MXElement( 'clamp', clamp, [ 'in', 'low', 'high' ] ),
new MXElement( 'min', min, [ 'in1', 'in2' ] ),
new MXElement( 'max', max, [ 'in1', 'in2' ] ),
new MXElement( 'normalize', normalize, [ 'in' ] ),
new MXElement( 'magnitude', length, [ 'in1', 'in2' ] ),
new MXElement( 'dotproduct', dot, [ 'in1', 'in2' ] ),
new MXElement( 'crossproduct', cross, [ 'in' ] ),
//new MtlXElement( 'transformpoint', ... ),
//new MtlXElement( 'transformvector', ... ),
//new MtlXElement( 'transformnormal', ... ),
//new MtlXElement( 'transformmatrix', ... ),
new MtlXElement( 'normalmap', normalMap, [ 'in', 'scale' ] ),
new MXElement( 'normalmap', normalMap, [ 'in', 'scale' ] ),
//new MtlXElement( 'transpose', ... ),
//new MtlXElement( 'determinant', ... ),
//new MtlXElement( 'invertmatrix', ... ),
Expand All @@ -83,44 +83,44 @@ const MtlXElements = [
//new MtlXElement( 'dot', ... ),

// << Adjustment >>
new MtlXElement( 'remap', remap, [ 'in', 'inlow', 'inhigh', 'outlow', 'outhigh' ] ),
new MtlXElement( 'smoothstep', smoothstep, [ 'in', 'low', 'high' ] ),
new MXElement( 'remap', remap, [ 'in', 'inlow', 'inhigh', 'outlow', 'outhigh' ] ),
new MXElement( 'smoothstep', smoothstep, [ 'in', 'low', 'high' ] ),
//new MtlXElement( 'curveadjust', ... ),
//new MtlXElement( 'curvelookup', ... ),
new MtlXElement( 'luminance', luminance, [ 'in', 'lumacoeffs' ] ),
new MtlXElement( 'rgbtohsv', mx_rgbtohsv, [ 'in' ] ),
new MtlXElement( 'hsvtorgb', mx_hsvtorgb, [ 'in' ] ),
new MXElement( 'luminance', luminance, [ 'in', 'lumacoeffs' ] ),
new MXElement( 'rgbtohsv', mx_rgbtohsv, [ 'in' ] ),
new MXElement( 'hsvtorgb', mx_hsvtorgb, [ 'in' ] ),

// << Mix >>
new MtlXElement( 'mix', mix, [ 'bg', 'fg', 'mix' ] ),
new MXElement( 'mix', mix, [ 'bg', 'fg', 'mix' ] ),

// << Channel >>
new MtlXElement( 'combine2', vec2, [ 'in1', 'in2' ] ),
new MtlXElement( 'combine3', vec3, [ 'in1', 'in2', 'in3' ] ),
new MtlXElement( 'combine4', vec4, [ 'in1', 'in2', 'in3', 'in4' ] ),
new MXElement( 'combine2', vec2, [ 'in1', 'in2' ] ),
new MXElement( 'combine3', vec3, [ 'in1', 'in2', 'in3' ] ),
new MXElement( 'combine4', vec4, [ 'in1', 'in2', 'in3', 'in4' ] ),

// << Procedural >>
new MtlXElement( 'ramplr', mx_ramplr, [ 'valuel', 'valuer', 'texcoord' ] ),
new MtlXElement( 'ramptb', mx_ramptb, [ 'valuet', 'valueb', 'texcoord' ] ),
new MtlXElement( 'splitlr', mx_splitlr, [ 'valuel', 'valuer', 'texcoord' ] ),
new MtlXElement( 'splittb', mx_splittb, [ 'valuet', 'valueb', 'texcoord' ] ),
new MtlXElement( 'noise2d', mx_noise_float, [ 'texcoord', 'amplitude', 'pivot' ] ),
new MtlXElement( 'noise3d', mx_noise_float, [ 'texcoord', 'amplitude', 'pivot' ] ),
new MtlXElement( 'fractal3d', mx_fractal_noise_float, [ 'position', 'octaves', 'lacunarity', 'diminish', 'amplitude' ] ),
new MtlXElement( 'cellnoise2d', mx_cell_noise_float, [ 'texcoord' ] ),
new MtlXElement( 'cellnoise3d', mx_cell_noise_float, [ 'texcoord' ] ),
new MtlXElement( 'worleynoise2d', mx_worley_noise_float, [ 'texcoord', 'jitter' ] ),
new MtlXElement( 'worleynoise3d', mx_worley_noise_float, [ 'texcoord', 'jitter' ] ),
new MXElement( 'ramplr', mx_ramplr, [ 'valuel', 'valuer', 'texcoord' ] ),
new MXElement( 'ramptb', mx_ramptb, [ 'valuet', 'valueb', 'texcoord' ] ),
new MXElement( 'splitlr', mx_splitlr, [ 'valuel', 'valuer', 'texcoord' ] ),
new MXElement( 'splittb', mx_splittb, [ 'valuet', 'valueb', 'texcoord' ] ),
new MXElement( 'noise2d', mx_noise_float, [ 'texcoord', 'amplitude', 'pivot' ] ),
new MXElement( 'noise3d', mx_noise_float, [ 'texcoord', 'amplitude', 'pivot' ] ),
new MXElement( 'fractal3d', mx_fractal_noise_float, [ 'position', 'octaves', 'lacunarity', 'diminish', 'amplitude' ] ),
new MXElement( 'cellnoise2d', mx_cell_noise_float, [ 'texcoord' ] ),
new MXElement( 'cellnoise3d', mx_cell_noise_float, [ 'texcoord' ] ),
new MXElement( 'worleynoise2d', mx_worley_noise_float, [ 'texcoord', 'jitter' ] ),
new MXElement( 'worleynoise3d', mx_worley_noise_float, [ 'texcoord', 'jitter' ] ),

// << Supplemental >>
//new MtlXElement( 'tiledimage', ... ),
//new MtlXElement( 'triplanarprojection', triplanarTextures, [ 'filex', 'filey', 'filez' ] ),
//new MtlXElement( 'ramp4', ... ),
//new MtlXElement( 'place2d', mx_place2d, [ 'texcoord', 'pivot', 'scale', 'rotate', 'offset' ] ),
new MtlXElement( 'safepower', mx_safepower, [ 'in1', 'in2' ] ),
new MtlXElement( 'contrast', mx_contrast, [ 'in', 'amount', 'pivot' ] ),
new MXElement( 'safepower', mx_safepower, [ 'in1', 'in2' ] ),
new MXElement( 'contrast', mx_contrast, [ 'in', 'amount', 'pivot' ] ),
//new MtlXElement( 'hsvadjust', ... ),
new MtlXElement( 'saturate', saturation, [ 'in', 'amount' ] ),
new MXElement( 'saturate', saturation, [ 'in', 'amount' ] ),
//new MtlXElement( 'extract', ... ),
//new MtlXElement( 'separate2', ... ),
//new MtlXElement( 'separate3', ... ),
Expand All @@ -129,7 +129,7 @@ const MtlXElements = [
];

const MtlXLibrary = {};
MtlXElements.forEach( element => MtlXLibrary[ element.name ] = element );
MXElements.forEach( element => MtlXLibrary[ element.name ] = element );

class MaterialXLoader extends Loader {

Expand Down
3 changes: 2 additions & 1 deletion examples/jsm/nodes/Nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import * as NodeUtils from './core/NodeUtils.js';
export { NodeUtils };

// math
export { default as MathNode, EPSILON, INFINITY, radians, degrees, exp, exp2, log, log2, sqrt, inverseSqrt, floor, ceil, normalize, fract, sin, cos, tan, asin, acos, atan, abs, sign, length, negate, oneMinus, dFdx, dFdy, round, reciprocal, trunc, fwidth, atan2, min, max, mod, step, reflect, distance, difference, dot, cross, pow, pow2, pow3, pow4, transformDirection, mix, clamp, saturate, refract, smoothstep, faceForward } from './math/MathNode.js';
export { default as MathNode, EPSILON, INFINITY, radians, degrees, exp, exp2, log, log2, sqrt, inverseSqrt, floor, ceil, normalize, fract, sin, cos, tan, asin, acos, atan, abs, sign, length, negate, oneMinus, dFdx, dFdy, round, reciprocal, trunc, fwidth, bitcast, atan2, min, max, mod, step, reflect, distance, difference, dot, cross, pow, pow2, pow3, pow4, transformDirection, mix, clamp, saturate, refract, smoothstep, faceForward } from './math/MathNode.js';
export { default as OperatorNode, add, sub, mul, div, remainder, equal, lessThan, greaterThan, lessThanEqual, greaterThanEqual, and, or, xor, bitAnd, bitOr, bitXor, shiftLeft, shiftRight } from './math/OperatorNode.js';
export { default as CondNode, cond } from './math/CondNode.js';
export { default as HashNode, hash } from './math/HashNode.js';
Expand All @@ -49,6 +49,7 @@ export { default as ArrayElementNode } from './utils/ArrayElementNode.js';
export { default as ConvertNode } from './utils/ConvertNode.js';
export { default as DiscardNode, discard } from './utils/DiscardNode.js';
export { default as EquirectUVNode, equirectUV } from './utils/EquirectUVNode.js';
export { default as FunctionOverloadingNode, overloadingFn } from './utils/FunctionOverloadingNode.js';
export { default as JoinNode } from './utils/JoinNode.js';
export { default as LoopNode, loop } from './utils/LoopNode.js';
export { default as MatcapUVNode, matcapUV } from './utils/MatcapUVNode.js';
Expand Down
6 changes: 3 additions & 3 deletions examples/jsm/nodes/code/CodeNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ class CodeNode extends Node {
this.code = code;
this.language = language;

this._includes = includes;
this.includes = includes;

}

setIncludes( includes ) {

this._includes = includes;
this.includes = includes;

return this;

}

getIncludes( /*builder*/ ) {

return this._includes;
return this.includes;

}

Expand Down
29 changes: 26 additions & 3 deletions examples/jsm/nodes/core/NodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import NodeCode from './NodeCode.js';
import NodeKeywords from './NodeKeywords.js';
import NodeCache from './NodeCache.js';
import ParameterNode from './ParameterNode.js';
import FunctionNode from '../code/FunctionNode.js';
import { createNodeMaterialFromType } from '../materials/NodeMaterial.js';
import { NodeUpdateType, defaultBuildStages, shaderStages } from './constants.js';

Expand Down Expand Up @@ -42,8 +43,6 @@ const typeFromArray = new Map( [
[ Float32Array, 'float' ]
] );

const isNonPaddingElementArray = new Set( [ Int32Array, Uint32Array, Float32Array ] );

const toFloat = ( value ) => {

value = Number( value );
Expand Down Expand Up @@ -95,6 +94,8 @@ class NodeBuilder {
this.stacks = [];
this.tab = '\t';

this.currentFunctionNode = null;

this.context = {
keywords: new NodeKeywords(),
material: this.material
Expand Down Expand Up @@ -552,7 +553,7 @@ class NodeBuilder {
if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data;

const array = dataAttribute.array;
const itemSize = isNonPaddingElementArray.has( array.constructor ) ? attribute.itemSize : dataAttribute.stride || attribute.itemSize;
const itemSize = attribute.itemSize;
const normalized = attribute.normalized;

let arrayType;
Expand Down Expand Up @@ -848,6 +849,22 @@ class NodeBuilder {

}

buildFunctionNode( shaderNode ) {

const fn = new FunctionNode();

const previous = this.currentFunctionNode;

this.currentFunctionNode = fn;

fn.code = this.buildFunctionCode( shaderNode );

this.currentFunctionNode = previous;

return fn;

}

flowShaderNode( shaderNode ) {

const layout = shaderNode.layout;
Expand Down Expand Up @@ -920,6 +937,12 @@ class NodeBuilder {

}

getFunctionOperator() {

return null;

}

flowChildNode( node, output = null ) {

const previousFlow = this.flow;
Expand Down
2 changes: 2 additions & 0 deletions examples/jsm/nodes/core/VarNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class VarNode extends Node {
this.node = node;
this.name = name;

this.isVarNode = true;

}

isGlobal() {
Expand Down
2 changes: 1 addition & 1 deletion examples/jsm/nodes/functions/PhysicalLightingModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ class PhysicalLightingModel extends LightingModel {
f90: clearcoatF90
} );

const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecularDirect, this.clearcoatSpecularIndirect ).mul( clearcoat );
const clearcoatLight = outgoingLight.mul( clearcoat.mul( Fcc ).oneMinus() ).add( this.clearcoatSpecularDirect.add( this.clearcoatSpecularIndirect ).mul( clearcoat ) );

outgoingLight.assign( clearcoatLight );

Expand Down
20 changes: 10 additions & 10 deletions examples/jsm/nodes/materialx/MaterialXNodes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
mx_perlin_noise_float, mx_perlin_noise_vec2, mx_perlin_noise_vec3,
mx_perlin_noise_float, mx_perlin_noise_vec3,
mx_worley_noise_float as worley_noise_float, mx_worley_noise_vec2 as worley_noise_vec2, mx_worley_noise_vec3 as worley_noise_vec3,
mx_cell_noise_float as cell_noise_float,
mx_fractal_noise_float as fractal_noise_float, mx_fractal_noise_vec2 as fractal_noise_vec2, mx_fractal_noise_vec3 as fractal_noise_vec3, mx_fractal_noise_vec4 as fractal_noise_vec4
Expand All @@ -8,7 +8,7 @@ import { mx_hsvtorgb, mx_rgbtohsv } from './lib/mx_hsv.js';
import { mx_srgb_texture_to_lin_rec709 } from './lib/mx_transform_color.js';
import { mix, smoothstep } from '../math/MathNode.js';
import { uv } from '../accessors/UVNode.js';
import { float, vec2, vec4 } from '../shadernode/ShaderNode.js';
import { float, vec2, vec4, int } from '../shadernode/ShaderNode.js';

export const mx_aastep = ( threshold, value ) => {

Expand Down Expand Up @@ -42,7 +42,7 @@ export const mx_safepower = ( in1, in2 = 1 ) => {
export const mx_contrast = ( input, amount = 1, pivot = .5 ) => float( input ).sub( pivot ).mul( amount ).add( pivot );

export const mx_noise_float = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_float( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec2( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
//export const mx_noise_vec2 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
export const mx_noise_vec3 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => mx_perlin_noise_vec3( texcoord.convert( 'vec2|vec3' ) ).mul( amplitude ).add( pivot );
export const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => {

Expand All @@ -54,15 +54,15 @@ export const mx_noise_vec4 = ( texcoord = uv(), amplitude = 1, pivot = 0 ) => {

};

export const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => worley_noise_float( texcoord.convert( 'vec2|vec3' ), jitter, 1 );
export const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec2( texcoord.convert( 'vec2|vec3' ), jitter, 1 );
export const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec3( texcoord.convert( 'vec2|vec3' ), jitter, 1 );
export const mx_worley_noise_float = ( texcoord = uv(), jitter = 1 ) => worley_noise_float( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) );
export const mx_worley_noise_vec2 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec2( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) );
export const mx_worley_noise_vec3 = ( texcoord = uv(), jitter = 1 ) => worley_noise_vec3( texcoord.convert( 'vec2|vec3' ), jitter, int( 1 ) );

export const mx_cell_noise_float = ( texcoord = uv() ) => cell_noise_float( texcoord.convert( 'vec2|vec3' ) );

export const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_float( position, octaves, lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec2( position, octaves, lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec3( position, octaves, lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec4( position, octaves, lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_float = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_float( position, int( octaves ), lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec2( position, int( octaves ), lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_vec3 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec3( position, int( octaves ), lacunarity, diminish ).mul( amplitude );
export const mx_fractal_noise_vec4 = ( position = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_vec4( position, int( octaves ), lacunarity, diminish ).mul( amplitude );

export { mx_hsvtorgb, mx_rgbtohsv, mx_srgb_texture_to_lin_rec709 };

0 comments on commit 11f9df5

Please sign in to comment.