当前位置:首页 > 实验 > 正文内容

未命名

Luz3周前 (01-05)实验87

实验名称:

简单光照明模型

一、实验目的

了解简单光照明模型的基本原理;

掌握简单光照明模型的计算方法;

根据WebGL光照示范代码,实现简单物体的光照效果。


二、实验内容

(1) 示范代码为立方体在一束平行光照射下的漫反射光照效果。结合所给示范代码,学习掌握简单光照明模型的基本原理与算法实现;

(2) 修改示范代码,给出不同光照参数和立方体位置,观察与验证光照效果;

(3) 示范代码仅有漫反射光的光照效果,请尝试为其添加环境反射光和镜面反射光效果。

简单光照明模型指的是物体表面上一点P 反射到视点的光强I 为环境光的反射光强e I 、理想漫反射光强d I 、和镜面反射光s I 的总和,即



其中,R,V,N 为单位矢量,如图 1 所示。 p I 为点光源发出的入射光强; a I 为环境光的漫反射光强; a K 为环境光的漫反射系数; d K 为漫反射系数; s K 为镜面反射系数;n 为镜面反射指数,用以反映物体表面的光滑程度,表面越光滑,n 越大。这些参数与材料表面特性有关。



在用Phong模型进行真实感图形计算时,对物体表面上的每个点P,均需计算光线的反射方向R,再由V计算(V⋅R)。为减少计算量,常用(N⋅H)近似(V⋅R),这里H为L和V的角平分向量,即:



在这种简化下,由于对所有的点总共只需计算一次H的值,节省了计算时间。

本次实验中,我们假定使用的光源光线为平行光,光线方向为单位向量L (-0.5,1,1),视点在 (0.0,0.0,5.0)点处,视线方向V需要逐点计算。


三、实验代码及结果

(关键代码)

var gl;

function startup(){

var canvas =

document.getElementById('myGLCanvas');//获取<canvas>元素

    gl = createGLContext(canvas);

    setupShaders(); 

  var n = initVertexBuffers(gl);

  if (n < 0) {

    console.log('Failed to set the positions of the vertices');

    return;

  }

  gl.clearColor(0.8, 0.8, 0.8, 1.0);

  gl.enable(gl.DEPTH_TEST);

  var u_MvpMatrix = 

gl.getUniformLocation(gl.program, 'u_MvpMatrix');

  var u_LightColor =

 gl.getUniformLocation(gl.program, 'u_LightColor');

  var u_LightDirection =

 gl.getUniformLocation(gl.program, 'u_LightDirection');

  if (!u_MvpMatrix || !u_LightColor || !u_LightDirection) { 

    console.log('Failed to get the storage location');   return;

  }

    gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0); // Set the light color (white)

var lightDirection =

vec3.fromValues(-0.5, 1, 1);

vec3.normalize(lightDirection,lightDirection); // Normalize

    gl.uniform3fv(u_LightDirection, lightDirection);


var eye = vec3.fromValues(0.0, 0.0, 5.0);

  var center = vec3.fromValues(0.0, 0.0, 0.0);

  var up = vec3.fromValues(0.0, 1.0, 0.0);

  var vMatrix = mat4.create();

  mat4.lookAt(vMatrix, eye, center, up);

  // Model Matrix

  var mMatrix = mat4.create();

  mat4.scale(mMatrix, mMatrix, [1.0, 1.0, 1.0]);

  mat4.rotate(mMatrix, mMatrix, 

Math.PI/4, [0.0, 1.0, 0.0]);

  var pMatrix = mat4.create();

  mat4.frustum(pMatrix, -1.0, 1.0, -1.0, 1.0, 1.5, 20.0);

  var mvpMatrix = mat4.create();

  mat4.multiply(mvpMatrix, vMatrix, 

mMatrix);

  mat4.multiply(mvpMatrix, pMatrix,

 mvpMatrix);

  gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix);

   gl.drawElements(gl.TRIANGLES, n, 

gl.UNSIGNED_BYTE, 0);

 }

// 立方体绘制

function initVertexBuffers(gl) {

  // Create a cube

  var vertices = new Float32Array([    

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, 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,-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 colors = new Float32Array([    

1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0, 

1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,

1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0, 

1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0, 

1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0, 

1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0

  ]);

  var normals = new Float32Array([ 

   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   

0.0, 0.0, 1.0,   0.0, 0.0, 1.0,  

1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   

1.0, 0.0, 0.0,   1.0, 0.0, 0.0,  

0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   

0.0, 1.0, 0.0,   0.0, 1.0, 0.0,  

   -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  

-1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  

0.0,-1.0, 0.0,   0.0,-1.0, 0.0,

   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,  

0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   

0.0, 0.0,-1.0,   0.0, 0.0,-1.0   

  ]);

   var indices = new Uint8Array([

     0, 1, 2,   0, 2, 3,    // front

     4, 5, 6,   4, 6, 7,    // right

     8, 9,10,   8,10,11,    // up

    12,13,14,  12,14,15,    // left

    16,17,18,  16,18,19,    // down

    20,21,22,  20,22,23     // back

  ]);

var indexBuffer = gl.createBuffer();

  if (!indexBuffer) 

    return -1;

  if (!initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT)) return -1;


 if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;

  if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

  return indices.length;

}

function initArrayBuffer (gl, attribute, data, num, type) {

  var buffer = gl.createBuffer();

  if (!buffer) {

    console.log('Failed to create the buffer object');

    return false;

  }

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

   var a_attribute = 

   getAttribLocation(gl.program, attribute);

  if (a_attribute < 0) {

    console.log('Failed to get the storage location of ' + attribute);

    return false;

  }

  gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);

  gl.enableVertexAttribArray(a_attribute);

  gl.bindBuffer(gl.ARRAY_BUFFER, null);

  return true;

}


