You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
3.7 KiB

import TempNode from '../core/TempNode.js';
import { addNodeClass } from '../core/Node.js';
import { texture } from '../accessors/TextureNode.js';
import { textureCubeUV } from './PMREMUtils.js';
import { uniform } from '../core/UniformNode.js';
import { NodeUpdateType } from '../core/constants.js';
import { nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
import { WebGLCoordinateSystem } from 'three';
let _generator = null;
const _cache = new WeakMap();
function _generateCubeUVSize( imageHeight ) {
const maxMip = Math.log2( imageHeight ) - 2;
const texelHeight = 1.0 / imageHeight;
const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
return { texelWidth, texelHeight, maxMip };
}
function _getPMREMFromTexture( texture ) {
let cacheTexture = _cache.get( texture );
const pmremVersion = cacheTexture !== undefined ? cacheTexture.pmremVersion : - 1;
if ( pmremVersion !== texture.pmremVersion ) {
if ( texture.isCubeTexture ) {
if ( texture.source.data.some( ( texture ) => texture === undefined ) ) {
throw new Error( 'PMREMNode: Undefined texture in CubeTexture. Use onLoad callback or async loader' );
}
cacheTexture = _generator.fromCubemap( texture, cacheTexture );
} else {
if ( texture.image === undefined ) {
throw new Error( 'PMREMNode: Undefined image in Texture. Use onLoad callback or async loader' );
}
cacheTexture = _generator.fromEquirectangular( texture, cacheTexture );
}
cacheTexture.pmremVersion = texture.pmremVersion;
_cache.set( texture, cacheTexture );
}
return cacheTexture.texture;
}
class PMREMNode extends TempNode {
constructor( value, uvNode = null, levelNode = null ) {
super( 'vec3' );
this._value = value;
this._pmrem = null;
this.uvNode = uvNode;
this.levelNode = levelNode;
this._generator = null;
this._texture = texture( null );
this._width = uniform( 0 );
this._height = uniform( 0 );
this._maxMip = uniform( 0 );
this.updateBeforeType = NodeUpdateType.RENDER;
}
set value( value ) {
this._value = value;
this._pmrem = null;
}
get value() {
return this._value;
}
updateFromTexture( texture ) {
const cubeUVSize = _generateCubeUVSize( texture.image.height );
this._texture.value = texture;
this._width.value = cubeUVSize.texelWidth;
this._height.value = cubeUVSize.texelHeight;
this._maxMip.value = cubeUVSize.maxMip;
}
updateBefore() {
let pmrem = this._pmrem;
const pmremVersion = pmrem ? pmrem.pmremVersion : - 1;
const texture = this._value;
if ( pmremVersion !== texture.pmremVersion ) {
if ( texture.isPMREMTexture === true ) {
pmrem = texture;
} else {
pmrem = _getPMREMFromTexture( texture );
}
this._pmrem = pmrem;
this.updateFromTexture( pmrem );
}
}
setup( builder ) {
if ( _generator === null ) {
_generator = builder.createPMREMGenerator();
}
//
this.updateBefore( builder );
//
let uvNode = this.uvNode;
if ( uvNode === null && builder.context.getUV ) {
uvNode = builder.context.getUV( this );
}
//
const texture = this.value;
if ( builder.renderer.coordinateSystem === WebGLCoordinateSystem && texture.isPMREMTexture !== true && texture.isRenderTargetTexture === true ) {
uvNode = vec3( uvNode.x.negate(), uvNode.yz );
}
//
let levelNode = this.levelNode;
if ( levelNode === null && builder.context.getTextureLevel ) {
levelNode = builder.context.getTextureLevel( this );
}
//
return textureCubeUV( this._texture, uvNode, levelNode, this._width, this._height, this._maxMip );
}
}
export const pmremTexture = nodeProxy( PMREMNode );
addNodeClass( 'PMREMNode', PMREMNode );
export default PMREMNode;