16.光照(平行光)

16.光照(平行光)1 基本概念 着色 根据光照条件 重建 物体表面明暗不一效果 的过程光源类型 1 平行光 没有衰减的平行的光线 类似于太阳光

大家好,欢迎来到IT知识分享网。

1.基本概念:

    着色:根据光照条件,重建“物体表面明暗不一效果”的过程

    光源类型:

        (1)平行光:没有衰减的平行的光线,类似于太阳光。用一个方向和一个颜色定义。

        (2)点光源:理想化为质点点光源,类似于人造灯泡,有光线衰减。用光源位置和颜色定义。

        (3)环境光:用于模拟真实世界中的非直射光(由光源发出经过墙壁或其他物体反射的光)。只需要指定颜色。

    反射光取决于以下两个因素:

        (1)入射光(入射光的方向和颜色)

        (2)物体表面类型(物体表面的固有颜色(基底色),和反射特性)

    物体表面反射光线的方式有两种:

        (1)漫反射:针对平行光和点光源而言,漫反射的反射光在各个方向上是均匀的,反射强度受入射角影响。

                我们将入射光线与表面法线形成的夹角为入射角,用B表示,那么

                <漫反射光颜色>=<入射光颜色>x<表面基底色>x cosB,乘法操作在矢量上逐分量进行

16.光照(平行光)

        (2)环境反射:针对环境光而言,反射光的方向就是入射光的反方向,所以反射光是各向均匀的。

                <环境反射光颜色>=<入射光颜色>x<表面基底色>

    综上:<表面的反射光颜色>=<漫反射光颜色>+<环境反射光颜色>

2.平行光漫反射的计算:

    平行光:平行光下物体每个面上光线的入射角是相同的,所以只要确定cosB的值再利用公式计算即可。

                 根据向量之间的点乘,a.b = |a|x|b|xcosB,如果a,b向量的模都是1,那么cosB = a.b,那么我们应该首先将a,b向量进行归一化

        (1)归一化:将矢量的长度调整为1,同时保持方向不变

                    GLSL ES提供了归一化函数,其原理是,将矢量的各个分量处以矢量的模,即n( nx/|n| , ny/|n| , nz/|n| )。

        (2)确定法向量方向:

                   法向量表示的是方向,平行平面的法向量相同;每个平面有两个方向相反的法向量,在三维图形学中,法向量方向和顶点的绘制顺序有关,法向量指向顶点绘制顺序逆时针的一方

        cosB = <光线方向>.<法线方向>,其中光线方向是入射光线的反方向(因为该方向与法线夹角才是入射角)。

    <漫反射光颜色>=<入射光颜色>x<表面基底色>x(<光线方向>x<法线方向>)

16.光照(平行光)

3.程序实现:

    (1)法向量和光线方向向量归一化:

            由于物体表面的法向量和顶点有关,法向量的归一化放在顶点着色器中进行

‘attribute vec4 a_Normal;\n’ +

‘vec3 normal = normalize(vec3(a_Normal));\n’ +

            在GLSL ES中,normalize()方法将矢量进行归一化,由于a_Normal声明为vec4类型,法向量由前三个分量x y z 定义,所以先使用vec3()构造器取出前三个分量

          光线方向矢量归一化:

            光线方向和物体本身无关,所以放在js代码中进行归一化,放在顶点着色器中会执行n遍,浪费计算机资源

    //设置光线方向

    var lightDirection = new Vector3([0.5,3.0,4.0]);

    //入射光线归一化

    lightDirection.normalize();

    gl.uniform3fv(u_LightDirection,lightDirection.elements);

            cuon-matrix.js中为Vector3类型提供了normalize()函数,调用后归一化后的分量值存入对象本身。

    (2)漫反射光颜色计算

   ‘ float nDotL = max(dot(u_LightDirection,normal),0.0);\n’ +

    ‘vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;\n’+

        法向量和光线方向向量的点乘运算:dot(n,l ),GLSL  ES内置dot方法计算矢量的点乘,入参为两个矢量,返回点积(标量)

        当点积结果小于0时,说明入射光线方向与法线夹角大于90度,光线照在平面的背面,所以颜色值为0,max(a,b)将a,b中较大的值赋给变量

    (3)环境光的计算

‘uniform vec3 u_AmbientLight;\n’ +

‘vec3 ambient = u_AmbientLight * a_Color.rgb;\n’+

        a_Color是一个vec4类型变量,前三个分量代表rgb值,只取其前三个分量进行计算

    (4)反射光颜色 = 漫反射光颜色+环境反射光颜色

