Osvětlení

Toto je kapitola o Phongovu modelu, kterým se řeší osvětlení ve 3D. Stále se nebude programovat, ale teorie zde probíraná je nezbytná pro pochopení vytváření osvětlené scény v 3D.

Osvětlení

Knihovna OpenGL má jakous takous podporu pro osvětlení, ale hodně jednoduchou a navíc deprecated (v budoucích verzích bude odstraněna).

Pokud chcete nějaký objekt osvětlit, musíte si osvětlení spočítat sami.

3D objekty se v OpenGL skládají z trojúhelníků. Osvětlit objekt tedy vlastně znamená, že zvýšíte intenzitu barvy těch trojůhelníků, které chcete nasvítit (které jsou čelem ke zdroji světla).

Výpočty barev trojůhelníků se dají provést dvěma způsoby.
Prvním způsob je ten, že se vypočítá barva pro každý vrchol (vertex) trojůhelníku a barvy uvnitř jeho plochy se nechají mezi vrcholy interpolovat grafickou kartou.
Druhý způsob je ten, že se vypočítává barva (osvětlení) pro každý pixel (shader).
Případně se dají kombinovat oba způsoby.

Shader je něco jako „virtuální pixel“. Grafická karta spočítá jeho barvu, ale při vykreslování na plátno může být překryt jiným shaderem na stejné pozici s menší souřadnicí z, nebo může být výsledná barva pixelu kombinací barev těchto shaderů (čímž se simuluje průhlednost) atp. Shader tedy není to samé jako pixel, ale můžete o něm prozatím uvažovat jako o „virtuálním“ pixelu.

Barva se skládá ze čtyř složek: červená = r (red), zelená = g (green), modrá = b (blue) a průhlednost = a (alpha).
Složky barvy i průhlednost mohou nabývat hodnot v intervalu <0.0,1.0>. Kde 1.0 je nejintenzivnější barva (resp. neprůhledná) a 0.0 je žádná barva (resp. 100% průhledná).

Takže barva (1,1,1,1) je neprůhledná bílá, (0,0,0,1) černá, (0,1,0,1) zelená, (?,?,?,0) zcela průhledná atp.

Barvu můžete občas zadávat i bez průhlednosti, tj. třeba jen (0,1,0) pro zelenou neprůhlednou barvu (alpha bude automaticky 1.0).

Phongův osvětlovací model

Na wikipedii se můžete podívat na obrázek, který ukazuje tzv. Phongův osvětlovací model. Ten popisuje několik různých složek světla, jejichž složením se získá výsledné osvětlení objektu. Postup pro výpočet intenzity světla těchto složek popisuji níže.

Phongův osvětlovací model

Zdroj: wikipedia

Okolní světlo (Ambient light)

Ambientní světlo osvětluje všechny plochy všech objektů rovnoměrně. Nebere tedy v potaz pozici zdroje světla (žádná není, svítí se všude), ani jeho vzdálenost. Pouze intenzitu.

Řekněme, že máme objekt s barvou (r, g, b). Jeho barva může mít maximální intenzitu (1, 1, 1) (úplně bílá) a minimální (0, 0, 0) (úplně černá barva, tedy „úplně ve tmě“).

Změna intenzity barvy se dá jednoduše měnit vynásobení barvy nějakým scalárem (nezáporným).

Například řekněme, že průměrné osvětlení má intenzitu 0.5. Pak bude výsledná barva mít hodnotu (0.5*r, 0.5*g, 0.5*b). (Hodnota průhlednosti alpha by se neměla osvětlením měnit).

Pro tmavě zelenou barvu (0, 0.5, 0) to znamená, že bude mít v takovémto osvětlení barvu (0, 0.25, 0) (ještě tmavější zelená).
Pro intenzitu 1.0 zůstane barva (0, 0.5, 0). Pro intenzitu 3 bude barva (0, 1.5, 0), což se automaticky ořízne na (0, 1.0, 0) – světlejší než 1.0 už barva být nemůže.

