glClipPlane - Is there an equivalent in webGL?

情到浓时终转凉″ 提交于 2019-12-11 02:16:10

问题


I have a 3D mesh. Is there any possibility to render the sectional view (clipping) like glClipPlane in OpenGL?

I am using Three.js r65.

The latest shader that I have added is:
Fragment Shader:

uniform float time;
uniform vec2 resolution; 
varying vec2 vUv; 
void main( void ) 
{ 
vec2 position = -1.0 + 2.0 * vUv; 
float red = abs( sin( position.x * position.y + time / 2.0 ) ); 
float green = abs( cos( position.x * position.y + time / 3.0 ) ); 
float blue = abs( cos( position.x * position.y + time / 4.0 ) ); 
if(position.x > 0.2  && position.y > 0.2 ) 
{  
discard; 
 } 
gl_FragColor = vec4( red, green, blue, 1.0 ); }


Vertex Shader:

varying vec2 vUv;
void main() 
{ 
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); 
gl_Position = projectionMatrix * mvPosition; 
}

回答1:


In the newer versions (> r.76) of three.js clipping is supported in the THREE.WebGLRenderer. There is an array property called clippingPlanes where you can add your custom clipping planes (THREE.Plane instances).

For three.js you can check these two examples:

1) WebGL clipping (code base here on GitHub)

2) WebGL clipping advanced (code base here on GitHub)


A simple example

To add a clipping plane to the renderer you can do:

var normal = new THREE.Vector3( -1, 0, 0 );
var constant = 0;
var plane = new THREE.Plane( normal, constant );
renderer.clippingPlanes = [plane];

Here a fiddle to demonstrate this.


You can also clip on object level by adding a clipping plane to the object material. For this to work you have to set the renderer localClippingEnabled property to true.

// set renderer
renderer.localClippingEnabled = true;

// add clipping plane to material
var normal = new THREE.Vector3( -1, 0, 0 );
var constant = 0;
var color = 0xff0000;
var plane = new THREE.Plane( normal, constant );
var material = new THREE.MeshBasicMaterial({ color: color });
material.clippingPlanes = [plane];
var mesh = new THREE.Mesh( geometry, material );

Note: In r.77 some of the clipping functionality in the THREE.WebGLRenderer was moved moved to a separate THREE.WebGLClipping class, check here for reference in the three.js master branch.




回答2:


Unfortunately in the OpenGL-ES specification against which WebGL has been specified there are no clip planes and the vertex shader stage lacks the gl_ClipDistance output, by which plane clipping is implemented in modern OpenGL.

However you can use the fragment shader to implement per-fragment clipping. In the fragment shader test the position of the incoming fragment against your set of clip planes and if the fragment does not pass the test discard it.

Update

Let's have a look at how clip planes are defined in fixed function pipeline OpenGL:

void ClipPlane( enum p, double eqn[4] );

The value of the first argument, p, is a symbolic constant,CLIP PLANEi, where i is an integer between 0 and n − 1, indicating one of n client-defined clip planes. eqn is an array of four double-precision floating-point values. These are the coefficients of a plane equation in object coordinates: p1, p2, p3, and p4 (in that order). The inverse of the current model-view matrix is applied to these coefficients, at the time they are specified, yielding

p' = (p'1, p'2, p'3, p'4) = (p1, p2, p3, p4) inv(M)

(where M is the current model-view matrix; the resulting plane equation is unde- fined if M is singular and may be inaccurate if M is poorly-conditioned) to obtain the plane equation coefficients in eye coordinates. All points with eye coordinates transpose( (x_e, y_e,z_e, w_e) ) that satisfy

(p'1, p'2, p'3, p'4)   x_e  ≥ 0
                      y_e 
                      z_e 
                      w_e 

lie in the half-space defined by the plane; points that do not satisfy this condition do not lie in the half-space.

So what you do is, you add uniforms by which you pass the clip plane parameters p' and add another out/in pair of variables between the vertex and fragment shader to pass the vertex eye space position. Then in the fragment shader the first thing you do is performing the clip plane equation test and if it doesn't pass you discard the fragment.

In the vertex shader

in  vec3 vertex_position;
out vec4 eyespace_pos;

uniform mat4 modelview;

void main()
{
    /* ... */
    eyespace_pos = modelview * vec4(vertex_position, 1);
    /* ... */
}

In the fragment shader

in vec4 eyespace_pos;

uniform vec4 clipplane;

void main()
{
    if( dot( eyespace_pos, clipplane) < 0 ) {
        discard;
    }
    /* ... */
}


来源:https://stackoverflow.com/questions/22628186/glclipplane-is-there-an-equivalent-in-webgl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!