2011-09-13 20 views
19

Ho bisogno di ritagliare alcune centinaia di oggetti sotto un piano di ritaglio in OpenGL ES 2.0 e apprezzerei le idee di persone più esperte con questo sottoinsieme di OpenGL.Piani di ritaglio in OpenGL ES 2.0

In OpenGL ES 1.x c'è glClipPlane. Sul desktop hai glClipPlane o gl_ClipDistance nel tuo shader. Nessuno di questi due è disponibile in OpenGL ES 2.0. Sembra che questo tipo di funzionalità sia completamente scomparso con 2.0.

Sembra che l'unico modo per fare ciò sia A) eseguire l'equazione del piano nello shader del frammento, o B) scrivere uno shader di vertici molto complesso che posiziona i vertici sul piano se sono dietro di esso.

(A) sarebbe lento rispetto a glClipPlane, poiché il ritaglio "regolare" viene eseguito dopo il vertex shader e prima dello shader di frammenti, ogni frammento dovrebbe comunque essere parzialmente elaborato e scartato.

(B) sarebbe molto difficile rendere compatibile tra gli ombreggiatori, dal momento che non possiamo scartare i vertici dobbiamo allinearli con il piano e regolare gli attributi per quelli che sono "tagliati". Non è possibile interpolare tra i vertici nello shader senza inviare tutti i vertici in una trama e campionarlo, il che sarebbe estremamente costoso. Spesso sarebbe probabilmente impossibile interpolare i dati in modo corretto.

Ho anche pensato di allineare il piano vicino con il piano di ritaglio che sarebbe una soluzione efficiente.

E disegnare un piano dopo aver eseguito il rendering dell'intera scena e aver verificato l'assenza di profondità non funzionerà neanche (a meno che non si stia guardando perpendicolare al piano).

Ciò che funziona per un singolo oggetto consiste nel disegnare il piano nel buffer di profondità e quindi eseguire il rendering dell'oggetto con glDepthFunc (GL_GREATER), ma come previsto non funziona quando uno degli oggetti si trova dietro un altro. Ho cercato di sviluppare questo concetto, ma alla fine ho trovato qualcosa di molto simile ai volumi ombra e altrettanto costoso.

Quindi cosa mi manca? Come faresti il ​​ritaglio piano in OpenGL ES 2.0?

risposta

5

A quanto pare ero a qualcosa quando ho tentato di fare ritaglio utilizzando la matrice di proiezione. Esattamente come fare questo è descritto in questo articolo che ho trovato: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf

Spero che questo possa aiutare altre persone che stanno cercando di farlo.

+0

ho anche incontrato la mancanza di glClipPlane in GLES2. Questo documento è la migliore risposta che abbiamo? – Harold

+0

Le pagine 13-14 di questo documento ImageTec descrivono la stessa tecnica, ma in una presentazione un po 'più semplice. (Http://www.imgtec.com/powervr/insider/docs/POWERVR.Shader%20Based%20Water%20Effects.1.11f.OGLES2External.pdf) –

1

Non so se questo si applica a OpenGL ES, ma OpenGL ha l'output variabile gl_ClipDistance abilitato da glEnable (GL_CLIP_DISTANCE0). Una volta abilitato, la primitiva viene ritagliata in modo tale che gl_ClipDistance [0]> = 0 dopo il vertex e gli shaders geometrici.

La distanza clip può essere specificato come solo un prodotto scalare con un'equazione aereo mondo-space:

http://github.prideout.net/clip-planes/

6

Ecco due soluzioni che ho trovato su Vuforia SDK forums.

  1. utilizzando shader di Harri Smatt:

    uniform mat4 uModelM; 
    uniform mat4 uViewProjectionM; 
    attribute vec3 aPosition; 
    varying vec3 vPosition; 
    void main() { 
        vec4 pos = uModelM * vec4(aPosition, 1.0); 
        gl_Position = uViewProjectionM * pos; 
        vPosition = pos.xyz/pos.w; 
    } 
    

    precision mediump float; 
    varying vec3 vPosition; 
    void main() { 
        if (vPosition.z < 0.0) { 
        discard; 
        } else { 
        // Choose actual color for rendering.. 
        } 
    } 
    
  2. Uso quad in tampone profondità di Alessandro Boccalatte:

    • disabilitare colore crei (cioè set il glColorMask(false, false, false, false);)
    • rendono un quad che corrisponde alla forma del marker (ad es. solo un quad con le stesse dimensioni e posizione/orientamento del marker); questo sarà resa solo nel buffer di profondità (perché abbiamo disattivato la scrittura buffer di colore nel passaggio precedente)
    • abilitare di nuovo la maschera di colore (glColorMask(true, true, true, true);)
    • rendere i modelli 3D