实验结果:














四、实验提高及结果

  在球体上实现简单光照明的实现与效果验证。


<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title></title>

    <style>

        body{

            margin: 0;

            padding: 0;

        }

    </style>

</head>

<body>

<canvas id="cvs" width="800" height="800"></canvas>

<div></div>

 

<script id="vertex" type="text/v-shader">

  precision highp float;

  attribute vec3 position;

  uniform mat4 mat;

  varying vec4 color;

  void main(){

    gl_Position=mat*vec4(position,1.0);

 

    //color=vec4(gl_Position.x,gl_Position.y,gl_Position.z,0.8);

color=vec4(1,0,0,0.8);

}

</script>

<script  id="fragment" type="text/f-shader">

#ifdef GL_ES

    precision mediump float;

#endif

    varying vec4 color;

    void main(){

        gl_FragColor=color;

    }

</script>

 

<script type="text/javascript">

    (function(global){

        var cvs = document.getElementById("cvs");

         var gl = cvs.getContext("experimental-webgl");

        var vertex = gl.createShader(gl.VERTEX_SHADER);

        var fragment = gl.createShader(gl.FRAGMENT_SHADER);

        var paogram = gl.createProgram();

 

        gl.shaderSource(vertex,document.getElementById("vertex").text);

        gl.shaderSource(fragment,document.getElementById("fragment").text);

        gl.compileShader(vertex);

        gl.compileShader(fragment);

        gl.attachShader(paogram,vertex);

        gl.attachShader(paogram,fragment);

        gl.linkProgram(paogram);

        gl.useProgram(paogram);

     

        var drawQiu02=function(rX,rY,rZ,r,m){

            var arr= new Array();

          

            var bufR=-r;

            function getMaxY(a,z,r){

                var angle=0;

                var addAng=360/a;

                var d=new Array();

     

                for(var i =0;i<a;i++){

                    d.push(Math.sin(Math.PI/180*angle)*r,Math.cos(Math.PI/180*angle)*r,z);

                    angle+=addAng;

                }

                return d;

            }

            var addAng=360/m;

                var angle=0;

                var bufR = r;

                var angle02=0;

                var addAng02=addAng;

              

              

            for(var i = 0;i<m/2;i++){

                

                if(i>=m/4){

                    var z =Math.sin(Math.PI/180*angle)*-r;

                }else{

                    var z =Math.sin(Math.PI/180*angle)*-r;

                }

                console.log(z);

                angle+=addAng;

                

                var arr1=getMaxY(m,z,bufR);

                if(i>=m/4){

                    z=Math.sin(Math.PI/180*angle)*-r

                }else{

                    z=-Math.sin(Math.PI/180*angle)*-r;

                }

                bufR=Math.sqrt(r*r-r*Math.sin(Math.PI/180*angle)*r*Math.sin(Math.PI/180*angle));

                var arr2=getMaxY(m,z,bufR);

          

                for(var q=0;q<arr1.length;q+=3){

                        if(q==0){

                            arr.push(arr1[q],arr1[q+1],arr1[q+2]);

                            arr.push(arr2[q],arr2[q+1],arr2[q+2]);

                            arr.push(arr1[arr1.length-3],arr1[arr1.length-2],arr1[arr1.length-1]);

                            arr.push(arr1[q],arr1[q+1],arr1[q+2]);

                            arr.push(arr2[q],arr2[q+1],arr2[q+2]);

                            arr.push(arr2[q+3],arr2[q+4],arr2[q+5]);

                        }else if(q==arr1.length-3){

                            arr.push(arr1[q],arr1[q+1],arr1[q+2]);

                            arr.push(arr2[q],arr2[q+1],arr2[q+2]);

                            arr.push(arr1[q-3],arr1[q-2],arr1[q-1]);

                            arr.push(arr1[q],arr1[q+1],arr1[q+2]);

                            arr.push(arr2[q],arr2[q+1],arr2[q+2]);

                            arr.push(arr2[0],arr2[1],arr2[2]);

                        }else{

                            arr.push(arr1[q],arr1[q+1],arr1[q+2]);

                            arr.push(arr2[q],arr2[q+1],arr2[q+2]);

                            arr.push(arr1[q-3],arr1[q-2],arr1[q-1]);

                            arr.push(arr1[q],arr1[q+1],arr1[q+2]);

                            arr.push(arr2[q],arr2[q+1],arr2[q+2]);

                            arr.push(arr2[q+3],arr2[q+4],arr2[q+5]);

                        }

                       

                }

            }

            return arr;

        }

 

        data=drawQiu02(0,0,0,0.5,180);

        var positionIndex = gl.getAttribLocation(paogram,"position");

        var matIndex = gl.getUniformLocation(paogram,"mat");

        console.log(gl.getShaderInfoLog(vertex));

        var mM=[

            1,0,0,0,

            0,1,0,0,

            0,0,1,0,

            0,0,0,1

        ];

        console.log(gl.getShaderInfoLog(fragment));

 

 

        global.rotateX=function (angle){

            var c = Math.cos(Math.PI/180*angle);

            var s = Math.sin(Math.PI/180*angle);

            var mM1=mM[1],mM5=mM[5],mM9=mM[9];

            mM[1] = c*mM[1] - s*mM[2];

            mM[5] = c*mM[5] - s*mM[6];

            mM[9] = c*mM[9] - s*mM[10];

 

            mM[2]=s*mM1+c*mM[2];

            mM[6]=s*mM5+c*mM[6];

            mM[10]=s*mM9+c*mM[10];

 

        };

        global.rotateY=function (angle){

            var c = Math.cos(Math.PI/180*angle);

            var s = Math.sin(Math.PI/180*angle);

            var mM0=mM[0],mM8=mM[8],mM4=mM[4];

            mM[0] = c*mM[0] + s*mM[2];

            mM[4] = c*mM[4] + s*mM[6];

            mM[8] = c*mM[8] + s*mM[10];

 

            mM[2] = c*mM[2]-s*mM0;

            mM[6] = c*mM[6]-s*mM4;

            mM[10] = c*mM[10]-s*mM8;

        };

        global.rotateZ=function (angle){

            var c = Math.cos(Math.PI/180*angle);

            var s = Math.sin(Math.PI/180*angle);

            var mM0=mM[0],mM4=mM[4],mM8=mM[8];

            mM[0] = c*mM[0]-s*mM[1];

            mM[4] =  c*mM[4]-s*mM[5];

            mM[8] =  c*mM[8]-s*mM[9];

 

            mM[1]=s*mM0+c*mM[1];

            mM[5]=s*mM4+c*mM[5];

            mM[9]=s*mM8+c*mM[9];

        };

        global.moveX= function(distance){

            mM[0]=mM[0]+distance*mM[3];

            mM[4]=mM[4]+distance*mM[7];

            mM[8]=mM[8]+distance*mM[11];

            mM[12]=mM[12]+distance*mM[15];

        };

        global.moveY= function(distance){

            mM[1]=distance*mM[3]+mM[1];

            mM[5]=distance*mM[7]+mM[5];

            mM[9]=distance*mM[11]+mM[9];

            mM[13]=distance*mM[15]+mM[13];

        };

        global.moveZ= function(distance){

            mM[2]=distance*mM[3]+mM[2];

            mM[6]=distance*mM[7]+mM[6];

            mM[10]=distance*mM[11]+mM[10];

            mM[14]=distance*mM[15]+mM[14];

        };

        global.scaleFun=function(scale){

            mM[0]=scale*mM[0];

            mM[4]=scale*mM[4];

            mM[8]=scale*mM[8];

            mM[12]=scale*mM[12];

            mM[1]=scale*mM[1];

            mM[5]=scale*mM[5];

            mM[9]=scale*mM[9];

            mM[13]=scale*mM[13];

            mM[2]=scale*mM[2];

            mM[6]=scale*mM[6];

            mM[10]=scale*mM[10];

            mM[14]=scale*mM[14];

        };

        var buffer = gl.createBuffer();

        gl.bindBuffer(gl.ARRAY_BUFFER,buffer);

        gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(data),gl.STATIC_DRAW);

        gl.vertexAttribPointer(positionIndex,3,gl.FLOAT,false,0,0);

 

        gl.enableVertexAttribArray(positionIndex);

        var dis= 0.05;

        var angle=0.5;

        function fun(){

 

            rotateX(angle);

            rotateY(angle);

            rotateZ(angle);

 

            gl.uniformMatrix4fv(matIndex,false,new Float32Array(mM));

            gl.clearColor(0.5, 0.5, 0.5, 1);

            gl.clear(gl.COLOR_BUFFER_BIT);

            gl.drawArrays(gl.LINE_STRIP,0,data.length/3);

            requestAnimationFrame(fun);

        }

        fun();

 

    })(window);

</script>

</body>

</html>



实验结果:

image.png


五、试验分析(思考)

根据代码示例,分析视角的改变在代码中的位置,通过改变视角方向,观察立方体的效果。其次分析出立方体所添加的漫反射代码位置,根据环境光,镜面反射的数学原理,改动代码,向量相加,求出所有环境光的影响。


发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。