Quellcode durchsuchen

WebGPURenderer: Add Anisotropy Support & Resolve Scissor Issues in WebGL Backend (#27609)

* fix anisotropy and stencil

* puppeteer doesnt like webgpu
Renaud Rohlinger vor 1 Jahr
Ursprung
Commit
ce36e0d140

+ 2 - 1
examples/files.json

@@ -369,7 +369,8 @@
 		"webgpu_tsl_transpiler",
 		"webgpu_video_panorama",
 		"webgpu_postprocessing_afterimage",
-		"webgpu_multisampled_renderbuffers"
+		"webgpu_multisampled_renderbuffers",
+		"webgpu_materials_texture_anisotropy"
 	],
 	"webaudio": [
 		"webaudio_orientation",

+ 2 - 0
examples/jsm/renderers/common/Backend.js

@@ -120,6 +120,8 @@ class Backend {
 
 	}
 
+	setScissorTest( boolean ) { }
+
 	getClearColor() {
 
 		const renderer = this.renderer;

+ 2 - 0
examples/jsm/renderers/common/Renderer.js

@@ -522,6 +522,8 @@ class Renderer {
 
 		this._scissorTest = boolean;
 
+		this.backend.setScissorTest( boolean );
+
 	}
 
 	getViewport( target ) {

+ 28 - 3
examples/jsm/renderers/webgl/WebGLBackend.js

@@ -96,6 +96,14 @@ class WebGLBackend extends Backend {
 
 		}
 
+		if ( renderContext.scissor ) {
+
+			const { x, y, width, height } = renderContext.scissorValue;
+
+			gl.scissor( x, y, width, height );
+
+		}
+
 		const occlusionQueryCount = renderContext.occlusionQueryCount;
 
 		if ( occlusionQueryCount > 0 ) {
@@ -288,6 +296,22 @@ class WebGLBackend extends Backend {
 
 	}
 
+	setScissorTest( boolean ) {
+
+		const gl = this.gl;
+
+		if ( boolean ) {
+
+			gl.enable( gl.SCISSOR_TEST );
+
+		} else {
+
+			gl.disable( gl.SCISSOR_TEST );
+
+		}
+
+	}
+
 	clear( color, depth, stencil, descriptor = null ) {
 
 		const { gl } = this;
@@ -364,18 +388,19 @@ class WebGLBackend extends Backend {
 
 		const gl = this.gl;
 
-		if ( ! this.discard )  {
+		if ( ! this.discard ) {
 
 			// required here to handle async behaviour of render.compute()
 			gl.enable( gl.RASTERIZER_DISCARD );
 			this.discard = true;
+
 		}
 
 		const { programGPU, transformBuffers, attributes } = this.get( pipeline );
 
 		const vaoKey = this._getVaoKey( null, attributes );
 
-		let vaoGPU = this.vaoCache[ vaoKey ];
+		const vaoGPU = this.vaoCache[ vaoKey ];
 
 		if ( vaoGPU === undefined ) {
 
@@ -709,7 +734,7 @@ class WebGLBackend extends Backend {
 
 		const fragmentProgram = {
 			stage: 'fragment',
-			code: "#version 300 es\nprecision highp float;\nvoid main() {}"
+			code: '#version 300 es\nprecision highp float;\nvoid main() {}'
 		};
 
 		this.createProgram( fragmentProgram );

+ 7 - 5
examples/jsm/renderers/webgl/utils/WebGLTextureUtils.js

@@ -172,7 +172,9 @@ class WebGLTextureUtils {
 
 	setTextureParameters( textureType, texture ) {
 
-		const { gl, extensions } = this;
+		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 ] );
@@ -200,16 +202,16 @@ class WebGLTextureUtils {
 
 		if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
 
-			//extension = extensions.get( 'EXT_texture_filter_anisotropic' );
+			const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
 
 			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 /*|| properties.get( texture ).__currentAnisotropy*/ ) {
+			if ( texture.anisotropy > 1 || currentAnisotropy !== texture.anisotropy ) {
 
-				//gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
-				//properties.get( texture ).__currentAnisotropy = texture.anisotropy;
+				gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, backend.getMaxAnisotropy() ) );
+				backend.get( texture ).currentAnisotropy = texture.anisotropy;
 
 			}
 

BIN
examples/screenshots/webgpu_materials_texture_anisotropy.jpg


+ 245 - 0
examples/webgpu_materials_texture_anisotropy.html

@@ -0,0 +1,245 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgpu - materials - anisotropic texture filtering</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+		<style>
+			body {
+				color: #444;
+				background-color: #f1f1f1;
+			}
+			a {
+				color: #08f;
+			}
+
+			.lbl {
+				color: #fff;
+				font-size: 16px;
+				font-weight: bold;
+				position: absolute;
+				bottom: 0px;
+				z-index: 100;
+				text-shadow: #000 1px 1px 1px;
+				background-color: rgba(0,0,0,0.85);
+				padding: 1em;
+			}
+
+			#lbl_left {
+				text-align:left;
+				left:0px;
+			}
+
+			#lbl_right {
+				text-align:left;
+				right:0px
+			}
+
+			.g { color:#aaa }
+			.c { color:#fa0 }
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - anisotropic texture filtering example
+		</div>
+
+		<div id="lbl_left" class="lbl">
+		anisotropy: <span class="c" id="val_left"></span><br/>
+		</div>
+
+		<div id="lbl_right" class="lbl">
+		anisotropy: <span class="c" id="val_right"></span><br/>
+		</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import Stats from 'three/addons/libs/stats.module.js';
+			import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
+
+
+			let container, stats;
+
+			let camera, scene1, scene2, renderer;
+
+			let mouseX = 0, mouseY = 0;
+
+
+			init().then( () => animate() );
+
+
+			async function init() {
+
+				const SCREEN_WIDTH = window.innerWidth;
+				const SCREEN_HEIGHT = window.innerHeight;
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				renderer = new WebGPURenderer( { antialias: true, forceWebGL: false } );
+
+				await renderer.init();
+				// RENDERER
+
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
+				renderer.autoClear = false;
+
+				renderer.domElement.style.position = 'relative';
+				container.appendChild( renderer.domElement );
+
+				//
+
+				camera = new THREE.PerspectiveCamera( 35, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 25000 );
+				camera.position.z = 1500;
+
+				scene1 = new THREE.Scene();
+				scene1.fog = new THREE.Fog( 0xf2f7ff, 1, 25000 );
+
+				scene2 = new THREE.Scene();
+				scene2.fog = new THREE.Fog( 0xf2f7ff, 1, 25000 );
+
+				scene1.add( new THREE.AmbientLight( 0xeef0ff, 3 ) );
+				scene2.add( new THREE.AmbientLight( 0xeef0ff, 3 ) );
+
+				const light1 = new THREE.DirectionalLight( 0xffffff, 6 );
+				light1.position.set( 1, 1, 1 );
+				scene1.add( light1 );
+
+				const light2 = new THREE.DirectionalLight( 0xffffff, 6 );
+				light2.position.set( 1, 1, 1 );
+				scene2.add( light2 );
+
+				// GROUND
+
+				const textureLoader = new THREE.TextureLoader();
+
+				const maxAnisotropy = renderer.getMaxAnisotropy();
+
+				const texture1 = textureLoader.load( 'textures/crate.gif' );
+				const material1 = new THREE.MeshPhongMaterial( { color: 0xffffff, map: texture1 } );
+
+
+				texture1.colorSpace = THREE.SRGBColorSpace;
+				texture1.anisotropy = renderer.getMaxAnisotropy();
+				texture1.wrapS = texture1.wrapT = THREE.RepeatWrapping;
+				texture1.repeat.set( 512, 512 );
+
+				const texture2 = textureLoader.load( 'textures/crate.gif' );
+				const material2 = new THREE.MeshPhongMaterial( { color: 0xffffff, map: texture2 } );
+
+				texture2.colorSpace = THREE.SRGBColorSpace;
+				texture2.anisotropy = 1;
+				texture2.wrapS = texture2.wrapT = THREE.RepeatWrapping;
+				texture2.repeat.set( 512, 512 );
+
+				if ( maxAnisotropy > 0 ) {
+
+					document.getElementById( 'val_left' ).innerHTML = texture1.anisotropy;
+					document.getElementById( 'val_right' ).innerHTML = texture2.anisotropy;
+
+				} else {
+
+					document.getElementById( 'val_left' ).innerHTML = 'not supported';
+					document.getElementById( 'val_right' ).innerHTML = 'not supported';
+
+				}
+
+				//
+
+				const geometry = new THREE.PlaneGeometry( 100, 100 );
+
+				const mesh1 = new THREE.Mesh( geometry, material1 );
+				mesh1.rotation.x = - Math.PI / 2;
+				mesh1.scale.set( 1000, 1000, 1000 );
+
+				const mesh2 = new THREE.Mesh( geometry, material2 );
+				mesh2.rotation.x = - Math.PI / 2;
+				mesh2.scale.set( 1000, 1000, 1000 );
+
+				scene1.add( mesh1 );
+				scene2.add( mesh2 );
+
+				// STATS1
+
+				stats = new Stats();
+				container.appendChild( stats.dom );
+
+				document.addEventListener( 'mousemove', onDocumentMouseMove );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function onDocumentMouseMove( event ) {
+
+				const windowHalfX = window.innerWidth / 2;
+				const windowHalfY = window.innerHeight / 2;
+
+				mouseX = ( event.clientX - windowHalfX );
+				mouseY = ( event.clientY - windowHalfY );
+
+			}
+
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				const SCREEN_WIDTH = window.innerWidth;
+	const SCREEN_HEIGHT = window.innerHeight;
+
+				camera.position.x += ( mouseX - camera.position.x ) * .05;
+				camera.position.y = THREE.MathUtils.clamp( camera.position.y + ( - ( mouseY - 200 ) - camera.position.y ) * .05, 50, 1000 );
+
+				camera.lookAt( scene1.position );
+				renderer.clear();
+
+				renderer.setScissorTest( true );
+
+				renderer.setScissor( 0, 0, SCREEN_WIDTH / 2 - 2, SCREEN_HEIGHT );
+				renderer.render( scene1, camera );
+
+				renderer.setScissorTest( true );
+
+				renderer.setScissor( SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 2 - 2, SCREEN_HEIGHT );
+				renderer.render( scene2, camera );
+
+				// renderer.setScissorTest( false );
+
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 2 - 1
test/e2e/puppeteer.js

@@ -140,7 +140,8 @@ const exceptionList = [
 	'webgpu_compute_particles',
 	'webgpu_compute_particles_rain',
 	'webgpu_compute_particles_snow',
-	'webgpu_compute_points'
+	'webgpu_compute_points',
+	'webgpu_materials_texture_anisotropy'
 
 ];