Skip to content

Commit 449d18a

Browse files
PWhiddymrdoob
authored andcommitted
Intersection option for WebGLRenderer clipping method (mrdoob#9470)
* Add material option * Local clipIntersection * Updated Docs * improving global/local clipping interaction * intersection parameter update * intersection shader fix * removed commented code * remove comment
1 parent f039ee7 commit 449d18a

File tree

8 files changed

+180
-7
lines changed

8 files changed

+180
-7
lines changed

docs/api/materials/Material.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ <h3>[property:Array clippingPlanes]</h3>
119119
User-defined clipping planes specified as THREE.Plane objects in world space. These planes apply to the objects this material is attached to. Points in space whose dot product with the plane is negative are cut away. Default is null.
120120
</div>
121121

122+
<h3>[property:Boolean clipIntersection]</h3>
123+
124+
<div>Changes the behavior of clipping planes so that only their intersection is clipped, rather than their union. Default is false. See <a href="http://threejs.org/examples/#webgl_clipping_intersection">example</a> </div>
125+
122126
<h3>[property:Boolean clipShadows]</h3>
123127
<div>
124128
Defines whether to clip shadows according to the clipping planes specified on this material. Default is false.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>three.js webgl - clipIntersection</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7+
<style>
8+
body {
9+
margin: 0px;
10+
background-color: #000000;
11+
overflow: hidden;
12+
}
13+
</style>
14+
</head>
15+
<body>
16+
17+
<script src="../build/three.js"></script>
18+
<script src="js/controls/OrbitControls.js"></script>
19+
<script src="js/libs/stats.min.js"></script>
20+
<script src="js/libs/dat.gui.min.js"></script>
21+
22+
<script>
23+
24+
25+
26+
function init() {
27+
28+
camera = new THREE.PerspectiveCamera(
29+
40, window.innerWidth / window.innerHeight, 1, 800 );
30+
31+
camera.position.set( -20, 10, 50 );
32+
camera.lookAt( new THREE.Vector3( 0, 0, 0) );
33+
34+
scene = new THREE.Scene();
35+
36+
// Lights
37+
38+
var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
39+
scene.add( light );
40+
41+
var clipPlanes = [ new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ),
42+
new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), 0 ),
43+
new THREE.Plane( new THREE.Vector3( 0, 0, -1 ), 0 ) ]
44+
45+
scene.add( new THREE.AmbientLight( 0x505050 ) );
46+
47+
balls = new THREE.Object3D();
48+
49+
for ( var i = 1; i < 25; i++ ) {
50+
balls.add( new THREE.Mesh(
51+
new THREE.SphereBufferGeometry( i / 2, 48, 48),
52+
new THREE.MeshStandardMaterial( { color: new THREE.Color( Math.sin( i * 0.5 ) * 0.5 + 0.5,
53+
Math.cos( i * 1.5 ) * 0.5 + 0.5,
54+
Math.sin( i * 4.5 + 0 ) * 0.5 + 0.5 ),
55+
roughness: 0.95, metalness: 0.0, side: THREE.DoubleSide, clippingPlanes: clipPlanes, clipIntersection: true } )
56+
) );
57+
}
58+
59+
scene.add( balls );
60+
61+
// Renderer
62+
63+
var container = document.body;
64+
65+
renderer = new THREE.WebGLRenderer();
66+
renderer.antialias = true;
67+
renderer.setPixelRatio( window.devicePixelRatio );
68+
renderer.setSize( window.innerWidth, window.innerHeight );
69+
renderer.setClearColor( 0x222222 );
70+
renderer.localClippingEnabled = true;
71+
72+
window.addEventListener( 'resize', onWindowResize, false );
73+
container.appendChild( renderer.domElement );
74+
75+
76+
// Stats
77+
78+
stats = new Stats();
79+
container.appendChild( stats.dom );
80+
81+
// GUI
82+
83+
mode = {};
84+
mode.clipIntersection = true;
85+
mode.clipPosition = 0;
86+
var gui = new dat.GUI();
87+
gui.width = 800;
88+
gui.add( mode, 'clipIntersection' ).onChange( function() {
89+
for (var i = 0; i < balls.children.length; i++) {
90+
balls.children[i].material.clipIntersection = !balls.children[i].material.clipIntersection;
91+
}
92+
} );
93+
94+
gui.add( mode, 'clipPosition', -16, 16 ).onChange( function( value ) {
95+
96+
} );
97+
98+
// Controls
99+
100+
var controls = new THREE.OrbitControls( camera, renderer.domElement );
101+
controls.target.set( 0, 1, 0 );
102+
controls.update();
103+
104+
// Start
105+
106+
startTime = Date.now();
107+
time = 0;
108+
109+
}
110+
111+
function onWindowResize() {
112+
113+
camera.aspect = window.innerWidth / window.innerHeight;
114+
camera.updateProjectionMatrix();
115+
116+
renderer.setSize( window.innerWidth, window.innerHeight );
117+
118+
}
119+
120+
function animate() {
121+
122+
123+
requestAnimationFrame( animate );
124+
125+
126+
for ( var obj = 0; obj < balls.children.length; obj++ ) {
127+
var current = balls.children[ obj ].material;
128+
for ( var i = 0; i < current.clippingPlanes.length; i++ ) {
129+
var plane = current.clippingPlanes[ i ];
130+
plane.constant = ( 49 * plane.constant + mode.clipPosition ) / 50;
131+
}
132+
}
133+
134+
135+
stats.begin();
136+
renderer.render( scene, camera );
137+
stats.end();
138+
139+
}
140+
141+
init();
142+
animate();
143+
144+
</script>
145+
146+
</body>
147+
</html>