Takto jednoduše se dá počítat s bílým světlem. Světlo ale také může mít barvy. Například můžete vzít načervenalé světlo (2.0, 1.0, 1.0), a osvětlit jím šedivou barvu (0.5, 0.5, 0.5) tak, že vynásobíte jednotlivé složky. Výsledná barva pak bude mít hodnotu (0.5*2, 0.5*1, 0.5*1.0) = (1.0, 0.5, 0.5) (šedivá barva zčervená).

Ambientní světlo se tedy udává jako třírozměrný vektor, kde jednotlivé složky určují intenzitu osvětlení v barvách r,g,b. Tato hodnota se vynásobí s barvou objektu (vertexů nebo shaderů) a tím se scéna osvětlí (nebo případně ztmaví). Matematicky by se to dalo zapsat třeba takto:

color'= color*lightColor*intenzita

Kde color' je výsledná barva, color je původní barva (3-rozměrný vektor), lightColor jsou barevné složky světla (3-rozměrný vektor) a intenzita je scalár (nezáporný).

Difúzní světlo (Diffuse light)

Difůzní světlo už bere v potaz, pod jakým úhlem světlo na plochu dopadá. Čím je úhel větší, tím meší je intenzita světla (a naopak).

Při výpočtu difúzní složky světla už musíte znát směr, kterým světelné paprsky míří, případně i pozici světelného zdroje.

Difúzní světlo

Difúzní světlo

První případ, kde se bere v potaz jen směr, si můžete představit jako osvětlení sluncem. Slunce je tak daleko, že můžete výpočet zjednodušit tím, že berete všechny paprsky jako by byly rovnoběžné. Intenzita světla se počítá jako kosínus vektoru určující směr světla a normály plochy.

Pokud jsou tyto vektory rovnoběžné, vyjde kosínus 1 (maximální osvětlení), pokud jsou kolmé, vyjde 0 (žádné osvětlení).

Co je tedy potřeba pro výpočet světelné složky difúzního světla?

  • Intenzita barevných složek světla lightColor = (rs, gs, bs);
  • Směr, kterým se svítí lightDirection = (xs, ys, zs);
  • Směrový vektor osvětlované plochy normal = (x, y, z);
  • Barva plochy (vertexu nebo shaderu) color = (r, g, b);

K výpočtu kosínu mezi dvěma vektory se používá tzv. dot product. Pro tento výpočet existuje už hotová funkce, kterou můžete použít, nazvaná dot(). Takže nebudu popisovat matematiku, která se za touto funkcí skrývá, ikdyž je triviální.

Pokud argumenty funkce dot() jsou normalizované vektory (vektory délky 1), pak vrací kosínus úhlu, který vektory svírají.

Výsledek této funkce (s normalizovanými vektory) může být v intervalu <-1, 1>.

Pokud vyjde kosínus záporný, tak to znamená, že je plocha ke zdroji světla „zády“. V takovém případě se použije jako intenzita 0.0 (jinak by světlo barvu ztmavovalo, což je asi nesmysl).

Výpočet difuzního světla, resp. výsledné barvy vertexu nebo shaderu tedy vypadá takto:

color'= color* lightColor* max dot -ligtDirectionnormal 0.0

Všiměte si, že jsem otočil znaménko u lightDirection. Aby mi funkce dot() vrátila to správné znaménko, nesmí vektory ukazovat proti sobě (světlo se obvykle zadává ve směru proti ploše, kterou má osvětlit).

Mohl jsem dát znaménko i před funkci dot(), vyšlo by to stejně.

Druhá možnost, která bere v potaz i pozici světla, se liší pouze v tom, že se vektor určující směr světla vypočítává pro každý vertex nebo shader.

Výpočet tohoto vektoru je jednoduchý – odečtěte od sebe pozici světla a pozici vertexu (nebo shaderu), jehož barvu chcete spočítat.

lightDirection= vertexPosition- lightPosition

