| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <title>three.js webgpu - materialx noise</title>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
- <meta property="og:title" content="three.js webgpu - materialx noise">
- <meta property="og:type" content="website">
- <meta property="og:url" content="https://threejs.org/examples/webgpu_materialx_noise.html">
- <meta property="og:image" content="https://threejs.org/examples/screenshots/webgpu_materialx_noise.jpg">
- <link type="text/css" rel="stylesheet" href="example.css">
- </head>
- <body>
- <div id="info">
- <a href="https://threejs.org/" target="_blank" rel="noopener" class="logo-link"></a>
- <div class="title-wrapper">
- <a href="https://threejs.org/" target="_blank" rel="noopener">three.js</a><span>MaterialX Noise</span>
- </div>
- <small>MaterialX noise functions.</small>
- </div>
- <script type="importmap">
- {
- "imports": {
- "three": "../build/three.webgpu.js",
- "three/webgpu": "../build/three.webgpu.js",
- "three/tsl": "../build/three.tsl.js",
- "three/addons/": "./jsm/"
- }
- }
- </script>
- <script type="module">
- import * as THREE from 'three/webgpu';
- import {
- Fn, add, dot, element, float, floor, int, mix, mul, normalWorld, sub, time, uv, vec2, vec3,
- mx_cell_noise_float,
- mx_fractal_noise_vec3,
- mx_modulo,
- mx_noise_vec3,
- mx_unifiednoise2d,
- mx_unifiednoise3d,
- mx_worley_noise_float_2d,
- mx_worley_noise_float_3d
- } from 'three/tsl';
- import { Inspector } from 'three/addons/inspector/Inspector.js';
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
- import { HDRCubeTextureLoader } from 'three/addons/loaders/HDRCubeTextureLoader.js';
- import { FontLoader } from 'three/addons/loaders/FontLoader.js';
- import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
- import { mxHextileComputeBlendWeights, mxHextileCoord } from 'three/addons/loaders/materialx/MaterialXHextile.js';
- let container;
- let camera, scene, renderer;
- let particleLight;
- let group;
- const spheres = [];
- init();
- async function init() {
- container = document.createElement( 'div' );
- document.body.appendChild( container );
- camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 1000 );
- camera.position.z = 190;
- scene = new THREE.Scene();
- group = new THREE.Group();
- scene.add( group );
- const [ hdrTexture, font ] = await Promise.all( [
- new HDRCubeTextureLoader()
- .setPath( 'textures/cube/pisaHDR/' )
- .loadAsync( [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ] ),
- new FontLoader().loadAsync( 'fonts/helvetiker_regular.typeface.json' )
- ] );
- const geometry = new THREE.SphereGeometry( 5, 64, 32 );
- const labelMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff } );
- const position2D = uv( 0 ).mul( 12 ).add( vec2( time.mul( .35 ), time.mul( .19 ) ) );
- const position3D = normalWorld.mul( 4 ).add( vec3( time.mul( .35 ), time.mul( .19 ), time.mul( .27 ) ) );
- const fractal2D = vec3( position2D.x, position2D.y, 0 ).mul( .35 );
- const fractal3D = position3D.mul( .35 );
- const unifiedOffset2D = vec2( time.mul( .35 ), time.mul( .19 ) );
- const unifiedOffset3D = vec3( time.mul( .35 ), time.mul( .19 ), time.mul( .27 ) );
- const unifiedNoise3D = ( noiseType, position, freq, offset, jitter = 1, outmin = 0, outmax = 1, clampoutput = false, octaves = 1, lacunarity = 2, diminish = .5, style = 0 ) => Fn( () => mx_unifiednoise3d( noiseType, position, freq, offset, jitter, outmin, outmax, clampoutput, octaves, lacunarity, diminish, style ) )();
- const textileTexcoord = ( speedX, speedY ) => uv( 0 ).mul( 3 ).add( vec2( time.mul( speedX ), time.mul( speedY ) ) );
- const checkerboard = ( color1, color2, uvtiling, uvoffset, texcoord ) => {
- const tiledUv = sub( mul( texcoord, uvtiling ), uvoffset );
- const checkerMix = mx_modulo( dot( floor( tiledUv ), vec2( 1, 1 ) ), float( 2 ) );
- return mix( color2, color1, checkerMix );
- };
- const hextiledCheckerboard = ( texcoord, {
- color1 = vec3( 1, 1, 1 ),
- color2 = vec3( 0, 0, 0 ),
- uvtiling = vec2( 4, 4 ),
- uvoffset = vec2( 0, 0 ),
- tiling = vec2( 1, 1 ),
- rotation = 0,
- rotationrange = vec2( 0, 360 ),
- scale = 0,
- scalerange = vec2( .5, 2 ),
- offset = 0,
- offsetrange = vec2( 0, 1 ),
- falloff = .5,
- falloffcontrast = .5,
- lumacoeffs = vec3( 0.2722287, 0.6740818, 0.0536895 )
- } = {} ) => {
- const tileData = mxHextileCoord( mul( texcoord, tiling ), rotation, rotationrange, scale, scalerange, offset, offsetrange );
- const c0 = checkerboard( color1, color2, uvtiling, uvoffset, tileData.coords[ 0 ] );
- const c1 = checkerboard( color1, color2, uvtiling, uvoffset, tileData.coords[ 1 ] );
- const c2 = checkerboard( color1, color2, uvtiling, uvoffset, tileData.coords[ 2 ] );
- const luminanceWeights = mix(
- vec3( 1, 1, 1 ),
- vec3( dot( c0, lumacoeffs ), dot( c1, lumacoeffs ), dot( c2, lumacoeffs ) ),
- vec3( falloffcontrast, falloffcontrast, falloffcontrast )
- );
- const blendWeights = mxHextileComputeBlendWeights( luminanceWeights, tileData.weights, falloff );
- return add( add( mul( element( blendWeights, 0 ), c0 ), mul( element( blendWeights, 1 ), c1 ) ), mul( element( blendWeights, 2 ), c2 ) );
- };
- const noiseExamples = [
- { label: [ 'Noise', '2D' ], createNode: () => mx_noise_vec3( position2D ) },
- { label: [ 'Noise', '3D' ], createNode: () => mx_noise_vec3( position3D ) },
- { label: [ 'Cellnoise', '2D' ], createNode: () => mx_cell_noise_float( position2D ) },
- { label: [ 'Cellnoise', '3D' ], createNode: () => mx_cell_noise_float( position3D ) },
- { label: [ 'Worley', '2D style 0' ], createNode: () => mx_worley_noise_float_2d( position2D, 1, 0 ) },
- { label: [ 'Worley', '3D style 0' ], createNode: () => mx_worley_noise_float_3d( position3D, 1, 0 ) },
- { label: [ 'Worley', '2D style 1' ], createNode: () => mx_worley_noise_float_2d( position2D, 1, 1 ) },
- { label: [ 'Worley', '3D style 1' ], createNode: () => mx_worley_noise_float_3d( position3D, 1, 1 ) },
- { label: [ 'Fractal', '2D' ], createNode: () => mx_fractal_noise_vec3( fractal2D ) },
- { label: [ 'Fractal', '3D' ], createNode: () => mx_fractal_noise_vec3( fractal3D ) },
- { label: [ 'Unified Perlin', '2D' ], createNode: () => mx_unifiednoise2d( int( 0 ), position2D, vec2( 1, 1 ), unifiedOffset2D ) },
- { label: [ 'Unified Perlin', '3D' ], createNode: () => unifiedNoise3D( int( 0 ), position3D, vec3( 1, 1, 1 ), unifiedOffset3D ) },
- { label: [ 'Unified Cell', '2D' ], createNode: () => mx_unifiednoise2d( int( 1 ), position2D, vec2( 1, 1 ), unifiedOffset2D ) },
- { label: [ 'Unified Cell', '3D' ], createNode: () => unifiedNoise3D( int( 1 ), position3D, vec3( 1, 1, 1 ), unifiedOffset3D ) },
- { label: [ 'Unified Worley', '2D style 0' ], createNode: () => mx_unifiednoise2d( int( 2 ), position2D, vec2( 1, 1 ), unifiedOffset2D, 1, 0, 1, false, 1, 2, .5, 0 ) },
- { label: [ 'Unified Worley', '3D style 0' ], createNode: () => unifiedNoise3D( int( 2 ), position3D, vec3( 1, 1, 1 ), unifiedOffset3D, 1, 0, 1, false, 1, 2, .5, 0 ) },
- { label: [ 'Unified Worley', '2D style 1' ], createNode: () => mx_unifiednoise2d( int( 2 ), position2D, vec2( 1, 1 ), unifiedOffset2D, 1, 0, 1, false, 1, 2, .5, 1 ) },
- { label: [ 'Unified Worley', '3D style 1' ], createNode: () => unifiedNoise3D( int( 2 ), position3D, vec3( 1, 1, 1 ), unifiedOffset3D, 1, 0, 1, false, 1, 2, .5, 1 ) },
- { label: [ 'Unified Fractal', '2D' ], createNode: () => mx_unifiednoise2d( int( 3 ), position2D, vec2( 1, 1 ), unifiedOffset2D, 1, 0, 1, false, 3 ) },
- { label: [ 'Unified Fractal', '3D' ], createNode: () => unifiedNoise3D( int( 3 ), position3D, vec3( 1, 1, 1 ), unifiedOffset3D, 1, 0, 1, false, 3 ) },
- {
- label: [ 'Hex Tiled', 'checkerboard' ],
- createNode: () => hextiledCheckerboard( textileTexcoord( .08, .04 ), {
- color1: vec3( 1, 1, 1 ),
- color2: vec3( 0, 0, 0 ),
- uvtiling: vec2( 8, 8 ),
- tiling: vec2( 2.2, 2.2 ),
- rotation: .25,
- scale: .1,
- offset: .2,
- falloff: .35,
- falloffcontrast: .25
- } )
- }
- ];
- createNoiseGrid( noiseExamples, geometry, font, labelMaterial );
- scene.background = hdrTexture;
- scene.environment = hdrTexture;
- // LIGHTS
- particleLight = new THREE.Mesh(
- new THREE.SphereGeometry( 0.4, 8, 8 ),
- new THREE.MeshBasicMaterial( { color: 0xffffff } )
- );
- scene.add( particleLight );
- particleLight.add( new THREE.PointLight( 0xffffff, 1000 ) );
- renderer = new THREE.WebGPURenderer( { antialias: true } );
- renderer.setAnimationLoop( render );
- renderer.setPixelRatio( window.devicePixelRatio );
- renderer.setSize( window.innerWidth, window.innerHeight );
- renderer.inspector = new Inspector();
- container.appendChild( renderer.domElement );
- //
- renderer.toneMapping = THREE.ACESFilmicToneMapping;
- renderer.toneMappingExposure = 1.25;
- // EVENTS
- new OrbitControls( camera, renderer.domElement );
- window.addEventListener( 'resize', onWindowResize );
- }
- //
- function onWindowResize() {
- const width = window.innerWidth;
- const height = window.innerHeight;
- camera.aspect = width / height;
- camera.updateProjectionMatrix();
- renderer.setSize( width, height );
- }
- //
- function render() {
- const timer = Date.now() * 0.00025;
- particleLight.position.x = Math.sin( timer * 7 ) * 30;
- particleLight.position.y = Math.cos( timer * 5 ) * 40;
- particleLight.position.z = Math.cos( timer * 3 ) * 30;
- for ( let i = 0; i < spheres.length; i ++ ) {
- const child = spheres[ i ];
- child.rotation.y += 0.005;
- }
- renderer.render( scene, camera );
- }
- function createNoiseGrid( noiseExamples, geometry, font, labelMaterial ) {
- const columns = 7;
- const spacingX = 15.5;
- const spacingY = 18;
- const rowOffset = ( Math.ceil( noiseExamples.length / columns ) - 1 ) * spacingY * .5;
- const columnOffset = ( columns - 1 ) * spacingX * .5;
- const errorMaterial = new THREE.MeshBasicMaterial( { color: 0xff3333 } );
- for ( let i = 0; i < noiseExamples.length; i ++ ) {
- const example = noiseExamples[ i ];
- const column = i % columns;
- const row = Math.floor( i / columns );
- const x = column * spacingX - columnOffset;
- const y = rowOffset - row * spacingY;
- const labelLines = example.label.slice();
- const material = new THREE.MeshPhysicalNodeMaterial();
- try {
- material.colorNode = example.createNode();
- } catch ( error ) {
- console.error( `Failed to create MaterialX noise sample: ${ example.label.join( ' ' ) }`, error );
- labelLines.push( 'Failed' );
- }
- const mesh = new THREE.Mesh( geometry, material.colorNode ? material : errorMaterial );
- mesh.position.set( x, y, 0 );
- group.add( mesh );
- spheres.push( mesh );
- const label = createLabel( labelLines, font, labelMaterial );
- label.position.set( x, y - 7.5, 0 );
- group.add( label );
- }
- }
- function createLabel( lines, font, material ) {
- const label = new THREE.Group();
- const lineHeight = 1.55;
- const startY = ( lines.length - 1 ) * lineHeight * .5;
- for ( let i = 0; i < lines.length; i ++ ) {
- const textGeometry = new TextGeometry( lines[ i ], {
- font: font,
- size: 1.15,
- depth: 0.02,
- curveSegments: 2
- } );
- textGeometry.computeBoundingBox();
- const boundingBox = textGeometry.boundingBox;
- const offsetX = - 0.5 * ( boundingBox.max.x - boundingBox.min.x );
- const offsetY = - 0.5 * ( boundingBox.max.y - boundingBox.min.y );
- textGeometry.translate( offsetX, offsetY, 0 );
- const textMesh = new THREE.Mesh( textGeometry, material );
- textMesh.position.y = startY - i * lineHeight;
- label.add( textMesh );
- }
- return label;
- }
- </script>
- </body>
- </html>
|