| import { |
| REVISION, |
| RGBAFormat, |
| HalfFloatType, |
| FloatType, |
| UnsignedByteType, |
| TriangleFanDrawMode, |
| TriangleStripDrawMode, |
| TrianglesDrawMode, |
| LinearToneMapping, |
| BackSide |
| } from '../constants.js'; |
| import { _Math } from '../math/Math.js'; |
| import { DataTexture } from '../textures/DataTexture.js'; |
| import { Frustum } from '../math/Frustum.js'; |
| import { Matrix4 } from '../math/Matrix4.js'; |
| import { ShaderLib } from './shaders/ShaderLib.js'; |
| import { UniformsLib } from './shaders/UniformsLib.js'; |
| import { cloneUniforms } from './shaders/UniformsUtils.js'; |
| import { Vector2 } from '../math/Vector2.js'; |
| import { Vector3 } from '../math/Vector3.js'; |
| import { Vector4 } from '../math/Vector4.js'; |
| import { WebGLAnimation } from './webgl/WebGLAnimation.js'; |
| import { WebGLAttributes } from './webgl/WebGLAttributes.js'; |
| import { WebGLBackground } from './webgl/WebGLBackground.js'; |
| import { WebGLBufferRenderer } from './webgl/WebGLBufferRenderer.js'; |
| import { WebGLCapabilities } from './webgl/WebGLCapabilities.js'; |
| import { WebGLClipping } from './webgl/WebGLClipping.js'; |
| import { WebGLExtensions } from './webgl/WebGLExtensions.js'; |
| import { WebGLGeometries } from './webgl/WebGLGeometries.js'; |
| import { WebGLIndexedBufferRenderer } from './webgl/WebGLIndexedBufferRenderer.js'; |
| import { WebGLInfo } from './webgl/WebGLInfo.js'; |
| import { WebGLMorphtargets } from './webgl/WebGLMorphtargets.js'; |
| import { WebGLObjects } from './webgl/WebGLObjects.js'; |
| import { WebGLPrograms } from './webgl/WebGLPrograms.js'; |
| import { WebGLProperties } from './webgl/WebGLProperties.js'; |
| import { WebGLRenderLists } from './webgl/WebGLRenderLists.js'; |
| import { WebGLRenderStates } from './webgl/WebGLRenderStates.js'; |
| import { WebGLShadowMap } from './webgl/WebGLShadowMap.js'; |
| import { WebGLState } from './webgl/WebGLState.js'; |
| import { WebGLTextures } from './webgl/WebGLTextures.js'; |
| import { WebGLUniforms } from './webgl/WebGLUniforms.js'; |
| import { WebGLUtils } from './webgl/WebGLUtils.js'; |
| import { WebVRManager } from './webvr/WebVRManager.js'; |
| import { WebXRManager } from './webvr/WebXRManager.js'; |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| function WebGLRenderer( parameters ) { |
|
|
| console.log( 'THREE.WebGLRenderer', REVISION ); |
|
|
| parameters = parameters || {}; |
|
|
| var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), |
| _context = parameters.context !== undefined ? parameters.context : null, |
|
|
| _alpha = parameters.alpha !== undefined ? parameters.alpha : false, |
| _depth = parameters.depth !== undefined ? parameters.depth : true, |
| _stencil = parameters.stencil !== undefined ? parameters.stencil : true, |
| _antialias = parameters.antialias !== undefined ? parameters.antialias : false, |
| _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, |
| _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, |
| _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default'; |
|
|
| var currentRenderList = null; |
| var currentRenderState = null; |
|
|
| |
|
|
| this.domElement = _canvas; |
| this.context = null; |
|
|
| |
|
|
| this.autoClear = true; |
| this.autoClearColor = true; |
| this.autoClearDepth = true; |
| this.autoClearStencil = true; |
|
|
| |
|
|
| this.sortObjects = true; |
|
|
| |
|
|
| this.clippingPlanes = []; |
| this.localClippingEnabled = false; |
|
|
| |
|
|
| this.gammaFactor = 2.0; |
| this.gammaInput = false; |
| this.gammaOutput = false; |
|
|
| |
|
|
| this.physicallyCorrectLights = false; |
|
|
| |
|
|
| this.toneMapping = LinearToneMapping; |
| this.toneMappingExposure = 1.0; |
| this.toneMappingWhitePoint = 1.0; |
|
|
| |
|
|
| this.maxMorphTargets = 8; |
| this.maxMorphNormals = 4; |
|
|
| |
|
|
| var _this = this, |
|
|
| _isContextLost = false, |
|
|
| |
|
|
| _framebuffer = null, |
|
|
| _currentRenderTarget = null, |
| _currentFramebuffer = null, |
| _currentMaterialId = - 1, |
|
|
| |
|
|
| _currentGeometryProgram = { |
| geometry: null, |
| program: null, |
| wireframe: false |
| }, |
|
|
| _currentCamera = null, |
| _currentArrayCamera = null, |
|
|
| _currentViewport = new Vector4(), |
| _currentScissor = new Vector4(), |
| _currentScissorTest = null, |
|
|
| |
|
|
| _width = _canvas.width, |
| _height = _canvas.height, |
|
|
| _pixelRatio = 1, |
|
|
| _viewport = new Vector4( 0, 0, _width, _height ), |
| _scissor = new Vector4( 0, 0, _width, _height ), |
| _scissorTest = false, |
|
|
| |
|
|
| _frustum = new Frustum(), |
|
|
| |
|
|
| _clipping = new WebGLClipping(), |
| _clippingEnabled = false, |
| _localClippingEnabled = false, |
|
|
| |
|
|
| _projScreenMatrix = new Matrix4(), |
|
|
| _vector3 = new Vector3(); |
|
|
| function getTargetPixelRatio() { |
|
|
| return _currentRenderTarget === null ? _pixelRatio : 1; |
|
|
| } |
|
|
| |
|
|
| var _gl; |
|
|
| try { |
|
|
| var contextAttributes = { |
| alpha: _alpha, |
| depth: _depth, |
| stencil: _stencil, |
| antialias: _antialias, |
| premultipliedAlpha: _premultipliedAlpha, |
| preserveDrawingBuffer: _preserveDrawingBuffer, |
| powerPreference: _powerPreference |
| }; |
|
|
| |
|
|
| _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); |
| _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); |
|
|
| _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); |
|
|
| if ( _gl === null ) { |
|
|
| if ( _canvas.getContext( 'webgl' ) !== null ) { |
|
|
| throw new Error( 'Error creating WebGL context with your selected attributes.' ); |
|
|
| } else { |
|
|
| throw new Error( 'Error creating WebGL context.' ); |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| if ( _gl.getShaderPrecisionFormat === undefined ) { |
|
|
| _gl.getShaderPrecisionFormat = function () { |
|
|
| return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; |
|
|
| }; |
|
|
| } |
|
|
| } catch ( error ) { |
|
|
| console.error( 'THREE.WebGLRenderer: ' + error.message ); |
| throw error; |
|
|
| } |
|
|
| var extensions, capabilities, state, info; |
| var properties, textures, attributes, geometries, objects; |
| var programCache, renderLists, renderStates; |
|
|
| var background, morphtargets, bufferRenderer, indexedBufferRenderer; |
|
|
| var utils; |
|
|
| function initGLContext() { |
|
|
| extensions = new WebGLExtensions( _gl ); |
|
|
| capabilities = new WebGLCapabilities( _gl, extensions, parameters ); |
|
|
| if ( ! capabilities.isWebGL2 ) { |
|
|
| extensions.get( 'WEBGL_depth_texture' ); |
| extensions.get( 'OES_texture_float' ); |
| extensions.get( 'OES_texture_half_float' ); |
| extensions.get( 'OES_texture_half_float_linear' ); |
| extensions.get( 'OES_standard_derivatives' ); |
| extensions.get( 'OES_element_index_uint' ); |
| extensions.get( 'ANGLE_instanced_arrays' ); |
|
|
| } |
|
|
| extensions.get( 'OES_texture_float_linear' ); |
|
|
| utils = new WebGLUtils( _gl, extensions, capabilities ); |
|
|
| state = new WebGLState( _gl, extensions, utils, capabilities ); |
| state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); |
| state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); |
|
|
| info = new WebGLInfo( _gl ); |
| properties = new WebGLProperties(); |
| textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); |
| attributes = new WebGLAttributes( _gl ); |
| geometries = new WebGLGeometries( _gl, attributes, info ); |
| objects = new WebGLObjects( geometries, info ); |
| morphtargets = new WebGLMorphtargets( _gl ); |
| programCache = new WebGLPrograms( _this, extensions, capabilities, textures ); |
| renderLists = new WebGLRenderLists(); |
| renderStates = new WebGLRenderStates(); |
|
|
| background = new WebGLBackground( _this, state, objects, _premultipliedAlpha ); |
|
|
| bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); |
| indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); |
|
|
| info.programs = programCache.programs; |
|
|
| _this.context = _gl; |
| _this.capabilities = capabilities; |
| _this.extensions = extensions; |
| _this.properties = properties; |
| _this.renderLists = renderLists; |
| _this.state = state; |
| _this.info = info; |
|
|
| } |
|
|
| initGLContext(); |
|
|
| |
|
|
| var vr = null; |
|
|
| if ( typeof navigator !== 'undefined' ) { |
|
|
| vr = ( 'xr' in navigator ) ? new WebXRManager( _this ) : new WebVRManager( _this ); |
|
|
| } |
|
|
| this.vr = vr; |
|
|
| |
|
|
| var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize ); |
|
|
| this.shadowMap = shadowMap; |
|
|
| |
|
|
| this.getContext = function () { |
|
|
| return _gl; |
|
|
| }; |
|
|
| this.getContextAttributes = function () { |
|
|
| return _gl.getContextAttributes(); |
|
|
| }; |
|
|
| this.forceContextLoss = function () { |
|
|
| var extension = extensions.get( 'WEBGL_lose_context' ); |
| if ( extension ) extension.loseContext(); |
|
|
| }; |
|
|
| this.forceContextRestore = function () { |
|
|
| var extension = extensions.get( 'WEBGL_lose_context' ); |
| if ( extension ) extension.restoreContext(); |
|
|
| }; |
|
|
| this.getPixelRatio = function () { |
|
|
| return _pixelRatio; |
|
|
| }; |
|
|
| this.setPixelRatio = function ( value ) { |
|
|
| if ( value === undefined ) return; |
|
|
| _pixelRatio = value; |
|
|
| this.setSize( _width, _height, false ); |
|
|
| }; |
|
|
| this.getSize = function ( target ) { |
|
|
| if ( target === undefined ) { |
|
|
| console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' ); |
|
|
| target = new Vector2(); |
|
|
| } |
|
|
| return target.set( _width, _height ); |
|
|
| }; |
|
|
| this.setSize = function ( width, height, updateStyle ) { |
|
|
| if ( vr.isPresenting() ) { |
|
|
| console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); |
| return; |
|
|
| } |
|
|
| _width = width; |
| _height = height; |
|
|
| _canvas.width = width * _pixelRatio; |
| _canvas.height = height * _pixelRatio; |
|
|
| if ( updateStyle !== false ) { |
|
|
| _canvas.style.width = width + 'px'; |
| _canvas.style.height = height + 'px'; |
|
|
| } |
|
|
| this.setViewport( 0, 0, width, height ); |
|
|
| }; |
|
|
| this.getDrawingBufferSize = function ( target ) { |
|
|
| if ( target === undefined ) { |
|
|
| console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' ); |
|
|
| target = new Vector2(); |
|
|
| } |
|
|
| return target.set( _width * _pixelRatio, _height * _pixelRatio ); |
|
|
| }; |
|
|
| this.setDrawingBufferSize = function ( width, height, pixelRatio ) { |
|
|
| _width = width; |
| _height = height; |
|
|
| _pixelRatio = pixelRatio; |
|
|
| _canvas.width = width * pixelRatio; |
| _canvas.height = height * pixelRatio; |
|
|
| this.setViewport( 0, 0, width, height ); |
|
|
| }; |
|
|
| this.getCurrentViewport = function ( target ) { |
|
|
| if ( target === undefined ) { |
|
|
| console.warn( 'WebGLRenderer: .getCurrentViewport() now requires a Vector4 as an argument' ); |
|
|
| target = new Vector4(); |
|
|
| } |
|
|
| return target.copy( _currentViewport ); |
|
|
| }; |
|
|
| this.getViewport = function ( target ) { |
|
|
| return target.copy( _viewport ); |
|
|
| }; |
|
|
| this.setViewport = function ( x, y, width, height ) { |
|
|
| if ( x.isVector4 ) { |
|
|
| _viewport.set( x.x, x.y, x.z, x.w ); |
|
|
| } else { |
|
|
| _viewport.set( x, y, width, height ); |
|
|
| } |
|
|
| state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); |
|
|
| }; |
|
|
| this.getScissor = function ( target ) { |
|
|
| return target.copy( _scissor ); |
|
|
| }; |
|
|
| this.setScissor = function ( x, y, width, height ) { |
|
|
| if ( x.isVector4 ) { |
|
|
| _scissor.set( x.x, x.y, x.z, x.w ); |
|
|
| } else { |
|
|
| _scissor.set( x, y, width, height ); |
|
|
| } |
|
|
| state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); |
|
|
| }; |
|
|
| this.getScissorTest = function () { |
|
|
| return _scissorTest; |
|
|
| }; |
|
|
| this.setScissorTest = function ( boolean ) { |
|
|
| state.setScissorTest( _scissorTest = boolean ); |
|
|
| }; |
|
|
| |
|
|
| this.getClearColor = function () { |
|
|
| return background.getClearColor(); |
|
|
| }; |
|
|
| this.setClearColor = function () { |
|
|
| background.setClearColor.apply( background, arguments ); |
|
|
| }; |
|
|
| this.getClearAlpha = function () { |
|
|
| return background.getClearAlpha(); |
|
|
| }; |
|
|
| this.setClearAlpha = function () { |
|
|
| background.setClearAlpha.apply( background, arguments ); |
|
|
| }; |
|
|
| this.clear = function ( color, depth, stencil ) { |
|
|
| var bits = 0; |
|
|
| if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; |
| if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; |
| if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; |
|
|
| _gl.clear( bits ); |
|
|
| }; |
|
|
| this.clearColor = function () { |
|
|
| this.clear( true, false, false ); |
|
|
| }; |
|
|
| this.clearDepth = function () { |
|
|
| this.clear( false, true, false ); |
|
|
| }; |
|
|
| this.clearStencil = function () { |
|
|
| this.clear( false, false, true ); |
|
|
| }; |
|
|
| |
|
|
| this.dispose = function () { |
|
|
| _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); |
| _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); |
|
|
| renderLists.dispose(); |
| renderStates.dispose(); |
| properties.dispose(); |
| objects.dispose(); |
|
|
| vr.dispose(); |
|
|
| animation.stop(); |
|
|
| }; |
|
|
| |
|
|
| function onContextLost( event ) { |
|
|
| event.preventDefault(); |
|
|
| console.log( 'THREE.WebGLRenderer: Context Lost.' ); |
|
|
| _isContextLost = true; |
|
|
| } |
|
|
| function onContextRestore( ) { |
|
|
| console.log( 'THREE.WebGLRenderer: Context Restored.' ); |
|
|
| _isContextLost = false; |
|
|
| initGLContext(); |
|
|
| } |
|
|
| function onMaterialDispose( event ) { |
|
|
| var material = event.target; |
|
|
| material.removeEventListener( 'dispose', onMaterialDispose ); |
|
|
| deallocateMaterial( material ); |
|
|
| } |
|
|
| |
|
|
| function deallocateMaterial( material ) { |
|
|
| releaseMaterialProgramReference( material ); |
|
|
| properties.remove( material ); |
|
|
| } |
|
|
|
|
| function releaseMaterialProgramReference( material ) { |
|
|
| var programInfo = properties.get( material ).program; |
|
|
| material.program = undefined; |
|
|
| if ( programInfo !== undefined ) { |
|
|
| programCache.releaseProgram( programInfo ); |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| function renderObjectImmediate( object, program ) { |
|
|
| object.render( function ( object ) { |
|
|
| _this.renderBufferImmediate( object, program ); |
|
|
| } ); |
|
|
| } |
|
|
| this.renderBufferImmediate = function ( object, program ) { |
|
|
| state.initAttributes(); |
|
|
| var buffers = properties.get( object ); |
|
|
| if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); |
| if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); |
| if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); |
| if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); |
|
|
| var programAttributes = program.getAttributes(); |
|
|
| if ( object.hasPositions ) { |
|
|
| _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position ); |
| _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); |
|
|
| state.enableAttribute( programAttributes.position ); |
| _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 ); |
|
|
| } |
|
|
| if ( object.hasNormals ) { |
|
|
| _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal ); |
| _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); |
|
|
| state.enableAttribute( programAttributes.normal ); |
| _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 ); |
|
|
| } |
|
|
| if ( object.hasUvs ) { |
|
|
| _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv ); |
| _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); |
|
|
| state.enableAttribute( programAttributes.uv ); |
| _gl.vertexAttribPointer( programAttributes.uv, 2, _gl.FLOAT, false, 0, 0 ); |
|
|
| } |
|
|
| if ( object.hasColors ) { |
|
|
| _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color ); |
| _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); |
|
|
| state.enableAttribute( programAttributes.color ); |
| _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 ); |
|
|
| } |
|
|
| state.disableUnusedAttributes(); |
|
|
| _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); |
|
|
| object.count = 0; |
|
|
| }; |
|
|
| this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { |
|
|
| var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); |
|
|
| state.setMaterial( material, frontFaceCW ); |
|
|
| var program = setProgram( camera, fog, material, object ); |
|
|
| var updateBuffers = false; |
|
|
| if ( _currentGeometryProgram.geometry !== geometry.id || |
| _currentGeometryProgram.program !== program.id || |
| _currentGeometryProgram.wireframe !== ( material.wireframe === true ) ) { |
|
|
| _currentGeometryProgram.geometry = geometry.id; |
| _currentGeometryProgram.program = program.id; |
| _currentGeometryProgram.wireframe = material.wireframe === true; |
| updateBuffers = true; |
|
|
| } |
|
|
| if ( object.morphTargetInfluences ) { |
|
|
| morphtargets.update( object, geometry, material, program ); |
|
|
| updateBuffers = true; |
|
|
| } |
|
|
| |
|
|
| var index = geometry.index; |
| var position = geometry.attributes.position; |
| var rangeFactor = 1; |
|
|
| if ( material.wireframe === true ) { |
|
|
| index = geometries.getWireframeAttribute( geometry ); |
| rangeFactor = 2; |
|
|
| } |
|
|
| var attribute; |
| var renderer = bufferRenderer; |
|
|
| if ( index !== null ) { |
|
|
| attribute = attributes.get( index ); |
|
|
| renderer = indexedBufferRenderer; |
| renderer.setIndex( attribute ); |
|
|
| } |
|
|
| if ( updateBuffers ) { |
|
|
| setupVertexAttributes( material, program, geometry ); |
|
|
| if ( index !== null ) { |
|
|
| _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer ); |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| var dataCount = Infinity; |
|
|
| if ( index !== null ) { |
|
|
| dataCount = index.count; |
|
|
| } else if ( position !== undefined ) { |
|
|
| dataCount = position.count; |
|
|
| } |
|
|
| var rangeStart = geometry.drawRange.start * rangeFactor; |
| var rangeCount = geometry.drawRange.count * rangeFactor; |
|
|
| var groupStart = group !== null ? group.start * rangeFactor : 0; |
| var groupCount = group !== null ? group.count * rangeFactor : Infinity; |
|
|
| var drawStart = Math.max( rangeStart, groupStart ); |
| var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; |
|
|
| var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); |
|
|
| if ( drawCount === 0 ) return; |
|
|
| |
|
|
| if ( object.isMesh ) { |
|
|
| if ( material.wireframe === true ) { |
|
|
| state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); |
| renderer.setMode( _gl.LINES ); |
|
|
| } else { |
|
|
| switch ( object.drawMode ) { |
|
|
| case TrianglesDrawMode: |
| renderer.setMode( _gl.TRIANGLES ); |
| break; |
|
|
| case TriangleStripDrawMode: |
| renderer.setMode( _gl.TRIANGLE_STRIP ); |
| break; |
|
|
| case TriangleFanDrawMode: |
| renderer.setMode( _gl.TRIANGLE_FAN ); |
| break; |
|
|
| } |
|
|
| } |
|
|
|
|
| } else if ( object.isLine ) { |
|
|
| var lineWidth = material.linewidth; |
|
|
| if ( lineWidth === undefined ) lineWidth = 1; |
|
|
| state.setLineWidth( lineWidth * getTargetPixelRatio() ); |
|
|
| if ( object.isLineSegments ) { |
|
|
| renderer.setMode( _gl.LINES ); |
|
|
| } else if ( object.isLineLoop ) { |
|
|
| renderer.setMode( _gl.LINE_LOOP ); |
|
|
| } else { |
|
|
| renderer.setMode( _gl.LINE_STRIP ); |
|
|
| } |
|
|
| } else if ( object.isPoints ) { |
|
|
| renderer.setMode( _gl.POINTS ); |
|
|
| } else if ( object.isSprite ) { |
|
|
| renderer.setMode( _gl.TRIANGLES ); |
|
|
| } |
|
|
| if ( geometry && geometry.isInstancedBufferGeometry ) { |
|
|
| if ( geometry.maxInstancedCount > 0 ) { |
|
|
| renderer.renderInstances( geometry, drawStart, drawCount ); |
|
|
| } |
|
|
| } else { |
|
|
| renderer.render( drawStart, drawCount ); |
|
|
| } |
|
|
| }; |
|
|
| function setupVertexAttributes( material, program, geometry ) { |
|
|
| if ( geometry && geometry.isInstancedBufferGeometry && ! capabilities.isWebGL2 ) { |
|
|
| if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) { |
|
|
| console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); |
| return; |
|
|
| } |
|
|
| } |
|
|
| state.initAttributes(); |
|
|
| var geometryAttributes = geometry.attributes; |
|
|
| var programAttributes = program.getAttributes(); |
|
|
| var materialDefaultAttributeValues = material.defaultAttributeValues; |
|
|
| for ( var name in programAttributes ) { |
|
|
| var programAttribute = programAttributes[ name ]; |
|
|
| if ( programAttribute >= 0 ) { |
|
|
| var geometryAttribute = geometryAttributes[ name ]; |
|
|
| if ( geometryAttribute !== undefined ) { |
|
|
| var normalized = geometryAttribute.normalized; |
| var size = geometryAttribute.itemSize; |
|
|
| var attribute = attributes.get( geometryAttribute ); |
|
|
| |
|
|
| if ( attribute === undefined ) continue; |
|
|
| var buffer = attribute.buffer; |
| var type = attribute.type; |
| var bytesPerElement = attribute.bytesPerElement; |
|
|
| if ( geometryAttribute.isInterleavedBufferAttribute ) { |
|
|
| var data = geometryAttribute.data; |
| var stride = data.stride; |
| var offset = geometryAttribute.offset; |
|
|
| if ( data && data.isInstancedInterleavedBuffer ) { |
|
|
| state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); |
|
|
| if ( geometry.maxInstancedCount === undefined ) { |
|
|
| geometry.maxInstancedCount = data.meshPerAttribute * data.count; |
|
|
| } |
|
|
| } else { |
|
|
| state.enableAttribute( programAttribute ); |
|
|
| } |
|
|
| _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); |
| _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement ); |
|
|
| } else { |
|
|
| if ( geometryAttribute.isInstancedBufferAttribute ) { |
|
|
| state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); |
|
|
| if ( geometry.maxInstancedCount === undefined ) { |
|
|
| geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; |
|
|
| } |
|
|
| } else { |
|
|
| state.enableAttribute( programAttribute ); |
|
|
| } |
|
|
| _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer ); |
| _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 ); |
|
|
| } |
|
|
| } else if ( materialDefaultAttributeValues !== undefined ) { |
|
|
| var value = materialDefaultAttributeValues[ name ]; |
|
|
| if ( value !== undefined ) { |
|
|
| switch ( value.length ) { |
|
|
| case 2: |
| _gl.vertexAttrib2fv( programAttribute, value ); |
| break; |
|
|
| case 3: |
| _gl.vertexAttrib3fv( programAttribute, value ); |
| break; |
|
|
| case 4: |
| _gl.vertexAttrib4fv( programAttribute, value ); |
| break; |
|
|
| default: |
| _gl.vertexAttrib1fv( programAttribute, value ); |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| state.disableUnusedAttributes(); |
|
|
| } |
|
|
| |
|
|
| this.compile = function ( scene, camera ) { |
|
|
| currentRenderState = renderStates.get( scene, camera ); |
| currentRenderState.init(); |
|
|
| scene.traverse( function ( object ) { |
|
|
| if ( object.isLight ) { |
|
|
| currentRenderState.pushLight( object ); |
|
|
| if ( object.castShadow ) { |
|
|
| currentRenderState.pushShadow( object ); |
|
|
| } |
|
|
| } |
|
|
| } ); |
|
|
| currentRenderState.setupLights( camera ); |
|
|
| scene.traverse( function ( object ) { |
|
|
| if ( object.material ) { |
|
|
| if ( Array.isArray( object.material ) ) { |
|
|
| for ( var i = 0; i < object.material.length; i ++ ) { |
|
|
| initMaterial( object.material[ i ], scene.fog, object ); |
|
|
| } |
|
|
| } else { |
|
|
| initMaterial( object.material, scene.fog, object ); |
|
|
| } |
|
|
| } |
|
|
| } ); |
|
|
| }; |
|
|
| |
|
|
| var onAnimationFrameCallback = null; |
|
|
| function onAnimationFrame( time ) { |
|
|
| if ( vr.isPresenting() ) return; |
| if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); |
|
|
| } |
|
|
| var animation = new WebGLAnimation(); |
| animation.setAnimationLoop( onAnimationFrame ); |
|
|
| if ( typeof window !== 'undefined' ) animation.setContext( window ); |
|
|
| this.setAnimationLoop = function ( callback ) { |
|
|
| onAnimationFrameCallback = callback; |
| vr.setAnimationLoop( callback ); |
|
|
| animation.start(); |
|
|
| }; |
|
|
| |
|
|
| this.render = function ( scene, camera ) { |
|
|
| var renderTarget, forceClear; |
|
|
| if ( arguments[ 2 ] !== undefined ) { |
|
|
| console.warn( 'THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' ); |
| renderTarget = arguments[ 2 ]; |
|
|
| } |
|
|
| if ( arguments[ 3 ] !== undefined ) { |
|
|
| console.warn( 'THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead.' ); |
| forceClear = arguments[ 3 ]; |
|
|
| } |
|
|
| if ( ! ( camera && camera.isCamera ) ) { |
|
|
| console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); |
| return; |
|
|
| } |
|
|
| if ( _isContextLost ) return; |
|
|
| |
|
|
| _currentGeometryProgram.geometry = null; |
| _currentGeometryProgram.program = null; |
| _currentGeometryProgram.wireframe = false; |
| _currentMaterialId = - 1; |
| _currentCamera = null; |
|
|
| |
|
|
| if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); |
|
|
| |
|
|
| if ( camera.parent === null ) camera.updateMatrixWorld(); |
|
|
| if ( vr.enabled ) { |
|
|
| camera = vr.getCamera( camera ); |
|
|
| } |
|
|
| |
|
|
| currentRenderState = renderStates.get( scene, camera ); |
| currentRenderState.init(); |
|
|
| scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget ); |
|
|
| _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); |
| _frustum.setFromMatrix( _projScreenMatrix ); |
|
|
| _localClippingEnabled = this.localClippingEnabled; |
| _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); |
|
|
| currentRenderList = renderLists.get( scene, camera ); |
| currentRenderList.init(); |
|
|
| projectObject( scene, camera, 0, _this.sortObjects ); |
|
|
| if ( _this.sortObjects === true ) { |
|
|
| currentRenderList.sort(); |
|
|
| } |
|
|
| |
|
|
| if ( _clippingEnabled ) _clipping.beginShadows(); |
|
|
| var shadowsArray = currentRenderState.state.shadowsArray; |
|
|
| shadowMap.render( shadowsArray, scene, camera ); |
|
|
| currentRenderState.setupLights( camera ); |
|
|
| if ( _clippingEnabled ) _clipping.endShadows(); |
|
|
| |
|
|
| if ( this.info.autoReset ) this.info.reset(); |
|
|
| if ( renderTarget !== undefined ) { |
|
|
| this.setRenderTarget( renderTarget ); |
|
|
| } |
|
|
| |
|
|
| background.render( currentRenderList, scene, camera, forceClear ); |
|
|
| |
|
|
| var opaqueObjects = currentRenderList.opaque; |
| var transparentObjects = currentRenderList.transparent; |
|
|
| if ( scene.overrideMaterial ) { |
|
|
| var overrideMaterial = scene.overrideMaterial; |
|
|
| if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial ); |
| if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial ); |
|
|
| } else { |
|
|
| |
|
|
| if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera ); |
|
|
| |
|
|
| if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera ); |
|
|
| } |
|
|
| |
|
|
| scene.onAfterRender( _this, scene, camera ); |
|
|
| |
|
|
| if ( _currentRenderTarget !== null ) { |
|
|
| |
|
|
| textures.updateRenderTargetMipmap( _currentRenderTarget ); |
|
|
| |
|
|
| textures.updateMultisampleRenderTarget( _currentRenderTarget ); |
|
|
| } |
|
|
| |
|
|
| state.buffers.depth.setTest( true ); |
| state.buffers.depth.setMask( true ); |
| state.buffers.color.setMask( true ); |
|
|
| state.setPolygonOffset( false ); |
|
|
| if ( vr.enabled ) { |
|
|
| vr.submitFrame(); |
|
|
| } |
|
|
| |
|
|
| currentRenderList = null; |
| currentRenderState = null; |
|
|
| }; |
|
|
| function projectObject( object, camera, groupOrder, sortObjects ) { |
|
|
| if ( object.visible === false ) return; |
|
|
| var visible = object.layers.test( camera.layers ); |
|
|
| if ( visible ) { |
|
|
| if ( object.isGroup ) { |
|
|
| groupOrder = object.renderOrder; |
|
|
| } else if ( object.isLight ) { |
|
|
| currentRenderState.pushLight( object ); |
|
|
| if ( object.castShadow ) { |
|
|
| currentRenderState.pushShadow( object ); |
|
|
| } |
|
|
| } else if ( object.isSprite ) { |
|
|
| if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { |
|
|
| if ( sortObjects ) { |
|
|
| _vector3.setFromMatrixPosition( object.matrixWorld ) |
| .applyMatrix4( _projScreenMatrix ); |
|
|
| } |
|
|
| var geometry = objects.update( object ); |
| var material = object.material; |
|
|
| if ( material.visible ) { |
|
|
| currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); |
|
|
| } |
|
|
| } |
|
|
| } else if ( object.isImmediateRenderObject ) { |
|
|
| if ( sortObjects ) { |
|
|
| _vector3.setFromMatrixPosition( object.matrixWorld ) |
| .applyMatrix4( _projScreenMatrix ); |
|
|
| } |
|
|
| currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null ); |
|
|
| } else if ( object.isMesh || object.isLine || object.isPoints ) { |
|
|
| if ( object.isSkinnedMesh ) { |
|
|
| object.skeleton.update(); |
|
|
| } |
|
|
| if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { |
|
|
| if ( sortObjects ) { |
|
|
| _vector3.setFromMatrixPosition( object.matrixWorld ) |
| .applyMatrix4( _projScreenMatrix ); |
|
|
| } |
|
|
| var geometry = objects.update( object ); |
| var material = object.material; |
|
|
| if ( Array.isArray( material ) ) { |
|
|
| var groups = geometry.groups; |
|
|
| for ( var i = 0, l = groups.length; i < l; i ++ ) { |
|
|
| var group = groups[ i ]; |
| var groupMaterial = material[ group.materialIndex ]; |
|
|
| if ( groupMaterial && groupMaterial.visible ) { |
|
|
| currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); |
|
|
| } |
|
|
| } |
|
|
| } else if ( material.visible ) { |
|
|
| currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| var children = object.children; |
|
|
| for ( var i = 0, l = children.length; i < l; i ++ ) { |
|
|
| projectObject( children[ i ], camera, groupOrder, sortObjects ); |
|
|
| } |
|
|
| } |
|
|
| function renderObjects( renderList, scene, camera, overrideMaterial ) { |
|
|
| for ( var i = 0, l = renderList.length; i < l; i ++ ) { |
|
|
| var renderItem = renderList[ i ]; |
|
|
| var object = renderItem.object; |
| var geometry = renderItem.geometry; |
| var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; |
| var group = renderItem.group; |
|
|
| if ( camera.isArrayCamera ) { |
|
|
| _currentArrayCamera = camera; |
|
|
| var cameras = camera.cameras; |
|
|
| for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { |
|
|
| var camera2 = cameras[ j ]; |
|
|
| if ( object.layers.test( camera2.layers ) ) { |
|
|
| if ( 'viewport' in camera2 ) { |
|
|
| state.viewport( _currentViewport.copy( camera2.viewport ) ); |
|
|
| } else { |
|
|
| var bounds = camera2.bounds; |
|
|
| var x = bounds.x * _width; |
| var y = bounds.y * _height; |
| var width = bounds.z * _width; |
| var height = bounds.w * _height; |
|
|
| state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) ); |
|
|
| } |
|
|
| currentRenderState.setupLights( camera2 ); |
|
|
| renderObject( object, scene, camera2, geometry, material, group ); |
|
|
| } |
|
|
| } |
|
|
| } else { |
|
|
| _currentArrayCamera = null; |
|
|
| renderObject( object, scene, camera, geometry, material, group ); |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| function renderObject( object, scene, camera, geometry, material, group ) { |
|
|
| object.onBeforeRender( _this, scene, camera, geometry, material, group ); |
| currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); |
|
|
| object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); |
| object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); |
|
|
| if ( object.isImmediateRenderObject ) { |
|
|
| state.setMaterial( material ); |
|
|
| var program = setProgram( camera, scene.fog, material, object ); |
|
|
| _currentGeometryProgram.geometry = null; |
| _currentGeometryProgram.program = null; |
| _currentGeometryProgram.wireframe = false; |
|
|
| renderObjectImmediate( object, program ); |
|
|
| } else { |
|
|
| _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); |
|
|
| } |
|
|
| object.onAfterRender( _this, scene, camera, geometry, material, group ); |
| currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); |
|
|
| } |
|
|
| function initMaterial( material, fog, object ) { |
|
|
| var materialProperties = properties.get( material ); |
|
|
| var lights = currentRenderState.state.lights; |
| var shadowsArray = currentRenderState.state.shadowsArray; |
|
|
| var lightsHash = materialProperties.lightsHash; |
| var lightsStateHash = lights.state.hash; |
|
|
| var parameters = programCache.getParameters( |
| material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object ); |
|
|
| var code = programCache.getProgramCode( material, parameters ); |
|
|
| var program = materialProperties.program; |
| var programChange = true; |
|
|
| if ( program === undefined ) { |
|
|
| |
| material.addEventListener( 'dispose', onMaterialDispose ); |
|
|
| } else if ( program.code !== code ) { |
|
|
| |
| releaseMaterialProgramReference( material ); |
|
|
| } else if ( lightsHash.stateID !== lightsStateHash.stateID || |
| lightsHash.directionalLength !== lightsStateHash.directionalLength || |
| lightsHash.pointLength !== lightsStateHash.pointLength || |
| lightsHash.spotLength !== lightsStateHash.spotLength || |
| lightsHash.rectAreaLength !== lightsStateHash.rectAreaLength || |
| lightsHash.hemiLength !== lightsStateHash.hemiLength || |
| lightsHash.shadowsLength !== lightsStateHash.shadowsLength ) { |
|
|
| lightsHash.stateID = lightsStateHash.stateID; |
| lightsHash.directionalLength = lightsStateHash.directionalLength; |
| lightsHash.pointLength = lightsStateHash.pointLength; |
| lightsHash.spotLength = lightsStateHash.spotLength; |
| lightsHash.rectAreaLength = lightsStateHash.rectAreaLength; |
| lightsHash.hemiLength = lightsStateHash.hemiLength; |
| lightsHash.shadowsLength = lightsStateHash.shadowsLength; |
|
|
| programChange = false; |
|
|
| } else if ( parameters.shaderID !== undefined ) { |
|
|
| |
| return; |
|
|
| } else { |
|
|
| |
| programChange = false; |
|
|
| } |
|
|
| if ( programChange ) { |
|
|
| if ( parameters.shaderID ) { |
|
|
| var shader = ShaderLib[ parameters.shaderID ]; |
|
|
| materialProperties.shader = { |
| name: material.type, |
| uniforms: cloneUniforms( shader.uniforms ), |
| vertexShader: shader.vertexShader, |
| fragmentShader: shader.fragmentShader |
| }; |
|
|
| } else { |
|
|
| materialProperties.shader = { |
| name: material.type, |
| uniforms: material.uniforms, |
| vertexShader: material.vertexShader, |
| fragmentShader: material.fragmentShader |
| }; |
|
|
| } |
|
|
| material.onBeforeCompile( materialProperties.shader, _this ); |
|
|
| |
| code = programCache.getProgramCode( material, parameters ); |
|
|
| program = programCache.acquireProgram( material, materialProperties.shader, parameters, code ); |
|
|
| materialProperties.program = program; |
| material.program = program; |
|
|
| } |
|
|
| var programAttributes = program.getAttributes(); |
|
|
| if ( material.morphTargets ) { |
|
|
| material.numSupportedMorphTargets = 0; |
|
|
| for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { |
|
|
| if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { |
|
|
| material.numSupportedMorphTargets ++; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| if ( material.morphNormals ) { |
|
|
| material.numSupportedMorphNormals = 0; |
|
|
| for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { |
|
|
| if ( programAttributes[ 'morphNormal' + i ] >= 0 ) { |
|
|
| material.numSupportedMorphNormals ++; |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| var uniforms = materialProperties.shader.uniforms; |
|
|
| if ( ! material.isShaderMaterial && |
| ! material.isRawShaderMaterial || |
| material.clipping === true ) { |
|
|
| materialProperties.numClippingPlanes = _clipping.numPlanes; |
| materialProperties.numIntersection = _clipping.numIntersection; |
| uniforms.clippingPlanes = _clipping.uniform; |
|
|
| } |
|
|
| materialProperties.fog = fog; |
|
|
| |
| if ( lightsHash === undefined ) { |
|
|
| materialProperties.lightsHash = lightsHash = {}; |
|
|
| } |
|
|
| lightsHash.stateID = lightsStateHash.stateID; |
| lightsHash.directionalLength = lightsStateHash.directionalLength; |
| lightsHash.pointLength = lightsStateHash.pointLength; |
| lightsHash.spotLength = lightsStateHash.spotLength; |
| lightsHash.rectAreaLength = lightsStateHash.rectAreaLength; |
| lightsHash.hemiLength = lightsStateHash.hemiLength; |
| lightsHash.shadowsLength = lightsStateHash.shadowsLength; |
|
|
| if ( material.lights ) { |
|
|
| |
|
|
| uniforms.ambientLightColor.value = lights.state.ambient; |
| uniforms.directionalLights.value = lights.state.directional; |
| uniforms.spotLights.value = lights.state.spot; |
| uniforms.rectAreaLights.value = lights.state.rectArea; |
| uniforms.pointLights.value = lights.state.point; |
| uniforms.hemisphereLights.value = lights.state.hemi; |
|
|
| uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; |
| uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; |
| uniforms.spotShadowMap.value = lights.state.spotShadowMap; |
| uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix; |
| uniforms.pointShadowMap.value = lights.state.pointShadowMap; |
| uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; |
| |
|
|
| } |
|
|
| var progUniforms = materialProperties.program.getUniforms(), |
| uniformsList = |
| WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); |
|
|
| materialProperties.uniformsList = uniformsList; |
|
|
| } |
|
|
| function setProgram( camera, fog, material, object ) { |
|
|
| textures.resetTextureUnits(); |
|
|
| var materialProperties = properties.get( material ); |
| var lights = currentRenderState.state.lights; |
|
|
| var lightsHash = materialProperties.lightsHash; |
| var lightsStateHash = lights.state.hash; |
|
|
| if ( _clippingEnabled ) { |
|
|
| if ( _localClippingEnabled || camera !== _currentCamera ) { |
|
|
| var useCache = |
| camera === _currentCamera && |
| material.id === _currentMaterialId; |
|
|
| |
| |
| |
| _clipping.setState( |
| material.clippingPlanes, material.clipIntersection, material.clipShadows, |
| camera, materialProperties, useCache ); |
|
|
| } |
|
|
| } |
|
|
| if ( material.needsUpdate === false ) { |
|
|
| if ( materialProperties.program === undefined ) { |
|
|
| material.needsUpdate = true; |
|
|
| } else if ( material.fog && materialProperties.fog !== fog ) { |
|
|
| material.needsUpdate = true; |
|
|
| } else if ( material.lights && ( lightsHash.stateID !== lightsStateHash.stateID || |
| lightsHash.directionalLength !== lightsStateHash.directionalLength || |
| lightsHash.pointLength !== lightsStateHash.pointLength || |
| lightsHash.spotLength !== lightsStateHash.spotLength || |
| lightsHash.rectAreaLength !== lightsStateHash.rectAreaLength || |
| lightsHash.hemiLength !== lightsStateHash.hemiLength || |
| lightsHash.shadowsLength !== lightsStateHash.shadowsLength ) ) { |
|
|
| material.needsUpdate = true; |
|
|
| } else if ( materialProperties.numClippingPlanes !== undefined && |
| ( materialProperties.numClippingPlanes !== _clipping.numPlanes || |
| materialProperties.numIntersection !== _clipping.numIntersection ) ) { |
|
|
| material.needsUpdate = true; |
|
|
| } |
|
|
| } |
|
|
| if ( material.needsUpdate ) { |
|
|
| initMaterial( material, fog, object ); |
| material.needsUpdate = false; |
|
|
| } |
|
|
| var refreshProgram = false; |
| var refreshMaterial = false; |
| var refreshLights = false; |
|
|
| var program = materialProperties.program, |
| p_uniforms = program.getUniforms(), |
| m_uniforms = materialProperties.shader.uniforms; |
|
|
| if ( state.useProgram( program.program ) ) { |
|
|
| refreshProgram = true; |
| refreshMaterial = true; |
| refreshLights = true; |
|
|
| } |
|
|
| if ( material.id !== _currentMaterialId ) { |
|
|
| _currentMaterialId = material.id; |
|
|
| refreshMaterial = true; |
|
|
| } |
|
|
| if ( refreshProgram || _currentCamera !== camera ) { |
|
|
| p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); |
|
|
| if ( capabilities.logarithmicDepthBuffer ) { |
|
|
| p_uniforms.setValue( _gl, 'logDepthBufFC', |
| 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); |
|
|
| } |
|
|
| if ( _currentCamera !== camera ) { |
|
|
| _currentCamera = camera; |
|
|
| |
| |
| |
|
|
| refreshMaterial = true; |
| refreshLights = true; |
|
|
| } |
|
|
| |
| |
|
|
| if ( material.isShaderMaterial || |
| material.isMeshPhongMaterial || |
| material.isMeshStandardMaterial || |
| material.envMap ) { |
|
|
| var uCamPos = p_uniforms.map.cameraPosition; |
|
|
| if ( uCamPos !== undefined ) { |
|
|
| uCamPos.setValue( _gl, |
| _vector3.setFromMatrixPosition( camera.matrixWorld ) ); |
|
|
| } |
|
|
| } |
|
|
| if ( material.isMeshPhongMaterial || |
| material.isMeshLambertMaterial || |
| material.isMeshBasicMaterial || |
| material.isMeshStandardMaterial || |
| material.isShaderMaterial || |
| material.skinning ) { |
|
|
| p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); |
|
|
| } |
|
|
| } |
|
|
| |
| |
| |
|
|
| if ( material.skinning ) { |
|
|
| p_uniforms.setOptional( _gl, object, 'bindMatrix' ); |
| p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); |
|
|
| var skeleton = object.skeleton; |
|
|
| if ( skeleton ) { |
|
|
| var bones = skeleton.bones; |
|
|
| if ( capabilities.floatVertexTextures ) { |
|
|
| if ( skeleton.boneTexture === undefined ) { |
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| var size = Math.sqrt( bones.length * 4 ); |
| size = _Math.ceilPowerOfTwo( size ); |
| size = Math.max( size, 4 ); |
|
|
| var boneMatrices = new Float32Array( size * size * 4 ); |
| boneMatrices.set( skeleton.boneMatrices ); |
|
|
| var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); |
| boneTexture.needsUpdate = true; |
|
|
| skeleton.boneMatrices = boneMatrices; |
| skeleton.boneTexture = boneTexture; |
| skeleton.boneTextureSize = size; |
|
|
| } |
|
|
| p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); |
| p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); |
|
|
| } else { |
|
|
| p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| if ( refreshMaterial ) { |
|
|
| p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); |
| p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint ); |
|
|
| if ( material.lights ) { |
|
|
| |
|
|
| |
| |
| |
| |
| |
| |
|
|
| markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); |
|
|
| } |
|
|
| |
|
|
| if ( fog && material.fog ) { |
|
|
| refreshUniformsFog( m_uniforms, fog ); |
|
|
| } |
|
|
| if ( material.isMeshBasicMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
|
|
| } else if ( material.isMeshLambertMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
| refreshUniformsLambert( m_uniforms, material ); |
|
|
| } else if ( material.isMeshPhongMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
|
|
| if ( material.isMeshToonMaterial ) { |
|
|
| refreshUniformsToon( m_uniforms, material ); |
|
|
| } else { |
|
|
| refreshUniformsPhong( m_uniforms, material ); |
|
|
| } |
|
|
| } else if ( material.isMeshStandardMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
|
|
| if ( material.isMeshPhysicalMaterial ) { |
|
|
| refreshUniformsPhysical( m_uniforms, material ); |
|
|
| } else { |
|
|
| refreshUniformsStandard( m_uniforms, material ); |
|
|
| } |
|
|
| } else if ( material.isMeshMatcapMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
|
|
| refreshUniformsMatcap( m_uniforms, material ); |
|
|
| } else if ( material.isMeshDepthMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
| refreshUniformsDepth( m_uniforms, material ); |
|
|
| } else if ( material.isMeshDistanceMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
| refreshUniformsDistance( m_uniforms, material ); |
|
|
| } else if ( material.isMeshNormalMaterial ) { |
|
|
| refreshUniformsCommon( m_uniforms, material ); |
| refreshUniformsNormal( m_uniforms, material ); |
|
|
| } else if ( material.isLineBasicMaterial ) { |
|
|
| refreshUniformsLine( m_uniforms, material ); |
|
|
| if ( material.isLineDashedMaterial ) { |
|
|
| refreshUniformsDash( m_uniforms, material ); |
|
|
| } |
|
|
| } else if ( material.isPointsMaterial ) { |
|
|
| refreshUniformsPoints( m_uniforms, material ); |
|
|
| } else if ( material.isSpriteMaterial ) { |
|
|
| refreshUniformsSprites( m_uniforms, material ); |
|
|
| } else if ( material.isShadowMaterial ) { |
|
|
| m_uniforms.color.value = material.color; |
| m_uniforms.opacity.value = material.opacity; |
|
|
| } |
|
|
| |
| |
|
|
| if ( m_uniforms.ltc_1 !== undefined ) m_uniforms.ltc_1.value = UniformsLib.LTC_1; |
| if ( m_uniforms.ltc_2 !== undefined ) m_uniforms.ltc_2.value = UniformsLib.LTC_2; |
|
|
| WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); |
|
|
| } |
|
|
| if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { |
|
|
| WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); |
| material.uniformsNeedUpdate = false; |
|
|
| } |
|
|
| if ( material.isSpriteMaterial ) { |
|
|
| p_uniforms.setValue( _gl, 'center', object.center ); |
|
|
| } |
|
|
| |
|
|
| p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); |
| p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); |
| p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); |
|
|
| return program; |
|
|
| } |
|
|
| |
|
|
| function refreshUniformsCommon( uniforms, material ) { |
|
|
| uniforms.opacity.value = material.opacity; |
|
|
| if ( material.color ) { |
|
|
| uniforms.diffuse.value = material.color; |
|
|
| } |
|
|
| if ( material.emissive ) { |
|
|
| uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); |
|
|
| } |
|
|
| if ( material.map ) { |
|
|
| uniforms.map.value = material.map; |
|
|
| } |
|
|
| if ( material.alphaMap ) { |
|
|
| uniforms.alphaMap.value = material.alphaMap; |
|
|
| } |
|
|
| if ( material.specularMap ) { |
|
|
| uniforms.specularMap.value = material.specularMap; |
|
|
| } |
|
|
| if ( material.envMap ) { |
|
|
| uniforms.envMap.value = material.envMap; |
|
|
| |
| |
| |
| |
| uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1; |
|
|
| uniforms.reflectivity.value = material.reflectivity; |
| uniforms.refractionRatio.value = material.refractionRatio; |
|
|
| uniforms.maxMipLevel.value = properties.get( material.envMap ).__maxMipLevel; |
|
|
| } |
|
|
| if ( material.lightMap ) { |
|
|
| uniforms.lightMap.value = material.lightMap; |
| uniforms.lightMapIntensity.value = material.lightMapIntensity; |
|
|
| } |
|
|
| if ( material.aoMap ) { |
|
|
| uniforms.aoMap.value = material.aoMap; |
| uniforms.aoMapIntensity.value = material.aoMapIntensity; |
|
|
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| var uvScaleMap; |
|
|
| if ( material.map ) { |
|
|
| uvScaleMap = material.map; |
|
|
| } else if ( material.specularMap ) { |
|
|
| uvScaleMap = material.specularMap; |
|
|
| } else if ( material.displacementMap ) { |
|
|
| uvScaleMap = material.displacementMap; |
|
|
| } else if ( material.normalMap ) { |
|
|
| uvScaleMap = material.normalMap; |
|
|
| } else if ( material.bumpMap ) { |
|
|
| uvScaleMap = material.bumpMap; |
|
|
| } else if ( material.roughnessMap ) { |
|
|
| uvScaleMap = material.roughnessMap; |
|
|
| } else if ( material.metalnessMap ) { |
|
|
| uvScaleMap = material.metalnessMap; |
|
|
| } else if ( material.alphaMap ) { |
|
|
| uvScaleMap = material.alphaMap; |
|
|
| } else if ( material.emissiveMap ) { |
|
|
| uvScaleMap = material.emissiveMap; |
|
|
| } |
|
|
| if ( uvScaleMap !== undefined ) { |
|
|
| |
| if ( uvScaleMap.isWebGLRenderTarget ) { |
|
|
| uvScaleMap = uvScaleMap.texture; |
|
|
| } |
|
|
| if ( uvScaleMap.matrixAutoUpdate === true ) { |
|
|
| uvScaleMap.updateMatrix(); |
|
|
| } |
|
|
| uniforms.uvTransform.value.copy( uvScaleMap.matrix ); |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsLine( uniforms, material ) { |
|
|
| uniforms.diffuse.value = material.color; |
| uniforms.opacity.value = material.opacity; |
|
|
| } |
|
|
| function refreshUniformsDash( uniforms, material ) { |
|
|
| uniforms.dashSize.value = material.dashSize; |
| uniforms.totalSize.value = material.dashSize + material.gapSize; |
| uniforms.scale.value = material.scale; |
|
|
| } |
|
|
| function refreshUniformsPoints( uniforms, material ) { |
|
|
| uniforms.diffuse.value = material.color; |
| uniforms.opacity.value = material.opacity; |
| uniforms.size.value = material.size * _pixelRatio; |
| uniforms.scale.value = _height * 0.5; |
|
|
| uniforms.map.value = material.map; |
|
|
| if ( material.map !== null ) { |
|
|
| if ( material.map.matrixAutoUpdate === true ) { |
|
|
| material.map.updateMatrix(); |
|
|
| } |
|
|
| uniforms.uvTransform.value.copy( material.map.matrix ); |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsSprites( uniforms, material ) { |
|
|
| uniforms.diffuse.value = material.color; |
| uniforms.opacity.value = material.opacity; |
| uniforms.rotation.value = material.rotation; |
| uniforms.map.value = material.map; |
|
|
| if ( material.map !== null ) { |
|
|
| if ( material.map.matrixAutoUpdate === true ) { |
|
|
| material.map.updateMatrix(); |
|
|
| } |
|
|
| uniforms.uvTransform.value.copy( material.map.matrix ); |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsFog( uniforms, fog ) { |
|
|
| uniforms.fogColor.value = fog.color; |
|
|
| if ( fog.isFog ) { |
|
|
| uniforms.fogNear.value = fog.near; |
| uniforms.fogFar.value = fog.far; |
|
|
| } else if ( fog.isFogExp2 ) { |
|
|
| uniforms.fogDensity.value = fog.density; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsLambert( uniforms, material ) { |
|
|
| if ( material.emissiveMap ) { |
|
|
| uniforms.emissiveMap.value = material.emissiveMap; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsPhong( uniforms, material ) { |
|
|
| uniforms.specular.value = material.specular; |
| uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); |
|
|
| if ( material.emissiveMap ) { |
|
|
| uniforms.emissiveMap.value = material.emissiveMap; |
|
|
| } |
|
|
| if ( material.bumpMap ) { |
|
|
| uniforms.bumpMap.value = material.bumpMap; |
| uniforms.bumpScale.value = material.bumpScale; |
| if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; |
|
|
| } |
|
|
| if ( material.normalMap ) { |
|
|
| uniforms.normalMap.value = material.normalMap; |
| uniforms.normalScale.value.copy( material.normalScale ); |
| if ( material.side === BackSide ) uniforms.normalScale.value.negate(); |
|
|
| } |
|
|
| if ( material.displacementMap ) { |
|
|
| uniforms.displacementMap.value = material.displacementMap; |
| uniforms.displacementScale.value = material.displacementScale; |
| uniforms.displacementBias.value = material.displacementBias; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsToon( uniforms, material ) { |
|
|
| refreshUniformsPhong( uniforms, material ); |
|
|
| if ( material.gradientMap ) { |
|
|
| uniforms.gradientMap.value = material.gradientMap; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsStandard( uniforms, material ) { |
|
|
| uniforms.roughness.value = material.roughness; |
| uniforms.metalness.value = material.metalness; |
|
|
| if ( material.roughnessMap ) { |
|
|
| uniforms.roughnessMap.value = material.roughnessMap; |
|
|
| } |
|
|
| if ( material.metalnessMap ) { |
|
|
| uniforms.metalnessMap.value = material.metalnessMap; |
|
|
| } |
|
|
| if ( material.emissiveMap ) { |
|
|
| uniforms.emissiveMap.value = material.emissiveMap; |
|
|
| } |
|
|
| if ( material.bumpMap ) { |
|
|
| uniforms.bumpMap.value = material.bumpMap; |
| uniforms.bumpScale.value = material.bumpScale; |
| if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; |
|
|
| } |
|
|
| if ( material.normalMap ) { |
|
|
| uniforms.normalMap.value = material.normalMap; |
| uniforms.normalScale.value.copy( material.normalScale ); |
| if ( material.side === BackSide ) uniforms.normalScale.value.negate(); |
|
|
| } |
|
|
| if ( material.displacementMap ) { |
|
|
| uniforms.displacementMap.value = material.displacementMap; |
| uniforms.displacementScale.value = material.displacementScale; |
| uniforms.displacementBias.value = material.displacementBias; |
|
|
| } |
|
|
| if ( material.envMap ) { |
|
|
| |
| uniforms.envMapIntensity.value = material.envMapIntensity; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsPhysical( uniforms, material ) { |
|
|
| refreshUniformsStandard( uniforms, material ); |
|
|
| uniforms.reflectivity.value = material.reflectivity; |
|
|
| uniforms.clearCoat.value = material.clearCoat; |
| uniforms.clearCoatRoughness.value = material.clearCoatRoughness; |
|
|
| } |
|
|
| function refreshUniformsMatcap( uniforms, material ) { |
|
|
| if ( material.matcap ) { |
|
|
| uniforms.matcap.value = material.matcap; |
|
|
| } |
|
|
| if ( material.bumpMap ) { |
|
|
| uniforms.bumpMap.value = material.bumpMap; |
| uniforms.bumpScale.value = material.bumpScale; |
| if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; |
|
|
| } |
|
|
| if ( material.normalMap ) { |
|
|
| uniforms.normalMap.value = material.normalMap; |
| uniforms.normalScale.value.copy( material.normalScale ); |
| if ( material.side === BackSide ) uniforms.normalScale.value.negate(); |
|
|
| } |
|
|
| if ( material.displacementMap ) { |
|
|
| uniforms.displacementMap.value = material.displacementMap; |
| uniforms.displacementScale.value = material.displacementScale; |
| uniforms.displacementBias.value = material.displacementBias; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsDepth( uniforms, material ) { |
|
|
| if ( material.displacementMap ) { |
|
|
| uniforms.displacementMap.value = material.displacementMap; |
| uniforms.displacementScale.value = material.displacementScale; |
| uniforms.displacementBias.value = material.displacementBias; |
|
|
| } |
|
|
| } |
|
|
| function refreshUniformsDistance( uniforms, material ) { |
|
|
| if ( material.displacementMap ) { |
|
|
| uniforms.displacementMap.value = material.displacementMap; |
| uniforms.displacementScale.value = material.displacementScale; |
| uniforms.displacementBias.value = material.displacementBias; |
|
|
| } |
|
|
| uniforms.referencePosition.value.copy( material.referencePosition ); |
| uniforms.nearDistance.value = material.nearDistance; |
| uniforms.farDistance.value = material.farDistance; |
|
|
| } |
|
|
| function refreshUniformsNormal( uniforms, material ) { |
|
|
| if ( material.bumpMap ) { |
|
|
| uniforms.bumpMap.value = material.bumpMap; |
| uniforms.bumpScale.value = material.bumpScale; |
| if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; |
|
|
| } |
|
|
| if ( material.normalMap ) { |
|
|
| uniforms.normalMap.value = material.normalMap; |
| uniforms.normalScale.value.copy( material.normalScale ); |
| if ( material.side === BackSide ) uniforms.normalScale.value.negate(); |
|
|
| } |
|
|
| if ( material.displacementMap ) { |
|
|
| uniforms.displacementMap.value = material.displacementMap; |
| uniforms.displacementScale.value = material.displacementScale; |
| uniforms.displacementBias.value = material.displacementBias; |
|
|
| } |
|
|
| } |
|
|
| |
|
|
| function markUniformsLightsNeedsUpdate( uniforms, value ) { |
|
|
| uniforms.ambientLightColor.needsUpdate = value; |
|
|
| uniforms.directionalLights.needsUpdate = value; |
| uniforms.pointLights.needsUpdate = value; |
| uniforms.spotLights.needsUpdate = value; |
| uniforms.rectAreaLights.needsUpdate = value; |
| uniforms.hemisphereLights.needsUpdate = value; |
|
|
| } |
|
|
| |
|
|
| this.setFramebuffer = function ( value ) { |
|
|
| _framebuffer = value; |
|
|
| }; |
|
|
| this.getRenderTarget = function () { |
|
|
| return _currentRenderTarget; |
|
|
| }; |
|
|
| this.setRenderTarget = function ( renderTarget, activeCubeFace, activeMipMapLevel ) { |
|
|
| _currentRenderTarget = renderTarget; |
|
|
| if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { |
|
|
| textures.setupRenderTarget( renderTarget ); |
|
|
| } |
|
|
| var framebuffer = _framebuffer; |
| var isCube = false; |
|
|
| if ( renderTarget ) { |
|
|
| var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; |
|
|
| if ( renderTarget.isWebGLRenderTargetCube ) { |
|
|
| framebuffer = __webglFramebuffer[ activeCubeFace || 0 ]; |
| isCube = true; |
|
|
| } else if ( renderTarget.isWebGLMultisampleRenderTarget ) { |
|
|
| framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; |
|
|
| } else { |
|
|
| framebuffer = __webglFramebuffer; |
|
|
| } |
|
|
| _currentViewport.copy( renderTarget.viewport ); |
| _currentScissor.copy( renderTarget.scissor ); |
| _currentScissorTest = renderTarget.scissorTest; |
|
|
| } else { |
|
|
| _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); |
| _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); |
| _currentScissorTest = _scissorTest; |
|
|
| } |
|
|
| if ( _currentFramebuffer !== framebuffer ) { |
|
|
| _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); |
| _currentFramebuffer = framebuffer; |
|
|
| } |
|
|
| state.viewport( _currentViewport ); |
| state.scissor( _currentScissor ); |
| state.setScissorTest( _currentScissorTest ); |
|
|
| if ( isCube ) { |
|
|
| var textureProperties = properties.get( renderTarget.texture ); |
| _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + ( activeCubeFace || 0 ), textureProperties.__webglTexture, activeMipMapLevel || 0 ); |
|
|
| } |
|
|
| }; |
|
|
| this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { |
|
|
| if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { |
|
|
| console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); |
| return; |
|
|
| } |
|
|
| var framebuffer = properties.get( renderTarget ).__webglFramebuffer; |
|
|
| if ( framebuffer ) { |
|
|
| var restore = false; |
|
|
| if ( framebuffer !== _currentFramebuffer ) { |
|
|
| _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); |
|
|
| restore = true; |
|
|
| } |
|
|
| try { |
|
|
| var texture = renderTarget.texture; |
| var textureFormat = texture.format; |
| var textureType = texture.type; |
|
|
| if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { |
|
|
| console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); |
| return; |
|
|
| } |
|
|
| if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && |
| ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && |
| ! ( textureType === HalfFloatType && ( capabilities.isWebGL2 ? extensions.get( 'EXT_color_buffer_float' ) : extensions.get( 'EXT_color_buffer_half_float' ) ) ) ) { |
|
|
| console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); |
| return; |
|
|
| } |
|
|
| if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { |
|
|
| |
|
|
| if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { |
|
|
| _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); |
|
|
| } |
|
|
| } else { |
|
|
| console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); |
|
|
| } |
|
|
| } finally { |
|
|
| if ( restore ) { |
|
|
| _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); |
|
|
| } |
|
|
| } |
|
|
| } |
|
|
| }; |
|
|
| this.copyFramebufferToTexture = function ( position, texture, level ) { |
|
|
| var width = texture.image.width; |
| var height = texture.image.height; |
| var glFormat = utils.convert( texture.format ); |
|
|
| textures.setTexture2D( texture, 0 ); |
|
|
| _gl.copyTexImage2D( _gl.TEXTURE_2D, level || 0, glFormat, position.x, position.y, width, height, 0 ); |
|
|
| }; |
|
|
| this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level ) { |
|
|
| var width = srcTexture.image.width; |
| var height = srcTexture.image.height; |
| var glFormat = utils.convert( dstTexture.format ); |
| var glType = utils.convert( dstTexture.type ); |
|
|
| textures.setTexture2D( dstTexture, 0 ); |
|
|
| if ( srcTexture.isDataTexture ) { |
|
|
| _gl.texSubImage2D( _gl.TEXTURE_2D, level || 0, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); |
|
|
| } else { |
|
|
| _gl.texSubImage2D( _gl.TEXTURE_2D, level || 0, position.x, position.y, glFormat, glType, srcTexture.image ); |
|
|
| } |
|
|
| }; |
|
|
| } |
|
|
|
|
| export { WebGLRenderer }; |
|
|