TeaPot 用webgl畫茶壺(2) Phong Shading

來源:互聯網
上載者:User

標籤:length   rom   identity   沒有   ice   from   tco   大小   角度   

在Fragment Shader裡應用Phong Shading使得茶壺更逼真。即使是單一顏色的茶壺,只要光源的位置變化,或眼睛的位置變化,看到的茶壺的各個部分的顏色明暗是不一定一樣的。所謂Phong Shading就是Phong這個人提出的一種決定每個像素顏色的方法。

總的來說,我們希望看到怎樣的茶壺?我們希望它跟真的一樣,有光照著它,所以照到的地方亮,照不到的地方暗,迎著光的地方還有高亮反射光。

點e看到點p有顏色,是因為有光子從p跑到了e。點p有光子,除非p是光源,不然光子肯定是從別的地方跑來。這個別的地方之一,就是光源,有光源照著p。但是,如果沒有光源的直射,比如拉上窗帘的房間裡,還是可以看到p,因為p點周圍無數個點(茶壺上其它部分,杯子,桌子等等)都往它發射著光子。這是別的地方之二,環境。

 

總結一下一個點p(不是光源),被在e點看到了,說明

1. 有光子從別的地方跑到了p。

  兩個可能的來處,一是光源,一是環境。

2.p點的光子又跑到了e

到達p的光子有三個可能,一是被吸收產生熱量,二是打入內部又散射出來,三是直接從表面反射出去。被吸收的就不用考慮了,剩下的一部分散射,一部分反射,散射是指這一部分光子從p出來後往各個方向跑(當然還是沿著直線),有一個方向指向e,e會看到散射光。散射光往往代表p本來的顏色,反射光與p本來的顏色幾乎無關,因為它沒有進入p內部而是在p處改變了方向,它還是原來的光。因為環境給p的光子是從各個方向來的,不好分析它們的反射方向,數量又不大,所以一般認為從環境裡到達p的光子全都散射出去了。

 

環境裡到達p的光子強度是固定的,而且它到達茶壺其它p1,p2等等的光子強度一樣。而同一個光源,給茶壺各個p,p1,p2的光子強度卻不是固定的。這個強度的大小與入射角度有關。Lambertian表示可以用  cos(p的法向量n與入射光的反方向向量l的夾角)*L的強度  來代表光源L到達p的強度,也就是n=normalize(n),l=normalize(l),dot(n,l)*L的強度。dot(n,l)可能小於0,小於0代表光是從p背面照著它,所以沒有光子跑到p,max(0, dot(n,l))*L的強度。

光源的反射部分的方向是可以算出的,是向量r。e-p與r的夾角越小,說明接收的反射的越多。也可以看,向量h與n的夾角,h=normalize(e-p+l)。

p點的顏色=環境光線的強度與顏色*散射係數+光源強度與顏色*max(0, dot(n,l))*散射係數+光源強度與顏色*pow(dot(h,n),P)

散射係數與p本身顏色緊密相關。pow是為了快速縮小高亮大小,否則高亮不真。P是光滑係數。

pow(dot(h,n),P)是改良的Phong shading。Phong提出的是pow(max(0,dot(r,e-p)),P)。區別是當e-p與r是鈍角時,改良後的Phong Shading依然會產生反射光。光滑的表面放大後依然粗糙,有面向各個方向的Microfacets。

http://opengl.datenwolf.net/gltut/html/Illumination/Tutorial%2011.html

