Explorar o código

WebGLRenderer: Add `WEBGL_clip_cull_distance` support. (#27371)

* init WEBGL_clip_cull_distance support

* remove unecessary conditions webgl2

* try fix directx

* feedbacks

* remove unecessary code

* Update webgl_clipculldistance.html

Style clean up.

* Update WebGLExtensions.js

* Update webgl_clipculldistance.html

* replace material with shader

* remove unused time const

* Update webgl_clipculldistance.html

Simplify example.

* Update clipping example.

* Revert builds.

* ShaderMaterial: Update `extensions` and docs.

---------

Co-authored-by: Michael Herzog <[email protected]>
Renaud Rohlinger hai 1 ano
pai
achega
f765d87b6f

+ 2 - 2
docs/api/ar/materials/ShaderMaterial.html

@@ -327,8 +327,8 @@ this.extensions = {
 	derivatives: false, // set to use derivatives
 	fragDepth: false, // set to use fragment depth values 
 	drawBuffers: false, // set to use draw buffers 
-	shaderTextureLOD: false // set to use
-	shader texture LOD 
+	shaderTextureLOD: false, // set to use shader texture LOD
+	clipCullDistance: false // set to use vertex shader clipping
 };
 			</code>
 		</p>

+ 2 - 2
docs/api/en/materials/ShaderMaterial.html

@@ -345,8 +345,8 @@ this.extensions = {
 	derivatives: false, // set to use derivatives
 	fragDepth: false, // set to use fragment depth values 
 	drawBuffers: false, // set to use draw buffers 
-	shaderTextureLOD: false // set to use
-	shader texture LOD 
+	shaderTextureLOD: false, // set to use shader texture LOD
+	clipCullDistance: false // set to use vertex shader clipping
 };
 			</code>
 		</p>

+ 2 - 1
docs/api/fr/materials/ShaderMaterial.html

@@ -316,7 +316,8 @@ et la page [page:BufferAttribute] pour un aperçu détaillé de l'API `BufferAtt
 				derivatives: false, // set to use derivatives
 				fragDepth: false, // set to use fragment depth values
 				drawBuffers: false, // set to use draw buffers
-				shaderTextureLOD: false // set to use shader texture LOD
+				shaderTextureLOD: false, // set to use shader texture LOD
+				clipCullDistance: false // set to use vertex shader clipping
 			};
 		</code>
 		</p>

+ 2 - 1
docs/api/it/materials/ShaderMaterial.html

@@ -321,7 +321,8 @@ this.extensions = {
 	derivatives: false, // impostato per utilizzare le direttive
 	fragDepth: false, // impostato per utilizzare i valori di profondità del frammento
 	drawBuffers: false, // impostato per utilizzare i buffer di disegno
-	shaderTextureLOD: false // impostato per utilizzare la texture dello shader LOD
+	shaderTextureLOD: false, // impostato per utilizzare la texture dello shader LOD
+	clipCullDistance: false // set to use vertex shader clipping
 };
 		</code>
 		</p>

+ 2 - 1
docs/api/zh/materials/ShaderMaterial.html

@@ -283,7 +283,8 @@ this.extensions = {
 	derivatives: false, // set to use derivatives
 	fragDepth: false, // set to use fragment depth values
 	drawBuffers: false, // set to use draw buffers
-	shaderTextureLOD: false // set to use shader texture LOD
+	shaderTextureLOD: false, // set to use shader texture LOD
+	clipCullDistance: false // set to use vertex shader clipping
 };
 		</code>
 		</p>

+ 1 - 0
examples/files.json