Výsledek se dosadí do předchozího vzorce a je hotovo. Dejte si jen pozor na pořadí operandů při odčítání, aby vám vektor neukazoval na opačnou stranu, než chcete.

Lesklé světlo (Specular light)

Lesklé světlo je takové, které se odráží od povrchu směrem k očím pozorovatele. Jako když házíte prasátka :-).

Musíte spočítat, pod jakým úhlem se světlo odrazí a jaký úhel svírá toto odražené světlo se směrem, kterým se dívá pozorovatel.

To je trochu složitější matematický výpočet, ale naštěstí existuje funkce relfect(), která vám s tím pomůže.

Vektor, který určuje směr pohledu se spočítá jako rozdíl pozice vertexu (shaderu) a pozice kamery. Výsledek je pak potřeba kvůli dalším výpočtům normalizovat.
Kamera se ale vždycky dívá z pozice [0,0,0] (pohyb kamerou je ve simulován pohybem modelu), takže směr pohledu se vypočítá takto:

eyeDirection=normalize-vertexPosition

Pro směr odrazu použiji funkci reflect():

reflectionDirection=reflect-lightDirectionnormal

Kde lightDirection je vektor určující směr, kterým svítí světlo a normal je jednotkový vektor kolmý na osvětlovanou plochu.

Při výpočtu lesklého světla se pro výpočet směru světla obvykle bere v potaz i pozice zdroje – viz výpočet lightDirection druhého případu u difuzního světla.

Výpočet intenzity světla vypadá stejně jako u difuzního světla:

intenzita= max dotreflectionDirectioneyeDirection 0.0

Intenzitu ještě můžete zostřit nebo rozptýlit tak, že ji umocníte na n-tou. Čím je n větší, tím je odražené světlo ostřejší. Intenzita totiž vychází <=0. Čím víc jí umocníte a čím menší je intenzita tím menší číslo vám vyjde – intenzita světla s rostoucím úhlem mezi okem a odraženým světlem rychleji klesá.

intenzita'=powintenzitan

Když to dáme všechno dohromady a nezapomeneme na barvu lesklého světla, získáme výslednou barvu takto:

color' = color * lightColor * pow max dotreflectionDirectioneyeDirection 0.0 n
Osvětlení

Animace ukazuje jehlan, kolem kterého rotuje zdroj světla kolem osy z. Nejlépe to uvidíte, když si jehlan nasměrujete špičkou k sobě.

Světlo „létá“ tak blízko jehlanu, že když otočíte jehlan odchlípnutou stranou přímo k sobě, světlo prolétne až za ní, takže tuto stranu neuvidíte osvětlenou.

Při výpočtu difuzního i lesklého světla jsem bral v potaz pocici zdroje světla.

