From e684e3c45705e619a270dd714a622f6a0f6e06a6 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Tue, 6 Aug 2024 10:47:56 +0200 Subject: [PATCH] Nodes: Add `CubeMapNode`. --- examples/files.json | 1 + .../screenshots/webgpu_materials_envmaps.jpg | Bin 0 -> 40976 bytes examples/webgpu_materials_envmaps.html | 156 +++++++++++++++++ src/nodes/lighting/BasicEnvironmentNode.js | 3 +- src/nodes/utils/CubeMapNode.js | 157 ++++++++++++++++++ 5 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 examples/screenshots/webgpu_materials_envmaps.jpg create mode 100644 examples/webgpu_materials_envmaps.html create mode 100644 src/nodes/utils/CubeMapNode.js diff --git a/examples/files.json b/examples/files.json index 9c297749d34866..a1a233aa83eaf7 100644 --- a/examples/files.json +++ b/examples/files.json @@ -347,6 +347,7 @@ "webgpu_materials", "webgpu_materials_basic", "webgpu_materials_displacementmap", + "webgpu_materials_envmaps", "webgpu_materials_lightmap", "webgpu_materials_matcap", "webgpu_materials_sss", diff --git a/examples/screenshots/webgpu_materials_envmaps.jpg b/examples/screenshots/webgpu_materials_envmaps.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8b01c918d91f6f29d80304b971afe63ea03e2e05 GIT binary patch literal 40976 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 DBpNvE literal 0 HcmV?d00001 diff --git a/examples/webgpu_materials_envmaps.html b/examples/webgpu_materials_envmaps.html new file mode 100644 index 00000000000000..dde1c4e0736e22 --- /dev/null +++ b/examples/webgpu_materials_envmaps.html @@ -0,0 +1,156 @@ + + + + three.js webgpu - materials - environment maps + + + + + + +
+ three.js - webgpu environment mapping example
+ Equirectangular Map by Jón Ragnarsson. +
+ + + + + + + + \ No newline at end of file diff --git a/src/nodes/lighting/BasicEnvironmentNode.js b/src/nodes/lighting/BasicEnvironmentNode.js index 68cbf5dda86bcf..a07a39ec1c948f 100644 --- a/src/nodes/lighting/BasicEnvironmentNode.js +++ b/src/nodes/lighting/BasicEnvironmentNode.js @@ -1,5 +1,6 @@ import LightingNode from './LightingNode.js'; import { addNodeClass } from '../core/Node.js'; +import { cubeMapNode } from '../utils/CubeMapNode.js'; class BasicEnvironmentNode extends LightingNode { @@ -15,7 +16,7 @@ class BasicEnvironmentNode extends LightingNode { // environment property is used in the finish() method of BasicLightingModel - builder.context.environment = this.envNode; + builder.context.environment = cubeMapNode( this.envNode ); } diff --git a/src/nodes/utils/CubeMapNode.js b/src/nodes/utils/CubeMapNode.js new file mode 100644 index 00000000000000..3f3e5e06b436bc --- /dev/null +++ b/src/nodes/utils/CubeMapNode.js @@ -0,0 +1,157 @@ +import TempNode from '../core/TempNode.js'; +import { addNodeClass } from '../core/Node.js'; +import { NodeUpdateType } from '../core/constants.js'; +import { nodeProxy } from '../shadernode/ShaderNode.js'; +import { CubeTexture } from '../../textures/CubeTexture.js'; +import { cubeTexture } from '../accessors/CubeTextureNode.js'; +import CubeRenderTarget from '../../renderers/common/CubeRenderTarget.js'; +import { CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from '../../constants'; + +const _cache = new WeakMap(); + +class CubeMapNode extends TempNode { + + constructor( envNode ) { + + super( 'vec3' ); + + this.envNode = envNode; + + this._cubeTexture = null; + this._cubeTextureNode = cubeTexture(); + + const defaultTexture = new CubeTexture(); + defaultTexture.isRenderTargetTexture = true; + + this._defaultTexture = defaultTexture; + + this.updateBeforeType = NodeUpdateType.RENDER; + + } + + updateBefore( frame ) { + + const { renderer, material } = frame; + + const envNode = this.envNode; + + if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) { + + const texture = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ]; + + if ( texture && texture.isTexture ) { + + const mapping = texture.mapping; + + if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { + + // check for converted cubemap map + + if ( _cache.has( texture ) ) { + + const cubeMap = _cache.get( texture ); + + mapTextureMapping( cubeMap, texture.mapping ); + this._cubeTexture = cubeMap; + + } else { + + // create cube map from equirectangular map + + const image = texture.image; + + if ( isEquirectangularMapReady( image ) ) { + + const renderTarget = new CubeRenderTarget( image.height ); + renderTarget.fromEquirectangularTexture( renderer, texture ); + + mapTextureMapping( renderTarget.texture, texture.mapping ); + this._cubeTexture = renderTarget.texture; + + _cache.set( texture, renderTarget.texture ); + + texture.addEventListener( 'dispose', onTextureDispose ); + + } else { + + // default cube texture as fallback when equirectangular texture is not yet loaded + + this._cubeTexture = this._defaultTexture; + + } + + } + + // + + this._cubeTextureNode.value = this._cubeTexture; + + } else { + + // envNode already refers to a cube map + + this._cubeTextureNode = this.envNode; + + } + + } + + } + + } + + setup( builder ) { + + this.updateBefore( builder ); + + return this._cubeTextureNode; + + } + +} + +function isEquirectangularMapReady( image ) { + + if ( image === null || image === undefined ) return false; + + return image.height > 0; + +} + +function onTextureDispose( event ) { + + const texture = event.target; + + texture.removeEventListener( 'dispose', onTextureDispose ); + + const renderTarget = _cache.get( texture ); + + if ( renderTarget !== undefined ) { + + _cache.delete( texture ); + + renderTarget.dispose(); + + } + +} + +function mapTextureMapping( texture, mapping ) { + + if ( mapping === EquirectangularReflectionMapping ) { + + texture.mapping = CubeReflectionMapping; + + } else if ( mapping === EquirectangularRefractionMapping ) { + + texture.mapping = CubeRefractionMapping; + + } + +} + +export const cubeMapNode = nodeProxy( CubeMapNode ); + +addNodeClass( 'CubeMapNode', CubeMapNode ); + +export default CubeMapNode;