2011-09-13 45 views
19

Tôi cần phải cắt vài trăm đối tượng dưới một mặt phẳng cắt trong OpenGL ES 2.0 và sẽ đánh giá cao ý tưởng từ những người có kinh nghiệm hơn với tập con này của OpenGL.Clipping-planes trong OpenGL ES 2.0

Trong OpenGL ES 1.x có glClipPlane. Trên desktop, bạn có glClipPlane, hoặc gl_ClipDistance trong shader của bạn. Cả hai loại này đều không có trong OpenGL ES 2.0. Dường như loại chức năng này biến mất hoàn toàn với 2.0. Có vẻ như cách duy nhất để thực hiện điều này là A) chạy phương trình phẳng trong trình đổ bóng phân đoạn, hoặc B) viết một bóng đổ đỉnh phức tạp để định vị các đỉnh trên mặt phẳng nếu chúng nằm phía sau nó.

(A) sẽ chậm so với glClipPlane, vì việc cắt "thường xuyên" được thực hiện sau khi đổ bóng đỉnh và trước trình đổ bóng, mỗi đoạn sẽ vẫn phải được xử lý và loại bỏ một phần.

(B) sẽ rất khó để tương thích giữa các trình đổ bóng, vì chúng ta không thể loại bỏ các đỉnh, chúng ta phải căn chỉnh chúng với mặt phẳng và điều chỉnh các thuộc tính cho các mặt cắt. Nó không thể nội suy giữa các đỉnh trong bóng đổ mà không gửi tất cả các đỉnh trong một kết cấu và lấy mẫu nó, mà sẽ cực kỳ tốn kém. Thường thì có lẽ sẽ không thể nội suy dữ liệu một cách đúng đắn.

Tôi cũng đã nghĩ đến việc căn chỉnh mặt phẳng gần với mặt phẳng cắt sẽ là giải pháp hiệu quả.

Và vẽ một mặt phẳng sau khi hiển thị toàn cảnh và kiểm tra độ sâu thất bại sẽ không hoạt động (trừ khi bạn đang nhìn gần vuông góc với mặt phẳng).

Điều gì làm việc cho một đối tượng là vẽ mặt phẳng vào bộ đệm sâu và sau đó hiển thị đối tượng bằng glDepthFunc (GL_GREATER), nhưng như mong đợi nó không hoạt động khi một trong các đối tượng nằm sau một đối tượng khác. Tôi đã cố gắng để xây dựng trên khái niệm này nhưng cuối cùng đã kết thúc với một cái gì đó rất giống với khối lượng bóng và cũng đắt tiền.

Vì vậy, tôi đang thiếu gì? Làm thế nào bạn sẽ làm máy bay cắt trong OpenGL ES 2.0?

Trả lời

5

Dường như tôi đã từng làm điều gì đó khi tôi cố gắng cắt bớt bằng ma trận chiếu. Chính xác cách thực hiện điều này được mô tả trong bài báo này tôi tìm thấy: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf

Tôi hy vọng điều này sẽ giúp những người khác đang tìm cách làm điều này.

+0

Tôi cũng đã gặp phải sự thiếu glClipPlane trong GLES2. Đây có phải là câu trả lời hay nhất mà chúng tôi có? – Harold

+0

Trang 13-14 của bài báo này mô tả cùng một kỹ thuật, nhưng trong một bài trình bày hơi đơn giản hơn. (http://www.imgtec.com/powervr/insider/docs/POWERVR.Shader%20Based%20Water%20Effects.1.11f.OGLES2External.pdf) –

1

Tôi không biết nếu điều này áp dụng cho OpenGL ES, nhưng OpenGL có đầu ra thay đổi gl_ClipDistance được kích hoạt bởi glEnable (GL_CLIP_DISTANCE0). Sau khi được kích hoạt, nguyên thủy được cắt bớt sao cho gl_ClipDistance [0]> = 0 sau khi đổ bóng và đổ bóng hình học.

Đoạn clip khoảng cách có thể được quy định như chỉ là một dấu chấm sản phẩm với một phương trình mặt phẳng không gian thế giới:

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

6

Đây là hai giải pháp tôi đã tìm thấy trên Vuforia SDK forums.

  1. Sử dụng shaders bởi 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. Sử dụng quad trong depth buffer bởi Alessandro Boccalatte:

    • disable màu văn bản (ví dụ: bộ glColorMask(false, false, false, false);)
    • làm cho một hình tứ giác phù hợp với hình dạng điểm đánh dấu (tức là chỉ một quad với cùng kích thước và vị trí/hướng của điểm đánh dấu); điều này sẽ chỉ được trả lại vào depth buffer (vì chúng ta tàn tật viết đệm màu trong bước trước)
    • phép trở lại mặt nạ màu (glColorMask(true, true, true, true);)
    • làm cho các mô hình 3D của bạn
0

Vì phần mở rộng EXT_clip_cull_distance không có sẵn trong OpenGL ES 2.0 (vì phần mở rộng này là OpenGL ES 3.0 là bắt buộc), việc cắt bớt phải được mô phỏng. Nó có thể được mô phỏng trong bộ đổ bóng, bằng cách loại bỏ các mảnh vỡ. Xem Fragment Shader - Special operations.

Xem thêm [Đặc điểm kỹ thuật ngôn ngữ bóng mờ OpenGL ES 1.00; 6.4 Nhảy; trang 58]:

loại bỏ từ khóa chỉ được phép trong trình đổ bóng phân đoạn. Nó có thể được sử dụng trong một shader fragment để từ bỏ hoạt động trên fragment hiện tại. Từ khóa này làm cho phân đoạn bị loại bỏ và không có cập nhật cho bất kỳ bộ đệm nào sẽ xảy ra. Nó thường sẽ được sử dụng trong một tuyên bố có điều kiện, ví dụ:

if (intensity < 0.0) 
    discard; 

Một chương trình shader mà giả lập gl_ClipDistance có thể trông như thế này:

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); 
} 

Ví dụ WebGL sau đây minh họa điều này. Lưu ý, ngữ cảnh WebGL 1.0 tuân thủ chặt chẽ với 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>

Các vấn đề liên quan