WebGL三角形错误照明

问题描述

我有一个问题,可能与此类似:WebGL shading/lighting too dark on some triangles
我正在尝试将我的旧练习之一从使用过时的glaux的C ++ OpenGL移植到WebGL。
问题在于圆锥体显示错误的照明,当有多个切片时闪烁微弱:

enter image description here


一个以阿基米德螺线为底的圆锥,当有单个切片时可以使用:

enter image description here

enter image description here


左边是120个扇区,右边是12个扇区,在WebGL上是可以的。
当我使用多个切片(例如3个切片)时,问题就开始了:

enter image description here

enter image description here


该图像看起来有点脏,请参阅左侧图像。上部三角形(在右侧图像中突出显示)看起来显示的是错误的照明。
当我显示法线时,看起来计算正确。由于法线在两个三角形的拐角处重合:

enter image description here


我想使代码段更短,但是数学确实很长,也无法从GitHub添加脚本,因此我将它们内联。 verts代表顶点,verts_norms代表法线,nverts代表突出显示的法线。数学很简单,两个对称的阿基米德螺旋线相互叠加:
螺旋描述为F(φ)= [φ* cos(φ),φ* sin(φ)]
计算出的法线∇F(φ)= [sin(φ)+φ* cos(φ),-cos(φ)+φ* sin(φ),φ]


更新1,着色器:
<canvas id = "cone1 heart geometry" width = "400" height = "400"  class="yellow">
   <script src="./webgl3/cone1_heart_geometry3.js"></script>
   <script type="x-shader/x-vertex">
       attribute vec4 coordinates;
       attribute vec3 inputnormal;
       uniform float isDrawnorms;

       varying vec3 nm; //varying mediump
       varying float isnormsColor; //in place of flag
       void main()
       {
          gl_Position = coordinates;
          nm = inputnormal;
          isnormsColor = isDrawnorms;
       }
   </script>
   <script type="x-shader/x-fragment">
      precision mediump float;
      varying vec3 nm; //varying mediump

      varying float isnormsColor;
      const vec4  greenColor     = vec4( 0.0,1.0,0.0,1.0);
      const vec3 lightDirection  = -normalize(vec3(-1.0,-1.0,-1.0));
      void main()
      {
         if (isnormsColor < 0.5) gl_FragColor = vec4(greenColor.rgb * dot(lightDirection,normalize(nm)),1.0);
         if (isnormsColor > 0.5) gl_FragColor = vec4(0.5 * (nm + vec3(1.0)),1.0);
      }
   </script>
</canvas>
<html>
<head>
   <title>webgl test</title>
      <style>
         canvas.cyan    {border:2px solid cyan;}
         canvas.magenta {border:2px solid magenta;}
         canvas.blue    {border:2px solid blue;}
         canvas.red     {border:2px solid red;}
         canvas.yellow  {border:2px solid yellow;}
         canvas.green   {border:1px solid green;}
         div.sample { display: inline-block;white-space: Nowrap; border:1px solid magenta}
      </style>
<script>
const RADGRAD    = Math.PI / 180;
const C2PI       = 2 * Math.PI;
function wrap(x)
{
    if (isFinite(x)) return x;
    if (x == Number.POSITIVE_INFINITY) return Number.MAX_VALUE;
    if (x == Number.NEGATIVE_INFINITY) return Number.MIN_VALUE;
    return 0.0;
}
function delta3v(p1,p2)
{
   return {x:(p2.x - p1.x),y:(p2.y - p1.y),z:(p2.z - p1.z)};
}
function cross3v(p1,p2,p3)
{
    let v1 = delta3v(p1,p2);
    let v2 = delta3v(p1,p3);
    return {x:(v1.y * v2.z - v1.z * v2.y),y:(v1.z * v2.x - v1.x * v2.z),z: (v1.x * v2.y - v1.y * v2.x)};
}


function mul3v(v,f)
{
    return [v[0] * f[0],v[1] * f[1],v[2] * f[2]];
}
function dot3v(v,f)
{
    return v[0] * f[0]   +   v[1] * f[1]   +   v[2] * f[2];
}

