diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89616bbd870762..6222b0c6ccea64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: contents: read steps: - name: Git checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: @@ -54,7 +54,7 @@ jobs: CI: ${{ matrix.CI }} steps: - name: Git checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: diff --git a/.github/workflows/codeql-code-scanning.yml b/.github/workflows/codeql-code-scanning.yml index 9614b9c71d0882..4fec234684b8fa 100644 --- a/.github/workflows/codeql-code-scanning.yml +++ b/.github/workflows/codeql-code-scanning.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/read-size.yml b/.github/workflows/read-size.yml index 807026a7b25fa1..4962807a83857a 100644 --- a/.github/workflows/read-size.yml +++ b/.github/workflows/read-size.yml @@ -22,7 +22,7 @@ jobs: contents: read steps: - name: Git checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: diff --git a/.github/workflows/report-size.yml b/.github/workflows/report-size.yml index ad38c3f904ba0e..73aea72458ae95 100644 --- a/.github/workflows/report-size.yml +++ b/.github/workflows/report-size.yml @@ -58,7 +58,7 @@ jobs: # This runs on the base branch of the PR, meaning "dev" - name: Git checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 - name: Install Node uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: diff --git a/examples/files.json b/examples/files.json index 9f99a3c4f776f3..318161ba0a3e25 100644 --- a/examples/files.json +++ b/examples/files.json @@ -505,6 +505,7 @@ "webgpu_video_panorama", "webgpu_volume_caustics", "webgpu_volume_cloud", + "webgpu_volume_fire", "webgpu_volume_lighting", "webgpu_volume_lighting_rectarea", "webgpu_volume_lighting_traa", @@ -582,6 +583,7 @@ "misc_exporter_draco", "misc_exporter_gcode", "misc_exporter_gltf", + "misc_exporter_gltf_normals", "misc_exporter_obj", "misc_exporter_ply", "misc_exporter_stl", diff --git a/examples/jsm/exporters/GLTFExporter.js b/examples/jsm/exporters/GLTFExporter.js index d98bbe94a001b7..ab3bb954be245a 100644 --- a/examples/jsm/exporters/GLTFExporter.js +++ b/examples/jsm/exporters/GLTFExporter.js @@ -1046,6 +1046,57 @@ class GLTFWriter { } + /** + * Builds a copy of the given normal map with the red and/or green channels + * inverted (`color = 255 - color`). This is used to bake the sign of + * `material.normalScale` and the tangent-space convention into the texture, + * since glTF only supports OpenGL-style normal maps with a univariate, + * positive scale. + * + * @param {THREE.Texture} normalMap The source normal map. + * @param {boolean} flipX Whether to invert the red channel (normal X). + * @param {boolean} flipY Whether to invert the green channel (normal Y). + * @return {Promise} The derived normal map texture. + */ + async buildNormalMapTextureAsync( normalMap, flipX, flipY ) { + + if ( normalMap instanceof CompressedTexture ) { + + normalMap = await this.decompressTextureAsync( normalMap ); + + } + + const image = normalMap.image; + + const canvas = getCanvas(); + canvas.width = image.width; + canvas.height = image.height; + + const context = canvas.getContext( '2d', { + willReadFrequently: true, + } ); + + context.drawImage( image, 0, 0, canvas.width, canvas.height ); + + const imageData = context.getImageData( 0, 0, canvas.width, canvas.height ); + const data = imageData.data; + + for ( let i = 0; i < data.length; i += 4 ) { + + if ( flipX ) data[ i + 0 ] = 255 - data[ i + 0 ]; + if ( flipY ) data[ i + 1 ] = 255 - data[ i + 1 ]; + + } + + context.putImageData( imageData, 0, 0 ); + + const texture = normalMap.clone(); + texture.source = new Source( canvas ); + + return texture; + + } + async decompressTextureAsync( texture, maxTextureSize = Infinity ) { if ( this.textureUtils === null ) { @@ -1575,14 +1626,20 @@ class GLTFWriter { /** * Process material * @param {THREE.Material} material Material to process + * @param {THREE.BufferGeometry} [geometry] Geometry the material is used with. * @return {Promise} Index of the processed material in the "materials" array */ - async processMaterialAsync( material ) { + async processMaterialAsync( material, geometry ) { const cache = this.cache; const json = this.json; - if ( cache.materials.has( material ) ) return cache.materials.get( material ); + // Whether the geometry provides explicit tangents. The exported normal map depends on + // this, so it is part of the material cache key. + const hasTangent = geometry !== undefined && geometry.hasAttribute( 'tangent' ); + const cacheKey = material.normalMap ? material.uuid + ':' + hasTangent : material.uuid; + + if ( cache.materials.has( cacheKey ) ) return cache.materials.get( cacheKey ); if ( material.isShaderMaterial ) { @@ -1677,16 +1734,36 @@ class GLTFWriter { // normalTexture if ( material.normalMap ) { + const normalScale = material.normalScale; + + // glTF only supports OpenGL-style normal maps with a univariate, positive scale. + // A negative `normalScale` component is baked into the texture by inverting the + // corresponding channel. Meshes without explicit tangents use the opposite + // green-channel convention, so the green channel is inverted in that case too. + // + // The no-tangent green flip is the counterpart of GLTFLoader, which negates + // `normalScale.y` on import for the same case. + const flipX = normalScale.x < 0; + const flipY = hasTangent ? normalScale.y < 0 : normalScale.y > 0; + + let normalMap = material.normalMap; + + if ( flipX || flipY ) { + + normalMap = await this.buildNormalMapTextureAsync( material.normalMap, flipX, flipY ); + + } + const normalMapDef = { - index: await this.processTextureAsync( material.normalMap ), + index: await this.processTextureAsync( normalMap ), texCoord: material.normalMap.channel }; - if ( material.normalScale && material.normalScale.x !== 1 ) { + if ( Math.abs( normalScale.x ) !== 1 ) { - // glTF normal scale is univariate. Ignore `y`, which may be flipped. - // Context: https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995 - normalMapDef.scale = material.normalScale.x; + // glTF normal scale is univariate. The magnitude of `x` is used; the sign of + // both components has already been baked into the texture above. + normalMapDef.scale = Math.abs( normalScale.x ); } @@ -1743,7 +1820,7 @@ class GLTFWriter { } ); const index = json.materials.push( materialDef ) - 1; - cache.materials.set( material, index ); + cache.materials.set( cacheKey, index ); return index; } @@ -2061,7 +2138,7 @@ class GLTFWriter { } - const material = await this.processMaterialAsync( materials[ groups[ i ].materialIndex ] ); + const material = await this.processMaterialAsync( materials[ groups[ i ].materialIndex ], geometry ); if ( material !== null ) primitive.material = material; diff --git a/examples/jsm/tsl/math/curlNoise.js b/examples/jsm/tsl/math/curlNoise.js new file mode 100644 index 00000000000000..64f0a6848a352b --- /dev/null +++ b/examples/jsm/tsl/math/curlNoise.js @@ -0,0 +1,107 @@ +import { mod, Fn, vec2, div, vec4, dot, floor, step, sub, min, max, mul, abs, vec3, inverseSqrt, add, float } from 'three/tsl'; + +/** + * Permutation polynomial for noise generation. + * + * @tsl + * @function + * @param {Node} x - Input vector. + * @return {Node} Permuted vector. + */ +export const permute = /*@__PURE__*/ Fn( ( [ x ] ) => { + + return mod( x.mul( x ).mul( 34. ).add( x ), 289. ); + +}, { x: 'vec4', return: 'vec4' } ); + +/** + * 3D Simplex noise implementation in TSL. + * + * @tsl + * @function + * @param {Node} v - Input coordinate vector. + * @return {Node} Simplex noise value. + */ +export const snoise = /*@__PURE__*/ Fn( ( [ v ] ) => { + + const C = div( 1., vec2( 6, 3 ) ); + const D = vec4( 0, .5, 1, 2 ); + const i = floor( v.add( dot( v, C.yyy ) ) ); + const x0 = v.sub( i ).add( dot( i, C.xxx ) ); + const g = step( x0.yzx, x0.xyz ); + const l = sub( 1., g ); + const i1 = min( g.xyz, l.zxy ); + const i2 = max( g.xyz, l.zxy ); + const x1 = x0.sub( i1 ).add( C.x ); + const x2 = x0.sub( i2 ).add( C.y ); + const x3 = x0.sub( D.yyy ); + i.assign( mod( i, 289. ) ); + const p = permute( permute( permute( i.z.add( vec4( 0., i1.z, i2.z, 1. ) ) ).add( i.y ).add( vec4( 0., i1.y, i2.y, 1. ) ) ).add( i.x ).add( vec4( 0., i1.x, i2.x, 1. ) ) ); + const ns = mul( .142857142857, D.wyz ).sub( D.xzx ); + const j = p.sub( mul( 49., floor( p.mul( ns.z ).mul( ns.z ) ) ) ); + const x_ = floor( j.mul( ns.z ) ); + const x = x_.mul( ns.x ).add( ns.yyyy ); + const y = floor( j.sub( mul( 7., x_ ) ) ).mul( ns.x ).add( ns.yyyy ); + const h = sub( 1., abs( x ) ).sub( abs( y ) ); + const b0 = vec4( x.xy, y.xy ); + const b1 = vec4( x.zw, y.zw ); + const sh = step( h, vec4( 0 ) ).negate(); + const a0 = b0.xzyw.add( floor( b0 ).mul( 2. ).add( 1. ).xzyw.mul( sh.xxyy ) ); + const a1 = b1.xzyw.add( floor( b1 ).mul( 2. ).add( 1. ).xzyw.mul( sh.zzww ) ); + const p0 = vec3( a0.xy, h.x ); + const p1 = vec3( a0.zw, h.y ); + const p2 = vec3( a1.xy, h.z ); + const p3 = vec3( a1.zw, h.w ); + const norm = inverseSqrt( vec4( dot( p0, p0 ), dot( p1, p1 ), dot( p2, p2 ), dot( p3, p3 ) ) ); + p0.mulAssign( norm.x ); + p1.mulAssign( norm.y ); + p2.mulAssign( norm.z ); + p3.mulAssign( norm.w ); + const m = max( sub( .6, vec4( dot( x0, x0 ), dot( x1, x1 ), dot( x2, x2 ), dot( x3, x3 ) ) ), 0. ); + + return add( .5, mul( 12., dot( m.mul( m ).mul( m ), vec4( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 ), dot( p3, x3 ) ) ) ) ); + +}, { v: 'vec3', return: 'float' } ); + +/** + * 3D Simplex noise vector. Returns a vec3 containing three independent noise samples. + * + * @tsl + * @function + * @param {Node} x - Input coordinate vector. + * @return {Node} Vector of three noise values. + */ +export const snoiseVec3 = /*@__PURE__*/ Fn( ( [ x ] ) => { + + return vec3( snoise( vec3( x ).mul( 2. ).sub( 1. ) ), snoise( vec3( x.y.sub( 19.1 ), x.z.add( 33.4 ), x.x.add( 47.2 ) ) ).mul( 2. ).sub( 1. ), snoise( vec3( x.z.add( 74.2 ), x.x.sub( 124.5 ), x.y.add( 99.4 ) ).mul( 2. ).sub( 1. ) ) ); + +}, { x: 'vec3', return: 'vec3' } ); + +/** + * 3D Curl noise in TSL. Generates a divergence-free vector field from simplex noise. + * + * @tsl + * @function + * @param {Node} p - Input coordinate vector. + * @return {Node} Curl noise vector. + */ +export const curlNoise = /*@__PURE__*/ Fn( ( [ p ] ) => { + + const e = float( .1 ); + const dx = vec3( e, 0.0, 0.0 ); + const dy = vec3( 0.0, e, 0.0 ); + const dz = vec3( 0.0, 0.0, e ); + const p_x0 = snoiseVec3( p.sub( dx ) ); + const p_x1 = snoiseVec3( p.add( dx ) ); + const p_y0 = snoiseVec3( p.sub( dy ) ); + const p_y1 = snoiseVec3( p.add( dy ) ); + const p_z0 = snoiseVec3( p.sub( dz ) ); + const p_z1 = snoiseVec3( p.add( dz ) ); + const x = p_y1.z.sub( p_y0.z ).sub( p_z1.y ).add( p_z0.y ); + const y = p_z1.x.sub( p_z0.x ).sub( p_x1.z ).add( p_x0.z ); + const z = p_x1.y.sub( p_x0.y ).sub( p_y1.x ).add( p_y0.x ); + const divisor = div( 1.0, mul( 2.0, e ) ); + + return vec3( x, y, z ).mul( divisor ); + +}, { p: 'vec3', return: 'vec3' } ); diff --git a/examples/misc_exporter_gltf_normals.html b/examples/misc_exporter_gltf_normals.html new file mode 100644 index 00000000000000..4c87c75a991786 --- /dev/null +++ b/examples/misc_exporter_gltf_normals.html @@ -0,0 +1,215 @@ + + + + three.js webgl - exporter - gltf - normals + + + + + + + + + +
+ three.js webgl - exporter - gltf - normals