@@ -299,6 +299,7 @@
 	"webgl2": [
 		"webgl2_buffergeometry_attributes_integer",
 		"webgl2_buffergeometry_attributes_none",
+		"webgl2_clipculldistance",
 		"webgl2_materials_texture2darray",
 		"webgl2_materials_texture3d",
 		"webgl2_materials_texture3d_partialupdate",

BIN=BIN
examples/screenshots/webgl2_clipculldistance.jpg


+ 189 - 0
examples/webgl2_clipculldistance.html

@@ -0,0 +1,189 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js WebGL 2 - clip cull distance</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" />
+	</head>
+	<body>
+		<div id="container"></div>
+
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener" >three.js</a> - vertex shader clipping via
+			<a href="https://registry.khronos.org/webgl/extensions/WEBGL_clip_cull_distance/" target="_blank" rel="noopener" >WEBGL_clip_cull_distance</a>
+			<div id="notSupported" style="display:none">WEBGL_clip_cull_distance not supported</div>
+		</div>
+
+		<script id="vertexShader" type="x-shader/x-vertex">
+
+			uniform float time;
+
+			varying vec4 vColor;
+
+			void main() {
+
+				vColor = color;
+
+				#ifdef USE_CLIP_DISTANCE
+					vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
+					gl_ClipDistance[ 0 ] = worldPosition.x - sin( time ) * ( 0.5 );
+				#endif
+
+				gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+
+			}
+
+		</script>
+
+		<script id="fragmentShader" type="x-shader/x-fragment">
+
+			varying vec4 vColor;
+
+			void main() {
+
+				gl_FragColor = vColor;
+
+			}
+
+		</script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+			import * as THREE from 'three';
+			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+			import Stats from 'three/addons/libs/stats.module.js';
+
+			let camera, controls, clock, scene, renderer, stats;
+
+			let material;
+
+			init();
+			animate();
+
+			function init() {
+
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10 );
+				camera.position.z = 2;
+
+				scene = new THREE.Scene();
+
+				clock = new THREE.Clock();
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				if ( renderer.extensions.has( 'WEBGL_clip_cull_distance' ) === false ) {
+
+					document.getElementById( 'notSupported' ).style.display = '';
+					return;
+
+				}
+
+				const ext = renderer
+					.getContext()
+					.getExtension( 'WEBGL_clip_cull_distance' );
+				const gl = renderer.getContext();
+
+				gl.enable( ext.CLIP_DISTANCE0_WEBGL );
+
+				// geometry
+
+				const vertexCount = 200 * 3;
+
+				const geometry = new THREE.BufferGeometry();
+
+				const positions = [];
+				const colors = [];
+
+				for ( let i = 0; i < vertexCount; i ++ ) {
+
+					// adding x,y,z
+					positions.push( Math.random() - 0.5 );
+					positions.push( Math.random() - 0.5 );
+					positions.push( Math.random() - 0.5 );
+
+					// adding r,g,b,a
+					colors.push( Math.random() * 255 );
+					colors.push( Math.random() * 255 );
+					colors.push( Math.random() * 255 );
+					colors.push( Math.random() * 255 );
+
+				}
+
+				const positionAttribute = new THREE.Float32BufferAttribute( positions, 3 );
+				const colorAttribute = new THREE.Uint8BufferAttribute( colors, 4 );
+				colorAttribute.normalized = true;
+
+				geometry.setAttribute( 'position', positionAttribute );
+				geometry.setAttribute( 'color', colorAttribute );
+
+				// material
+
+				material = new THREE.ShaderMaterial( {
+
+					uniforms: {
+						time: { value: 1.0 }
+					},
+					vertexShader: document.getElementById( 'vertexShader' ).textContent,
+					fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
+					side: THREE.DoubleSide,
+					transparent: true,
+					vertexColors: true
+
+				} );
+
+				material.extensions.clipCullDistance = true;
+
+				const mesh = new THREE.Mesh( geometry, material );
+				scene.add( mesh );
+
+				//
+
+				controls = new OrbitControls( camera, renderer.domElement );
+
+				//
+
+				stats = new Stats();
+				document.body.appendChild( stats.dom );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				controls.update();
+				stats.update();
+
+				material.uniforms.time.value = clock.getElapsedTime();
+
+				renderer.render( scene, camera );
+
+			}
+		</script>
+	</body>
+</html>

+ 2 - 1
src/materials/ShaderMaterial.js

@@ -36,7 +36,8 @@ class ShaderMaterial extends Material {
 			derivatives: false, // set to use derivatives
 			fragDepth: false, // set to use fragment depth values
 			drawBuffers: false, // set to use draw buffers
-			shaderTextureLOD: false // set to use shader texture LOD
+			shaderTextureLOD: false, // set to use shader texture LOD
+			clipCullDistance: false // set to use vertex shader clipping
 		};
 
 		// When rendered geometry doesn't include these attributes but the material does,

+ 1 - 0
src/renderers/webgl/WebGLExtensions.js

@@ -54,6 +54,7 @@ function WebGLExtensions( gl ) {
 			if ( capabilities.isWebGL2 ) {
 
 				getExtension( 'EXT_color_buffer_float' );
+				getExtension( 'WEBGL_clip_cull_distance' );
 
 			} else {
 

+ 14 - 0
src/renderers/webgl/WebGLProgram.js

@@ -147,6 +147,16 @@ function generateExtensions( parameters ) {
 
 }
 
+function generateVertexExtensions( parameters ) {
+
+	const chunks = [
+		parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : ''
+	];
+
+	return chunks.filter( filterEmptyLine ).join( '\n' );
+
+}
+
 function generateDefines( defines ) {
 
 	const chunks = [];
@@ -451,6 +461,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 
 	const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
 
+	const customVertexExtensions = generateVertexExtensions( parameters );
+
 	const customDefines = generateDefines( defines );
 
 	const program = gl.createProgram();
@@ -503,6 +515,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 
 			customDefines,
 
+			parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
 			parameters.batching ? '#define USE_BATCHING' : '',
 			parameters.instancing ? '#define USE_INSTANCING' : '',
 			parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
@@ -843,6 +856,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 		versionString = '#version 300 es\n';
 
 		prefixVertex = [
+			customVertexExtensions,
 			'precision mediump sampler2DArray;',
 			'#define attribute in',
 			'#define varying out',

+ 1 - 0
src/renderers/webgl/WebGLPrograms.js

@@ -356,6 +356,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true,
 			extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true,
 			extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true,
+			extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ),
 
 			rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ),
 			rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ),