-
-
Notifications
You must be signed in to change notification settings - Fork 35.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nodes: Add CubeMapNode
.
#29073
Merged
Merged
Nodes: Add CubeMapNode
.
#29073
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>three.js webgpu - materials - environment maps</title> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | ||
<link type="text/css" rel="stylesheet" href="main.css"> | ||
</head> | ||
<body> | ||
|
||
<div id="info"> | ||
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgpu environment mapping example<br/> | ||
Equirectangular Map by <a href="http://www.flickr.com/photos/jonragnarsson/2294472375/" target="_blank" rel="noopener">Jón Ragnarsson</a>. | ||
</div> | ||
|
||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"three": "../build/three.webgpu.js", | ||
"three/tsl": "../build/three.webgpu.js", | ||
"three/addons/": "./jsm/" | ||
} | ||
} | ||
</script> | ||
|
||
|
||
<script type="module"> | ||
|
||
import * as THREE from 'three'; | ||
|
||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; | ||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; | ||
|
||
let controls, camera, scene, renderer; | ||
let textureEquirec, textureCube; | ||
let sphereMesh, sphereMaterial, params; | ||
|
||
init(); | ||
|
||
function init() { | ||
|
||
// CAMERAS | ||
|
||
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 100 ); | ||
camera.position.set( 0, 0, 2.5 ); | ||
|
||
// SCENE | ||
|
||
scene = new THREE.Scene(); | ||
|
||
// Textures | ||
|
||
const loader = new THREE.CubeTextureLoader(); | ||
loader.setPath( 'textures/cube/Bridge2/' ); | ||
|
||
textureCube = loader.load( [ 'posx.jpg', 'negx.jpg', 'posy.jpg', 'negy.jpg', 'posz.jpg', 'negz.jpg' ] ); | ||
|
||
const textureLoader = new THREE.TextureLoader(); | ||
|
||
textureEquirec = textureLoader.load( 'textures/2294472375_24a3b8ef46_o.jpg' ); | ||
textureEquirec.mapping = THREE.EquirectangularReflectionMapping; | ||
textureEquirec.colorSpace = THREE.SRGBColorSpace; | ||
|
||
scene.background = textureCube; | ||
|
||
// | ||
|
||
const geometry = new THREE.IcosahedronGeometry( 1, 15 ); | ||
sphereMaterial = new THREE.MeshBasicMaterial( { envMap: textureCube } ); | ||
sphereMesh = new THREE.Mesh( geometry, sphereMaterial ); | ||
scene.add( sphereMesh ); | ||
|
||
// | ||
|
||
renderer = new THREE.WebGPURenderer(); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
renderer.setAnimationLoop( animate ); | ||
document.body.appendChild( renderer.domElement ); | ||
|
||
// | ||
|
||
controls = new OrbitControls( camera, renderer.domElement ); | ||
controls.minDistance = 1.5; | ||
controls.maxDistance = 6; | ||
|
||
// | ||
|
||
params = { | ||
Cube: function () { | ||
|
||
scene.background = textureCube; | ||
|
||
sphereMaterial.envMap = textureCube; | ||
sphereMaterial.needsUpdate = true; | ||
|
||
}, | ||
Equirectangular: function () { | ||
|
||
scene.background = textureEquirec; | ||
|
||
sphereMaterial.envMap = textureEquirec; | ||
sphereMaterial.needsUpdate = true; | ||
|
||
}, | ||
Refraction: false | ||
}; | ||
|
||
const gui = new GUI( { width: 300 } ); | ||
gui.add( params, 'Cube' ); | ||
gui.add( params, 'Equirectangular' ); | ||
gui.add( params, 'Refraction' ).onChange( function ( value ) { | ||
|
||
if ( value ) { | ||
|
||
textureEquirec.mapping = THREE.EquirectangularRefractionMapping; | ||
textureCube.mapping = THREE.CubeRefractionMapping; | ||
|
||
} else { | ||
|
||
textureEquirec.mapping = THREE.EquirectangularReflectionMapping; | ||
textureCube.mapping = THREE.CubeReflectionMapping; | ||
|
||
} | ||
|
||
sphereMaterial.needsUpdate = true; | ||
|
||
} ); | ||
gui.open(); | ||
|
||
window.addEventListener( 'resize', onWindowResize ); | ||
|
||
} | ||
|
||
function onWindowResize() { | ||
|
||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
|
||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
|
||
} | ||
|
||
// | ||
|
||
function animate() { | ||
|
||
camera.lookAt( scene.position ); | ||
renderer.render( scene, camera ); | ||
|
||
} | ||
|
||
</script> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sunag This module should be for internal use only so it is not exported in
Nodes.js
. Still, I'm a bit unsure about the nameCubeMapNode
since its quite similar toCubeTextureNode
.CubeMapNode
should be in some sense the non-PBR version ofPMREMNode
. Meaning it encapsulate different inputs to provide a single environment map format for the material.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we need this, wouldn't just manipulating the UV be enough since we don't need to pre-filter for non-PBR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with using equirectangular uvs are the artifacts that result at the poles which do not occur with the cube map format. They were previously reported as bugs which was one reason for not directly supporting equirectangular textures in the shader.
I'm afraid users will complain when the artifacts appear again when migrating from
WebGLRenderer
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, if so let's merge the PR, it seems good to me.