0

Poiché l'estensione EXT_clip_cull_distance non è disponibile in OpenGL ES 2.0 (poiché per questa estensione è richiesto OpenGL ES 3.0), è necessario emulare il clipping. Può essere emulato nello shader dei frammenti, scartando i frammenti. Vedi Fragment Shader - Special operations.

Vedere anche [Specifica OpenGL ES Shading Language 1.00; 6.4 salti; pagina 58]:

Il scarti parola è consentito solo all'interno shader frammento. Può essere utilizzato all'interno di un framment shader per abbandonare l'operazione sul frammento corrente. Questa parola chiave fa scartare il frammento e non si verifica alcun aggiornamento a nessun buffer. E 'in genere utilizzato all'interno di un'istruzione condizionale, ad esempio:

if (intensity < 0.0) 
    discard; 

Un programma di shader che emula gl_ClipDistance può apparire come questo:

Vertex Shader:

attribute vec3 inPos; 
attribute vec3 inCol; 

varying vec3 vertCol; 
varying float clip_distance; 

uniform mat4 u_projectionMat44; 
uniform mat4 u_viewMat44; 
uniform mat4 u_modelMat44; 
uniform vec4 u_clipPlane; 

void main() 
{ 
    vertCol  = inCol; 
    vec4 modelPos = u_modelMat44 * vec4(inPos, 1.0); 
    gl_Position = u_projectionMat44 * u_viewMat44 * viewPos; 
    clip_distance = dot(modelPos, u_clipPlane); 
} 

Fragment Shader:

varying vec3 vertPos; 
varying vec3 vertCol; 
varying float clip_distance; 

void main() 
{ 
    if (clip_distance < 0.0) 
     discard; 
    gl_FragColor = vec4(vertCol.rgb, 1.0); 
} 

Il seguente esempio WebGL lo dimostra. Nota: il contesto WebGL 1.0 è conforme all'API OpenGL ES 2.0.