Vedle animace můžete zapínat a vypínat ambientní, difuzní i lesklé světlo. (Vypnutí ambientního světla vlastně není vypnutí, ale nastavení jeho intenzity na (0, 0, 0)).



  1. <script id="shader-vs-reflect" type="x-shader/x-vertex">
  2.     attribute vec3 aVertexPosition;
  3.     attribute vec3 aVertexNormal;
  4.     attribute vec4 aVertexColor;
  5.     uniform mat4 uMVMatrix;
  6.     uniform mat4 uPMatrix;
  7.     uniform mat3 uNMatrix;
  8.  
  9.  
  10.     varying vec4 vColor;
  11.     varying vec4 mvPosition;
  12.     varying vec3 transformedNormal;
  13.  
  14.     void main(void) {
  15.         mvPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
  16.         gl_Position = uPMatrix * mvPosition;
  17.         vColor = aVertexColor;
  18.         transformedNormal = uNMatrix * aVertexNormal;
  19.     }
  20. </script>
  21.  
  22. <script id="shader-fs-reflect" type="x-shader/x-fragment">
  23.     precision mediump float;
  24.  
  25.     uniform vec3 uAmbientColor;
  26.     uniform vec3 uLightingPosition;
  27.     uniform vec3 uDirectionalColor;
  28.     uniform bool uLightBothSides;
  29.     uniform bool uUseSpecular;
  30.     uniform bool uUseDirectional;
  31.  
  32.     varying vec4 vColor;
  33.     varying vec4 mvPosition;
  34.     varying vec3 transformedNormal;
  35.  
  36.     void main(void) {
  37.         vec3 vLightIntenzity = uAmbientColor;
  38.  
  39.         vec3 normal = normalize(transformedNormal);
  40.         vec3 lightDirection = normalize(uLightingPosition - mvPosition.xyz);
  41.         // directional light
  42.         if(uUseDirectional) {
  43.                 float lightIntenzity = dot(normal, lightDirection);
  44.                 if(uLightBothSides) {
  45.                         lightIntenzity = max(lightIntenzity, -lightIntenzity);
  46.                 }else {
  47.                         lightIntenzity = max(lightIntenzity, 0.0);
  48.                 }
  49.                 vLightIntenzity += uDirectionalColor * lightIntenzity;
  50.         }
  51.  
  52.         // specular light
  53.         if(uUseSpecular) {
  54.                 vec3 eyeDirection = normalize(-mvPosition.xyz);
  55.                 vec3 reflectionDirection = reflect(-lightDirection, normal);
  56.                 float specularLightIntenzity = max(dot(reflectionDirection, eyeDirection),0.0);
  57.                 specularLightIntenzity = pow(specularLightIntenzity,10.0);
  58.                 vLightIntenzity += uDirectionalColor * specularLightIntenzity;
  59.         }
  60.  
  61.         gl_FragColor = vec4(vColor.rgb * vLightIntenzity, vColor.a);
  62.     }
  63. </script>
  1.     $(function() {
  2.         var lastX, lastY;
  3.         var canvas1 = document.getElementById('reflect1-canvas');
  4.         var canvas2 = document.getElementById('reflect2-canvas');
  5.         var canvas3 = document.getElementById('reflect3-canvas');
  6.         var lastDownTarget;
  7.         $(document).on('mousedown', function(event) {
  8.             lastDownTarget = event.target;
  9.             lastX = event.pageX; lastY = event.pageY;
  10.         });
  11.  
  12.         $(document).on('mousemove', function(event) {
  13.             if(lastDownTarget != canvas1 && lastDownTarget != canvas2 && lastDownTarget != canvas3)
  14.                 return;
  15.             var buttonDown = event.buttons == null ?event.wich : event.buttons;
  16.             if(!buttonDown) return;
  17.  
  18.             x = event.pageY - lastY;
  19.             y = event.pageX - lastX;
  20.             lastX = event.pageX;
  21.             lastY = event.pageY;
  22.                
  23.             var xAngle = WebGLUtils.degToRad(x/5.0);
  24.             var yAngle = WebGLUtils.degToRad(y/5.0);
  25.             updateAngles(xAngle, yAngle);
  26.             event.preventDefault();
  27.             return false;
  28.         });
  29.     });
  1.     var rotationMatrix = mat4.create();
  2.     mat4.identity(rotationMatrix);
  3.     mat4.rotate(rotationMatrix, rotationMatrix, 3.1415/14.0, [0, 1, 0]);
  4.     mat4.rotate(rotationMatrix, rotationMatrix, 3.1415/2.5, [1, 0, 0]);
  5.  
  6.     function updateAngles(xAngle, yAngle) {
  7.          var newRotationMatrix = mat4.create();
  8.          mat4.identity(newRotationMatrix);
  9.          mat4.rotate(newRotationMatrix, newRotationMatrix, xAngle, [1, 0, 0]);
  10.          mat4.rotate(newRotationMatrix, newRotationMatrix, yAngle, [0, 1, 0]);
  11.          mat4.multiply(rotationMatrix, newRotationMatrix, rotationMatrix);
  12.     }
  13.  
  14.     var rLight = 0; // rotace osvetleni ve stupnich
  15.     function drawScene(gl, canvas) {
  16.         var pMatrix = mat4.create();
  17.         var viewMatrix = mat4.create();
  18.         var mvMatrix = mat4.create();
  19.         var nMatrix = mat3.create();
  20.         gl.viewport(0, 0, canvas.width, canvas.height);
  21.         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  22.  
  23.         mat4.identity(pMatrix);
  24.         mat4.identity(viewMatrix);
  25.         mat4.identity(mvMatrix);
  26.  
  27.         /********************************************/
  28.         mat4.perspective(pMatrix, WebGLUtils.degToRad(45), canvas.width / canvas.height, 1.0, 100.0);
  29.         mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -10.0]);
  30.         mat4.multiply(mvMatrix, mvMatrix, rotationMatrix);
  31.         mat4.multiply(mvMatrix, viewMatrix, mvMatrix);
  32.         mat3.fromMat4(nMatrix, mvMatrix);
  33.         mat3.invert(nMatrix, nMatrix);
  34.         mat3.transpose(nMatrix, nMatrix);
  35.         /********************************************/
  36.         setMatrixUniforms(gl, pMatrix, mvMatrix, nMatrix, rLight);
  37.  
  38.         // vykresli osy
  39.         gl.bindBuffer(gl.ARRAY_BUFFER, buffers.lineBuffer);
  40.         gl.vertexAttribPointer(variables.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
  41.  
  42.         gl.bindBuffer(gl.ARRAY_BUFFER, buffers.lineNormalBuffer);
  43.         gl.vertexAttribPointer(variables.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
  44.  
  45.         gl.bindBuffer(gl.ARRAY_BUFFER, buffers.lineColorBuffer);
  46.         gl.vertexAttribPointer(variables.aVertexColor, 3, gl.FLOAT, false, 0, 0);
  47.  
  48.         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.lineIndicesBuffer);
  49.         gl.uniform1i(variables.uLightBothSides, 0);
  50.         gl.drawElements(gl.TRIANGLES, lineIndices.length, gl.UNSIGNED_SHORT, 0);
  51.  
  52.         // vykresli jehlan
  53.         gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positionBuffer);
  54.         gl.vertexAttribPointer(variables.aVertexPosition, 3, gl.FLOAT, false, 0, 0);
  55.  
  56.         gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normalBuffer);
  57.         gl.vertexAttribPointer(variables.aVertexNormal, 3, gl.FLOAT, false, 0, 0);
  58.  
  59.         gl.bindBuffer(gl.ARRAY_BUFFER, buffers.colorBuffer);
  60.         gl.vertexAttribPointer(variables.aVertexColor, 4, gl.FLOAT, false, 0, 0);
  61.  
  62.         gl.uniform1i(variables.uLightBothSides, 0);
  63.         gl.drawArrays(gl.TRIANGLES, 0, vertices.length/3);
  64.     }
  65.  
  66.     var lastTime = 0;
  67.     function animate() {
  68.         var timeNow = new Date().getTime();
  69.         if (lastTime != 0) {
  70.             var elapsed = timeNow - lastTime;
  71.             rLight += (45 * elapsed) / 1000.0;
  72.         }
  73.         if(rLight >= 360) rLight -= 360;
  74.         lastTime = timeNow;
  75.     }
  1. var variables = {};
  2. var buffers = {};
  3.  
  4. function initVariables(gl, shaderProgram) {
  5.     variables.aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition");
  6.     variables.aVertexNormal = gl.getAttribLocation(shaderProgram, "aVertexNormal");
  7.     variables.aVertexColor = gl.getAttribLocation(shaderProgram, "aVertexColor");
  8.     variables.uPMatrix = gl.getUniformLocation(shaderProgram, "uPMatrix");
  9.     variables.uMVMatrix = gl.getUniformLocation(shaderProgram, "uMVMatrix");
  10.     variables.uNMatrix = gl.getUniformLocation(shaderProgram, "uNMatrix");
  11.     variables.uAmbientColor = gl.getUniformLocation(shaderProgram, "uAmbientColor");
  12.     variables.uLightingPosition = gl.getUniformLocation(shaderProgram, "uLightingPosition");
  13.     variables.uDirectionalColor = gl.getUniformLocation(shaderProgram, "uDirectionalColor");
  14.     variables.uLightBothSides = gl.getUniformLocation(shaderProgram, "uLightBothSides");
  15.     variables.uUseSpecular = gl.getUniformLocation(shaderProgram, "uUseSpecular");
  16.     variables.uUseDirectional = gl.getUniformLocation(shaderProgram, "uUseDirectional");
  17.     gl.enableVertexAttribArray(variables.aVertexPosition);
  18.     gl.enableVertexAttribArray(variables.aVertexNormal);
  19.     gl.enableVertexAttribArray(variables.aVertexColor);
  20. }
  21.  
  22. function setMatrixUniforms(gl, pMatrix, mvMatrix, nMatrix, rLight) {
  23.     var useAmbient = $('input[type=checkbox]#uUseAmbient').is(':checked');
  24.     var useDirectional = $('input[type=checkbox]#uUseDirectional').is(':checked');
  25.     var useSpecular = $('input[type=checkbox]#uUseSpecular').is(':checked');
  26.  
  27.     gl.uniformMatrix4fv(variables.uPMatrix, false, pMatrix);
  28.     gl.uniformMatrix4fv(variables.uMVMatrix, false, mvMatrix);
  29.     gl.uniformMatrix3fv(variables.uNMatrix, false, nMatrix);
  30.     gl.uniform3f(variables.uDirectionalColor,0.8,0.8,0.8);
  31.  
  32.     rLight = WebGLUtils.degToRad(rLight);
  33.     var x = 2.0*Math.cos(rLight);
  34.     var y = 2.0*Math.sin(rLight);
  35.     z = -9.5;
  36.     gl.uniform3f(variables.uLightingPosition, x, y, z);
  37.  
  38.     gl.uniform1i(variables.uUseDirectional, useDirectional);
  39.     gl.uniform1i(variables.uUseSpecular, useSpecular);
  40.     if(useAmbient) {
  41.             gl.uniform3f(variables.uAmbientColor,0.2,0.2,0.2);
  42.     } else {
  43.             gl.uniform3f(variables.uAmbientColor,0.0,0.0,0.0);
  44.     }
  45. }
  46. var initBuffers = function(gl) {
  47.     buffers.positionBuffer = gl.createBuffer();
  48.     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positionBuffer);
  49.     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  50.  
  51.     buffers.colorBuffer = gl.createBuffer();
  52.     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.colorBuffer);
  53.     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
  54.  
  55.     var normals = createNormals(vertices, [1,1,1,1,1,1]);
  56.     buffers.normalBuffer = gl.createBuffer();
  57.     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normalBuffer);
  58.     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
  59. }
  60.  
  61. var initBuffersLines = function(gl) {
  62. }
  63.  
  64. function createNormals(vertices, direction) {
  65.    var normals = [];
  66.    var n = vec3.create();
  67.    var v1 =  vec3.create();
  68.    var v2 =  vec3.create();
  69.    for(var i = 0; i < vertices.length; i+=9) {
  70.         var j = i / 9;
  71.         var a = vec3.fromValues(vertices[i],vertices[i+1],vertices[i+2]);
  72.         var b = vec3.fromValues(vertices[i+3],vertices[i+4],vertices[i+5]);
  73.         var c = vec3.fromValues(vertices[i+6],vertices[i+7],vertices[i+8]);
  74.         vec3.sub(v1,a,b);
  75.         vec3.sub(v2,b,c);
  76.         vec3.cross(n, direction[j] ? v1 : v2, direction[j] ? v2 : v1);
  77.         vec3.normalize(n, n);
  78.         normals.push(n[0],n[1],n[2]);
  79.         normals.push(n[0],n[1],n[2]);
  80.         normals.push(n[0],n[1],n[2]);
  81.    }
  82.    return normals;
  83. }
  84. initBuffersLines = function(gl) {
  85.  
  86.     buffers.lineBuffer = gl.createBuffer();
  87.     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.lineBuffer);
  88.     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lines), gl.STATIC_DRAW);
  89.  
  90.     buffers.lineColorBuffer = gl.createBuffer();
  91.     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.lineColorBuffer);
  92.     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lineColors), gl.STATIC_DRAW);
  93.  
  94.     buffers.lineIndicesBuffer = gl.createBuffer();
  95.     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.lineIndicesBuffer);
  96.     gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(lineIndices), gl.STATIC_DRAW);
  97.  
  98.     var lineNormals = createLineNormals(lines, lineIndices);
  99.     buffers.lineNormalBuffer = gl.createBuffer();
  100.     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.lineNormalBuffer);
  101.     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lineNormals), gl.STATIC_DRAW);
  102. };
  103.  
  104. function createLineNormals(vertices, lineIndices) {
  105.    var normals = [];
  106.    var n = vec3.create();
  107.    var v1 =  vec3.create();
  108.    var v2 =  vec3.create();
  109.    for(var ii = 0; ii < lineIndices.length; ii+=3) {
  110.         var i1 = lineIndices[ii]*3;
  111.         var i2 = lineIndices[ii+1]*3;
  112.         var i3 = lineIndices[ii+2]*3;
  113.         var a = vec3.fromValues(vertices[i1],vertices[i1+1],vertices[i1+2]);
  114.         var b = vec3.fromValues(vertices[i2],vertices[i2+1],vertices[i2+2]);
  115.         var c = vec3.fromValues(vertices[i3],vertices[i3+1],vertices[i3+2]);
  116.         vec3.sub(v1,a,b);
  117.         vec3.sub(v2,b,c);
  118.         vec3.cross(n, v1, v2);
  119.         vec3.normalize(n, n);
  120.  
  121.         normals[i1] = n[0];
  122.         normals[i1+1] = n[1];
  123.         normals[i1+2] = n[2];
  124.         normals[i2] = n[0];
  125.         normals[i2+1] = n[1];
  126.         normals[i2+2] = n[2];
  127.         normals[i3] = n[0];
  128.         normals[i3+1] = n[1];
  129.         normals[i3+2] = n[2];
  130.  
  131.    }
  132.    return normals;
  133. }
  134. function tick(gl, canvas) {
  135.     drawScene(gl, canvas);
  136.     animate();
  137.     requestAnimFrame(function() { tick(gl, canvas);});
  138. }
  139.  
  140.  
  141. function webGLStart() {
  142.     var canvas = document.getElementById("reflect1-canvas");
  143.     var gl = WebGLUtils.setupWebGL(canvas, { antialias: true });
  144.     if(!gl) return;
  145.     var shaderProgram = WebGLUtils.initShaders(gl, "shader-vs-reflect","shader-fs-reflect");
  146.     gl.useProgram(shaderProgram);
  147.     initVariables(gl,shaderProgram);
  148.     initBuffers(gl);
  149.     initBuffersLines(gl);
  150.     gl.clearColor(.0, .0, .0, 1.0);
  151.     gl.enable(gl.DEPTH_TEST);
  152.     tick(gl, canvas);
  153. }
  154.  
  155. webGLStart();

Závěr

Pokud vám té matematiky bylo málo, další výklad, přehledně a srozumitelně podaný, najdete třeba na http://chortle.ccsu.edu.

Pokud vám bylo matiky moc, pamatujte, že stačí rozumět tomu co je cílem výpočtu. Vzorečky si vždycky můžete odtud zkopírovat nebo si je někde vygooglit ;).

Komentář Hlášení chyby
Created: 1.3.2016
Last updated: 22.11.2017
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..