‘v_Color = vec4(diffuse + ambient,a_Color.a);\n’ +

        最后计算的反射光有三个分量,v_Color有四个分量,将a_Color的a分量值写入

    (5)顶点法向量的写入

            顶点的法向量依赖于顶点组成的平面(TRIANGLE),由多个TRIANGLE共用的顶点在绘制每个TRIANGLE时拥有不同法向量(由顶点绘制顺序决定),例如正六面体中每个顶点被三面共用,那么需要的法向量就有64个

4.绘制光照立方体

var VSHADER_SOURCE = 'attribute vec4 a_Position;\n' + 'attribute vec4 a_Color;\n' + 'attribute vec4 a_Normal;\n' + 'uniform mat4 u_MvpMatrix;\n' + 'uniform vec3 u_LightColor;\n' + 'uniform vec3 u_LightDirection;\n' + 'varying vec4 v_Color;\n' + 'void main(){\n' + 'gl_Position = u_MvpMatrix * a_Position;\n' + //对法向量进行归一化 'vec3 normal = normalize(vec3(a_Normal));\n' + //计算光线方向和法向量乘积,已经完成归一化,u_LightDirection在js代码中已经完成归一化 'float nDotL = max(dot(u_LightDirection,normal),0.0);\n' + //计算漫反射光的颜色 'vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;\n'+ //a_Color.a是GLSL ES中对矢量的访问符,r,g,b,a 'v_Color = vec4(diffuse,a_Color.a);\n' + '}\n'; var FSHADER_SOURCE = 'precision mediump float;\n'+ 'varying vec4 v_Color;\n' + 'void main(){\n' + 'gl_FragColor = v_Color;\n' + '}\n'; function main(){ var canvas =document.getElementById('webgl'); var gl = canvas.getContext('webgl'); initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE); var n = initVertexBuffers(gl); //开启深度检测 gl.enable(gl.DEPTH_TEST); gl.clearColor(1.0,0.0,0.0,1.0); var u_LightColor = gl.getUniformLocation(gl.program,'u_LightColor'); var u_LightDirection = gl.getUniformLocation(gl.program,'u_LightDirection'); var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix'); //设置光线颜色 gl.uniform3f(u_LightColor,1.0,1.0,1.0); //设置光线方向 var lightDirection = new Vector3([0.5,3.0,4.0]); //入射光线归一化 lightDirection.normalize(); gl.uniform3fv(u_LightDirection,lightDirection.elements); //计算模型视图投影矩阵 var mvpMatrix = new Matrix4(); mvpMatrix.setPerspective(30,canvas.width/canvas.height,1,100); mvpMatrix.lookAt(3,3,7,0,0,0,0,1,0); //mvpMatrix.rotate(180,0,1,0); gl.uniformMatrix4fv(u_MvpMatrix,false,mvpMatrix.elements); gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0); } function initVertexBuffers(gl){ var verteices = 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 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,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,//顶面顶点法向量 0.0,-1.0,0.0, 0.0,-1.0,0.0, 0.0,-1.0,0.0, 0.0,-1.0,0.0//底面顶点法向量 ]); var colors = new Float32Array([ 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //前面的顶点颜色 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //右面顶点颜色 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //后面顶点颜色 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //左面顶点颜色 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //顶面顶点颜色 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //底面顶点颜色 ]); var indices = new Uint8Array([ 0,1,2,0,2,3, //前面的顶点索引 4,5,6,4,6,7, //右面顶点索引 8,9,10,8,10,11, //后面顶点索引 12,13,14,12,14,15, //左面顶点索引 16,17,18,16,18,19, //顶面顶点索引 20,21,22,20,22,23 //底面顶点索引 ]); var indexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW); initArrayBuffer(gl,verteices,3,gl.FLOAT,'a_Position'); initArrayBuffer(gl,colors,3,gl.FLOAT,'a_Color'); initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal'); return indices.length; } function initArrayBuffer(gl,data,num,type,attribute){ var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,buffer); gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW); var a_attribute = gl.getAttribLocation(gl.program,attribute); gl.vertexAttribPointer(a_attribute,num,type,false,0,0); gl.enableVertexAttribArray(a_attribute); return true; }

5.运动物体的光照效果:

    当物体发生平移、旋缩放等变换时,顶点的法向量可能会发生改变,根据模型矩阵计算变换后的法向量的方法是:

        用模型矩阵的逆转置矩阵乘以原法向量,就可以得到变换后的法向量。

    Matrix4提供了计算逆转置矩阵的方法:

        (1)求原矩阵的逆矩阵:

                Matrix4 . setInverseOf(m):将m矩阵的逆矩阵赋值给自身

        (2)对逆矩阵进行转置:

                Matrix4 . transpose():对自身进行操作,将自身设置为转置后的结果。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121459.html

(0)
上一篇 2025-10-23 15:15
下一篇 2025-10-23 15:20

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信