UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

182 lines (165 loc) 5.57 kB
import TempNode from '../core/TempNode.js'; import { NodeUpdateType } from '../core/constants.js'; import { nodeProxy } from '../tsl/TSLBase.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.js'; const _cache = new WeakMap(); /** * This node can be used to automatically convert environment maps in the * equirectangular format into the cube map format. * * @augments TempNode */ class CubeMapNode extends TempNode { static get type() { return 'CubeMapNode'; } /** * Constructs a new cube map node. * * @param {Node} envNode - The node representing the environment map. */ constructor(envNode) { super('vec3'); /** * The node representing the environment map. * * @type {Node} */ this.envNode = envNode; /** * A reference to the internal cube texture. * * @private * @type {?CubeTexture} * @default null */ this._cubeTexture = null; /** * A reference to the internal cube texture node. * * @private * @type {CubeTextureNode} */ this._cubeTextureNode = cubeTexture(null); const defaultTexture = new CubeTexture(); defaultTexture.isRenderTargetTexture = true; /** * A default cube texture that acts as a placeholder. * It is used when the conversion from equirectangular to cube * map has not finished yet for a given texture. * * @private * @type {CubeTexture} */ this._defaultTexture = defaultTexture; /** * The `updateBeforeType` is set to `NodeUpdateType.RENDER` since the node updates * the texture once per render in its {@link CubeMapNode#updateBefore} method. * * @type {string} * @default 'render' */ 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; } } export default CubeMapNode; /** * Returns true if the given equirectangular image has been fully loaded * and is ready for further processing. * * @private * @param {Image} image - The equirectangular image to check. * @return {boolean} Whether the image is ready or not. */ function isEquirectangularMapReady(image) { if (image === null || image === undefined) return false; return image.height > 0; } /** * This function is executed when `dispose()` is called on the equirectangular * texture. In this case, the generated cube map with its render target * is deleted as well. * * @private * @param {Object} event - The event object. */ function onTextureDispose(event) { const texture = event.target; texture.removeEventListener('dispose', onTextureDispose); const renderTarget = _cache.get(texture); if (renderTarget !== undefined) { _cache.delete(texture); renderTarget.dispose(); } } /** * This function makes sure the generated cube map uses the correct * texture mapping that corresponds to the equirectangular original. * * @private * @param {Texture} texture - The cube texture. * @param {number} mapping - The original texture mapping. */ function mapTextureMapping(texture, mapping) { if (mapping === EquirectangularReflectionMapping) { texture.mapping = CubeReflectionMapping; } else if (mapping === EquirectangularRefractionMapping) { texture.mapping = CubeRefractionMapping; } } /** * TSL function for creating a cube map node. * * @tsl * @function * @param {Node} envNode - The node representing the environment map. * @returns {CubeMapNode} */ export const cubeMapNode = /*@__PURE__*/nodeProxy(CubeMapNode).setParameterLength(1);