【问题标题】:What kind of blurs can be implemented in pixel shaders?在像素着色器中可以实现什么样的模糊?
【发布时间】:2012-07-01 13:32:22
【问题描述】:

高斯、框、径向、方向、运动模糊、缩放模糊等

我读到高斯模糊可以分解为可以在像素着色器中实现的通道,但找不到任何样本。

是否可以假设任何与自身以外的像素相关的效果都不能在像素着色器中实现?

【问题讨论】:

    标签: glsl shader gpu hlsl pixel-shader


    【解决方案1】:

    您可以实现一切,只要您能够将信息传递给着色器。

    在这种情况下,诀窍是执行多次渲染。最终着色器将采用一定数量的采样器,即非模糊源,用于计算模糊值。

    例如,使用多个纹理可以模拟基于累积缓冲区的效果。


    要实现高斯模糊,请将场景渲染到帧缓冲区对象上,并在颜色附件上附加纹理。这是第一关。

    作为第二遍,渲染一个带纹理的四边形,其中纹理是在第一步中生成的。纹理坐标从顶点阶段传递到片段阶段,在四边形上插值。确实,每个片段都有纹理坐标;为每个坐标应用偏移量以获取底层坐标周围的文本,并执行高斯模糊。

    【讨论】:

    • 谢谢,我可以为这些模糊传递什么样的输入?我以为我只得到一个像素及其颜色等,而不是它的坐标或其他任何东西。你还知道我如何将高斯或框模糊作为像素着色器实现吗?
    【解决方案2】:

    用于后期处理效果的通用“管道”

    setRenderTarget(myRenderTarget); // or FBO in GL
    drawAwsomeScene();
    
    setdefaultRenderTarget();   // draw to screen...
    
    blurShader.use();
    // shader needs to know what is the size of one pixel on the screen
    blurShader.uniform2f("texelSize", 1/screenW, 1/screenH);
    
    // set the texture with scene rendered...
    setRenderTargetTexture();
    
    drawFullScreenQuad();
    
    // other effects...
    

    有用的例子/模糊教程:http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/

    【讨论】:

      【解决方案3】:

      我实现了一个通用的卷积片段着色器(pixel shader)

      #version 120
      
      uniform sampler2D texUnit;
      uniform float[9] conMatrix;
      uniform float conWeight;
      uniform vec2 conPixel;
      
      void main(void)
      {
          vec4 color = vec4(0.0);
          vec2 texCoord = gl_TexCoord[0].st;
          vec2 offset = conPixel * 1.5;
          vec2 start = texCoord - offset;
          vec2 current = start;
      
          for (int i = 0; i < 9; i++)
          {
              color += texture2D( texUnit, current ) * conMatrix[i]; 
      
              current.x += conPixel.x;
              if (i == 2 || i == 5) {
                  current.x = start.x;
                  current.y += conPixel.y; 
              }
          }
      
          gl_FragColor = color * conWeight;
      }
      

      对于模糊:

      where conPixel is {1/screen width, 1/screen height}
      where conMatrix is {1.0, 1.0, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0}
      where conWeight is 1.0 / 9.0
      where texUnit is 0
      

      【讨论】:

        【解决方案4】:

        实现场景模糊效果的常见实现是 Gaussian blur,通过 2 次后处理实现。
        这是一个近似值,它首先在第 1 遍中沿 X 轴模糊,在第 2 遍中沿 Y 轴模糊(反之亦然)。这会为强模糊带来更好的性能。
        模糊着色器使用normal (or Gaussian) distribution。对于 2 个通道,使用相同的着色器程序,2 个通道具有单独的方向设置,存储在统一的 vec2 u_dir 中。模糊效果的强度可以通过 [0.0, 1.0] 范围内的统一变量 float u_sigma 变化。
        场景被写入帧缓冲区,纹理绑定到颜色平面。屏幕空间通道使用纹理作为输入以沿 X 轴模糊输出。 X 轴模糊通道写入另一个帧缓冲区,纹理绑定到其颜色平面。此纹理用作输入,用于沿 Y 轴的最终模糊过程。
        模糊算法的详细描述可以在问题OpenGL es 2.0 Gaussian blur on triangleLeranOpenGL - Gaussian blur 的答案中找到。

        模糊顶点着色器

        #version 330
        
        in  vec2 inPos;
        out vec2 pos;
        
        void main()
        {
            pos = inPos;
            gl_Position = vec4( inPos, 0.0, 1.0 );
        }
        

        模糊片段着色器

        #version 330
        
        in vec2 pos;
        
        uniform sampler2D u_texture;
        uniform vec2      u_textureSize;
        uniform float     u_sigma;
        uniform vec2      u_dir;
        
        float CalcGauss( float x, float sigma )
        {
            if ( sigma <= 0.0 )
                return 0.0;
          return exp( -(x*x) / (2.0 * sigma) ) / (2.0 * 3.14157 * sigma);
        }
        
        void main()
        {
            vec2 texC     = pos.st * 0.5 + 0.5;
            vec4 texCol   = texture2D( u_texture, texC );
            vec4 gaussCol = vec4( texCol.rgb, 1.0 );
            vec2 step     = u_dir / u_textureSize;
            for ( int i = 1; i <= 32; ++ i )
            {
                float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
                if ( weight < 1.0/255.0 )
                    break;
                texCol    = texture2D( u_texture, texC + step * float(i) );
                gaussCol += vec4( texCol.rgb * weight, weight );
                texCol    = texture2D( u_texture, texC - step * float(i) );
                gaussCol += vec4( texCol.rgb * weight, weight );
            }
            gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
            gl_FragColor = vec4( gaussCol.rgb, 1.0 );
        }
        

        另请参阅以下问题的答案:

        查看 WebGL 示例:

        var readInput = true;
        function changeEventHandler(event){
        readInput = true;
        }
        
        (function loadscene() {
        
        var resize, gl, progDraw, progBlur, vp_size, blurFB;
        var canvas;
        var camera;
        var bufCube = {};
        var bufQuad = {};
        var shininess = 10.0;
        var glow = 10.0;
        var sigma = 0.8;
        var radius = 1.0;
        
        function render(deltaMS){
        
            if ( readInput ) {
                //readInput = false;
                var sliderScale = 100;
                sigma     = document.getElementById( "sigma" ).value / sliderScale;
                radius    = document.getElementById( "radius" ).value / sliderScale;
            }
        
            vp_size = [canvas.width, canvas.height];
            camera.Update( vp_size );
                
            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 framebuffer
            gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[0] );
            gl.viewport( 0, 0, blurFB[0].width, blurFB[0].height );
            gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
        
            // setup view projection and model
            var prjMat = camera.Perspective();
            var viewMat = camera.Orbit();
            var modelMat = IdentM44();
            modelMat = camera.AutoModelMatrix();
            
            // set up draw shader
            ShProg.Use( progDraw.prog );
            ShProg.SetM44( progDraw.prog, "u_projectionMat44", prjMat );
            ShProg.SetM44( progDraw.prog, "u_modelViewMat44", Multiply(viewMat, modelMat) );
            ShProg.SetF1( progDraw.prog, "u_shininess", shininess );
            
            // draw scene
            VertexBuffer.Draw( bufCube );
        
            // set blur-X framebuffer and bind frambuffer texture
            gl.bindFramebuffer( gl.FRAMEBUFFER, blurFB[1] );
            gl.viewport( 0, 0, blurFB[1].width, blurFB[1].height );
            gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
            var texUnit = 1;
            gl.activeTexture( gl.TEXTURE0 + texUnit );
            gl.bindTexture( gl.TEXTURE_2D, blurFB[0].color0_texture );
        
            // set up blur-X shader
            ShProg.Use( progBlur.prog );
            ShProg.SetI1( progBlur.prog, "u_texture", texUnit )
            ShProg.SetF2( progBlur.prog, "u_textureSize", vp_size );
            ShProg.SetF1( progBlur.prog, "u_sigma", sigma )
            ShProg.SetF1( progBlur.prog, "u_radius", radius )
            ShProg.SetF2( progBlur.prog, "u_dir", [1.0, 0.0] )
        
            // draw full screen space
            gl.enableVertexAttribArray( progBlur.inPos );
            gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
            gl.vertexAttribPointer( progBlur.inPos, 2, gl.FLOAT, false, 0, 0 ); 
            gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
            gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
            gl.disableVertexAttribArray( progBlur.inPos );
        
            // reset framebuffer and bind frambuffer texture
            gl.bindFramebuffer( gl.FRAMEBUFFER, null );
            gl.viewport( 0, 0, vp_size[0], vp_size[1] );
            gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
            texUnit = 2;
            gl.activeTexture( gl.TEXTURE0 + texUnit );
            gl.bindTexture( gl.TEXTURE_2D, blurFB[1].color0_texture );
        
            // set up pst process shader
            ShProg.SetI1( progBlur.prog, "u_texture", texUnit )
            ShProg.SetF1( progBlur.prog, "u_radius", radius )
            ShProg.SetF2( progBlur.prog, "u_dir", [0.0, 1.0] )
        
            // draw full screen space
            gl.enableVertexAttribArray( progBlur.inPos );
            gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
            gl.vertexAttribPointer( progBlur.inPos, 2, gl.FLOAT, false, 0, 0 ); 
            gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
            gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
            gl.disableVertexAttribArray( progBlur.inPos );
        
            requestAnimationFrame(render);
        }
        
        function initScene() {
        
            canvas = document.getElementById( "canvas");
            gl = canvas.getContext( "experimental-webgl" );
            if ( !gl )
                return null;
        
            progDraw = {}
            progDraw.prog = ShProg.Create( 
            [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER },
                { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER }
            ] );
            if ( !progDraw.prog )
                return null;
            progDraw.inPos = gl.getAttribLocation( progDraw.prog, "inPos" );
            progDraw.inNV  = gl.getAttribLocation( progDraw.prog, "inNV" );
            progDraw.inCol = gl.getAttribLocation( progDraw.prog, "inCol" );
        
            progBlur = {}
            progBlur.prog = ShProg.Create( 
            [ { source : "post-shader-vs", stage : gl.VERTEX_SHADER },
                { source : "blur-shader-fs", stage : gl.FRAGMENT_SHADER }
            ] );
            progBlur.inPos = gl.getAttribLocation( progBlur.prog, "inPos" );
            if ( !progBlur.prog )
                return;    
            
            // 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 );
        
            bufQuad.pos = gl.createBuffer();
            gl.bindBuffer( gl.ARRAY_BUFFER, bufQuad.pos );
            gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ] ), gl.STATIC_DRAW );
            bufQuad.inx = gl.createBuffer();
            gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufQuad.inx );
            gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ), gl.STATIC_DRAW );  
            
            camera = new Camera( [0, 3, 0.0], [0, 0, 0], [0, 0, 1], 90, vp_size, 0.5, 100 );
        
            window.onresize = resize;
            resize();
            requestAnimationFrame(render);
        }
        
        function resize() {
            //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight];
            vp_size = [window.innerWidth, window.innerHeight]
            //vp_size = [256, 256]
            canvas.width = vp_size[0];
            canvas.height = vp_size[1];
        
            var fbsize = Math.max(vp_size[0], vp_size[1]);
            fbsize = 1 << 31 - Math.clz32(fbsize); // nearest power of 2
        
            blurFB = [];
            for ( var i = 0; i < 2; ++ i ) {
                fb = gl.createFramebuffer();
                fb.width = fbsize;
                fb.height = fbsize;
                gl.bindFramebuffer( gl.FRAMEBUFFER, fb );
                fb.color0_texture = gl.createTexture();
                gl.bindTexture( gl.TEXTURE_2D, fb.color0_texture );
                gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
                gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
                gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, fb.width, fb.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
                fb.renderbuffer = gl.createRenderbuffer();
                gl.bindRenderbuffer( gl.RENDERBUFFER, fb.renderbuffer );
                gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, fb.width, fb.height );
                gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fb.color0_texture, 0 );
                gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, fb.renderbuffer );
                gl.bindTexture( gl.TEXTURE_2D, null );
                gl.bindRenderbuffer( gl.RENDERBUFFER, null );
                gl.bindFramebuffer( gl.FRAMEBUFFER, null );
                blurFB.push( fb );
            }
        }
        
        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 ];
        }
        
        function IdentM44() {
            return [ 1, 0, 0, 0,    0, 1, 0, 0,    0, 0, 1, 0,    0, 0, 0, 1 ];
        };
        
        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 = matA.slice(0);
            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 Rotate(matA, angRad, axis) {
            var s = Math.sin(angRad), c = Math.cos(angRad);
            var x = axis[0], y = axis[1], z = axis[2]; 
            matB = [
                x*x*(1-c)+c,   x*y*(1-c)-z*s, x*z*(1-c)+y*s, 0,
                y*x*(1-c)+z*s, y*y*(1-c)+c,   y*z*(1-c)-x*s, 0,
                z*x*(1-c)-y*s, z*y*(1-c)+x*s, z*z*(1-c)+c,   0,
                0,             0,             0,             1 ];
            return Multiply(matA, matB);
        }    
        
        function Multiply(matA, matB) {
            matC = IdentM44();
            for (var i0=0; i0<4; ++i0 )
                for (var i1=0; i1<4; ++i1 )
                    matC[i0*4+i1] = matB[i0*4+0] * matA[0*4+i1] + matB[i0*4+1] * matA[1*4+i1] + matB[i0*4+2] * matA[2*4+i1] + matB[i0*4+3] * matA[3*4+i1]  
            return matC;
        }
        
        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 ];
        }
        
        Camera = function( pos, target, up, fov_y, vp, near, far ) {
        this.Time = function() { return Date.now(); }
        this.pos = pos;
        this.target = target;
        this.up = up;
        this.fov_y = fov_y;
        this.vp = vp;
        this.near = near;
        this.far = far;
        this.orbit_mat = this.current_orbit_mat = this.model_mat = this.current_model_mat = IdentM44();
        this.mouse_drag = this.auto_spin = false;
        this.auto_rotate = true;
        this.mouse_start = [0, 0];
        this.mouse_drag_axis = [0, 0, 0];
        this.mouse_drag_angle = 0;
        this.mouse_drag_time = 0;
        this.drag_start_T = this.rotate_start_T = this.Time();
        this.Ortho = function() {
            var fn = this.far + this.near;
            var f_n = this.far - this.near;
            var w = this.vp[0];
            var h = this.vp[1];
            return [
                2/w, 0,   0,       0,
                0,   2/h, 0,       0,
                0,   0,   -2/f_n,  0,
                0,   0,   -fn/f_n, 1 ];
        };  
        this.Perspective = function() {
            var n = this.near;
            var f = this.far;
            var fn = f + n;
            var f_n = f - n;
            var r = this.vp[0] / this.vp[1];
            var t = 1 / Math.tan( Math.PI * this.fov_y / 360 );
            return [
                t/r, 0, 0,          0,
                0,   t, 0,          0,
                0,   0, -fn/f_n,   -1,
                0,   0, -2*f*n/f_n, 0 ];
        }; 
        this.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 ); 
            return [mx[0], my[0], mz[0], 0, mx[1], my[1], mz[1], 0, mx[2], my[2], mz[2], 0, tx, ty, tz, 1]; 
        };
        this.Orbit = function() {
            return Multiply(this.LookAt(), this.OrbitMatrix());
        }; 
        this.OrbitMatrix = function() {
            return (this.mouse_drag || (this.auto_rotate && this.auto_spin)) ? Multiply(this.current_orbit_mat, this.orbit_mat) : this.orbit_mat;
        };
        this.AutoModelMatrix = function() {
            return this.auto_rotate ? Multiply(this.current_model_mat, this.model_mat) : this.model_mat;
        };
        this.Update = function(vp_size) {
            if (vp_size)
                this.vp = vp_size;
            var current_T = this.Time();
            this.current_model_mat = IdentM44()
            if (this.mouse_drag) {
                this.current_orbit_mat = Rotate(IdentM44(), this.mouse_drag_angle, this.mouse_drag_axis);
            } else if (this.auto_rotate) {
                if (this.auto_spin ) {
                    if (this.mouse_drag_time > 0 ) {
                        var angle = this.mouse_drag_angle * (current_T - this.rotate_start_T) / this.mouse_drag_time;
                        this.current_orbit_mat = Rotate(IdentM44(), angle, this.mouse_drag_axis);
                    }
                } else {
                    var auto_angle_x = Fract( (current_T - this.rotate_start_T) / 13000.0 ) * 2.0 * Math.PI;
                    var auto_angle_y = Fract( (current_T - this.rotate_start_T) / 17000.0 ) * 2.0 * Math.PI;
                    this.current_model_mat = RotateAxis( this.current_model_mat, auto_angle_x, 0 );
                    this.current_model_mat = RotateAxis( this.current_model_mat, auto_angle_y, 1 );
                }
            }
        };
        this.ChangeMotionMode = function(drag, spin, auto ) {
            var new_drag = drag;
            var new_auto = new_drag ? false : auto;
            var new_spin = new_auto ? spin : false;
            change = this.mouse_drag != new_drag || this.auto_rotate != new_auto || this.auto_spin != new_spin; 
            if (!change)
                return;
            if (new_drag && !this.mouse_drag) {
                this.drag_start_T = this.Time();
                this.mouse_drag_angle = 0.0;
                this.mouse_drag_time = 0;
            }
            if (new_auto && !this.auto_rotate)
                this.rotate_start_T = this.Time();
            this.mouse_drag = new_drag; 
            this.auto_rotate = new_auto;  
            this.auto_spin = new_spin;
            this.orbit_mat = Multiply(this.current_orbit_mat, this.orbit_mat);
            this.current_orbit_mat = IdentM44();
            this.model_mat = Multiply(this.current_model_mat, this.model_mat);
            this.current_model_mat = IdentM44();
        };
        this.OnMouseDown = function( event ) {
            var rect = gl.canvas.getBoundingClientRect();
            if ( event.clientX < rect.left || event.clientX > rect.right ) return;
            if ( event.clientY < rect.top || event.clientY > rect.bottom ) return;
            if (event.button == 0) { // left button
                this.mouse_start = [event.clientX, event.clientY]; 
                this.ChangeMotionMode( true, false, false );
            }
        };
        this.OnMouseUp = function( event ) {
            if (event.button == 0) { // left button
                this.ChangeMotionMode( false, true, true );
            } else if (event.button == 1) {// middle button
                this.ChangeMotionMode( false, false, !this.auto_rotate );
            }
        };
        this.OnMouseMove = function( event ) {
            var dx = (event.clientX-this.mouse_start[0]) / this.vp[0];
            var dy = (event.clientY-this.mouse_start[1]) / this.vp[1];
            var len = Math.sqrt(dx*dx + dy*dy);
            if (this.mouse_drag && len > 0) {
                this.mouse_drag_angle = Math.PI*len;
                this.mouse_drag_axis = [dy/len, 0, -dx/len];
                this.mouse_drag_time = this.Time() - this.drag_start_T;
            }
        };
        
        this.domElement = document;
        var cam = this;
        //this.domElement.addEventListener( 'contextmenu', function(e) { event.preventDefault(); }, false );
        this.domElement.addEventListener( 'mousedown', function(e) { cam.OnMouseDown(e) }, false );
        this.domElement.addEventListener( 'mouseup', function(e) { cam.OnMouseUp(e) }, false );
        this.domElement.addEventListener( 'mousemove', function(e) { cam.OnMouseMove(e) }, false );
        //this.domElement.addEventListener( 'mousewheel', hid_events.onMouseWheel, false );
        //this.domElement.addEventListener( 'DOMMouseScroll', hid_events.onMouseWheel, false ); // firefox
        }
        
        var ShProg = {};
        ShProg.Create = function( shaderList ) {
            var shaderObjs = [];
            for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
                var shderObj = this.Compile( shaderList[i_sh].source, shaderList[i_sh].stage );
                if ( shderObj == 0 )
                    return 0;
                shaderObjs.push( shderObj );
            }
            var progObj = this.Link( shaderObjs )
            if ( progObj != 0 ) {
                progObj.attrInx = {};
                var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
                for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
                    var name = gl.getActiveAttrib( progObj, i_n ).name;
                    progObj.attrInx[name] = gl.getAttribLocation( progObj, name );
                }
                progObj.uniLoc = {};
                var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
                for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
                    var name = gl.getActiveUniform( progObj, i_n ).name;
                    progObj.uniLoc[name] = gl.getUniformLocation( progObj, name );
                }
            }
            return progObj;
        }
        ShProg.AttrI = function( progObj, name ) { return progObj.attrInx[name]; } 
        ShProg.UniformL = function( progObj, name ) { return progObj.uniLoc[name]; } 
        ShProg.Use = function( progObj ) { gl.useProgram( progObj ); } 
        ShProg.SetI1  = function( progObj, name, val ) { if(progObj.uniLoc[name]) gl.uniform1i( progObj.uniLoc[name], val ); }
        ShProg.SetF1  = function( progObj, name, val ) { if(progObj.uniLoc[name]) gl.uniform1f( progObj.uniLoc[name], val ); }
        ShProg.SetF2  = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform2fv( progObj.uniLoc[name], arr ); }
        ShProg.SetF3  = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform3fv( progObj.uniLoc[name], arr ); }
        ShProg.SetF4  = function( progObj, name, arr ) { if(progObj.uniLoc[name]) gl.uniform4fv( progObj.uniLoc[name], arr ); }
        ShProg.SetM33 = function( progObj, name, mat ) { if(progObj.uniLoc[name]) gl.uniformMatrix3fv( progObj.uniLoc[name], false, mat ); }
        ShProg.SetM44 = function( progObj, name, mat ) { if(progObj.uniLoc[name]) gl.uniformMatrix4fv( progObj.uniLoc[name], false, mat ); }
        ShProg.Compile = 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;
        } 
        ShProg.Link = 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 = {
        Create: function(attribs, indices) {
            var buffer = { buf: [], attr: [], inx: gl.createBuffer(), inxLen: indices.length };
            for (var i=0; i<attribs.length; ++i) {
                buffer.buf.push(gl.createBuffer());
                buffer.attr.push({ size : attribs[i].attrSize, loc : attribs[i].attrLoc });
                gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buf[i]);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array( attribs[i].data ), gl.STATIC_DRAW);
            }
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer.inx);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW);
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
            return buffer;
        },
        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(bufObj.primitve_type ? bufObj.primitve_type : 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 { margin: 0; overflow: hidden; }
        #gui { position : absolute; top : 0; left : 0; }
        <script id="draw-shader-vs" type="x-shader/x-vertex">
        precision mediump float;
        
        attribute vec3 inPos;
        attribute vec3 inNV;
        attribute vec3 inCol;
        
        varying vec3 vertPos;
        varying vec3 vertNV;
        varying vec3 vertCol;
        
        uniform mat4 u_projectionMat44;
        uniform mat4 u_modelViewMat44;
        
        void main()
        {
            vertNV      = mat3( u_modelViewMat44 ) * normalize( inNV );
            vertCol     = inCol;
            vec4 pos    = u_modelViewMat44 * vec4( inPos, 1.0 );
            vertPos     = pos.xyz / pos.w;
            gl_Position = u_projectionMat44 * pos;
        }
        </script>
        
        <script id="draw-shader-fs" type="x-shader/x-fragment">
        precision mediump float;
        
        varying vec3 vertPos;
        varying vec3 vertNV;
        varying vec3 vertCol;
        
        uniform float u_shininess;
        
        void main()
        {
            vec3 color = vertCol;
            vec3  normalV  = normalize( vertNV );
            vec3  eyeV     = normalize( -vertPos );
            vec3  halfV    = normalize( eyeV + normalV );
            float NdotH    = max( 0.0, dot( normalV, halfV ) );
            float shineFac = ( u_shininess + 2.0 ) * pow( NdotH, u_shininess ) / ( 2.0 * 3.14159265 );
            gl_FragColor   = vec4( color.rgb * (0.2 + NdotH), 1.0 );
        } 
        </script>
        
        <script id="post-shader-vs" type="x-shader/x-vertex">
        precision mediump float;
        
        attribute vec2 inPos;
        
        varying   vec2 pos;
        
        void main()
        {
            pos = inPos;
            gl_Position = vec4( inPos, 0.0, 1.0 );
        }
        </script>
        
        <script id="blur-shader-fs" type="x-shader/x-fragment">
        precision mediump float;
        
        varying vec2 pos;
        
        uniform sampler2D u_texture;
        uniform vec2      u_textureSize;
        uniform float     u_sigma;
        uniform float     u_radius;
        uniform vec2      u_dir;
        
        float CalcGauss( float x, float sigma )
        {
            if ( sigma <= 0.0 )
                return 0.0;
          return exp( -(x*x) / (2.0 * sigma) ) / (2.0 * 3.14157 * sigma);
        }
        
        void main()
        {
            vec2 texC     = pos.st * 0.5 + 0.5;
            vec4 texCol   = texture2D( u_texture, texC );
            vec4 gaussCol = vec4( texCol.rgb, 1.0 );
            vec2 step     = u_dir / u_textureSize;
            for ( int i = 1; i <= 32; ++ i )
            {
                float weight = CalcGauss( float(i) / 32.0, u_sigma * 0.5 );
                if ( weight < 1.0/255.0 )
                    break;
                texCol    = texture2D( u_texture, texC + u_radius * step * float(i) );
                gaussCol += vec4( texCol.rgb * weight, weight );
                texCol    = texture2D( u_texture, texC - u_radius * step * float(i) );
                gaussCol += vec4( texCol.rgb * weight, weight );
            }
            gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
            gl_FragColor = vec4( gaussCol.rgb, 1.0 );
        }
        </script>
        
        <div>
        <form id="gui" name="inputs">
        <table>
        <tr> <td> <font color= #CCF>radius</font> </td> 
                <td> <input type="range" id="radius" min="1" max="1000" value="350" onchange="changeEventHandler(event);"/></td> </tr>
        <tr> <td> <font color= #CCF>blur</font> </td> 
                <td> <input type="range" id="sigma" min="1" max="100" value="5" onchange="changeEventHandler(event);"/></td> </tr>
        </table>
        </form>
        </div>
        
        <canvas id="canvas" style="border: none;"></canvas>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-09-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多