src/materials/Material.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ function Material() {
3939
this.depthWrite = true;
4040

4141
this.clippingPlanes = null;
42+
this.clipIntersection = false;
4243
this.clipShadows = false;
4344

4445
this.colorWrite = true;
@@ -302,6 +303,7 @@ Material.prototype = {
302303

303304
this.visible = source.visible;
304305
this.clipShadows = source.clipShadows;
306+
this.clipIntersection = source.clipIntersection;
305307

306308
var srcPlanes = source.clippingPlanes,
307309
dstPlanes = null;

src/renderers/WebGLRenderer.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,7 @@ function WebGLRenderer( parameters ) {
15411541
var materialProperties = properties.get( material );
15421542

15431543
var parameters = programCache.getParameters(
1544-
material, _lights, fog, _clipping.numPlanes, object );
1544+
material, _lights, fog, _clipping.numPlanes, _clipping.numIntersection, object );
15451545

15461546
var code = programCache.getProgramCode( material, parameters );
15471547

@@ -1644,6 +1644,7 @@ function WebGLRenderer( parameters ) {
16441644
material.clipping === true ) {
16451645

16461646
materialProperties.numClippingPlanes = _clipping.numPlanes;
1647+
materialProperties.numIntersection = _clipping.numIntersection;
16471648
uniforms.clippingPlanes = _clipping.uniform;
16481649

16491650
}
@@ -1719,7 +1720,7 @@ function WebGLRenderer( parameters ) {
17191720
// object instead of the material, once it becomes feasible
17201721
// (#8465, #8379)
17211722
_clipping.setState(
1722-
material.clippingPlanes, material.clipShadows,
1723+
material.clippingPlanes, material.clipIntersection, material.clipShadows,
17231724
camera, materialProperties, useCache );
17241725

17251726
}
@@ -1741,7 +1742,8 @@ function WebGLRenderer( parameters ) {
17411742
material.needsUpdate = true;
17421743

17431744
} else if ( materialProperties.numClippingPlanes !== undefined &&
1744-
materialProperties.numClippingPlanes !== _clipping.numPlanes ) {
1745+
( materialProperties.numClippingPlanes !== _clipping.numPlanes ||
1746+
materialProperties.numIntersection !== _clipping.numIntersection ) ) {
17451747

17461748
material.needsUpdate = true;
17471749

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
#if NUM_CLIPPING_PLANES > 0
22

3-
for ( int i = 0; i < NUM_CLIPPING_PLANES; ++ i ) {
3+
for ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {
44

55
vec4 plane = clippingPlanes[ i ];
66
if ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;
77

88
}
9+
10+
#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES
11+
12+
bool clipped = true;
13+
for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {
14+
vec4 plane = clippingPlanes[ i ];
15+
clipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;
16+
}
17+
18+
if ( clipped ) discard;
19+
20+
#endif
921

1022
#endif

src/renderers/webgl/WebGLClipping.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function WebGLClipping() {
2121

2222
this.uniform = uniform;
2323
this.numPlanes = 0;
24+
this.numIntersection = 0;
2425

2526
this.init = function( planes, enableLocalClipping, camera ) {
2627

@@ -55,7 +56,7 @@ function WebGLClipping() {
5556

5657
};
5758

58-
this.setState = function( planes, clipShadows, camera, cache, fromCache ) {
59+
this.setState = function( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {
5960

6061
if ( ! localClippingEnabled ||
6162
planes === null || planes.length === 0 ||
@@ -90,6 +91,7 @@ function WebGLClipping() {
9091
}
9192

9293
cache.clippingState = dstArray;
94+
this.numIntersection = clipIntersection ? this.numPlanes : 0;
9395
this.numPlanes += nGlobal;
9496

9597
}
@@ -107,6 +109,7 @@ function WebGLClipping() {
107109
}
108110

109111
scope.numPlanes = numGlobalPlanes;
112+
scope.numIntersection = 0;
110113

111114
}
112115

@@ -151,6 +154,7 @@ function WebGLClipping() {
151154
}
152155

153156
scope.numPlanes = nPlanes;
157+
154158
return dstArray;
155159

156160
}

src/renderers/webgl/WebGLProgram.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ function WebGLProgram( renderer, code, material, parameters ) {
451451
parameters.flipSided ? '#define FLIP_SIDED' : '',
452452

453453
'#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
454+
'#define UNION_CLIPPING_PLANES ' + (parameters.numClippingPlanes - parameters.numClipIntersection),
454455

455456
parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
456457
parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',

src/renderers/webgl/WebGLPrograms.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function WebGLPrograms( renderer, capabilities ) {
3232
"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
3333
"numDirLights", "numPointLights", "numSpotLights", "numHemiLights",
3434
"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
35-
"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "depthPacking"
35+
"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking"
3636
];
3737

3838

@@ -104,7 +104,7 @@ function WebGLPrograms( renderer, capabilities ) {
104104

105105
}
106106

107-
this.getParameters = function ( material, lights, fog, nClipPlanes, object ) {
107+
this.getParameters = function ( material, lights, fog, nClipPlanes, nClipIntersection, object ) {
108108

109109
var shaderID = shaderIDs[ material.type ];
110110

@@ -181,6 +181,7 @@ function WebGLPrograms( renderer, capabilities ) {
181181
numHemiLights: lights.hemi.length,
182182

183183
numClippingPlanes: nClipPlanes,
184+
numClipIntersection: nClipIntersection,
184185

185186
shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && lights.shadows.length > 0,
186187
shadowMapType: renderer.shadowMap.type,

0 commit comments

Comments
 (0)