1
0

MaterialXNodeLibrary.js 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. import {
  2. abs,
  3. add,
  4. clamp,
  5. floor,
  6. ceil,
  7. round,
  8. sign,
  9. sin,
  10. cos,
  11. tan,
  12. asin,
  13. acos,
  14. sqrt,
  15. log,
  16. exp,
  17. min,
  18. max,
  19. normalize,
  20. length,
  21. dot,
  22. cross,
  23. mul,
  24. div,
  25. pow,
  26. distance,
  27. remap,
  28. luminance,
  29. mx_rgbtohsv,
  30. mx_hsvtorgb,
  31. mix,
  32. saturation as mx_saturation,
  33. transpose,
  34. determinant,
  35. inverse,
  36. mat3,
  37. mx_ramp4,
  38. mx_ramplr,
  39. mx_ramptb,
  40. mx_splitlr,
  41. mx_splittb,
  42. mx_fractal_noise_float,
  43. mx_fractal_noise_vec3,
  44. mx_noise_float,
  45. mx_noise_vec3,
  46. mx_cell_noise_float,
  47. mx_cell_noise_vec3,
  48. mx_smoothstep,
  49. mx_worley_noise_float_2d,
  50. mx_worley_noise_float_3d,
  51. mx_worley_noise_vec3_style,
  52. mx_unifiednoise2d,
  53. mx_unifiednoise3d,
  54. mx_modulo,
  55. mx_invert,
  56. mx_place2d,
  57. mx_rotate2d,
  58. mx_rotate3d,
  59. mx_safepower,
  60. mx_contrast,
  61. element,
  62. reflect,
  63. refract,
  64. mx_timer,
  65. mx_frame,
  66. mx_ifgreater,
  67. mx_ifgreatereq,
  68. mx_ifequal,
  69. mx_atan2,
  70. positionLocal,
  71. positionWorld,
  72. normalWorld,
  73. tangentWorld,
  74. bitangentWorld,
  75. cameraPosition,
  76. mx_heighttonormal,
  77. float,
  78. int,
  79. bool,
  80. color,
  81. modelNormalMatrix,
  82. modelWorldMatrix,
  83. modelWorldMatrixInverse,
  84. vec2,
  85. vec3,
  86. vec4,
  87. fract,
  88. sub,
  89. step,
  90. and as tslAnd,
  91. or as tslOr,
  92. xor as tslXor,
  93. not as tslNot,
  94. Fn,
  95. Loop,
  96. } from 'three/tsl';
  97. import { normalizeSpaceName, toBooleanNode, toVec3Channels } from './MaterialXUtils.js';
  98. const createMXElement = ( name, nodeFunc, params = [], defaults = {}, usesNode = false ) => ( { name, nodeFunc, params, defaults, usesNode } );
  99. const mx_range = ( inNode, inLow, inHigh, outLow, outHigh, gamma = 1 ) => {
  100. const inSpan = max( sub( inHigh, inLow ), 1e-6 );
  101. const normalized = div( sub( inNode, inLow ), inSpan );
  102. const reciprocalGamma = div( 1, gamma );
  103. const gammaApplied = mul( pow( abs( normalized ), reciprocalGamma ), sign( normalized ) );
  104. return add( outLow, mul( gammaApplied, sub( outHigh, outLow ) ) );
  105. };
  106. const mx_open_pbr_anisotropy = ( roughness = 0, anisotropy = 0 ) => {
  107. const anisoInvert = sub( float( 1 ), anisotropy );
  108. const anisoInvertSq = mul( anisoInvert, anisoInvert );
  109. const denom = add( anisoInvertSq, float( 1 ) );
  110. const fraction = div( float( 2 ), denom );
  111. const sqrtFraction = sqrt( fraction );
  112. const roughSq = mul( roughness, roughness );
  113. const alphaX = mul( roughSq, sqrtFraction );
  114. const alphaY = mul( anisoInvert, alphaX );
  115. return vec2( alphaX, alphaY );
  116. };
  117. const mx_boolean = ( inNode ) => toBooleanNode( inNode );
  118. const mx_and = ( in1, in2 ) => tslAnd( mx_boolean( in1 ), mx_boolean( in2 ) );
  119. const mx_or = ( in1, in2 ) => tslOr( mx_boolean( in1 ), mx_boolean( in2 ) );
  120. const mx_xor = ( in1, in2 ) => tslXor( mx_boolean( in1 ), mx_boolean( in2 ) );
  121. const mx_not = ( inNode ) => tslNot( mx_boolean( inNode ) );
  122. const mx_checkerboard = ( color1, color2, uvtiling, uvoffset, texcoord ) => {
  123. const tiledUv = sub( mul( texcoord, uvtiling ), uvoffset );
  124. const checkerMix = mx_modulo( dot( floor( tiledUv ), vec2( 1, 1 ) ), float( 2 ) );
  125. return mix( color2, color1, checkerMix );
  126. };
  127. const mx_circle = ( texcoord, center, radius ) => {
  128. const delta = sub( texcoord, center );
  129. const distanceSquared = dot( delta, delta );
  130. const radiusSquared = mul( radius, radius );
  131. return mx_ifgreater( distanceSquared, radiusSquared, 0, 1 );
  132. };
  133. const mx_normalmap = (
  134. value = vec3( 0.5, 0.5, 1.0 ),
  135. scale = 1.0,
  136. normal = vec3( 0.0, 0.0, 1.0 ),
  137. tangent = vec3( 1.0, 0.0, 0.0 ),
  138. bitangent = vec3( 0.0, 1.0, 0.0 ),
  139. ) => {
  140. const mapValue = toVec3Channels( value );
  141. const decoded = sub( mul( mapValue, 2.0 ), vec3( 1.0, 1.0, 1.0 ) );
  142. const safeValue = dot( mapValue, mapValue ).equal( 0 ).mix( decoded, vec3( 0.0, 0.0, 1.0 ) );
  143. const normalScale = vec2( scale );
  144. const blended =
  145. add(
  146. add(
  147. mul( tangent, mul( element( safeValue, 0 ), element( normalScale, 0 ) ) ),
  148. mul( bitangent, mul( element( safeValue, 1 ), element( normalScale, 1 ) ) ),
  149. ),
  150. mul( normal, element( safeValue, 2 ) ),
  151. );
  152. return normalize( blended );
  153. };
  154. const mx_bump = (
  155. height,
  156. scale = 1,
  157. normal = vec3( 0.0, 0.0, 1.0 ),
  158. tangent = vec3( 1.0, 0.0, 0.0 ),
  159. bitangent = vec3( 0.0, 1.0, 0.0 ),
  160. ) => mx_normalmap( mx_heighttonormal( height, 1 ), scale, normal, tangent, bitangent );
  161. const mx_dot = ( inNode ) => inNode;
  162. const mx_viewdirection = ( space = 'world' ) => {
  163. const outputSpace = normalizeSpaceName( space, 'world' );
  164. const worldDirection = normalize( sub( positionWorld, cameraPosition ) );
  165. if ( outputSpace === 'world' ) {
  166. return worldDirection;
  167. }
  168. return mx_transformnormal( worldDirection, 'world', outputSpace );
  169. };
  170. const mx_blackbody = ( temperature = 5000 ) => {
  171. const temperatureKelvin = clamp( temperature, float( 800 ), float( 25000 ) );
  172. const t = div( float( 1000 ), temperatureKelvin );
  173. const t2 = mul( t, t );
  174. const t3 = mul( t2, t );
  175. const lowX = add( add( mul( float( - 0.2661239 ), t3 ), mul( float( - 0.234358 ), t2 ) ), add( mul( float( 0.8776956 ), t ), float( 0.17991 ) ) );
  176. const highX = add(
  177. add( mul( float( - 3.0258469 ), t3 ), mul( float( 2.1070379 ), t2 ) ),
  178. add( mul( float( 0.2226347 ), t ), float( 0.24039 ) ),
  179. );
  180. const xc = mx_ifgreatereq( temperatureKelvin, float( 4000 ), highX, lowX );
  181. const xc2 = mul( xc, xc );
  182. const xc3 = mul( xc2, xc );
  183. const ycLow = add(
  184. add( mul( float( - 1.1063814 ), xc3 ), mul( float( - 1.3481102 ), xc2 ) ),
  185. add( mul( float( 2.18555832 ), xc ), float( - 0.20219683 ) ),
  186. );
  187. const ycMid = add(
  188. add( mul( float( - 0.9549476 ), xc3 ), mul( float( - 1.37418593 ), xc2 ) ),
  189. add( mul( float( 2.09137015 ), xc ), float( - 0.16748867 ) ),
  190. );
  191. const ycHigh = add(
  192. add( mul( float( 3.081758 ), xc3 ), mul( float( - 5.8733867 ), xc2 ) ),
  193. add( mul( float( 3.75112997 ), xc ), float( - 0.37001483 ) ),
  194. );
  195. const ycLowMid = mx_ifgreatereq( temperatureKelvin, float( 2222 ), ycMid, ycLow );
  196. const yc = mx_ifgreatereq( temperatureKelvin, float( 4000 ), ycHigh, ycLowMid );
  197. const safeYc = max( yc, float( 1e-6 ) );
  198. const xyz = vec3( div( xc, safeYc ), float( 1 ), div( sub( sub( float( 1 ), xc ), yc ), safeYc ) );
  199. const rgb = vec3(
  200. add( add( mul( float( 3.2406 ), element( xyz, 0 ) ), mul( float( - 1.5372 ), element( xyz, 1 ) ) ), mul( float( - 0.4986 ), element( xyz, 2 ) ) ),
  201. add( add( mul( float( - 0.9689 ), element( xyz, 0 ) ), mul( float( 1.8758 ), element( xyz, 1 ) ) ), mul( float( 0.0415 ), element( xyz, 2 ) ) ),
  202. add( add( mul( float( 0.0557 ), element( xyz, 0 ) ), mul( float( - 0.204 ), element( xyz, 1 ) ) ), mul( float( 1.057 ), element( xyz, 2 ) ) ),
  203. );
  204. const clampedRgb = max( rgb, vec3( 0, 0, 0 ) );
  205. const validYcMask = step( float( 1e-6 ), yc );
  206. return mix( vec3( 1, 1, 1 ), clampedRgb, validYcMask );
  207. };
  208. const mx_unpremult = ( input ) => {
  209. const alpha = element( input, 3 );
  210. const rgb = toVec3Channels( input );
  211. const unpremultiplied = alpha.equal( 0 ).mix( rgb, div( rgb, alpha ) );
  212. return vec4( unpremultiplied, alpha );
  213. };
  214. const mx_colorcorrect = (
  215. input,
  216. hue = 0,
  217. saturationAmount = 1,
  218. gamma = 1,
  219. lift = 0,
  220. gain = 1,
  221. contrast = 1,
  222. contrastPivot = 0.5,
  223. exposure = 0,
  224. ) => {
  225. const rgbInput = toVec3Channels( input );
  226. const hsv = mx_rgbtohsv( rgbInput );
  227. const hueAdjusted = mx_hsvtorgb( add( hsv, vec3( hue, 0, 0 ) ) );
  228. const saturationAdjusted = mx_saturation( hueAdjusted, saturationAmount );
  229. const gammaAdjusted = mx_range( saturationAdjusted, 0, 1, 0, 1, gamma );
  230. const liftApplied = add( mul( gammaAdjusted, sub( 1, lift ) ), lift );
  231. const gainApplied = mul( liftApplied, gain );
  232. const contrastApplied = mx_contrast( gainApplied, contrast, contrastPivot );
  233. const exposureApplied = mul( contrastApplied, pow( 2, exposure ) );
  234. const preserveAlpha = input && ( input.nodeType === 'vec4' || input.nodeType === 'color4' );
  235. return preserveAlpha ? vec4( exposureApplied, element( input, 3 ) ) : exposureApplied;
  236. };
  237. const mx_minus = ( fg, bg, mixval = 1 ) => add( mul( mixval, sub( bg, fg ) ), mul( sub( 1, mixval ), bg ) );
  238. const mx_difference = ( fg, bg, mixval = 1 ) => add( mul( mixval, abs( sub( bg, fg ) ) ), mul( sub( 1, mixval ), bg ) );
  239. const mx_screen = ( fg, bg, mixval = 1 ) => {
  240. const screened = sub( 1, mul( sub( 1, fg ), sub( 1, bg ) ) );
  241. return mix( bg, screened, mixval );
  242. };
  243. const mx_overlay = ( fg, bg, mixval = 1 ) => {
  244. const lowBranch = mul( mul( 2, fg ), bg );
  245. const highBranch = sub( 1, mul( mul( 2, sub( 1, fg ) ), sub( 1, bg ) ) );
  246. const overlayed = mix( lowBranch, highBranch, step( 0.5, bg ) );
  247. return mix( bg, overlayed, mixval );
  248. };
  249. const mx_transformnormal = ( inNode = vec3( 0, 0, 1 ), fromspace = 'world', tospace = 'world' ) => {
  250. const from = normalizeSpaceName( fromspace, 'world' );
  251. const to = normalizeSpaceName( tospace, 'world' );
  252. const inNormal = vec3( inNode );
  253. if ( from === to ) {
  254. return normalize( inNormal );
  255. }
  256. if ( from === 'object' && to === 'world' ) {
  257. return normalize( mul( inNormal, modelNormalMatrix ) );
  258. }
  259. return normalize( mul( inNormal, mat3( modelWorldMatrix ) ) );
  260. };
  261. const mx_transformvector = ( inNode = vec3( 0, 0, 0 ), fromspace = 'world', tospace = 'world' ) => {
  262. const from = normalizeSpaceName( fromspace, 'world' );
  263. const to = normalizeSpaceName( tospace, 'world' );
  264. const inVector = vec3( inNode );
  265. if ( from === to ) {
  266. return inVector;
  267. }
  268. if ( from === 'object' && to === 'world' ) {
  269. return mul( inVector, mat3( modelWorldMatrix ) );
  270. }
  271. return mul( inVector, mat3( modelWorldMatrixInverse ) );
  272. };
  273. const mx_transformpoint = ( inNode = vec3( 0, 0, 0 ), fromspace = 'world', tospace = 'world' ) => {
  274. const from = normalizeSpaceName( fromspace, 'world' );
  275. const to = normalizeSpaceName( tospace, 'world' );
  276. const inPoint = vec3( inNode );
  277. if ( from === to ) {
  278. return inPoint;
  279. }
  280. const point4 = vec4( inPoint, 1 );
  281. const matrix = from === 'object' && to === 'world' ? modelWorldMatrix : modelWorldMatrixInverse;
  282. const transformed4 = mul( matrix, point4 );
  283. return vec3( element( transformed4, 0 ), element( transformed4, 1 ), element( transformed4, 2 ) );
  284. };
  285. const mx_burn_channel = ( fg, bg, mixval = 1 ) => {
  286. const composed = add( mul( mixval, sub( 1, div( sub( 1, bg ), fg ) ) ), mul( sub( 1, mixval ), bg ) );
  287. return mul( composed, step( float( 1e-6 ), abs( fg ) ) );
  288. };
  289. const mx_dodge_channel = ( fg, bg, mixval = 1 ) => {
  290. const composed = add( mul( mixval, div( bg, sub( 1, fg ) ) ), mul( sub( 1, mixval ), bg ) );
  291. return mul( composed, step( float( 1e-6 ), abs( sub( 1, fg ) ) ) );
  292. };
  293. const isVec3Like = ( node ) =>
  294. node && ( node.nodeType === 'vec3' || node.nodeType === 'color' || node.nodeType === 'color3' );
  295. const isVec4Like = ( node ) => node && ( node.nodeType === 'vec4' || node.nodeType === 'color4' );
  296. const applyBlendByChannel = ( channelFunc, fg, bg, mixval = 1 ) => {
  297. if ( isVec4Like( fg ) || isVec4Like( bg ) ) {
  298. return vec4(
  299. channelFunc( element( fg, 0 ), element( bg, 0 ), mixval ),
  300. channelFunc( element( fg, 1 ), element( bg, 1 ), mixval ),
  301. channelFunc( element( fg, 2 ), element( bg, 2 ), mixval ),
  302. channelFunc( element( fg, 3 ), element( bg, 3 ), mixval ),
  303. );
  304. }
  305. if ( isVec3Like( fg ) || isVec3Like( bg ) ) {
  306. return vec3(
  307. channelFunc( element( fg, 0 ), element( bg, 0 ), mixval ),
  308. channelFunc( element( fg, 1 ), element( bg, 1 ), mixval ),
  309. channelFunc( element( fg, 2 ), element( bg, 2 ), mixval ),
  310. );
  311. }
  312. return channelFunc( fg, bg, mixval );
  313. };
  314. const mx_burn = ( fg, bg, mixval = 1 ) => applyBlendByChannel( mx_burn_channel, fg, bg, mixval );
  315. const mx_dodge = ( fg, bg, mixval = 1 ) => applyBlendByChannel( mx_dodge_channel, fg, bg, mixval );
  316. const mixColor4 = ( bg, fg, factor ) =>
  317. vec4(
  318. mix( element( bg, 0 ), element( fg, 0 ), factor ),
  319. mix( element( bg, 1 ), element( fg, 1 ), factor ),
  320. mix( element( bg, 2 ), element( fg, 2 ), factor ),
  321. mix( element( bg, 3 ), element( fg, 3 ), factor ),
  322. );
  323. const mxRampSegment = ( x, color1, color2, interval1, interval2, interpolation ) => {
  324. const linearClamped = clamp( x, interval1, interval2 );
  325. const rangeSize = sub( interval2, interval1 );
  326. const safeRange = max( rangeSize, float( 1e-6 ) );
  327. const linearRemap = div( sub( linearClamped, interval1 ), safeRange );
  328. const smoothVal = mx_smoothstep( x, interval1, interval2 );
  329. const interpolationDistanceToLinear = abs( sub( interpolation, float( 0 ) ) );
  330. const useLinear = sub( float( 1 ), step( float( 0.5 ), interpolationDistanceToLinear ) );
  331. const interpFactor = mix( smoothVal, linearRemap, useLinear );
  332. const mixedColor = mixColor4( color1, color2, interpFactor );
  333. const stepColor = mixColor4( color1, color2, step( interval2, x ) );
  334. const interpolationDistanceToStep = abs( sub( interpolation, float( 2 ) ) );
  335. const useStep = sub( float( 1 ), step( float( 0.5 ), interpolationDistanceToStep ) );
  336. return mixColor4( mixedColor, stepColor, useStep );
  337. };
  338. const mx_ramp_gradient = (
  339. x = 0,
  340. interval1 = 0,
  341. interval2 = 1,
  342. color1 = vec4( 0, 0, 0, 1 ),
  343. color2 = vec4( 1, 1, 1, 1 ),
  344. interpolation = 1,
  345. prevColor = vec4( 0, 0, 0, 1 ),
  346. intervalNum = 1,
  347. numIntervals = 2,
  348. ) => {
  349. const xFloat = float( x );
  350. const interval1Float = float( interval1 );
  351. const interval2Float = float( interval2 );
  352. const interpolationFloat = float( interpolation );
  353. const intervalNumFloat = float( intervalNum );
  354. const numIntervalsFloat = float( numIntervals );
  355. const interpolated = mxRampSegment( xFloat, color1, color2, interval1Float, interval2Float, interpolationFloat );
  356. const withinInterval = mixColor4( prevColor, interpolated, step( add( interval1Float, float( 1e-6 ) ), xFloat ) );
  357. return mixColor4( withinInterval, prevColor, step( numIntervalsFloat, intervalNumFloat ) );
  358. };
  359. const mx_ramp = ( texcoord = vec2( 0, 0 ), type = 0, interpolation = 1, numIntervals = 2, ...rest ) => {
  360. const rampTypeFloat = float( type );
  361. const interpolationFloat = float( interpolation );
  362. const numIntervalsFloat = float( numIntervals );
  363. const clamped = clamp( texcoord, vec2( 0, 0 ), vec2( 1, 1 ) );
  364. const s = element( clamped, 0 );
  365. const t = element( clamped, 1 );
  366. const centeredS = sub( s, float( 0.5 ) );
  367. const centeredT = sub( t, float( 0.5 ) );
  368. const radialDist = sqrt( add( mul( centeredS, centeredS ), mul( centeredT, centeredT ) ) );
  369. const radialVal = clamp( mul( radialDist, float( 2 ) ), float( 0 ), float( 1 ) );
  370. const circularAngle = add( div( mx_atan2( centeredT, centeredS ), float( Math.PI * 2 ) ), float( 0.5 ) );
  371. const boxVal = clamp( mul( max( abs( centeredS ), abs( centeredT ) ), float( 2 ) ), float( 0 ), float( 1 ) );
  372. const typeDistanceToRadial = abs( sub( rampTypeFloat, float( 1 ) ) );
  373. const typeDistanceToCircular = abs( sub( rampTypeFloat, float( 2 ) ) );
  374. const typeDistanceToBox = abs( sub( rampTypeFloat, float( 3 ) ) );
  375. const useRadial = sub( float( 1 ), step( float( 0.5 ), typeDistanceToRadial ) );
  376. const useCircular = sub( float( 1 ), step( float( 0.5 ), typeDistanceToCircular ) );
  377. const useBox = sub( float( 1 ), step( float( 0.5 ), typeDistanceToBox ) );
  378. const afterRadial = mix( s, radialVal, useRadial );
  379. const afterCircular = mix( afterRadial, circularAngle, useCircular );
  380. const rampX = mix( afterCircular, boxVal, useBox );
  381. const intervals = [];
  382. const colors = [];
  383. for ( let i = 0; i < 10; i += 1 ) {
  384. const intervalInput = rest[ i * 2 ];
  385. const colorInput = rest[ i * 2 + 1 ];
  386. intervals.push( intervalInput ?? float( i <= 1 ? i : 1 ) );
  387. colors.push( colorInput ?? vec4( i === 0 ? 0 : 1, i === 0 ? 0 : 1, i === 0 ? 0 : 1, 1 ) );
  388. }
  389. let result = colors[ 0 ];
  390. for ( let i = 0; i < 9; i += 1 ) {
  391. const iv1 = intervals[ i ];
  392. const iv2 = intervals[ i + 1 ];
  393. const c1 = colors[ i ];
  394. const c2 = colors[ i + 1 ];
  395. const intNum = float( i + 1 );
  396. const interpolated = mxRampSegment( rampX, c1, c2, iv1, iv2, interpolationFloat );
  397. const withinInterval = mixColor4( result, interpolated, step( add( iv1, float( 1e-6 ) ), rampX ) );
  398. result = mixColor4( withinInterval, result, step( numIntervalsFloat, intNum ) );
  399. }
  400. return result;
  401. };
  402. const defaultFloat = ( value ) => () => float( value );
  403. const defaultInt = ( value ) => () => int( value );
  404. const defaultBool = ( value ) => () => bool( value );
  405. const defaultColor = ( r, g, b ) => () => color( r, g, b );
  406. const defaultVec2 = ( x, y ) => () => vec2( x, y );
  407. const defaultVec3 = ( x, y, z ) => () => vec3( x, y, z );
  408. const defaultVec4 = ( x, y, z, w ) => () => vec4( x, y, z, w );
  409. const usesVec2Noise = ( nodeX ) => nodeX && nodeX.type === 'vector2';
  410. const usesVec3Noise = ( nodeX ) => nodeX && ( nodeX.type === 'vector3' || nodeX.type === 'color3' );
  411. const mx_noise_materialx = ( texcoord, amplitude, pivot, nodeX ) =>
  412. usesVec3Noise( nodeX ) ? mx_noise_vec3( texcoord, vec3( amplitude ), pivot ) : mx_noise_float( texcoord, amplitude, pivot );
  413. const mx_fractal_noise_materialx_2d = ( texcoord, octaves, lacunarity, diminish, amplitude, nodeX ) =>
  414. usesVec3Noise( nodeX ) ? mx_fractal_noise_vec3_materialx_2d( texcoord, octaves, lacunarity, diminish, amplitude ) : mx_fractal_noise_float_materialx_2d( texcoord, octaves, lacunarity, diminish, amplitude );
  415. const mx_fractal_noise_materialx_3d = ( position, octaves, lacunarity, diminish, amplitude, nodeX ) =>
  416. usesVec3Noise( nodeX ) ? mx_fractal_noise_vec3( position, octaves, lacunarity, diminish, vec3( amplitude ) ) : mx_fractal_noise_float( position, octaves, lacunarity, diminish, amplitude );
  417. const mx_cell_noise_materialx = ( position, nodeX ) =>
  418. usesVec3Noise( nodeX ) ? mx_cell_noise_vec3( position ) : mx_cell_noise_float( position );
  419. const mx_worley_noise_vec2_style = ( position, jitter, style ) => {
  420. const result = mx_worley_noise_vec3_style( position, jitter, style, 0 );
  421. return vec2( element( result, 0 ), element( result, 1 ) );
  422. };
  423. const mx_worley_noise_materialx_2d = ( texcoord, jitter, style, nodeX ) =>
  424. usesVec3Noise( nodeX ) ? mx_worley_noise_vec3_style( texcoord, jitter, style, 0 ) : usesVec2Noise( nodeX ) ? mx_worley_noise_vec2_style( texcoord, jitter, style ) : mx_worley_noise_float_2d( texcoord, jitter, style );
  425. const mx_worley_noise_materialx_3d = ( position, jitter, style, nodeX ) =>
  426. usesVec3Noise( nodeX ) ? mx_worley_noise_vec3_style( position, jitter, style, 0 ) : usesVec2Noise( nodeX ) ? mx_worley_noise_vec2_style( position, jitter, style ) : mx_worley_noise_float_3d( position, jitter, style );
  427. const mx_fractal_noise_float_materialx_2d = Fn( ( [ texcoordInput, octavesInput, lacunarityInput, diminishInput, amplitudeInput ] ) => {
  428. const texcoord = vec2( texcoordInput ).toVar();
  429. const octaves = int( octavesInput ).toVar();
  430. const lacunarity = float( lacunarityInput ).toVar();
  431. const diminish = float( diminishInput ).toVar();
  432. const amplitude = float( amplitudeInput ).toVar();
  433. const result = float( 0 ).toVar();
  434. const octaveAmplitude = float( 1 ).toVar();
  435. Loop( octaves, () => {
  436. result.addAssign( mul( octaveAmplitude, mx_noise_float( texcoord, float( 1 ), float( 0 ) ) ) );
  437. octaveAmplitude.mulAssign( diminish );
  438. texcoord.mulAssign( lacunarity );
  439. } );
  440. return mul( result, amplitude );
  441. } );
  442. const mx_fractal_noise_vec3_materialx_2d = Fn( ( [ texcoordInput, octavesInput, lacunarityInput, diminishInput, amplitudeInput ] ) => {
  443. const texcoord = vec2( texcoordInput ).toVar();
  444. const octaves = int( octavesInput ).toVar();
  445. const lacunarity = float( lacunarityInput ).toVar();
  446. const diminish = float( diminishInput ).toVar();
  447. const amplitude = vec3( amplitudeInput ).toVar();
  448. const result = vec3( 0 ).toVar();
  449. const octaveAmplitude = float( 1 ).toVar();
  450. Loop( octaves, () => {
  451. result.addAssign( mul( octaveAmplitude, mx_noise_vec3( texcoord, vec3( 1 ), float( 0 ) ) ) );
  452. octaveAmplitude.mulAssign( diminish );
  453. texcoord.mulAssign( lacunarity );
  454. } );
  455. return mul( result, amplitude );
  456. } );
  457. const MXElements = [
  458. createMXElement( 'add', add, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  459. createMXElement( 'subtract', sub, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  460. createMXElement( 'multiply', mul, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 1 ) } ),
  461. createMXElement( 'divide', div, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 1 ) } ),
  462. createMXElement( 'modulo', mx_modulo, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 1 ) } ),
  463. createMXElement( 'absval', abs, [ 'in' ], { in: defaultFloat( 0 ) } ),
  464. createMXElement( 'sign', sign, [ 'in' ], { in: defaultFloat( 0 ) } ),
  465. createMXElement( 'floor', floor, [ 'in' ], { in: defaultFloat( 0 ) } ),
  466. createMXElement( 'ceil', ceil, [ 'in' ], { in: defaultFloat( 0 ) } ),
  467. createMXElement( 'round', round, [ 'in' ], { in: defaultFloat( 0 ) } ),
  468. createMXElement( 'power', pow, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 1 ) } ),
  469. createMXElement( 'sin', sin, [ 'in' ], { in: defaultFloat( 0 ) } ),
  470. createMXElement( 'cos', cos, [ 'in' ], { in: defaultFloat( 0 ) } ),
  471. createMXElement( 'tan', tan, [ 'in' ], { in: defaultFloat( 0 ) } ),
  472. createMXElement( 'asin', asin, [ 'in' ], { in: defaultFloat( 0 ) } ),
  473. createMXElement( 'acos', acos, [ 'in' ], { in: defaultFloat( 0 ) } ),
  474. createMXElement( 'atan2', mx_atan2, [ 'iny', 'inx' ], { iny: defaultFloat( 0 ), inx: defaultFloat( 1 ) } ),
  475. createMXElement( 'sqrt', sqrt, [ 'in' ], { in: defaultFloat( 0 ) } ),
  476. createMXElement( 'ln', log, [ 'in' ], { in: defaultFloat( 1 ) } ),
  477. createMXElement( 'exp', exp, [ 'in' ], { in: defaultFloat( 0 ) } ),
  478. createMXElement( 'fract', fract, [ 'in' ], { in: defaultFloat( 0 ) } ),
  479. createMXElement( 'clamp', clamp, [ 'in', 'low', 'high' ], {
  480. in: defaultFloat( 0 ),
  481. low: defaultFloat( 0 ),
  482. high: defaultFloat( 1 ),
  483. } ),
  484. createMXElement( 'min', min, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  485. createMXElement( 'max', max, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  486. createMXElement( 'normalize', normalize, [ 'in' ], { in: defaultFloat( 0 ) } ),
  487. createMXElement( 'magnitude', length, [ 'in' ], { in: defaultFloat( 0 ) } ),
  488. createMXElement( 'length', length, [ 'in' ], { in: defaultFloat( 0 ) } ),
  489. createMXElement( 'dot', mx_dot, [ 'in' ], { in: defaultFloat( 0 ) } ),
  490. createMXElement( 'dotproduct', dot, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  491. createMXElement( 'viewdirection', mx_viewdirection, [ 'space' ], { space: () => 'world' } ),
  492. createMXElement( 'crossproduct', cross, [ 'in1', 'in2' ], { in1: defaultVec3( 0, 0, 0 ), in2: defaultVec3( 0, 0, 0 ) } ),
  493. createMXElement( 'distance', distance, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  494. createMXElement( 'invert', mx_invert, [ 'in', 'amount' ], { in: defaultFloat( 0 ), amount: defaultFloat( 1 ) } ),
  495. createMXElement( 'transformmatrix', mul, [ 'in', 'mat' ], { in: defaultFloat( 0 ) } ),
  496. createMXElement( 'transformnormal', mx_transformnormal, [ 'in', 'fromspace', 'tospace' ], {
  497. in: defaultVec3( 0, 0, 1 ),
  498. fromspace: () => 'world',
  499. tospace: () => 'world',
  500. } ),
  501. createMXElement( 'transformpoint', mx_transformpoint, [ 'in', 'fromspace', 'tospace' ], {
  502. in: defaultVec3( 0, 0, 0 ),
  503. fromspace: () => 'world',
  504. tospace: () => 'world',
  505. } ),
  506. createMXElement( 'transformvector', mx_transformvector, [ 'in', 'fromspace', 'tospace' ], {
  507. in: defaultVec3( 0, 0, 0 ),
  508. fromspace: () => 'world',
  509. tospace: () => 'world',
  510. } ),
  511. createMXElement( 'normalmap', mx_normalmap, [ 'in', 'scale', 'normal', 'tangent', 'bitangent' ], {
  512. in: defaultVec3( 0.5, 0.5, 1.0 ),
  513. scale: defaultFloat( 1 ),
  514. normal: () => normalWorld,
  515. tangent: () => tangentWorld,
  516. bitangent: () => bitangentWorld,
  517. } ),
  518. createMXElement( 'transpose', transpose, [ 'in' ] ),
  519. createMXElement( 'determinant', determinant, [ 'in' ] ),
  520. createMXElement( 'invertmatrix', inverse, [ 'in' ] ),
  521. createMXElement( 'creatematrix', mat3, [ 'in1', 'in2', 'in3' ], {
  522. in1: defaultVec3( 1, 0, 0 ),
  523. in2: defaultVec3( 0, 1, 0 ),
  524. in3: defaultVec3( 0, 0, 1 ),
  525. } ),
  526. createMXElement( 'remap', remap, [ 'in', 'inlow', 'inhigh', 'outlow', 'outhigh' ], {
  527. in: defaultFloat( 0 ),
  528. inlow: defaultFloat( 0 ),
  529. inhigh: defaultFloat( 1 ),
  530. outlow: defaultFloat( 0 ),
  531. outhigh: defaultFloat( 1 ),
  532. } ),
  533. createMXElement( 'range', mx_range, [ 'in', 'inlow', 'inhigh', 'outlow', 'outhigh', 'gamma' ], {
  534. in: defaultFloat( 0 ),
  535. inlow: defaultFloat( 0 ),
  536. inhigh: defaultFloat( 1 ),
  537. outlow: defaultFloat( 0 ),
  538. outhigh: defaultFloat( 1 ),
  539. gamma: defaultFloat( 1 ),
  540. } ),
  541. createMXElement( 'open_pbr_anisotropy', mx_open_pbr_anisotropy, [ 'roughness', 'anisotropy' ], {
  542. roughness: defaultFloat( 0 ),
  543. anisotropy: defaultFloat( 0 ),
  544. } ),
  545. createMXElement( 'smoothstep', mx_smoothstep, [ 'in', 'low', 'high' ], {
  546. in: defaultFloat( 0 ),
  547. low: defaultFloat( 0 ),
  548. high: defaultFloat( 1 ),
  549. } ),
  550. createMXElement( 'luminance', luminance, [ 'in', 'lumacoeffs' ], {
  551. in: defaultColor( 0, 0, 0 ),
  552. lumacoeffs: defaultColor( 0.2722287, 0.6740818, 0.0536895 ),
  553. } ),
  554. createMXElement( 'rgbtohsv', mx_rgbtohsv, [ 'in' ], { in: defaultColor( 0, 0, 0 ) } ),
  555. createMXElement( 'hsvtorgb', mx_hsvtorgb, [ 'in' ], { in: defaultColor( 0, 0, 0 ) } ),
  556. createMXElement( 'mix', mix, [ 'bg', 'fg', 'mix' ], { bg: defaultFloat( 0 ), fg: defaultFloat( 0 ), mix: defaultFloat( 0 ) } ),
  557. createMXElement( 'minus', mx_minus, [ 'fg', 'bg', 'mix' ], {
  558. fg: defaultFloat( 0 ),
  559. bg: defaultFloat( 0 ),
  560. mix: defaultFloat( 1 ),
  561. } ),
  562. createMXElement( 'difference', mx_difference, [ 'fg', 'bg', 'mix' ], {
  563. fg: defaultFloat( 0 ),
  564. bg: defaultFloat( 0 ),
  565. mix: defaultFloat( 1 ),
  566. } ),
  567. createMXElement( 'screen', mx_screen, [ 'fg', 'bg', 'mix' ], {
  568. fg: defaultFloat( 0 ),
  569. bg: defaultFloat( 0 ),
  570. mix: defaultFloat( 1 ),
  571. } ),
  572. createMXElement( 'overlay', mx_overlay, [ 'fg', 'bg', 'mix' ], {
  573. fg: defaultFloat( 0 ),
  574. bg: defaultFloat( 0 ),
  575. mix: defaultFloat( 1 ),
  576. } ),
  577. createMXElement( 'burn', mx_burn, [ 'fg', 'bg', 'mix' ], {
  578. fg: defaultFloat( 0 ),
  579. bg: defaultFloat( 0 ),
  580. mix: defaultFloat( 1 ),
  581. } ),
  582. createMXElement( 'dodge', mx_dodge, [ 'fg', 'bg', 'mix' ], {
  583. fg: defaultFloat( 0 ),
  584. bg: defaultFloat( 0 ),
  585. mix: defaultFloat( 1 ),
  586. } ),
  587. createMXElement(
  588. 'colorcorrect',
  589. mx_colorcorrect,
  590. [ 'in', 'hue', 'saturation', 'gamma', 'lift', 'gain', 'contrast', 'contrastpivot', 'exposure' ],
  591. {
  592. in: defaultColor( 1, 1, 1 ),
  593. hue: defaultFloat( 0 ),
  594. saturation: defaultFloat( 1 ),
  595. gamma: defaultFloat( 1 ),
  596. lift: defaultFloat( 0 ),
  597. gain: defaultFloat( 1 ),
  598. contrast: defaultFloat( 1 ),
  599. contrastpivot: defaultFloat( 0.5 ),
  600. exposure: defaultFloat( 0 ),
  601. },
  602. ),
  603. createMXElement( 'unpremult', mx_unpremult, [ 'in' ], { in: defaultVec4( 0, 0, 0, 1 ) } ),
  604. createMXElement( 'combine2', vec2, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 0 ) } ),
  605. createMXElement( 'combine3', vec3, [ 'in1', 'in2', 'in3' ], {
  606. in1: defaultFloat( 0 ),
  607. in2: defaultFloat( 0 ),
  608. in3: defaultFloat( 0 ),
  609. } ),
  610. createMXElement( 'combine4', vec4, [ 'in1', 'in2', 'in3', 'in4' ], {
  611. in1: defaultFloat( 0 ),
  612. in2: defaultFloat( 0 ),
  613. in3: defaultFloat( 0 ),
  614. in4: defaultFloat( 0 ),
  615. } ),
  616. createMXElement( 'ramplr', mx_ramplr, [ 'valuel', 'valuer', 'texcoord' ], {
  617. valuel: defaultFloat( 0 ),
  618. valuer: defaultFloat( 0 ),
  619. } ),
  620. createMXElement( 'ramptb', mx_ramptb, [ 'valueb', 'valuet', 'texcoord' ], {
  621. valueb: defaultFloat( 0 ),
  622. valuet: defaultFloat( 0 ),
  623. } ),
  624. createMXElement( 'ramp4', mx_ramp4, [ 'valuetl', 'valuetr', 'valuebl', 'valuebr', 'texcoord' ], {
  625. valuetl: defaultColor( 0, 0, 0 ),
  626. valuetr: defaultColor( 0, 0, 0 ),
  627. valuebl: defaultColor( 0, 0, 0 ),
  628. valuebr: defaultColor( 0, 0, 0 ),
  629. texcoord: defaultVec2( 0, 0 ),
  630. } ),
  631. createMXElement(
  632. 'ramp_gradient',
  633. mx_ramp_gradient,
  634. [ 'x', 'interval1', 'interval2', 'color1', 'color2', 'interpolation', 'prev_color', 'interval_num', 'num_intervals' ],
  635. {
  636. x: defaultFloat( 0 ),
  637. interval1: defaultFloat( 0 ),
  638. interval2: defaultFloat( 1 ),
  639. color1: defaultVec4( 0, 0, 0, 1 ),
  640. color2: defaultVec4( 1, 1, 1, 1 ),
  641. interpolation: defaultFloat( 1 ),
  642. prev_color: defaultVec4( 0, 0, 0, 1 ),
  643. interval_num: defaultFloat( 1 ),
  644. num_intervals: defaultFloat( 2 ),
  645. },
  646. ),
  647. createMXElement(
  648. 'ramp',
  649. mx_ramp,
  650. [
  651. 'texcoord',
  652. 'type',
  653. 'interpolation',
  654. 'num_intervals',
  655. 'interval1',
  656. 'color1',
  657. 'interval2',
  658. 'color2',
  659. 'interval3',
  660. 'color3',
  661. 'interval4',
  662. 'color4',
  663. 'interval5',
  664. 'color5',
  665. 'interval6',
  666. 'color6',
  667. 'interval7',
  668. 'color7',
  669. 'interval8',
  670. 'color8',
  671. 'interval9',
  672. 'color9',
  673. 'interval10',
  674. 'color10',
  675. ],
  676. {
  677. texcoord: defaultVec2( 0, 0 ),
  678. type: defaultFloat( 0 ),
  679. interpolation: defaultFloat( 1 ),
  680. num_intervals: defaultFloat( 2 ),
  681. interval1: defaultFloat( 0 ),
  682. color1: defaultVec4( 0, 0, 0, 1 ),
  683. interval2: defaultFloat( 1 ),
  684. color2: defaultVec4( 1, 1, 1, 1 ),
  685. interval3: defaultFloat( 1 ),
  686. color3: defaultVec4( 1, 1, 1, 1 ),
  687. interval4: defaultFloat( 1 ),
  688. color4: defaultVec4( 1, 1, 1, 1 ),
  689. interval5: defaultFloat( 1 ),
  690. color5: defaultVec4( 1, 1, 1, 1 ),
  691. interval6: defaultFloat( 1 ),
  692. color6: defaultVec4( 1, 1, 1, 1 ),
  693. interval7: defaultFloat( 1 ),
  694. color7: defaultVec4( 1, 1, 1, 1 ),
  695. interval8: defaultFloat( 1 ),
  696. color8: defaultVec4( 1, 1, 1, 1 ),
  697. interval9: defaultFloat( 1 ),
  698. color9: defaultVec4( 1, 1, 1, 1 ),
  699. interval10: defaultFloat( 1 ),
  700. color10: defaultVec4( 1, 1, 1, 1 ),
  701. },
  702. ),
  703. createMXElement( 'splitlr', mx_splitlr, [ 'valuel', 'valuer', 'center', 'texcoord' ], {
  704. valuel: defaultFloat( 0 ),
  705. valuer: defaultFloat( 0 ),
  706. center: defaultFloat( 0.5 ),
  707. } ),
  708. createMXElement( 'splittb', mx_splittb, [ 'valueb', 'valuet', 'center', 'texcoord' ], {
  709. valueb: defaultFloat( 0 ),
  710. valuet: defaultFloat( 0 ),
  711. center: defaultFloat( 0.5 ),
  712. } ),
  713. createMXElement( 'noise2d', mx_noise_materialx, [ 'texcoord', 'amplitude', 'pivot' ], {
  714. texcoord: defaultVec2( 0, 0 ),
  715. amplitude: defaultFloat( 1 ),
  716. pivot: defaultFloat( 0 ),
  717. }, true ),
  718. createMXElement( 'noise3d', mx_noise_materialx, [ 'position', 'amplitude', 'pivot' ], {
  719. position: () => positionLocal,
  720. amplitude: defaultFloat( 1 ),
  721. pivot: defaultFloat( 0 ),
  722. }, true ),
  723. createMXElement( 'fractal2d', mx_fractal_noise_materialx_2d, [ 'texcoord', 'octaves', 'lacunarity', 'diminish', 'amplitude' ], {
  724. texcoord: defaultVec2( 0, 0 ),
  725. octaves: defaultInt( 3 ),
  726. lacunarity: defaultFloat( 2.0 ),
  727. diminish: defaultFloat( 0.5 ),
  728. amplitude: defaultFloat( 1.0 ),
  729. }, true ),
  730. createMXElement( 'fractal3d', mx_fractal_noise_materialx_3d, [ 'position', 'octaves', 'lacunarity', 'diminish', 'amplitude' ], {
  731. position: () => positionLocal,
  732. octaves: defaultInt( 3 ),
  733. lacunarity: defaultFloat( 2.0 ),
  734. diminish: defaultFloat( 0.5 ),
  735. amplitude: defaultFloat( 1.0 ),
  736. }, true ),
  737. createMXElement( 'cellnoise2d', mx_cell_noise_materialx, [ 'texcoord' ], { texcoord: defaultVec2( 0, 0 ) }, true ),
  738. createMXElement( 'cellnoise3d', mx_cell_noise_materialx, [ 'position' ], { position: () => positionLocal }, true ),
  739. createMXElement( 'worleynoise2d', mx_worley_noise_materialx_2d, [ 'texcoord', 'jitter', 'style' ], {
  740. texcoord: defaultVec2( 0, 0 ),
  741. jitter: defaultFloat( 1 ),
  742. style: defaultInt( 0 ),
  743. }, true ),
  744. createMXElement( 'worleynoise3d', mx_worley_noise_materialx_3d, [ 'position', 'jitter', 'style' ], {
  745. position: () => positionLocal,
  746. jitter: defaultFloat( 1 ),
  747. style: defaultInt( 0 ),
  748. }, true ),
  749. createMXElement(
  750. 'unifiednoise2d',
  751. mx_unifiednoise2d,
  752. [
  753. 'type',
  754. 'texcoord',
  755. 'freq',
  756. 'offset',
  757. 'jitter',
  758. 'outmin',
  759. 'outmax',
  760. 'clampoutput',
  761. 'octaves',
  762. 'lacunarity',
  763. 'diminish',
  764. 'style',
  765. ],
  766. {
  767. type: defaultInt( 0 ),
  768. texcoord: defaultVec2( 0, 0 ),
  769. freq: defaultVec2( 1, 1 ),
  770. offset: defaultVec2( 0, 0 ),
  771. jitter: defaultFloat( 1 ),
  772. outmin: defaultFloat( 0 ),
  773. outmax: defaultFloat( 1 ),
  774. clampoutput: defaultBool( true ),
  775. octaves: defaultInt( 3 ),
  776. lacunarity: defaultFloat( 2 ),
  777. diminish: defaultFloat( 0.5 ),
  778. style: defaultInt( 0 ),
  779. },
  780. ),
  781. createMXElement(
  782. 'unifiednoise3d',
  783. mx_unifiednoise3d,
  784. [
  785. 'type',
  786. 'position',
  787. 'freq',
  788. 'offset',
  789. 'jitter',
  790. 'outmin',
  791. 'outmax',
  792. 'clampoutput',
  793. 'octaves',
  794. 'lacunarity',
  795. 'diminish',
  796. 'style',
  797. ],
  798. {
  799. type: defaultInt( 0 ),
  800. position: () => positionLocal,
  801. freq: defaultVec3( 1, 1, 1 ),
  802. offset: defaultVec3( 0, 0, 0 ),
  803. jitter: defaultFloat( 1 ),
  804. outmin: defaultFloat( 0 ),
  805. outmax: defaultFloat( 1 ),
  806. clampoutput: defaultBool( true ),
  807. octaves: defaultInt( 3 ),
  808. lacunarity: defaultFloat( 2 ),
  809. diminish: defaultFloat( 0.5 ),
  810. style: defaultInt( 0 ),
  811. },
  812. ),
  813. createMXElement( 'place2d', mx_place2d, [ 'texcoord', 'pivot', 'scale', 'rotate', 'offset', 'operationorder' ], {
  814. texcoord: defaultVec2( 0, 0 ),
  815. pivot: defaultVec2( 0, 0 ),
  816. scale: defaultVec2( 1, 1 ),
  817. rotate: defaultFloat( 0 ),
  818. offset: defaultVec2( 0, 0 ),
  819. operationorder: defaultInt( 0 ),
  820. } ),
  821. createMXElement( 'safepower', mx_safepower, [ 'in1', 'in2' ], { in1: defaultFloat( 0 ), in2: defaultFloat( 1 ) } ),
  822. createMXElement( 'contrast', mx_contrast, [ 'in', 'amount', 'pivot' ], {
  823. in: defaultFloat( 0 ),
  824. amount: defaultFloat( 1 ),
  825. pivot: defaultFloat( 0.5 ),
  826. } ),
  827. createMXElement( 'saturate', mx_saturation, [ 'in', 'amount' ], { in: defaultColor( 0, 0, 0 ), amount: defaultFloat( 1 ) } ),
  828. createMXElement( 'extract', element, [ 'in', 'index' ], { in: defaultFloat( 0 ), index: defaultInt( 0 ) } ),
  829. createMXElement( 'separate2', element, [ 'in' ], { in: defaultVec2( 0, 0 ) } ),
  830. createMXElement( 'separate3', element, [ 'in' ], { in: defaultVec3( 0, 0, 0 ) } ),
  831. createMXElement( 'separate4', element, [ 'in' ], { in: defaultVec4( 0, 0, 0, 0 ) } ),
  832. createMXElement( 'reflect', reflect, [ 'in', 'normal' ], { in: defaultVec3( 1, 0, 0 ) } ),
  833. createMXElement( 'refract', refract, [ 'in', 'normal', 'ior' ], { in: defaultVec3( 1, 0, 0 ), ior: defaultFloat( 1 ) } ),
  834. createMXElement( 'time', mx_timer ),
  835. createMXElement( 'frame', mx_frame ),
  836. createMXElement( 'ifgreater', mx_ifgreater, [ 'value1', 'value2', 'in1', 'in2' ], {
  837. value1: defaultFloat( 1 ),
  838. value2: defaultFloat( 0 ),
  839. in1: defaultFloat( 0 ),
  840. in2: defaultFloat( 0 ),
  841. } ),
  842. createMXElement( 'ifgreatereq', mx_ifgreatereq, [ 'value1', 'value2', 'in1', 'in2' ], {
  843. value1: defaultFloat( 1 ),
  844. value2: defaultFloat( 0 ),
  845. in1: defaultFloat( 0 ),
  846. in2: defaultFloat( 0 ),
  847. } ),
  848. createMXElement( 'ifequal', mx_ifequal, [ 'value1', 'value2', 'in1', 'in2' ], {
  849. value1: defaultFloat( 0 ),
  850. value2: defaultFloat( 0 ),
  851. in1: defaultFloat( 0 ),
  852. in2: defaultFloat( 0 ),
  853. } ),
  854. createMXElement( 'rotate2d', mx_rotate2d, [ 'in', 'amount' ], { in: defaultVec2( 0, 0 ), amount: defaultFloat( 0 ) } ),
  855. createMXElement( 'rotate3d', mx_rotate3d, [ 'in', 'amount', 'axis' ], {
  856. in: defaultVec3( 0, 0, 0 ),
  857. amount: defaultFloat( 0 ),
  858. axis: defaultVec3( 0, 1, 0 ),
  859. } ),
  860. createMXElement( 'heighttonormal', mx_heighttonormal, [ 'in', 'scale', 'texcoord' ], {
  861. in: defaultFloat( 0 ),
  862. scale: defaultFloat( 1 ),
  863. } ),
  864. createMXElement( 'and', mx_and, [ 'in1', 'in2' ], { in1: defaultBool( false ), in2: defaultBool( false ) } ),
  865. createMXElement( 'or', mx_or, [ 'in1', 'in2' ], { in1: defaultBool( false ), in2: defaultBool( false ) } ),
  866. createMXElement( 'xor', mx_xor, [ 'in1', 'in2' ], { in1: defaultBool( false ), in2: defaultBool( false ) } ),
  867. createMXElement( 'not', mx_not, [ 'in' ], { in: defaultBool( false ) } ),
  868. createMXElement( 'checkerboard', mx_checkerboard, [ 'color1', 'color2', 'uvtiling', 'uvoffset', 'texcoord' ], {
  869. color1: defaultColor( 1, 1, 1 ),
  870. color2: defaultColor( 0, 0, 0 ),
  871. uvtiling: defaultVec2( 8, 8 ),
  872. uvoffset: defaultVec2( 0, 0 ),
  873. texcoord: defaultVec2( 0, 0 ),
  874. } ),
  875. createMXElement( 'circle', mx_circle, [ 'texcoord', 'center', 'radius' ], {
  876. center: defaultVec2( 0, 0 ),
  877. radius: defaultFloat( 0.5 ),
  878. } ),
  879. createMXElement( 'bump', mx_bump, [ 'height', 'scale', 'normal', 'tangent', 'bitangent' ], {
  880. height: defaultFloat( 0 ),
  881. scale: defaultFloat( 1 ),
  882. normal: () => normalWorld,
  883. tangent: () => tangentWorld,
  884. bitangent: () => bitangentWorld,
  885. } ),
  886. createMXElement( 'blackbody', mx_blackbody, [ 'temperature' ], { temperature: defaultFloat( 5000 ) } ),
  887. ];
  888. const MtlXLibrary = Object.fromEntries( MXElements.map( ( entry ) => [ entry.name, entry ] ) );
  889. export { MtlXLibrary };
粤ICP备19079148号