var readInput = true; 
 
    function changeEventHandler(event){ 
 
    readInput = true; 
 
    } 
 
    
 
    (function loadscene() { 
 
    
 
    var gl, progDraw, vp_size; 
 
    var bufCube = {}; 
 
    var clip = 0.0; 
 
    
 
    function render(delteMS){ 
 

 
     if (readInput) { 
 
      readInput = false; 
 
      clip = (document.getElementById("clip").value - 50)/50; 
 
     } 
 

 
     Camera.create(); 
 
     Camera.vp = vp_size; 
 
      
 
     gl.viewport(0, 0, vp_size[0], vp_size[1]); 
 
     gl.enable(gl.DEPTH_TEST); 
 
     gl.clearColor(0.0, 0.0, 0.0, 1.0); 
 
     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
 

 
     // set up draw shader 
 
     ShaderProgram.Use(progDraw); 
 
     ShaderProgram.SetUniformM44(progDraw, "u_projectionMat44", Camera.Perspective()); 
 
     ShaderProgram.SetUniformM44(progDraw, "u_viewMat44", Camera.LookAt()); 
 
     var modelMat = IdentityMat44() 
 
     modelMat = RotateAxis(modelMat, CalcAng(delteMS, 13.0), 0); 
 
     modelMat = RotateAxis(modelMat, CalcAng(delteMS, 17.0), 1); 
 
     ShaderProgram.SetUniformM44(progDraw, "u_modelMat44", modelMat); 
 
     ShaderProgram.SetUniformF4(progDraw, "u_clipPlane", [1.0,-1.0,0.0,clip*1.7321]); 
 
     
 
     // draw scene 
 
     VertexBuffer.Draw(bufCube); 
 

 
     requestAnimationFrame(render); 
 
    } 
 
    
 
    function resize() { 
 
     //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight]; 
 
     vp_size = [window.innerWidth, window.innerHeight] 
 
     canvas.width = vp_size[0]; 
 
     canvas.height = vp_size[1]; 
 
    } 
 
    
 
    function initScene() { 
 
    
 
     canvas = document.getElementById("canvas"); 
 
     gl = canvas.getContext("experimental-webgl"); 
 
     //gl = canvas.getContext("webgl2"); 
 
     if (!gl) 
 
     return null; 
 
     
 
     /* 
 
     var ext_frag_depth = gl.getExtension("EXT_clip_cull_distance"); // gl_ClipDistance gl_CullDistance 
 
     if (!ext_frag_depth) 
 
      alert('no gl_ClipDistance and gl_CullDistance support'); 
 
     */ 
 

 
     progDraw = ShaderProgram.Create( 
 
     [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER }, 
 
      { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER } 
 
     ]); 
 
     if (!progDraw.progObj) 
 
      return null; 
 
     progDraw.inPos = ShaderProgram.AttributeIndex(progDraw, "inPos"); 
 
     progDraw.inNV = ShaderProgram.AttributeIndex(progDraw, "inNV"); 
 
     progDraw.inCol = ShaderProgram.AttributeIndex(progDraw, "inCol"); 
 
     
 
     // create cube 
 
     var cubePos = [ 
 
     -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 
 
     -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0 ]; 
 
     var cubeCol = [ 1.0, 0.0, 0.0, 1.0, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ]; 
 
     var cubeHlpInx = [ 0, 1, 2, 3, 1, 5, 6, 2, 5, 4, 7, 6, 4, 0, 3, 7, 3, 2, 6, 7, 1, 0, 4, 5 ]; 
 
     var cubePosData = []; 
 
     for (var i = 0; i < cubeHlpInx.length; ++ i) { 
 
     cubePosData.push(cubePos[cubeHlpInx[i]*3], cubePos[cubeHlpInx[i]*3+1], cubePos[cubeHlpInx[i]*3+2]); 
 
     } 
 
     var cubeNVData = []; 
 
     for (var i1 = 0; i1 < cubeHlpInx.length; i1 += 4) { 
 
     var nv = [0, 0, 0]; 
 
     for (i2 = 0; i2 < 4; ++ i2) { 
 
      var i = i1 + i2; 
 
      nv[0] += cubePosData[i*3]; nv[1] += cubePosData[i*3+1]; nv[2] += cubePosData[i*3+2]; 
 
     } 
 
     for (i2 = 0; i2 < 4; ++ i2) 
 
     cubeNVData.push(nv[0], nv[1], nv[2]); 
 
     } 
 
     var cubeColData = []; 
 
     for (var is = 0; is < 6; ++ is) { 
 
     for (var ip = 0; ip < 4; ++ ip) { 
 
     cubeColData.push(cubeCol[is*3], cubeCol[is*3+1], cubeCol[is*3+2]); 
 
     } 
 
     } 
 
     var cubeInxData = []; 
 
     for (var i = 0; i < cubeHlpInx.length; i += 4) { 
 
     cubeInxData.push(i, i+1, i+2, i, i+2, i+3); 
 
     } 
 
     bufCube = VertexBuffer.Create(
 
     [ { data : cubePosData, attrSize : 3, attrLoc : progDraw.inPos }, 
 
     { data : cubeNVData, attrSize : 3, attrLoc : progDraw.inNV }, 
 
     { data : cubeColData, attrSize : 3, attrLoc : progDraw.inCol } ], 
 
     cubeInxData); 
 
     
 
     window.onresize = resize; 
 
     resize(); 
 
     requestAnimationFrame(render); 
 
    } 
 
    
 
    function Fract(val) { 
 
     return val - Math.trunc(val); 
 
    } 
 
    function CalcAng(deltaTime, intervall) { 
 
     return Fract(deltaTime/(1000*intervall)) * 2.0 * Math.PI; 
 
    } 
 
    function CalcMove(deltaTime, intervall, range) { 
 
     var pos = self.Fract(deltaTime/(1000*intervall)) * 2.0 
 
     var pos = pos < 1.0 ? pos : (2.0-pos) 
 
     return range[0] + (range[1] - range[0]) * pos; 
 
    }  
 
    function EllipticalPosition(a, b, angRag) { 
 
     var a_b = a * a - b * b 
 
     var ea = (a_b <= 0) ? 0 : Math.sqrt(a_b); 
 
     var eb = (a_b >= 0) ? 0 : Math.sqrt(-a_b); 
 
     return [ a * Math.sin(angRag) - ea, b * Math.cos(angRag) - eb, 0 ]; 
 
    } 
 
    
 
    glArrayType = typeof Float32Array !="undefined" ? Float32Array : (typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array); 
 
    
 
    function IdentityMat44() { 
 
    var m = new glArrayType(16); 
 
    m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; 
 
    m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; 
 
    m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; 
 
    m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; 
 
    return m; 
 
    }; 
 
    
 
    function RotateAxis(matA, angRad, axis) { 
 
     var aMap = [ [1, 2], [2, 0], [0, 1] ]; 
 
     var a0 = aMap[axis][0], a1 = aMap[axis][1]; 
 
     var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad); 
 
     var matB = new glArrayType(16); 
 
     for (var i = 0; i < 16; ++ i) matB[i] = matA[i]; 
 
     for (var i = 0; i < 3; ++ i) { 
 
      matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng; 
 
      matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng; 
 
     } 
 
     return matB; 
 
    } 
 
    
 
    function Cross(a, b) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; } 
 
    function Dot(a, b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } 
 
    function Normalize(v) { 
 
     var len = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 
 
     return [ v[0]/len, v[1]/len, v[2]/len ]; 
 
    } 
 
    
 
    var Camera = {}; 
 
    Camera.create = function() { 
 
     this.pos = [0, 3, 0.0]; 
 
     this.target = [0, 0, 0]; 
 
     this.up  = [0, 0, 1]; 
 
     this.fov_y = 90; 
 
     this.vp  = [800, 600]; 
 
     this.near = 0.5; 
 
     this.far = 100.0; 
 
    } 
 
    Camera.Perspective = function() { 
 
     var fn = this.far + this.near; 
 
     var f_n = this.far - this.near; 
 
     var r = this.vp[0]/this.vp[1]; 
 
     var t = 1/Math.tan(Math.PI * this.fov_y/360); 
 
     var m = IdentityMat44(); 
 
     m[0] = t/r; m[1] = 0; m[2] = 0;        m[3] = 0; 
 
     m[4] = 0; m[5] = t; m[6] = 0;        m[7] = 0; 
 
     m[8] = 0; m[9] = 0; m[10] = -fn/f_n;      m[11] = -1; 
 
     m[12] = 0; m[13] = 0; m[14] = -2 * this.far * this.near/f_n; m[15] = 0; 
 
     return m; 
 
    } 
 
    Camera.LookAt = function() { 
 
     var mz = Normalize([ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ]); 
 
     var mx = Normalize(Cross(this.up, mz)); 
 
     var my = Normalize(Cross(mz, mx)); 
 
     var tx = Dot(mx, this.pos); 
 
     var ty = Dot(my, this.pos); 
 
     var tz = Dot([-mz[0], -mz[1], -mz[2]], this.pos); 
 
     var m = IdentityMat44(); 
 
     m[0] = mx[0]; m[1] = my[0]; m[2] = mz[0]; m[3] = 0; 
 
     m[4] = mx[1]; m[5] = my[1]; m[6] = mz[1]; m[7] = 0; 
 
     m[8] = mx[2]; m[9] = my[2]; m[10] = mz[2]; m[11] = 0; 
 
     m[12] = tx; m[13] = ty; m[14] = tz; m[15] = 1; 
 
     return m; 
 
    } 
 
    
 
    var ShaderProgram = {}; 
 
    ShaderProgram.Create = function(shaderList) { 
 
     var shaderObjs = []; 
 
     for (var i_sh = 0; i_sh < shaderList.length; ++ i_sh) { 
 
      var shderObj = this.CompileShader(shaderList[i_sh].source, shaderList[i_sh].stage); 
 
      if (shderObj == 0) 
 
       return 0; 
 
      shaderObjs.push(shderObj); 
 
     } 
 
     var prog = {} 
 
     prog.progObj = this.LinkProgram(shaderObjs) 
 
     if (prog.progObj) { 
 
      prog.attribIndex = {}; 
 
      var noOfAttributes = gl.getProgramParameter(prog.progObj, gl.ACTIVE_ATTRIBUTES); 
 
      for (var i_n = 0; i_n < noOfAttributes; ++ i_n) { 
 
       var name = gl.getActiveAttrib(prog.progObj, i_n).name; 
 
       prog.attribIndex[name] = gl.getAttribLocation(prog.progObj, name); 
 
      } 
 
      prog.unifomLocation = {}; 
 
      var noOfUniforms = gl.getProgramParameter(prog.progObj, gl.ACTIVE_UNIFORMS); 
 
      for (var i_n = 0; i_n < noOfUniforms; ++ i_n) { 
 
       var name = gl.getActiveUniform(prog.progObj, i_n).name; 
 
       prog.unifomLocation[name] = gl.getUniformLocation(prog.progObj, name); 
 
      } 
 
     } 
 
     return prog; 
 
    } 
 
    ShaderProgram.AttributeIndex = function(prog, name) { return prog.attribIndex[name]; } 
 
    ShaderProgram.UniformLocation = function(prog, name) { return prog.unifomLocation[name]; } 
 
    ShaderProgram.Use = function(prog) { gl.useProgram(prog.progObj); } 
 
    ShaderProgram.SetUniformI1 = function(prog, name, val) { if(prog.unifomLocation[name]) gl.uniform1i(prog.unifomLocation[name], val); } 
 
    ShaderProgram.SetUniformF1 = function(prog, name, val) { if(prog.unifomLocation[name]) gl.uniform1f(prog.unifomLocation[name], val); } 
 
    ShaderProgram.SetUniformF2 = function(prog, name, arr) { if(prog.unifomLocation[name]) gl.uniform2fv(prog.unifomLocation[name], arr); } 
 
    ShaderProgram.SetUniformF3 = function(prog, name, arr) { if(prog.unifomLocation[name]) gl.uniform3fv(prog.unifomLocation[name], arr); } 
 
    ShaderProgram.SetUniformF4 = function(prog, name, arr) { if(prog.unifomLocation[name]) gl.uniform4fv(prog.unifomLocation[name], arr); } 
 
    ShaderProgram.SetUniformM33 = function(prog, name, mat) { if(prog.unifomLocation[name]) gl.uniformMatrix3fv(prog.unifomLocation[name], false, mat); } 
 
    ShaderProgram.SetUniformM44 = function(prog, name, mat) { if(prog.unifomLocation[name]) gl.uniformMatrix4fv(prog.unifomLocation[name], false, mat); } 
 
    ShaderProgram.CompileShader = function(source, shaderStage) { 
 
     var shaderScript = document.getElementById(source); 
 
     if (shaderScript) 
 
     source = shaderScript.text; 
 
     var shaderObj = gl.createShader(shaderStage); 
 
     gl.shaderSource(shaderObj, source); 
 
     gl.compileShader(shaderObj); 
 
     var status = gl.getShaderParameter(shaderObj, gl.COMPILE_STATUS); 
 
     if (!status) alert(gl.getShaderInfoLog(shaderObj)); 
 
     return status ? shaderObj : null; 
 
    } 
 
    ShaderProgram.LinkProgram = function(shaderObjs) { 
 
     var prog = gl.createProgram(); 
 
     for (var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh) 
 
      gl.attachShader(prog, shaderObjs[i_sh]); 
 
     gl.linkProgram(prog); 
 
     status = gl.getProgramParameter(prog, gl.LINK_STATUS); 
 
     if (!status) alert("Could not initialise shaders"); 
 
     gl.useProgram(null); 
 
     return status ? prog : null; 
 
    } 
 
    
 
    var VertexBuffer = {}; 
 
    VertexBuffer.Create = function(attributes, indices) { 
 
     var buffer = {}; 
 
     buffer.buf = []; 
 
     buffer.attr = [] 
 
     for (var i = 0; i < attributes.length; ++ i) { 
 
      buffer.buf.push(gl.createBuffer()); 
 
      buffer.attr.push({ size : attributes[i].attrSize, loc : attributes[i].attrLoc }); 
 
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buf[i]); 
 
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(attributes[i].data), gl.STATIC_DRAW); 
 
     } 
 
     buffer.inx = gl.createBuffer(); 
 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer.inx); 
 
     gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); 
 
     buffer.inxLen = indices.length; 
 
     gl.bindBuffer(gl.ARRAY_BUFFER, null); 
 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 
 
     return buffer; 
 
    } 
 
    VertexBuffer.Draw = function(bufObj) { 
 
    for (var i = 0; i < bufObj.buf.length; ++ i) { 
 
      gl.bindBuffer(gl.ARRAY_BUFFER, bufObj.buf[i]); 
 
      gl.vertexAttribPointer(bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0); 
 
      gl.enableVertexAttribArray(bufObj.attr[i].loc); 
 
     } 
 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufObj.inx); 
 
     gl.drawElements(gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0); 
 
     for (var i = 0; i < bufObj.buf.length; ++ i) 
 
     gl.disableVertexAttribArray(bufObj.attr[i].loc); 
 
     gl.bindBuffer(gl.ARRAY_BUFFER, null); 
 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 
 
    } 
 
    
 
    initScene(); 
 
    
 
    })();
