添加关照、全局等高线、修改图层问题
This commit is contained in:
		
							
								
								
									
										751
									
								
								static/sdk/three/jsm/renderers/webgl/utils/WebGLTextureUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										751
									
								
								static/sdk/three/jsm/renderers/webgl/utils/WebGLTextureUtils.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,751 @@ | ||||
| import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, FloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, SRGBColorSpace, NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare } from 'three'; | ||||
|  | ||||
| let initialized = false, wrappingToGL, filterToGL, compareToGL; | ||||
|  | ||||
| class WebGLTextureUtils { | ||||
|  | ||||
| 	constructor( backend ) { | ||||
|  | ||||
| 		this.backend = backend; | ||||
|  | ||||
| 		this.gl = backend.gl; | ||||
| 		this.extensions = backend.extensions; | ||||
| 		this.defaultTextures = {}; | ||||
|  | ||||
| 		if ( initialized === false ) { | ||||
|  | ||||
| 			this._init( this.gl ); | ||||
|  | ||||
| 			initialized = true; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_init( gl ) { | ||||
|  | ||||
| 		// Store only WebGL constants here. | ||||
|  | ||||
| 		wrappingToGL = { | ||||
| 			[ RepeatWrapping ]: gl.REPEAT, | ||||
| 			[ ClampToEdgeWrapping ]: gl.CLAMP_TO_EDGE, | ||||
| 			[ MirroredRepeatWrapping ]: gl.MIRRORED_REPEAT | ||||
| 		}; | ||||
|  | ||||
| 		filterToGL = { | ||||
| 			[ NearestFilter ]: gl.NEAREST, | ||||
| 			[ NearestMipmapNearestFilter ]: gl.NEAREST_MIPMAP_NEAREST, | ||||
| 			[ NearestMipmapLinearFilter ]: gl.NEAREST_MIPMAP_LINEAR, | ||||
|  | ||||
| 			[ LinearFilter ]: gl.LINEAR, | ||||
| 			[ LinearMipmapNearestFilter ]: gl.LINEAR_MIPMAP_NEAREST, | ||||
| 			[ LinearMipmapLinearFilter ]: gl.LINEAR_MIPMAP_LINEAR | ||||
| 		}; | ||||
|  | ||||
| 		compareToGL = { | ||||
| 			[ NeverCompare ]: gl.NEVER, | ||||
| 			[ AlwaysCompare ]: gl.ALWAYS, | ||||
| 			[ LessCompare ]: gl.LESS, | ||||
| 			[ LessEqualCompare ]: gl.LEQUAL, | ||||
| 			[ EqualCompare ]: gl.EQUAL, | ||||
| 			[ GreaterEqualCompare ]: gl.GEQUAL, | ||||
| 			[ GreaterCompare ]: gl.GREATER, | ||||
| 			[ NotEqualCompare ]: gl.NOTEQUAL | ||||
| 		}; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	filterFallback( f ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
|  | ||||
| 		if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { | ||||
|  | ||||
| 			return gl.NEAREST; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return gl.LINEAR; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	getGLTextureType( texture ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
|  | ||||
| 		let glTextureType; | ||||
|  | ||||
| 		if ( texture.isCubeTexture === true ) { | ||||
|  | ||||
| 			glTextureType = gl.TEXTURE_CUBE_MAP; | ||||
|  | ||||
| 		} else if ( texture.isDataArrayTexture === true ) { | ||||
|  | ||||
| 			glTextureType = gl.TEXTURE_2D_ARRAY; | ||||
|  | ||||
| 		} else { | ||||
|  | ||||
| 			glTextureType = gl.TEXTURE_2D; | ||||
|  | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return glTextureType; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { | ||||
|  | ||||
| 		const { gl, extensions } = this; | ||||
|  | ||||
| 		if ( internalFormatName !== null ) { | ||||
|  | ||||
| 			if ( gl[ internalFormatName ] !== undefined ) return gl[ internalFormatName ]; | ||||
|  | ||||
| 			console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		let internalFormat = glFormat; | ||||
|  | ||||
| 		if ( glFormat === gl.RED ) { | ||||
|  | ||||
| 			if ( glType === gl.FLOAT ) internalFormat = gl.R32F; | ||||
| 			if ( glType === gl.HALF_FLOAT ) internalFormat = gl.R16F; | ||||
| 			if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.R8; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( glFormat === gl.RED_INTEGER ) { | ||||
|  | ||||
| 			if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.R8UI; | ||||
| 			if ( glType === gl.UNSIGNED_SHORT ) internalFormat = gl.R16UI; | ||||
| 			if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.R32UI; | ||||
| 			if ( glType === gl.BYTE ) internalFormat = gl.R8I; | ||||
| 			if ( glType === gl.SHORT ) internalFormat = gl.R16I; | ||||
| 			if ( glType === gl.INT ) internalFormat = gl.R32I; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( glFormat === gl.RG ) { | ||||
|  | ||||
| 			if ( glType === gl.FLOAT ) internalFormat = gl.RG32F; | ||||
| 			if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RG16F; | ||||
| 			if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RG8; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( glFormat === gl.RGB ) { | ||||
|  | ||||
| 			if ( glType === gl.FLOAT ) internalFormat = gl.RGB32F; | ||||
| 			if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RGB16F; | ||||
| 			if ( glType === gl.UNSIGNED_BYTE ) internalFormat = gl.RGB8; | ||||
| 			if ( glType === gl.UNSIGNED_SHORT_5_6_5 ) internalFormat = gl.RGB565; | ||||
| 			if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = gl.RGB5_A1; | ||||
| 			if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = gl.RGB4; | ||||
| 			if ( glType === gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = gl.RGB9_E5; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( glFormat === gl.RGBA ) { | ||||
|  | ||||
| 			if ( glType === gl.FLOAT ) internalFormat = gl.RGBA32F; | ||||
| 			if ( glType === gl.HALF_FLOAT ) internalFormat = gl.RGBA16F; | ||||
| 			if ( glType === gl.UNSIGNED_BYTE ) internalFormat = ( colorSpace === SRGBColorSpace && forceLinearTransfer === false ) ? gl.SRGB8_ALPHA8 : gl.RGBA8; | ||||
| 			if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = gl.RGBA4; | ||||
| 			if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = gl.RGB5_A1; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( glFormat === gl.DEPTH_COMPONENT ) { | ||||
|  | ||||
| 			if ( glType === gl.UNSIGNED_INT ) internalFormat = gl.DEPTH24_STENCIL8; | ||||
| 			if ( glType === gl.FLOAT ) internalFormat = gl.DEPTH_COMPONENT32F; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( glFormat === gl.DEPTH_STENCIL ) { | ||||
|  | ||||
| 			if ( glType === gl.UNSIGNED_INT_24_8 ) internalFormat = gl.DEPTH24_STENCIL8; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( internalFormat === gl.R16F || internalFormat === gl.R32F || | ||||
| 			internalFormat === gl.RG16F || internalFormat === gl.RG32F || | ||||
| 			internalFormat === gl.RGBA16F || internalFormat === gl.RGBA32F ) { | ||||
|  | ||||
| 			extensions.get( 'EXT_color_buffer_float' ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return internalFormat; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	setTextureParameters( textureType, texture ) { | ||||
|  | ||||
| 		const { gl, extensions, backend } = this; | ||||
|  | ||||
| 		const { currentAnisotropy } = backend.get( texture ); | ||||
|  | ||||
| 		gl.texParameteri( textureType, gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); | ||||
| 		gl.texParameteri( textureType, gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); | ||||
|  | ||||
| 		if ( textureType === gl.TEXTURE_3D || textureType === gl.TEXTURE_2D_ARRAY ) { | ||||
|  | ||||
| 			gl.texParameteri( textureType, gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		gl.texParameteri( textureType, gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); | ||||
|  | ||||
|  | ||||
| 		// follow WebGPU backend mapping for texture filtering | ||||
| 		const minFilter = ! texture.isVideoTexture && texture.minFilter === LinearFilter ? LinearMipmapLinearFilter : texture.minFilter; | ||||
|  | ||||
| 		gl.texParameteri( textureType, gl.TEXTURE_MIN_FILTER, filterToGL[ minFilter ] ); | ||||
|  | ||||
| 		if ( texture.compareFunction ) { | ||||
|  | ||||
| 			gl.texParameteri( textureType, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE ); | ||||
| 			gl.texParameteri( textureType, gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { | ||||
|  | ||||
| 			if ( texture.magFilter === NearestFilter ) return; | ||||
| 			if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; | ||||
| 			if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 | ||||
|  | ||||
| 			if ( texture.anisotropy > 1 || currentAnisotropy !== texture.anisotropy ) { | ||||
|  | ||||
| 				const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); | ||||
| 				gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, backend.getMaxAnisotropy() ) ); | ||||
| 				backend.get( texture ).currentAnisotropy = texture.anisotropy; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	createDefaultTexture( texture ) { | ||||
|  | ||||
| 		const { gl, backend, defaultTextures } = this; | ||||
|  | ||||
|  | ||||
| 		const glTextureType = this.getGLTextureType( texture ); | ||||
|  | ||||
| 		let textureGPU = defaultTextures[ glTextureType ]; | ||||
|  | ||||
| 		if ( textureGPU === undefined ) { | ||||
|  | ||||
| 			textureGPU = gl.createTexture(); | ||||
|  | ||||
| 			backend.state.bindTexture( glTextureType, textureGPU ); | ||||
| 			gl.texParameteri( glTextureType, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); | ||||
| 			gl.texParameteri( glTextureType, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); | ||||
|  | ||||
| 			// gl.texImage2D( glTextureType, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); | ||||
|  | ||||
| 			defaultTextures[ glTextureType ] = textureGPU; | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		backend.set( texture, { | ||||
| 			textureGPU, | ||||
| 			glTextureType, | ||||
| 			isDefault: true | ||||
| 		} ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	createTexture( texture, options ) { | ||||
|  | ||||
| 		const { gl, backend } = this; | ||||
| 		const { levels, width, height, depth } = options; | ||||
|  | ||||
| 		const glFormat = backend.utils.convert( texture.format, texture.colorSpace ); | ||||
| 		const glType = backend.utils.convert( texture.type ); | ||||
| 		const glInternalFormat = this.getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); | ||||
|  | ||||
| 		const textureGPU = gl.createTexture(); | ||||
| 		const glTextureType = this.getGLTextureType( texture ); | ||||
|  | ||||
| 		backend.state.bindTexture( glTextureType, textureGPU ); | ||||
|  | ||||
| 		gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); | ||||
| 		gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); | ||||
| 		gl.pixelStorei( gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); | ||||
| 		gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE ); | ||||
|  | ||||
| 		this.setTextureParameters( glTextureType, texture ); | ||||
|  | ||||
| 		if ( texture.isDataArrayTexture ) { | ||||
|  | ||||
| 			gl.texStorage3D( gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, width, height, depth ); | ||||
|  | ||||
| 		} else if ( ! texture.isVideoTexture ) { | ||||
|  | ||||
| 			gl.texStorage2D( glTextureType, levels, glInternalFormat, width, height ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		backend.set( texture, { | ||||
| 			textureGPU, | ||||
| 			glTextureType, | ||||
| 			glFormat, | ||||
| 			glType, | ||||
| 			glInternalFormat | ||||
| 		} ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	copyBufferToTexture( buffer, texture ) { | ||||
|  | ||||
| 		const { gl, backend } = this; | ||||
|  | ||||
| 		const { textureGPU, glTextureType, glFormat, glType } = backend.get( texture ); | ||||
|  | ||||
| 		const { width, height } = texture.source.data; | ||||
|  | ||||
| 		gl.bindBuffer( gl.PIXEL_UNPACK_BUFFER, buffer ); | ||||
|  | ||||
| 		backend.state.bindTexture( glTextureType, textureGPU ); | ||||
|  | ||||
| 		gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false ); | ||||
| 		gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false ); | ||||
| 		gl.texSubImage2D( glTextureType, 0, 0, 0, width, height, glFormat, glType, 0 ); | ||||
|  | ||||
| 		gl.bindBuffer( gl.PIXEL_UNPACK_BUFFER, null ); | ||||
|  | ||||
| 		backend.state.unbindTexture(); | ||||
| 		// debug | ||||
| 		// const framebuffer = gl.createFramebuffer(); | ||||
| 		// gl.bindFramebuffer( gl.FRAMEBUFFER, framebuffer ); | ||||
| 		// gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, glTextureType, textureGPU, 0 ); | ||||
|  | ||||
| 		// const readout = new Float32Array( width * height * 4 ); | ||||
|  | ||||
| 		// const altFormat = gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ); | ||||
| 		// const altType = gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ); | ||||
|  | ||||
| 		// gl.readPixels( 0, 0, width, height, altFormat, altType, readout ); | ||||
| 		// gl.bindFramebuffer( gl.FRAMEBUFFER, null ); | ||||
| 		// console.log( readout ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	updateTexture( texture, options ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
| 		const { width, height } = options; | ||||
| 		const { textureGPU, glTextureType, glFormat, glType, glInternalFormat } = this.backend.get( texture ); | ||||
|  | ||||
| 		if ( texture.isRenderTargetTexture || ( textureGPU === undefined /* unsupported texture format */ ) ) | ||||
| 			return; | ||||
|  | ||||
| 		const getImage = ( source ) => { | ||||
|  | ||||
| 			if ( source.isDataTexture ) { | ||||
|  | ||||
| 				return source.image.data; | ||||
|  | ||||
| 			} else if ( source instanceof ImageBitmap || source instanceof OffscreenCanvas || source instanceof HTMLImageElement || source instanceof HTMLCanvasElement ) { | ||||
|  | ||||
| 				return source; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			return source.data; | ||||
|  | ||||
| 		}; | ||||
|  | ||||
| 		this.backend.state.bindTexture( glTextureType, textureGPU ); | ||||
|  | ||||
| 		if ( texture.isCompressedTexture ) { | ||||
|  | ||||
| 			const mipmaps = texture.mipmaps; | ||||
|  | ||||
| 			for ( let i = 0; i < mipmaps.length; i ++ ) { | ||||
|  | ||||
| 				const mipmap = mipmaps[ i ]; | ||||
|  | ||||
| 				if ( texture.isCompressedArrayTexture ) { | ||||
|  | ||||
| 					const image = options.image; | ||||
|  | ||||
| 					if ( texture.format !== gl.RGBA ) { | ||||
|  | ||||
| 						if ( glFormat !== null ) { | ||||
|  | ||||
| 							gl.compressedTexSubImage3D( gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); | ||||
|  | ||||
|  | ||||
| 						} else { | ||||
|  | ||||
| 							console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); | ||||
|  | ||||
| 						} | ||||
|  | ||||
| 					} else { | ||||
|  | ||||
| 						gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); | ||||
|  | ||||
| 					} | ||||
|  | ||||
| 				} else { | ||||
|  | ||||
| 					if ( glFormat !== null ) { | ||||
|  | ||||
| 						gl.compressedTexSubImage2D( gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); | ||||
|  | ||||
| 					} else { | ||||
|  | ||||
| 						console.warn( 'Unsupported compressed texture format' ); | ||||
|  | ||||
| 					} | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 		} else if ( texture.isCubeTexture ) { | ||||
|  | ||||
| 			const images = options.images; | ||||
|  | ||||
| 			for ( let i = 0; i < 6; i ++ ) { | ||||
|  | ||||
| 				const image = getImage( images[ i ] ); | ||||
|  | ||||
| 				gl.texSubImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, width, height, glFormat, glType, image ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 		} else if ( texture.isDataArrayTexture ) { | ||||
|  | ||||
| 			const image = options.image; | ||||
|  | ||||
| 			gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); | ||||
|  | ||||
| 		} else if ( texture.isVideoTexture ) { | ||||
|  | ||||
| 			texture.update(); | ||||
|  | ||||
| 			gl.texImage2D( glTextureType, 0, glInternalFormat, glFormat, glType, options.image ); | ||||
|  | ||||
|  | ||||
| 		} else { | ||||
|  | ||||
| 			const image = getImage( options.image ); | ||||
|  | ||||
| 			gl.texSubImage2D( glTextureType, 0, 0, 0, width, height, glFormat, glType, image ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	generateMipmaps( texture ) { | ||||
|  | ||||
| 		const { gl, backend } = this; | ||||
| 		const { textureGPU, glTextureType } = backend.get( texture ); | ||||
|  | ||||
| 		backend.state.bindTexture( glTextureType, textureGPU ); | ||||
| 		gl.generateMipmap( glTextureType ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	deallocateRenderBuffers( renderTarget ) { | ||||
|  | ||||
|  | ||||
| 		const { gl, backend } = this; | ||||
|  | ||||
| 		// remove framebuffer reference | ||||
| 		if ( renderTarget ) { | ||||
|  | ||||
| 			const renderContextData = backend.get( renderTarget ); | ||||
|  | ||||
| 			renderContextData.renderBufferStorageSetup = undefined; | ||||
|  | ||||
| 			if ( renderContextData.framebuffer ) { | ||||
|  | ||||
| 				gl.deleteFramebuffer( renderContextData.framebuffer ); | ||||
| 				renderContextData.framebuffer = undefined; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			if ( renderContextData.depthRenderbuffer ) { | ||||
|  | ||||
| 				gl.deleteRenderbuffer( renderContextData.depthRenderbuffer ); | ||||
| 				renderContextData.depthRenderbuffer = undefined; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			if ( renderContextData.stencilRenderbuffer ) { | ||||
|  | ||||
| 				gl.deleteRenderbuffer( renderContextData.stencilRenderbuffer ); | ||||
| 				renderContextData.stencilRenderbuffer = undefined; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			if ( renderContextData.msaaFrameBuffer ) { | ||||
|  | ||||
| 				gl.deleteFramebuffer( renderContextData.msaaFrameBuffer ); | ||||
| 				renderContextData.msaaFrameBuffer = undefined; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			if ( renderContextData.msaaRenderbuffers ) { | ||||
|  | ||||
| 				for ( let i = 0; i < renderContextData.msaaRenderbuffers.length; i ++ ) { | ||||
|  | ||||
| 					gl.deleteRenderbuffer( renderContextData.msaaRenderbuffers[ i ] ); | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				renderContextData.msaaRenderbuffers = undefined; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	destroyTexture( texture ) { | ||||
|  | ||||
| 		const { gl, backend } = this; | ||||
| 		const { textureGPU, renderTarget } = backend.get( texture ); | ||||
|  | ||||
| 		this.deallocateRenderBuffers( renderTarget ); | ||||
| 		gl.deleteTexture( textureGPU ); | ||||
|  | ||||
| 		backend.delete( texture ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	copyTextureToTexture( position, srcTexture, dstTexture, level = 0 ) { | ||||
|  | ||||
| 		const { gl, backend } = this; | ||||
| 		const { state } = this.backend; | ||||
|  | ||||
| 		const width = srcTexture.image.width; | ||||
| 		const height = srcTexture.image.height; | ||||
| 		const { textureGPU: dstTextureGPU, glTextureType, glType, glFormat } = backend.get( dstTexture ); | ||||
|  | ||||
| 		state.bindTexture( glTextureType, dstTextureGPU ); | ||||
|  | ||||
| 		// As another texture upload may have changed pixelStorei | ||||
| 		// parameters, make sure they are correct for the dstTexture | ||||
| 		gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); | ||||
| 		gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); | ||||
| 		gl.pixelStorei( gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); | ||||
|  | ||||
| 		if ( srcTexture.isDataTexture ) { | ||||
|  | ||||
| 			gl.texSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); | ||||
|  | ||||
| 		} else { | ||||
|  | ||||
| 			if ( srcTexture.isCompressedTexture ) { | ||||
|  | ||||
| 				gl.compressedTexSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); | ||||
|  | ||||
| 			} else { | ||||
|  | ||||
| 				gl.texSubImage2D( gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		// Generate mipmaps only when copying level 0 | ||||
| 		if ( level === 0 && dstTexture.generateMipmaps ) gl.generateMipmap( gl.TEXTURE_2D ); | ||||
|  | ||||
| 		state.unbindTexture(); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	copyFramebufferToTexture( texture, renderContext ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
| 		const { state } = this.backend; | ||||
|  | ||||
| 		const { textureGPU } = this.backend.get( texture ); | ||||
|  | ||||
| 		const width = texture.image.width; | ||||
| 		const height = texture.image.height; | ||||
|  | ||||
| 		const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 ); | ||||
|  | ||||
| 		if ( requireDrawFrameBuffer ) { | ||||
|  | ||||
| 			let mask; | ||||
| 			let attachment; | ||||
|  | ||||
| 			if ( texture.isDepthTexture === true ) { | ||||
|  | ||||
| 				mask = gl.DEPTH_BUFFER_BIT; | ||||
| 				attachment = gl.DEPTH_ATTACHMENT; | ||||
|  | ||||
| 				if ( renderContext.stencil ) { | ||||
|  | ||||
| 					mask |= gl.STENCIL_BUFFER_BIT; | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 			} else { | ||||
|  | ||||
| 				mask = gl.COLOR_BUFFER_BIT; | ||||
| 				attachment = gl.COLOR_ATTACHMENT0; | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			const fb = gl.createFramebuffer(); | ||||
| 			state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); | ||||
|  | ||||
| 			gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureGPU, 0 ); | ||||
|  | ||||
| 			gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, gl.NEAREST ); | ||||
|  | ||||
| 			gl.deleteFramebuffer( fb ); | ||||
|  | ||||
| 		} else { | ||||
|  | ||||
| 			state.bindTexture( gl.TEXTURE_2D, textureGPU ); | ||||
| 			gl.copyTexSubImage2D( gl.TEXTURE_2D, 0, 0, 0, 0, 0, width, height ); | ||||
|  | ||||
| 			state.unbindTexture(); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if ( texture.generateMipmaps ) this.generateMipmaps( texture ); | ||||
|  | ||||
| 		this.backend._setFramebuffer( renderContext ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	// Setup storage for internal depth/stencil buffers and bind to correct framebuffer | ||||
| 	setupRenderBufferStorage( renderbuffer, renderContext ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
| 		const renderTarget = renderContext.renderTarget; | ||||
|  | ||||
| 		const { samples, depthTexture, depthBuffer, stencilBuffer, width, height } = renderTarget; | ||||
|  | ||||
| 		gl.bindRenderbuffer( gl.RENDERBUFFER, renderbuffer ); | ||||
|  | ||||
| 		if ( depthBuffer && ! stencilBuffer ) { | ||||
|  | ||||
| 			let glInternalFormat = gl.DEPTH_COMPONENT24; | ||||
|  | ||||
| 			if ( samples > 0 ) { | ||||
|  | ||||
| 				if ( depthTexture && depthTexture.isDepthTexture ) { | ||||
|  | ||||
| 					if ( depthTexture.type === gl.FLOAT ) { | ||||
|  | ||||
| 						glInternalFormat = gl.DEPTH_COMPONENT32F; | ||||
|  | ||||
| 					} | ||||
|  | ||||
| 				} | ||||
|  | ||||
| 				gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, glInternalFormat, width, height ); | ||||
|  | ||||
| 			} else { | ||||
|  | ||||
| 				gl.renderbufferStorage( gl.RENDERBUFFER, glInternalFormat, width, height ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
| 			gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer ); | ||||
|  | ||||
| 		} else if ( depthBuffer && stencilBuffer ) { | ||||
|  | ||||
| 			if ( samples > 0 ) { | ||||
|  | ||||
| 				gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, width, height ); | ||||
|  | ||||
| 			} else { | ||||
|  | ||||
| 				gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height ); | ||||
|  | ||||
| 			} | ||||
|  | ||||
|  | ||||
| 			gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderbuffer ); | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	async copyTextureToBuffer( texture, x, y, width, height ) { | ||||
|  | ||||
| 		const { backend, gl } = this; | ||||
|  | ||||
| 		const { textureGPU, glFormat, glType } = this.backend.get( texture ); | ||||
|  | ||||
| 		const fb = gl.createFramebuffer(); | ||||
|  | ||||
| 		gl.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); | ||||
| 		gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureGPU, 0 ); | ||||
|  | ||||
| 		const typedArrayType = this._getTypedArrayType( glType ); | ||||
| 		const bytesPerTexel = this._getBytesPerTexel( glFormat ); | ||||
|  | ||||
| 		const elementCount = width * height; | ||||
| 		const byteLength = elementCount * bytesPerTexel; | ||||
|  | ||||
| 		const buffer = gl.createBuffer(); | ||||
|  | ||||
| 		gl.bindBuffer( gl.PIXEL_PACK_BUFFER, buffer ); | ||||
| 		gl.bufferData( gl.PIXEL_PACK_BUFFER, byteLength, gl.STREAM_READ ); | ||||
| 		gl.readPixels( x, y, width, height, glFormat, glType, 0 ); | ||||
| 		gl.bindBuffer( gl.PIXEL_PACK_BUFFER, null ); | ||||
|  | ||||
| 		await backend.utils._clientWaitAsync(); | ||||
|  | ||||
| 		const dstBuffer = new typedArrayType( byteLength / typedArrayType.BYTES_PER_ELEMENT ); | ||||
|  | ||||
| 		gl.bindBuffer( gl.PIXEL_PACK_BUFFER, buffer ); | ||||
| 		gl.getBufferSubData( gl.PIXEL_PACK_BUFFER, 0, dstBuffer ); | ||||
| 		gl.bindBuffer( gl.PIXEL_PACK_BUFFER, null ); | ||||
|  | ||||
| 		gl.deleteFramebuffer( fb ); | ||||
|  | ||||
| 		return dstBuffer; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_getTypedArrayType( glType ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
|  | ||||
| 		if ( glType === gl.UNSIGNED_BYTE ) return Uint8Array; | ||||
|  | ||||
| 		if ( glType === gl.UNSIGNED_SHORT_4_4_4_4 ) return Uint16Array; | ||||
| 		if ( glType === gl.UNSIGNED_SHORT_5_5_5_1 ) return Uint16Array; | ||||
| 		if ( glType === gl.UNSIGNED_SHORT_5_6_5 ) return Uint16Array; | ||||
| 		if ( glType === gl.UNSIGNED_SHORT ) return Uint16Array; | ||||
| 		if ( glType === gl.UNSIGNED_INT ) return Uint32Array; | ||||
|  | ||||
| 		if ( glType === gl.FLOAT ) return Float32Array; | ||||
|  | ||||
| 		throw new Error( `Unsupported WebGL type: ${glType}` ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	_getBytesPerTexel( glFormat ) { | ||||
|  | ||||
| 		const { gl } = this; | ||||
|  | ||||
| 		if ( glFormat === gl.RGBA ) return 4; | ||||
| 		if ( glFormat === gl.RGB ) return 3; | ||||
| 		if ( glFormat === gl.ALPHA ) return 1; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| export default WebGLTextureUtils; | ||||
		Reference in New Issue
	
	Block a user