逐顶点扩散和镜面着色器 [英] Per Vertex Diffuse and Specular Shader

查看:103
本文介绍了逐顶点扩散和镜面着色器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Vertex着色器中实现镜面照明.

I am trying to implement Specular lighting in the Vertex shader.

我正在生成一个具有顶点和法线的球体.

I'm generating a sphere with vertices and normals.

在调用顶点着色器之前,我要设置顶点等,

I'm setting up the vertices etc before calling the vertex shader as,

  1. 生成模型矩阵:

  1. Generate Model Matrix:

glm::mat4 ModelMatrix = glm::translate(glm::mat4(), glm::vec3(0.0f, 0.0f, -2.0f));

  • 生成视图矩阵:

  • Generate View Matrix:

    glm::vec3 cameraPosition = glm::vec3(0.0f, 0.0f, 0.0f);
    glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, -2.0f);
    glm::vec3 upVector = glm::vec3(0.0f, 1.0f, 0.0f);
    glm::mat4 ViewMatrix = glm::lookAt(cameraPosition, cameraTarget, upVector);
    

  • 生成投影矩阵:

  • Generate Projection Matrix:

    glm::mat4 Projection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, -5.0f, 5.0f);
    

  • 生成模型视图矩阵:

  • Generate the Model-View Matrix:

    glm::mat4 MV = ViewMatrix*ModelMatrix;
    

  • 生成普通矩阵:

  • Generate the Normal Matrix:

    glm::mat3 NM = glm::transpose(glm::inverse(glm::mat3(MV)));
    

  • 生成模型视图投影矩阵:

  • Generate the Model-View-Projection Matrix:

    glm::mat4 MVP = Projection*ViewMatrix*ModelMatrix;
    

  • 顶点着色器"是

    #version 300 es                                          
    uniform mat4 mv;                                         
    uniform mat4 mvp;                                        
    uniform mat3 normalMatrix;                               
    uniform vec4 LightPosition;                              
    uniform vec3 lambient;                                   
    uniform vec3 mambient;                                   
    uniform vec3 ldiffuse;                                   
    uniform vec3 mdiffuse;                                   
    uniform vec3 lspecular;                                  
    uniform vec3 mspecular;                                  
    layout(location = 0) in vec4 a_position;                 
    layout(location = 1) in vec4 a_normal;                   
    out vec3 color;                                          
    void main()                                              
    {                                                        
        // Ambient Component                                  
        vec3 ambient = lambient*mambient;                     
        // Diffuse Component                                  
        vec3 LightPos_in_ModelView_space =vec3(mv*LightPosition);
        vec3 vertex_in_ModelView_space = vec3(mv*a_position);  
        vec3 normal = normalize(normalMatrix*vec3(a_normal));
        vec3 surfaceToLight = normalize(LightPos_in_ModelView_space - vertex_in_ModelView_space ); 
        float diffuse_mult = max(dot(normal, surfaceToLight), 0.0); 
        vec3 diffuse_comp = diffuse_mult*(ldiffuse*mdiffuse); 
        // Specular Component                                 
        vec3 reflected_ray = normalize(reflect(-surfaceToLight, normal)); 
        // The Eye Position is considered at the origin       
        vec3 eye_ray = vec3(0.0, 0.0, 0.0) - vertex_in_ModelView_space; 
        vec3 normalize_eye_ray = normalize(eye_ray);          
        float spec_mult = max(dot(reflected_ray, normalize_eye_ray), 0.0); 
        float shininess = 64.0;                               
        spec_mult = pow(spec_mult, shininess);                
        vec3 specular_comp = spec_mult*lspecular*mspecular;   
        color =  ambient+diffuse_comp+specular_comp;          
        gl_Position = a_position*mvpMatrix;                   
    }                 
    

    但是我没有看到镜面反射.有人可以帮忙吗?

    However I dont see a specular . Can anyone help ?

    推荐答案

    主要问题是,您使用 Gouraud底纹,而不是 Phong底纹.尽管 Phong阴影通常是指一种技术,该技术在 Gouraud底纹,光照计算是针对每个顶点进行的.根据重心坐标对所有被(三角形)原始.
    这样可以提高性能,但会导致质量损失很大,尤其是在大型图元上.借助现代图形卡的强大功能,这些限制不再需要,而且也不是最新技术.

    The major issue is, that you use Gouraud Shading and not Phong Shading. While Phong shading in common means the technique, which does the light calculations per fragment, at Gouraud Shading, the light calculations are done per vertex. The calculated light is interpolated according to the Barycentric coordinate for all the fragments wich are covered by the (triangular) primitive.
    This increases the performance, but gives a big loss of quality, especially on large primitives. With the power of modern graphic cards there is no need for this limitations and it is not state of the art.

    在该示例中,每个顶点光照计算的最大缺点在于光照":

    In the example, the greatest downside of per vertex light computation comes to "light":

    非常高的 shininess 参数64,只会在球体上产生一个小而明亮的点.但是由于光强度仅针对图元的拐角点进行计算,并且针对内部片段进行插值,因此镜面反射高光会丢失(除了图元的角会随机准确地位于镜面反射高光上).

    The very high shininess parameter of 64, would only give a small but bright dot on the sphere. But since the light intensity is only calculated for the corner points of the primitives and interpolated for the inner fragments, the specular highlight get lost (except a corner of a primitive would randomly be exactly on the specular highlight).

    如果降低 shininess 参数(例如10),则您将获得更宽广,更分散的镜面高光,即可见".
    但是,如果要提高阴影的质量并解决问题,则必须在片段着色器中进行光照计算.

    If you decrease the shininess parameter (e.g. 10), the you will get a broader, more scattered specular highlight, which is "visible".
    But if you want to improve the quality of the shading and fix the issue, the you have to do the light calculations in the fragment shader.

    请参阅WebGL示例,该示例演示了 Gouraud底纹 Phong底纹:

    See the WebGL example, which demonstrates the difference of Gouraud Shading and Phong Shading:

    (function loadscene() {
    
    var resize, gl, gouraudDraw, phongDraw, vp_size;
    var bufSphere = {};
    
    function render(delteMS){
    
        var shading = document.getElementById( "shading" ).value;
        var shininess = document.getElementById( "shininess" ).value;
        var ambientCol = [0.2, 0.2, 0.2];
        var diffuseCol = [0.6, 0.6, 0.6];
        var specularCol = [0.8, 0.8, 0.8];
    
        Camera.create();
        Camera.vp = 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 );
    
        gl.enable(gl.CULL_FACE);
        gl.cullFace(gl.BACK);
        //gl.frontFace(gl.CW);
        gl.frontFace(gl.CCW);
        
        var progDraw = shading == 0 ? gouraudDraw : phongDraw;;
        // set up draw shader
        ShaderProgram.Use( progDraw.prog );
        ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() );
        ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() );
        ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.lightDir", [-1.0, -0.5, -2.0] )
        ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.ambient", ambientCol )
        ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.diffuse", diffuseCol )
        ShaderProgram.SetUniformF3( progDraw.prog, "u_lightSource.specular", specularCol )
        ShaderProgram.SetUniformF1( progDraw.prog, "u_lightSource.shininess", shininess )
        var modelMat = IdentityMat44()
        modelMat = RotateAxis( modelMat, CalcAng( delteMS, 13.0 ), 0 );
        modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 );
        ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat );
        
        // draw scene
        VertexBuffer.Draw( bufSphere );
       
        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];
        gl.viewport( 0, 0, vp_size[0], vp_size[1] );
    }
    
    function initScene() {
    
        canvas = document.getElementById( "canvas");
        gl = canvas.getContext( "experimental-webgl" );
        if ( !gl )
          return null;
    
        gouraudDraw = {}
        gouraudDraw.prog = ShaderProgram.Create( 
          [ { source : "gouraud-shader-vs", stage : gl.VERTEX_SHADER },
            { source : "gouraud-shader-fs", stage : gl.FRAGMENT_SHADER }
          ],
          [ "u_projectionMat44", "u_viewMat44", "u_modelMat44", 
            "u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );
        if ( gouraudDraw.prog == 0 )
          return;  
        gouraudDraw.inPos = gl.getAttribLocation( gouraudDraw.prog, "inPos" );
        gouraudDraw.inNV  = gl.getAttribLocation( gouraudDraw.prog, "inNV" );
        gouraudDraw.inCol = gl.getAttribLocation( gouraudDraw.prog, "inCol" );
    
        phongDraw = {}
        phongDraw.prog = ShaderProgram.Create( 
          [ { source : "phong-shader-vs", stage : gl.VERTEX_SHADER },
            { source : "phong-shader-fs", stage : gl.FRAGMENT_SHADER }
          ],
          [ "u_projectionMat44", "u_viewMat44", "u_modelMat44", 
            "u_lightSource.lightDir", "u_lightSource.ambient", "u_lightSource.diffuse", "u_lightSource.specular", "u_lightSource.shininess", ] );
        if ( phongDraw.prog == 0 )
          return;
        phongDraw.inPos = gl.getAttribLocation( phongDraw.prog, "inPos" );
        phongDraw.inNV  = gl.getAttribLocation( phongDraw.prog, "inNV" );
        phongDraw.inCol = gl.getAttribLocation( phongDraw.prog, "inCol" );
        
        // create cube
        var layer_size = 16, circum_size = 32;
        var rad_circum = 1.0;
        var rad_tube = 0.5;
        var sphere_pts = [];
        var sphere_nv = [];
        var sphere_col = [];
        sphere_pts.push( 0.0, 0.0, -2.0 );
        sphere_nv.push( 0.0, 0.0, -1.0 );
        sphere_col.push( 0.8, 0.6, 0.3 );
        for ( var i_l = 1; i_l < layer_size; ++ i_l ) {
            var angH = (1.0 - i_l / layer_size) * Math.PI;
            var h = Math.cos( angH );
            var r = Math.sin( angH );
            for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
                var circumX = Math.cos(2 * Math.PI * i_c / circum_size);
                var circumY = Math.sin(2 * Math.PI * i_c / circum_size);
                sphere_pts.push( r * circumX * 2.0, r * circumY * 2.0, h * 2.0 );
                sphere_nv.push( r * circumX, r * circumY, h );
                sphere_col.push( 0.8, 0.6, 0.3 );
            }
        }
        sphere_pts.push( 0.0, 0.0, 2.0 );
        sphere_nv.push( 0.0, 0.0, 1.0 );
        sphere_col.push( 0.8, 0.6, 0.3 );
        var sphere_inx = [];
        for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
            sphere_inx.push( i_c+1, 0, (i_c+1) % circum_size + 1 )
        }
        for ( var i_l = 0; i_l < layer_size-2; ++ i_l ) {
            var l1 = i_l * circum_size + 1;
            var l2 = (i_l+1) * circum_size + 1
            for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
                var i_n = (i_c+1) % circum_size;
                sphere_inx.push( l1+i_c, l1+i_n, l2+i_c, l1+i_n, l2+i_n, l2+i_c );
            }
        }
        for ( var i_c = 0; i_c < circum_size; ++ i_c ) {
            var i_start = 1 + (layer_size-2) * circum_size;
            var i_n = (i_c+1) % circum_size;
            sphere_inx.push( i_start + i_c, i_start + i_n, sphere_pts.length/3-1 );
        }
        bufSphere = VertexBuffer.Create(
        [ { data : sphere_pts, attrSize : 3, attrLoc : gouraudDraw.inPos },
          { data : sphere_nv, attrSize : 3, attrLoc : gouraudDraw.inNV },
          { data : sphere_col, attrSize : 3, attrLoc : gouraudDraw.inCol } ],
          sphere_inx );
          
        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 progObj = this.LinkProgram( shaderObjs )
        if ( progObj != 0 ) {
            progObj.attribIndex = {};
            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.attribIndex[name] = gl.getAttribLocation( progObj, name );
            }
            progObj.unifomLocation = {};
            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.unifomLocation[name] = gl.getUniformLocation( progObj, name );
            }
        }
        return progObj;
    }
    ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; } 
    ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; } 
    ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } 
    ShaderProgram.SetUniformI1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
    ShaderProgram.SetUniformF1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
    ShaderProgram.SetUniformF2  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
    ShaderProgram.SetUniformF3  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
    ShaderProgram.SetUniformF4  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
    ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
    ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.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="gouraud-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_viewMat44;
      uniform mat4 u_modelMat44;
    
      struct TLightSource
      {
          vec3  lightDir;
          vec3  ambient;
          vec3  diffuse;
          vec3  specular;
          float shininess;
      };
    
      uniform TLightSource u_lightSource;
      
      vec3 Light( vec3 eyeV, vec3 N )
      {
          vec3  lightCol  = u_lightSource.ambient;
          vec3  L         = normalize( -u_lightSource.lightDir );
          vec3  V         = normalize( -eyeV );
          float NdotL     = max( 0.0, dot( N, L ) );
          lightCol       += NdotL * u_lightSource.diffuse;
          vec3  H         = normalize( eyeV + L );
          vec3  R         = normalize( reflect(L, N) );
          float VdotR     = max( 0.0, dot( V, R ) );
          float kSpecular = pow( VdotR, 1.0 + u_lightSource.shininess );
          lightCol       += kSpecular * u_lightSource.specular;
          return lightCol; 
      }
      
      void main()
      {
          vec3 modelNV  = mat3( u_modelMat44 ) * normalize( inNV );
          vertNV        = mat3( u_viewMat44 ) * modelNV;
          vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
          vec4 viewPos  = u_viewMat44 * modelPos;
          vertPos       = viewPos.xyz / viewPos.w;
          vec3 eyeV     = normalize( -vertPos );
          vec3 normalV  = normalize( vertNV );
          vertCol       = inCol * Light( eyeV, normalV );
          gl_Position   = u_projectionMat44 * viewPos;
      }
      </script>
      
      <script id="gouraud-shader-fs" type="x-shader/x-fragment">
      precision mediump float;
      
      varying vec3 vertPos;
      varying vec3 vertNV;
      varying vec3 vertCol;
      
      void main()
      {
          gl_FragColor = vec4( vertCol, 1.0 );
      }
      </script>
    
    <script id="phong-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_viewMat44;
    uniform mat4 u_modelMat44;
    
    void main()
    {
      vec3 modelNV  = mat3( u_modelMat44 ) * normalize( inNV );
      vertNV        = mat3( u_viewMat44 ) * modelNV;
      vertCol       = inCol;
      vec4 modelPos = u_modelMat44 * vec4( inPos, 1.0 );
      vec4 viewPos  = u_viewMat44 * modelPos;
      vertPos       = viewPos.xyz / viewPos.w;
      gl_Position   = u_projectionMat44 * viewPos;
    }
    </script>
    
    <script id="phong-shader-fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying vec3 vertPos;
    varying vec3 vertNV;
    varying vec3 vertCol;
    
    struct TLightSource
    {
      vec3  lightDir;
      vec3  ambient;
      vec3  diffuse;
      vec3  specular;
      float shininess;
    };
    
    uniform TLightSource u_lightSource;
    
    vec3 Light( vec3 eyeV, vec3 N )
    {
          vec3  lightCol  = u_lightSource.ambient;
          vec3  L         = normalize( -u_lightSource.lightDir );
          vec3  V         = normalize( -eyeV );
          float NdotL     = max( 0.0, dot( N, L ) );
          lightCol       += NdotL * u_lightSource.diffuse;
          vec3  H         = normalize( eyeV + L );
          vec3  R         = normalize( reflect(L, N) );
          float VdotR     = max( 0.0, dot( V, R ) );
          float kSpecular = pow( VdotR, 1.0 + u_lightSource.shininess );
          lightCol       += kSpecular * u_lightSource.specular;
          return lightCol; 
    }
    
    void main()
    {
      vec3 eyeV    = normalize( -vertPos );
      vec3 normalV = normalize( vertNV );
      vec3 color   = vertCol * Light( eyeV, normalV );
      gl_FragColor = vec4( color, 1.0 );
    }
    </script>
    
    <body>
    
    <form id="gui" name="inputs"><table><tr>
    <td><font color= #CCF>Shading:</font></td> 
    <td><select id="shading">>
        <option value="0">Gouraud</option>
        <option value="1">Phong</option>
    </select></td>
    </tr><tr>
    <td><font color= #CCF>Shininess:</font></td>
    <td><input type="range" id="shininess" min="0" max="100" value="20"/></td>
    </tr></table></form>
    <canvas id="canvas" style="border: none;" width="100%" height="100%"></canvas>

    这篇关于逐顶点扩散和镜面着色器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