</script>
<script>
function buildGlProgram(canvasVar)
{
   let canvas = null;
   let gl = null;
   if (typeof canvasVar == "string")
       canvas = document.getElementById(canvasVar);
   else if (typeof canvasVar == "object")
       canvas = canvasVar;
   //gl = canvas.getContext('webgl2');
   //gl = canvas.getContext('experimental-webgl2');
   gl = canvas.getContext('experimental-webgl');
   gl.viewport(0,canvas.width,canvas.height);
   
   let canvas_id = canvas.id;
   let codes = getGLshadercodes (canvas);

   let vertCode   = codes.vertCode;
   let vertShader = gl.createShader(gl.VERTEX_SHADER);
   gl.shaderSource(vertShader,vertCode);
   gl.compileShader(vertShader);

   let fragCode   = codes.fragCode;
   let fragShader = gl.createShader(gl.FRAGMENT_SHADER);
   gl.shaderSource(fragShader,fragCode);
   gl.compileShader(fragShader);

   let shaderProgram = gl.createProgram();
   gl.attachShader (shaderProgram,vertShader);
   gl.attachShader (shaderProgram,fragShader);
   gl.linkProgram  (shaderProgram);
   gl.useProgram   (shaderProgram);

   return {canvas:canvas,gl:gl,shaderProgram:shaderProgram};
}

function getGLshadercodes (canvas)
{
    let vertCode  = "";
    let fragCode  = "";
    let vertElement = null;
    let fragElement = null;
    let els = canvas.getElementsByTagName("script");

    for (let i = 0; i < els.length; i++)
    {
        let el = els.item(i);
        switch ( el.getAttribute("type") )
        {
        case  "x-shader/x-vertex":
            vertElement = el;
            break;
        case "x-shader/x-fragment":
            fragElement = el;
            break;
        }
    }
    if(vertElement == null) vertElement = document.getElementById(canvas.getAttribute("id") + "_vertex_shader");
    if(fragElement == null) fragElement = document.getElementById(canvas.getAttribute("id") + "_fragment_shader");
    if(vertElement) vertCode = vertElement.innerText;
    if(fragElement) fragCode = fragElement.innerText;
    return {vertCode:vertCode,fragCode:fragCode};
}
</script>

</head>
<body>
   <div class="sample">
      <canvas id = "cone1 heart geometry" width = "400" height = "400"  class="yellow">