+
+
+ + + + + + + diff --git a/examples/screenshots/misc_exporter_gltf_normals.jpg b/examples/screenshots/misc_exporter_gltf_normals.jpg new file mode 100644 index 00000000000000..729ee02adaddfe Binary files /dev/null and b/examples/screenshots/misc_exporter_gltf_normals.jpg differ diff --git a/examples/screenshots/webgpu_postprocessing_difference.jpg b/examples/screenshots/webgpu_postprocessing_difference.jpg index e31942b6aa572a..a4d3895c2b1446 100644 Binary files a/examples/screenshots/webgpu_postprocessing_difference.jpg and b/examples/screenshots/webgpu_postprocessing_difference.jpg differ diff --git a/examples/screenshots/webgpu_volume_fire.jpg b/examples/screenshots/webgpu_volume_fire.jpg new file mode 100644 index 00000000000000..001fe203e0b94e Binary files /dev/null and b/examples/screenshots/webgpu_volume_fire.jpg differ diff --git a/examples/textures/NormalMapDirectX.png b/examples/textures/NormalMapDirectX.png new file mode 100644 index 00000000000000..e367827fc8b2e3 Binary files /dev/null and b/examples/textures/NormalMapDirectX.png differ diff --git a/examples/textures/NormalMapOpenGL.png b/examples/textures/NormalMapOpenGL.png new file mode 100644 index 00000000000000..0dcfd615988785 Binary files /dev/null and b/examples/textures/NormalMapOpenGL.png differ diff --git a/examples/webgpu_volume_fire.html b/examples/webgpu_volume_fire.html new file mode 100644 index 00000000000000..a5000018b49590 --- /dev/null +++ b/examples/webgpu_volume_fire.html @@ -0,0 +1,1324 @@ + + + + three.js webgpu - volumetric fire simulation + + + + + + + + + + + +
+ + +
+ three.jsVolumetric Fire Simulation +
+ + 3D fluid simulation (semi-Lagrangian advection + curlNoise, buoyancy, Jacobi projection) on the GPU.
Drag the teapot to add turbulence.
+
+ + + + + + + diff --git a/package-lock.json b/package-lock.json index 9773c1e6e54ecf..4c9802d8281346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -487,9 +487,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", - "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", "cpu": [ "arm" ], @@ -501,9 +501,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", - "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", "cpu": [ "arm64" ], @@ -515,9 +515,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", - "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", "cpu": [ "arm64" ], @@ -529,9 +529,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", - "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", "cpu": [ "x64" ], @@ -543,9 +543,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", - "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", "cpu": [ "arm64" ], @@ -557,9 +557,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", - "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", "cpu": [ "x64" ], @@ -571,9 +571,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", - "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", "cpu": [ "arm" ], @@ -588,9 +588,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", - "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", "cpu": [ "arm" ], @@ -605,9 +605,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", - "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", "cpu": [ "arm64" ], @@ -622,9 +622,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", - "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", "cpu": [ "arm64" ], @@ -639,9 +639,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", - "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", "cpu": [ "loong64" ], @@ -656,9 +656,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", - "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", "cpu": [ "loong64" ], @@ -673,9 +673,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", - "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", "cpu": [ "ppc64" ], @@ -690,9 +690,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", - "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", "cpu": [ "ppc64" ], @@ -707,9 +707,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", - "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", "cpu": [ "riscv64" ], @@ -724,9 +724,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", - "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", "cpu": [ "riscv64" ], @@ -741,9 +741,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", - "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", "cpu": [ "s390x" ], @@ -758,9 +758,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", - "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", "cpu": [ "x64" ], @@ -775,9 +775,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", - "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", "cpu": [ "x64" ], @@ -792,9 +792,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", - "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", "cpu": [ "x64" ], @@ -806,9 +806,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", - "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", "cpu": [ "arm64" ], @@ -820,9 +820,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", - "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", "cpu": [ "arm64" ], @@ -834,9 +834,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", - "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", "cpu": [ "ia32" ], @@ -848,9 +848,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", - "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", "cpu": [ "x64" ], @@ -862,9 +862,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", - "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", "cpu": [ "x64" ], @@ -1562,9 +1562,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "63.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.2.tgz", - "integrity": "sha512-0TchoK1uS4VxHSo3P4CyWQ31Lm+6zsT+xkHMC5KbFKwgOf8YrXPf1Bl8EP7kpgw1wfe/Ui5jz5mSX7ou8WAVuw==", + "version": "63.0.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.7.tgz", + "integrity": "sha512-pxrqGO733F7xmVYB5vQOiciiT9uddxqehawnbPjZmW2YaJR6fT5cP3UQd2BNoE85ATspCMtNL8w/a5WDGX3Qwg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2663,9 +2663,9 @@ } }, "node_modules/rollup": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", - "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", "dev": true, "license": "MIT", "dependencies": { @@ -2679,31 +2679,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.0", - "@rollup/rollup-android-arm64": "4.62.0", - "@rollup/rollup-darwin-arm64": "4.62.0", - "@rollup/rollup-darwin-x64": "4.62.0", - "@rollup/rollup-freebsd-arm64": "4.62.0", - "@rollup/rollup-freebsd-x64": "4.62.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", - "@rollup/rollup-linux-arm-musleabihf": "4.62.0", - "@rollup/rollup-linux-arm64-gnu": "4.62.0", - "@rollup/rollup-linux-arm64-musl": "4.62.0", - "@rollup/rollup-linux-loong64-gnu": "4.62.0", - "@rollup/rollup-linux-loong64-musl": "4.62.0", - "@rollup/rollup-linux-ppc64-gnu": "4.62.0", - "@rollup/rollup-linux-ppc64-musl": "4.62.0", - "@rollup/rollup-linux-riscv64-gnu": "4.62.0", - "@rollup/rollup-linux-riscv64-musl": "4.62.0", - "@rollup/rollup-linux-s390x-gnu": "4.62.0", - "@rollup/rollup-linux-x64-gnu": "4.62.0", - "@rollup/rollup-linux-x64-musl": "4.62.0", - "@rollup/rollup-openbsd-x64": "4.62.0", - "@rollup/rollup-openharmony-arm64": "4.62.0", - "@rollup/rollup-win32-arm64-msvc": "4.62.0", - "@rollup/rollup-win32-ia32-msvc": "4.62.0", - "@rollup/rollup-win32-x64-gnu": "4.62.0", - "@rollup/rollup-win32-x64-msvc": "4.62.0", + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", "fsevents": "~2.3.2" } }, diff --git a/src/nodes/display/ColorAdjustment.js b/src/nodes/display/ColorAdjustment.js index 62233fe3b874f7..090a949a7e6242 100644 --- a/src/nodes/display/ColorAdjustment.js +++ b/src/nodes/display/ColorAdjustment.js @@ -30,7 +30,7 @@ export const grayscale = /*@__PURE__*/ Fn( ( [ color ] ) => { */ export const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { - return adjustment.mix( luminance( color.rgb ), color.rgb ); + return adjustment.mix( luminance( color.rgb ), color.rgb ).max( 0.0 ); } ); @@ -42,17 +42,17 @@ export const saturation = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] * @tsl * @function * @param {Node} color - The input color. - * @param {Node} [adjustment=1] - Controls the intensity of the vibrance effect. + * @param {Node} [adjustment=0] - Controls the intensity of the vibrance effect. * @return {Node} The updated color. */ -export const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { +export const vibrance = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 0 ) ] ) => { const average = add( color.r, color.g, color.b ).div( 3.0 ); const mx = color.r.max( color.g.max( color.b ) ); const amt = mx.sub( average ).mul( adjustment ).mul( - 3.0 ); - return mix( color.rgb, mx, amt ); + return mix( color.rgb, mx, amt ).max( 0.0 ); } ); @@ -71,7 +71,7 @@ export const hue = /*@__PURE__*/ Fn( ( [ color, adjustment = float( 1 ) ] ) => { const cosAngle = adjustment.cos(); - return vec3( color.rgb.mul( cosAngle ).add( k.cross( color.rgb ).mul( adjustment.sin() ).add( k.mul( dot( k, color.rgb ).mul( cosAngle.oneMinus() ) ) ) ) ); + return vec3( color.rgb.mul( cosAngle ).add( k.cross( color.rgb ).mul( adjustment.sin() ).add( k.mul( dot( k, color.rgb ).mul( cosAngle.oneMinus() ) ) ) ) ).max( 0.0 ); } ); @@ -123,18 +123,19 @@ export const cdl = /*@__PURE__*/ Fn( ( [ // NOTE: The ASC CDL v1.2 defines a [0, 1] clamp on the slope+offset term, and another on the // saturation term. Per the ACEScc specification and Filament, limits may be omitted to support - // values outside [0, 1], requiring a workaround for negative values in the power expression. + // if negative inputs to the power expression are avoided. We use `max( in, 0.0 )` + // on final output, but the lower limit may not be required in all cases. const luma = color.rgb.dot( vec3( luminanceCoefficients ) ); - const v = max( color.rgb.mul( slope ).add( offset ), 0.0 ).toVar(); - const pv = v.pow( power ).toVar(); + const v = max( color.rgb.mul( slope ).add( offset ), 0.0 ); + const pv = v.pow( power ); If( v.r.greaterThan( 0.0 ), () => { v.r.assign( pv.r ); } ); // eslint-disable-line If( v.g.greaterThan( 0.0 ), () => { v.g.assign( pv.g ); } ); // eslint-disable-line If( v.b.greaterThan( 0.0 ), () => { v.b.assign( pv.b ); } ); // eslint-disable-line - v.assign( luma.add( v.sub( luma ).mul( saturation ) ) ); + v.assign( luma.add( v.sub( luma ).mul( saturation ) ).max( 0 ) ); return vec4( v.rgb, color.a ); diff --git a/src/nodes/functions/VolumetricLightingModel.js b/src/nodes/functions/VolumetricLightingModel.js index 3fb2a3c3e1eae0..404bb155b044b2 100644 --- a/src/nodes/functions/VolumetricLightingModel.js +++ b/src/nodes/functions/VolumetricLightingModel.js @@ -38,15 +38,19 @@ class VolumetricLightingModel extends LightingModel { // This approach dynamically changes the direction of the ray, // prioritizing the ray from the camera to the object if it is inside the mesh, and from the object to the camera if it is far away. + const isFrontToBack = property( 'bool' ); + If( cameraPosition.sub( positionWorld ).length().greaterThan( modelRadius.mul( 2 ) ), () => { startPos.assign( cameraPosition ); endPos.assign( positionWorld ); + isFrontToBack.assign( true ); } ).Else( () => { startPos.assign( positionWorld ); endPos.assign( cameraPosition ); + isFrontToBack.assign( false ); } ); @@ -90,12 +94,17 @@ class VolumetricLightingModel extends LightingModel { scatteringDensity.assign( 0 ); let scatteringNode; + let scatteringEmissiveNode; if ( material.scatteringNode ) { - scatteringNode = material.scatteringNode( { - positionRay - } ); + scatteringNode = material.scatteringNode( { positionRay } ); + + } + + if ( material.scatteringEmissiveNode ) { + + scatteringEmissiveNode = material.scatteringEmissiveNode( { positionRay } ); } @@ -107,9 +116,28 @@ class VolumetricLightingModel extends LightingModel { } + const stepLight = scatteringDensity.mul( 0.01 ).toVar(); + + if ( scatteringEmissiveNode ) { + + stepLight.addAssign( scatteringEmissiveNode.mul( 0.01 ) ); + + } + // beer's law const falloff = scatteringDensity.mul( .01 ).negate().mul( stepSize ).exp(); + + If( isFrontToBack, () => { + + outgoingRayLight.addAssign( stepLight.mul( transmittance ).mul( stepSize ) ); + + } ).Else( () => { + + outgoingRayLight.assign( outgoingRayLight.mul( falloff ).add( stepLight.mul( stepSize ) ) ); + + } ); + transmittance.mulAssign( falloff ); // move along the ray @@ -118,7 +146,7 @@ class VolumetricLightingModel extends LightingModel { } ); - outgoingRayLight.addAssign( transmittance.saturate().oneMinus() ); + } @@ -151,7 +179,12 @@ class VolumetricLightingModel extends LightingModel { // TODO: We need a viewportOpaque*() ( output, depth ) to fit with modern rendering approaches const directLight = lightColor.xyz.toVar(); - directLight.mulAssign( lightNode.shadowNode ); // it no should be necessary if used in the same render pass + + if ( lightNode.shadowNode !== null ) { + + directLight.mulAssign( lightNode.shadowNode ); // it no should be necessary if used in the same render pass + + } this.scatteringLight( directLight, builder );