UNPKG

three

Version:

JavaScript 3D library

190 lines (137 loc) 10.2 kB
import { mx_perlin_noise_float, mx_perlin_noise_vec3, mx_worley_noise_float_2d as worley_noise_float_2d, mx_worley_noise_float_3d as worley_noise_float_3d, mx_worley_noise_vec2 as worley_noise_vec2, mx_worley_noise_vec3 as worley_noise_vec3, mx_worley_noise_vec3_style as worley_noise_vec3_style, mx_cell_noise_float as cell_noise_float, mx_cell_noise_vec3 as cell_noise_vec3, mx_unifiednoise2d as unifiednoise2d, mx_unifiednoise3d as unifiednoise3d, mx_fractal_noise_float_2d as fractal_noise_float_2d, 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 } from './MaterialXNoise.js'; import { mx_rotate2d, mx_rotate3d } from './MaterialXCore.js'; import { mx_hsvtorgb, mx_rgbtohsv } from './MaterialXColor.js'; import { mx_srgb_texture_to_lin_rec709 } from './MaterialXColorTransform.js'; import { float, vec2, vec3, vec4, int, add, sub, mul, div, atan, mix, pow, smoothstep, floor, abs, max, clamp, step, cross, dot, normalize } from '../tsl/TSLBase.js'; import { uv } from '../accessors/UV.js'; import { frameId, time } from '../utils/Timer.js'; export const mx_aastep = ( threshold, value ) => { threshold = float( threshold ); value = float( value ); const afwidth = vec2( value.dFdx(), value.dFdy() ).length().mul( 0.70710678118654757 ); return smoothstep( threshold.sub( afwidth ), threshold.add( afwidth ), value ); }; const _ramp = ( a, b, uv, p ) => mix( a, b, uv[ p ].clamp() ); export const mx_ramplr = ( valuel, valuer, texcoord = uv() ) => _ramp( valuel, valuer, texcoord, 'x' ); export const mx_ramptb = ( valueb, valuet, texcoord = uv() ) => _ramp( valueb, valuet, texcoord, 'y' ); // Bilinear ramp: interpolate between four corners (tl, tr, bl, br) using texcoord.x and texcoord.y export const mx_ramp4 = ( valuetl, valuetr, valuebl, valuebr, texcoord = uv() ) => { const u = texcoord.x.clamp(); const v = texcoord.y.clamp(); const top = mix( valuetl, valuetr, u ); const bottom = mix( valuebl, valuebr, u ); return mix( bottom, top, v ); }; const _split = ( a, b, center, uv, p ) => mix( a, b, mx_aastep( center, uv[ p ] ) ); export const mx_splitlr = ( valuel, valuer, center, texcoord = uv() ) => _split( valuel, valuer, center, texcoord, 'x' ); export const mx_splittb = ( valueb, valuet, center, texcoord = uv() ) => _split( valueb, valuet, center, texcoord, 'y' ); export const mx_transform_uv = ( uv_scale = 1, uv_offset = 0, uv_geo = uv() ) => uv_geo.mul( uv_scale ).add( uv_offset ); export const mx_safepower = ( in1, in2 = 1 ) => { in1 = float( in1 ); return in1.abs().pow( in2 ).mul( in1.sign() ); }; 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_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 ) => { texcoord = texcoord.convert( 'vec2|vec3' ); // overloading type const noise_vec4 = vec4( mx_perlin_noise_vec3( texcoord ), mx_perlin_noise_float( texcoord.add( vec2( 19, 73 ) ) ) ); return noise_vec4.mul( amplitude ).add( pivot ); }; export const mx_smoothstep = ( inNode, low = 0, high = 1 ) => { const range = sub( high, low ); const safeRange = max( abs( range ), float( 1e-6 ) ); const t = clamp( div( sub( inNode, low ), safeRange ), float( 0 ), float( 1 ) ); const hermite = mul( mul( t, t ), sub( float( 3 ), mul( float( 2 ), t ) ) ); const fallback = step( high, inNode ); const useFallback = step( high, low ); return mix( hermite, fallback, useFallback ); }; export const mx_cell_noise_vec3 = ( texcoord = uv() ) => cell_noise_vec3( texcoord.convert( 'vec2|vec3' ) ); export const mx_worley_noise_float_2d = ( texcoord = uv(), jitter = 1, style = 0 ) => worley_noise_float_2d( texcoord, jitter, style ); export const mx_worley_noise_float_3d = ( texcoord = uv(), jitter = 1, style = 0 ) => worley_noise_float_3d( texcoord, jitter, style ); export const mx_unifiednoise2d = ( noiseType, texcoord = uv(), freq = vec2( 1, 1 ), offset = vec2( 0, 0 ), jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = .5, style = 0 ) => unifiednoise2d( noiseType, texcoord, freq, offset, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish, style ); export const mx_unifiednoise3d = ( noiseType, texcoord = uv(), freq = vec3( 1, 1, 1 ), offset = vec3( 0, 0, 0 ), jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = .5, style = 0 ) => unifiednoise3d( noiseType, texcoord, freq, offset, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish, style ); export const mx_worley_noise_float = ( texcoord = uv(), jitter = 1, style = 0 ) => mx_worley_noise_float_3d( texcoord.convert( 'vec2|vec3' ), jitter, style ); 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, metric = 1 ) => worley_noise_vec3( texcoord.convert( 'vec2|vec3' ), jitter, int( metric ) ); export const mx_worley_noise_vec3_style = ( texcoord = uv(), jitter = 1, style = 0, metric = 0 ) => worley_noise_vec3_style( texcoord.convert( 'vec2|vec3' ), jitter, int( style ), int( metric ) ); export const mx_cell_noise_float = ( texcoord = uv() ) => cell_noise_float( texcoord.convert( 'vec2|vec3' ) ); export const mx_fractal_noise_float_2d = ( texcoord = uv(), octaves = 3, lacunarity = 2, diminish = .5, amplitude = 1 ) => fractal_noise_float_2d( texcoord, int( 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_rotate2d, mx_rotate3d }; export { mx_hsvtorgb, mx_rgbtohsv, mx_srgb_texture_to_lin_rec709 }; // === Moved from MaterialXLoader.js === // Math ops export const mx_add = ( in1, in2 = float( 0 ) ) => add( in1, in2 ); export const mx_subtract = ( in1, in2 = float( 0 ) ) => sub( in1, in2 ); export const mx_multiply = ( in1, in2 = float( 1 ) ) => mul( in1, in2 ); export const mx_divide = ( in1, in2 = float( 1 ) ) => div( in1, in2 ); export const mx_modulo = ( in1, in2 = float( 1 ) ) => sub( in1, mul( in2, floor( div( in1, in2 ) ) ) ); export const mx_power = ( in1, in2 = float( 1 ) ) => pow( in1, in2 ); export const mx_atan2 = ( in1 = float( 0 ), in2 = float( 1 ) ) => atan( in1, in2 ); export const mx_timer = () => time; export const mx_frame = () => frameId; export const mx_invert = ( in1, amount = float( 1 ) ) => sub( amount, in1 ); export const mx_ifgreater = ( value1, value2, in1, in2 ) => value1.greaterThan( value2 ).mix( in2, in1 ); export const mx_ifgreatereq = ( value1, value2, in1, in2 ) => value1.greaterThanEqual( value2 ).mix( in2, in1 ); export const mx_ifequal = ( value1, value2, in1, in2 ) => value1.equal( value2 ).mix( in2, in1 ); // Enhanced separate node to support multi-output referencing (outx, outy, outz, outw) export const mx_separate = ( in1, channelOrOut = null ) => { if ( typeof channelOrOut === 'string' ) { const map = { x: 0, r: 0, y: 1, g: 1, z: 2, b: 2, w: 3, a: 3 }; const c = channelOrOut.replace( /^out/, '' ).toLowerCase(); if ( map[ c ] !== undefined ) return in1.element( map[ c ] ); } if ( typeof channelOrOut === 'number' ) { return in1.element( channelOrOut ); } if ( typeof channelOrOut === 'string' && channelOrOut.length === 1 ) { const map = { x: 0, r: 0, y: 1, g: 1, z: 2, b: 2, w: 3, a: 3 }; if ( map[ channelOrOut ] !== undefined ) return in1.element( map[ channelOrOut ] ); } return in1; }; export const mx_place2d = ( texcoord, pivot = vec2( 0, 0 ), scale = vec2( 1, 1 ), rotate = float( 0 ), offset = vec2( 0, 0 ), operationorder = int( 0 ) ) => { const centered = sub( texcoord, pivot ); const srt = add( sub( mx_rotate2d( div( centered, scale ), rotate ), offset ), pivot ); const trs = add( div( mx_rotate2d( sub( centered, offset ), rotate ), scale ), pivot ); if ( typeof operationorder === 'number' ) return Math.abs( operationorder ) > Number.EPSILON ? trs : srt; return mix( srt, trs, step( 0.5, float( operationorder ) ) ); }; export const mx_heighttonormal = ( input, scale = 1, texcoord = uv() ) => { const sobelScale = float( 1.0 / 16.0 ); const height = float( input ); const uvNode = vec2( texcoord ); const dHdS = vec2( height.dFdx(), height.dFdy() ).mul( float( scale ) ).mul( sobelScale ); const dUdS = vec2( uvNode.x.dFdx(), uvNode.x.dFdy() ); const dVdS = vec2( uvNode.y.dFdx(), uvNode.y.dFdy() ); const tangent = vec3( dUdS.x, dVdS.x, dHdS.x ); const bitangent = vec3( dUdS.y, dVdS.y, dHdS.y ); let n = cross( tangent, bitangent ); const invalid = dot( n, n ).lessThan( float( 1e-12 ) ); n = invalid.mix( n, vec3( 0, 0, 1 ) ); const mirrored = n.z.lessThan( float( 0 ) ); n = mirrored.mix( n, n.mul( - 1 ) ); return normalize( n ).mul( 0.5 ).add( 0.5 ); };