html,body { 
 
    height: 100%; 
 
    width: 100%; 
 
    margin: 0; 
 
    overflow: hidden; 
 
} 
 

 
#gui { 
 
    position : absolute; 
 
    top : 0; 
 
    left : 0; 
 
}
<script id="draw-shader-vs" type="x-shader/x-vertex"> 
 
    precision highp float; 
 
    
 
    attribute vec3 inPos; 
 
    attribute vec3 inNV; 
 
    attribute vec3 inCol; 
 
    
 
    varying vec3 vertPos; 
 
    varying vec3 vertNV; 
 
    varying vec3 vertCol; 
 
    varying float clip_distance; 
 
    
 
    uniform mat4 u_projectionMat44; 
 
    uniform mat4 u_viewMat44; 
 
    uniform mat4 u_modelMat44; 
 
    uniform vec4 u_clipPlane; 
 
    
 
    void main() 
 
    { 
 
     mat4 mv  = u_viewMat44 * u_modelMat44; 
 
     vertCol  = inCol; 
 
     vertNV  = normalize(mat3(mv) * inNV); 
 
     vec4 viewPos = mv * vec4(inPos, 1.0); 
 
     vertPos  = viewPos.xyz; 
 
     gl_Position = u_projectionMat44 * viewPos; 
 

 
     vec4 modelPos = u_modelMat44 * vec4(inPos, 1.0); 
 
     vec4 clipPlane = vec4(normalize(u_clipPlane.xyz), u_clipPlane.w); 
 
     clip_distance = dot(modelPos, clipPlane); 
 
    } 
 
</script> 
 
    
 
<script id="draw-shader-fs" type="x-shader/x-fragment"> 
 
    precision mediump float; 
 

 
    varying vec3 vertPos; 
 
    varying vec3 vertNV; 
 
    varying vec3 vertCol; 
 
    varying float clip_distance; 
 
    
 
    void main() 
 
    { 
 
     if (clip_distance < 0.0) 
 
      discard; 
 
     vec3 color = vertCol; 
 
     gl_FragColor = vec4(color.rgb, 1.0); 
 
    } 
 
</script> 
 

 
<div> 
 
    <form id="gui" name="inputs"> 
 
     <table> 
 
      <tr> <td> <font color= #CCF>clipping</font> </td> 
 
       <td> <input type="range" id="clip" min="0" max="100" value="50" onchange="changeEventHandler(event);"/></td> </tr> 
 
     </table> 
 
    </form> 
 
</div> 
 

 

 
<canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>