<html>    <head>        <title>TeaPolt</title>    </head>        <body onload="main()">        <canvas id="viewPort" width="600" height="800">            This browser do not support webgl.        </canvas>        <script src="./examples/lib/cuon-matrix.js"></script>    <script src="./TeaPotData.js"></script>    <script>function main(){    //alert("bb");    //get webgl context    var viewPort = document.getElementById("viewPort");    var gl = viewPort.getContext("webgl") || viewPort.getContext("experimental-webgl");        var VERTEX_SHADER =    "attribute vec4 a_Position;\n" +    "attribute vec3 a_VNomal;\n" +    "varying vec4 v_Position;\n" +    "varying vec3 v_VNomal;\n" +    "uniform mat4 u_ModelMatrix;\n" +    "uniform mat4 u_ViewMatrix;\n" +    "uniform mat4 u_ProjMatrix;\n" +    "void main()\n" +    "{\n" +    " gl_Position = u_ProjMatrix*u_ViewMatrix*u_ModelMatrix*a_Position;\n" +    " v_Position = a_Position;\n" +    " v_VNomal = a_VNomal;\n" +    "}\n"; //光線向量l不是線性插值的,必須在FragmentShader裡算,所以每一個Fragment要帶它所對應的vertex在空間裡的位置(位置是可以插值的)。用著個位置和光源位置來算l。        var FRAGMENT_SHADER =     "#ifdef GL_ES\n" +    "precision mediump float;\n" +    "#endif\n" +    "uniform vec3 u_EyePosition;\n" +    "uniform vec3 u_pointLightPosition;\n" +    "varying vec4 v_Position;\n" +    "varying vec3 v_VNomal;\n" +    "void main()\n" +    "{\n" +    "   vec4 pointLightColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +    "   vec4 pointlightStrength = vec4(1.0, 1.0, 1.0, 1.0);\n" +    "   vec4 envLightColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +    "   vec4 envlightStrength = vec4(0.3, 0.3, 0.3, 1.0);\n" +    "   vec4 matrilColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +    "   float p = 6.0;\n" +    "   vec3 l = normalize(vec3(u_pointLightPosition.x - v_Position.x, u_pointLightPosition.y - v_Position.y, u_pointLightPosition.z - v_Position.z));\n" +    "   vec3 e = normalize(vec3(u_EyePosition.x - v_Position.x, u_EyePosition.y - v_Position.y, u_EyePosition.z - v_Position.z));\n" +    "   vec3 n = v_VNomal;\n" +    "   n = normalize(n);\n" +    "   float nl = dot(n, l);\n" +    "   if(nl<0.0) nl=0.0;\n" +    "   vec3 h = normalize(e+l);\n" +    "   float hn = dot(h, n);\n" +    "   gl_FragColor = matrilColor*envLightColor*envlightStrength+matrilColor*pointLightColor*pointlightStrength*nl+pointLightColor*pointlightStrength*pow(hn,p);\n" +    "}\n";    /*var VERTEX_SHADER =    "attribute vec4 a_Position;\n" +    "uniform mat4 u_ModelMatrix;\n" +    "uniform mat4 u_ViewMatrix;\n" +    "uniform mat4 u_ProjMatrix;\n" +    "void main()\n" +    "{\n" +    " gl_Position = u_ProjMatrix*u_ViewMatrix*u_ModelMatrix*a_Position;\n" +    "}\n";        var FRAGMENT_SHADER =     "#ifdef GL_ES\n" +    "precision mediump float;\n" +    "#endif\n" +    "void main()\n" +    "{\n" +    "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" +    "}\n";*/    var program = createProgram(gl, VERTEX_SHADER, FRAGMENT_SHADER);    if(!program)    {        return;    }    gl.useProgram(program);    gl.program = program;        var a_Position, u_ModelMatrix, u_ViewMatrix, u_ProjMatrix, a_VNomal, u_EyePosition, u_pointLightPosition;    a_Position = gl.getAttribLocation(gl.program, "a_Position");    a_VNomal = gl.getAttribLocation(gl.program, "a_VNomal");    u_ModelMatrix = gl.getUniformLocation(gl.program, "u_ModelMatrix");    u_ViewMatrix = gl.getUniformLocation(gl.program, "u_ViewMatrix");    u_ProjMatrix = gl.getUniformLocation(gl.program, "u_ProjMatrix");    u_EyePosition = gl.getUniformLocation(gl.program, "u_EyePosition");    u_pointLightPosition = gl.getUniformLocation(gl.program, "u_pointLightPosition");    if(a_Position < 0 || a_VNomal < 0 || !u_ModelMatrix || !u_ViewMatrix || !u_ProjMatrix || !u_EyePosition || !u_pointLightPosition)    {        alert("Failed to get store location from progrom");        return;    }               //The following code snippet creates a vertex buffer and binds the vertices to it      var teaPotvPropertiesData = gl.createBuffer();      gl.bindBuffer(gl.ARRAY_BUFFER, teaPotvPropertiesData); //alert("bb"+teaPotData);    gl.bufferData(gl.ARRAY_BUFFER, teaPotData.vertexPositions, gl.STATIC_DRAW);    var VFSIZE = teaPotData.vertexPositions.BYTES_PER_ELEMENTS;    gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, VFSIZE * 3, VFSIZE * 0 );    gl.enableVertexAttribArray(a_Position);        var teaPotnPropertiesData = gl.createBuffer();    gl.bindBuffer(gl.ARRAY_BUFFER, teaPotnPropertiesData);    gl.bufferData(gl.ARRAY_BUFFER, teaPotData.vertexNormals, gl.STATIC_DRAW);    var VNFSIZE = teaPotData.vertexNormals.BYTES_PER_ELEMENT;    gl.vertexAttribPointer(a_VNomal, 3, gl.FLOAT, false, VNFSIZE * 3, VNFSIZE * 0);    gl.enableVertexAttribArray(a_VNomal);              //The following code snippet creates a vertex buffer and binds the indices to it      teaPotPropertiesIndex = gl.createBuffer();      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, teaPotPropertiesIndex);      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, teaPotData.indices, gl.STATIC_DRAW);     var IINDEX = teaPotData.indices.length;    var IFSIZE = teaPotData.indices.BYTES_PER_ELEMENT;//new Uint16Array(indices)        var eyePosition = new Float32Array([0.0, 0.0, 100.0]);    var pointLightPosition = new Float32Array([0.0, 0.0, 50.0]);    gl.uniform3fv(u_EyePosition, eyePosition);    gl.uniform3fv(u_pointLightPosition, pointLightPosition);        var modelMatrix = new Matrix4();    var viewMatrix = new Matrix4();    var projMatrix = new Matrix4();    viewMatrix.setLookAt(eyePosition[0], eyePosition[1], eyePosition[2], 0.0, 0.0, 0.0, 0, 1, 0);    projMatrix.setPerspective(30,viewPort.width/viewPort.height,1,100);    //modelMatrix.setRotate(0, 0, 1, 0);    modelMatrix.setIdentity();    //viewMatrix.setIdentity();    //projMatrix.setIdentity();        gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);    gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);    gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);        gl.clearColor(0.0, 0.0, 0.0, 1.0);    gl.clear(gl.COLOR_BUFFER_BIT || gl.DEPTH_BUFFER_BIT);    //gl.drawArrays(gl.TRIANGLES, 0, n);    gl.drawElements(gl.TRIANGLES, IINDEX, gl.UNSIGNED_SHORT, IFSIZE * 0);}        function createProgram(gl, vShaderSource, fShaderSource){    var vShader = createShader(gl, gl.VERTEX_SHADER, vShaderSource);    var fShader = createShader(gl, gl.FRAGMENT_SHADER, fShaderSource);    if(!vShader || !fShader)    {        return null;    }    var program = gl.createProgram();    if(!program)    {        return null;    }    gl.attachShader(program, vShader);    gl.attachShader(program, fShader);    gl.linkProgram(program);    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);    if(!linked)    {        alert("Failed to link program " + gl.getProgramInfoLog(program));        gl.deleteProgram(program);        gl.deleteShader(fragmentShader);        gl.deleteShader(vertexShader);        return null;    }    return program;        }        function createShader(gl, type, source){    var shader = gl.createShader(type);    if(!shader)    {        alert("Failed to create "+ type + "shader");        return null;    }    gl.shaderSource(shader, source);    gl.compileShader(shader);    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);    if(!compiled)    {        alert("Failed to compile shader " + gl.getShaderInfoLog(shader));        gl.deleteShader(shader);        return null;    }        return shader;}        </script>    </body></html>

 

TeaPot 用webgl畫茶壺(2) Phong Shading

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.