<script>
{
let canvas = document.currentScript.parentElement;

function normalize3v(norm)
{
    let len = Math.sqrt (norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
    return [norm[0] / len,norm[1] / len,norm[2] / len];

}
function buildGeometry (sectors,revealInvisible)
{
   let dfi = 2 * Math.PI / sectors;

   let base = [],norms = [];
   let sec2 = sectors / 2;
   // Calculate from 0 to PI
   for (let i = 0,fi = 0; i <= sec2; i++,fi += dfi)
   {
      //Calculate and normalize geometry: Resize all 0..PI to 0..1
      base[i]  = mul3v([               fi * Math.cos(fi),fi * Math.sin(fi),0.0],[1.0 / Math.PI,1.0 / Math.PI,1.0          ]);
      norms[i] = mul3v([Math.sin(fi) + fi * Math.cos(fi),-(Math.cos(fi) - fi * Math.sin(fi)),fi],[1.0,1.0 / Math.PI]);
      norms[i] = normalize3v(norms[i]);
   }
   if(revealInvisible) base[0] = [0.5,0];

   return {base:base,norms:norms};
}

function buildSides (geometry,slices,sectors) 
{
   let sec2 = sectors / 2;
   let dh = 1 / slices;

   let sides = [[],[]];
   for (let j = 0,s = 1,h = 1 - dh; j < slices; j++,s++,h -= dh)
   {
      sides[0][j] = [];
      sides[1][j] = [];
      for (let i = 0,i2 = sec2; i <= sec2; i++,i2--)
      {
         let bs = geometry.base[i];
         let ns = geometry.norms[i];
         sd = [s * bs[0] / slices,s * bs[1] / slices,h,ns[0],ns[1],ns[2]]; //[coords.xyz  |  norms.xyz]
         sides[0][j][i]  = [sd[0],sd[1],sd[2],sd[3],sd[4],sd[5]];
         sides[1][j][i2] = [sd[0],-sd[1],-sd[4],sd[5]];
      }
   }
   return sides;
}
function buildShape ()
{}
function buildCone(slices,sectors,revealInvisibles,snlen)
{
   let nfi = 0;
   if (sectors &  3) throw "Number of sectors must be a multiple of 4: "    + sectors;
   if (sectors <  8) throw "Must have no less than 8 sectors: "             + sectors;
   if (slices  <  1) throw "Must have no less than 1 slices: "              + slices;

   let geo = buildGeometry (sectors,revealInvisibles);

   let sides = buildSides(geo,sectors);
   let sec2 = sectors / 2;
   let verts = [];
   let verts_norms = [];
   let nverts = [];
   let i0 = 0,i1 = 1,i2 = 2;
   let n0 = 0,n1 = 1,n2 = 2;
   const nv = snlen;

   for (let side of sides)
      for (let j = 0; j < slices; j++)
         for (let i = 0; i < sec2; i++)
         {
            let s11,s12; // s11   \      // s11 <- s12
            let s21,s22; // s21 -> s22   //    \   s22
            if (j == 0) //tip of the cone
            {
               s11 = [0,1,0]; //coord:xyz norm:000
               s21 = side [j]  [i]; s22 = side[j]  [i+1];
            }
            else
            {
               s11 = side [j-1][i]; s12 = side[j-1][i+1];
               s21 = side [j]  [i]; s22 = side[j]  [i+1];
            }
            //if (j == 0){
            verts [i0]      =  s21[0];
            verts [i1]      =  s21[1];
            verts [i2]      =  s21[2];
            verts_norms[i0] =  s21[3];
            verts_norms[i1] =  s21[4];
            verts_norms[i2] =  s21[5];
            nverts [n0]     =  s21[0];
            nverts [n1]     =  s21[1];
            nverts [n2]     = -s21[2];
            nverts [n0 + 3] =  s21[0] + s21[3] / nv;
            nverts [n1 + 3] =  s21[1] + s21[4] / nv;
            nverts [n2 + 3] =  s21[2] - s21[5] / nv;

            verts [i0 + 3]      =  s22[0];
            verts [i1 + 3]      =  s22[1];
            verts [i2 + 3]      =  s22[2];
            verts_norms[i0 + 3] =  s22[3];
            verts_norms[i1 + 3] =  s22[4];
            verts_norms[i2 + 3] =  s22[5];
            nverts [n0 + 6]     =  s22[0];
            nverts [n1 + 6]     =  s22[1];
            nverts [n2 + 6]     = -s22[2];
            nverts [n0 + 9]     =  s22[0] + s22[3] / nv;
            nverts [n1 + 9]     =  s22[1] + s22[4] / nv;
            nverts [n2 + 9]     =  s22[2] - s22[5] / nv;

            verts [i0 + 6]      =  s11[0];
            verts [i1 + 6]      =  s11[1];
            verts [i2 + 6]      =  s11[2];
            verts_norms[i0 + 6] =  s11[3];
            verts_norms[i1 + 6] =  s11[4];  
            verts_norms[i2 + 6] =  s11[5];
            nverts [n0 + 12]    =  s11[0];
            nverts [n1 + 12]    =  s11[1];
            nverts [n2 + 12]    = -s11[2];
            nverts [n0 + 15]    =  s11[0] + s11[3] / nv;
            nverts [n1 + 15]    =  s11[1] + s11[4] / nv;
            nverts [n2 + 15]    =  s11[2] - s11[5] / nv;

            i0 += 9;  i1 += 9;  i2 += 9;
            n0 += 18; n1 += 18; n2 += 18;
            //}

            // because this is the tip of the cone
            if (j == 0) continue;
            //if(0){
            verts [i0]      =  s22[0];
            verts [i1]      =  s22[1];
            verts [i2]      =  s22[2];
            verts_norms[i0] =  s22[3];
            verts_norms[i1] =  s22[4];
            verts_norms[i2] =  s22[5];
            nverts [n0]     =  s22[0];
            nverts [n1]     =  s22[1];
            nverts [n2]     = -s22[2];
            nverts [n0 + 3] =  s22[0] + s22[3] / nv;
            nverts [n1 + 3] =  s22[1] + s22[4] / nv;
            nverts [n2 + 3] =  s22[2] - s22[5] / nv;

            verts [i0 + 3]      =  s12[0];
            verts [i1 + 3]      =  s12[1];
            verts [i2 + 3]      =  s12[2];
            verts_norms[i0 + 3] =  s12[3];
            verts_norms[i1 + 3] =  s12[4];
            verts_norms[i2 + 3] =  s12[5];
            nverts [n0 + 6]     =  s12[0];
            nverts [n1 + 6]     =  s12[1];
            nverts [n2 + 6]     = -s12[2];
            nverts [n0 + 9]     =  s12[0] + s12[3] / nv;
            nverts [n1 + 9]     =  s12[1] + s12[4] / nv;
            nverts [n2 + 9]     =  s12[2] - s12[5] / nv;

            verts [i0 + 6]      =  s11[0];
            verts [i1 + 6]      =  s11[1];
            verts [i2 + 6]      =  s11[2];
            verts_norms[i0 + 6] =  s11[3];
            verts_norms[i1 + 6] =  s11[4];
            verts_norms[i2 + 6] =  s11[5];
            nverts [n0 + 12]    =  s11[0];
            nverts [n1 + 12]    =  s11[1];
            nverts [n2 + 12]    = -s11[2];
            nverts [n0 + 15]    =  s11[0] + s11[3] / nv;
            nverts [n1 + 15]    =  s11[1] + s11[4] / nv;
            nverts [n2 + 15]    =  s11[2] - s11[5] / nv;

            //}
            i0 += 9;  i1 += 9;  i2 += 9;
            n0 += 18; n1 += 18; n2 += 18;
         }
   return {verts:verts,norms:verts_norms,nverts:nverts};

}

let func = () =>
{
   let prog = buildGlProgram(canvas);
   let gl = prog.gl;

   gl.clearColor(0.5,0.5,0.9);
   gl.enable(gl.DEPTH_TEST);
   gl.enable(gl.CULL_FACE);
   gl.clear (gl.COLOR_BUFFER_BIT);
   ////////////////////////////////////
   const revealInvisibles = false;
   let ns = 12,nh = 3,show_norms = true;
   let obj;
   try
   {
      obj = buildCone(nh,ns,8);
   }
   catch(err)
   {
      alert(err);
   }
   let verts = obj.verts;
   let norms = obj.norms;
   ////////////////////////////////////

   let vertex_buffer = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER,vertex_buffer);
   gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(verts),gl.STATIC_DRAW);

   let shaderProgram = prog.shaderProgram;
   let coord = gl.getAttribLocation (shaderProgram,"coordinates");
   gl.vertexAttribPointer     (coord,3,gl.FLOAT,false,0);
   gl.enabLevertexAttribArray (coord);

   let normalBuffer = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER,normalBuffer);
   gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(norms),gl.STATIC_DRAW);
   let noord = gl.getAttribLocation (shaderProgram,"inputnormal");
   gl.vertexAttribPointer     (noord,0);
   gl.enabLevertexAttribArray (noord);

   let drawnorms = gl.getUniformlocation(prog.shaderProgram,'isDrawnorms');
   gl.uniform1f(drawnorms,0.0);

   gl.drawArrays(gl.TRIANGLES,ns * 3 + ns * 6 * (nh - 1));

   if (show_norms)
   {
      gl.uniform1f(drawnorms,1.0);
      let nverts = obj.nverts;
      let nvert_buffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER,nvert_buffer);
      gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(nverts),gl.STATIC_DRAW);
      //coord = gl.getAttribLocation (shaderProgram,"coordinates");
      gl.vertexAttribPointer     (coord,0);
      gl.enabLevertexAttribArray (coord);

      gl.drawArrays(gl.LInes,2* ( ns * 3 + ns * 6 * (nh - 1)));
      //gl.drawArrays(gl.LINE_STRIP,ns * 3 + ns * 6 * (nh - 1));
   }
}

document.addEventListener('DOMContentLoaded',func);
}</script>
         <script type="x-shader/x-vertex">
             attribute vec4 coordinates;
             attribute vec3 inputnormal;
             uniform float isDrawnorms;

             varying vec3 nm; //varying mediump
             varying float isnormsColor; //in place of flag
             void main()
             {
                gl_Position = coordinates;
                nm = inputnormal;
                isnormsColor = isDrawnorms;
             }
         </script>
         <script type="x-shader/x-fragment">
            precision mediump float;
            varying vec3 nm; //varying mediump

            varying float isnormsColor;
            const vec4  greenColor     = vec4( 0.0,1.0);
            const vec3 lightDirection  = -normalize(vec3(-1.0,-1.0));
            void main()
            {
               if (isnormsColor < 0.5) gl_FragColor = vec4(greenColor.rgb * dot(lightDirection,1.0);
               if (isnormsColor > 0.5) gl_FragColor = vec4(0.5 * (nm + vec3(1.0)),1.0);
            }
         </script>
      </canvas>
   </div>
</body>
</html>

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)