3

我有一个问题,可能类似于这个问题:WebGL shading/lighting too dark on some triangles
我试图将我的一个旧练习从使用已弃用 glaux 的 C++ OpenGL 移植到 WebGL。
问题是锥体显示错误,多切片时闪烁微弱: 有一个以阿基米德螺线为底的锥体,单切片时没问题: 左边它使用120个扇区,右边是12 个扇区,在 WebGL 上是可以的。 当我使用多个切片(例如 3 个切片)时,问题就开始了: 此图像看起来有点脏,请参见左侧图像。右侧图像中突出显示的上部三角形看起来像是显示了错误的照明。
在此处输入图像描述

在此处输入图像描述在此处输入图像描述

在此处输入图像描述在此处输入图像描述

当我显示法线时,它看起来像是正确计算的。因为法线在上下三角形的角上重合: 我想让代码片段更短,但是数学很长,也无法从 GitHub 中添加脚本,所以我将它们包含在内。表示顶点、法线和突出显示的法线。数学很简单,两个对称的阿基米德螺旋相互叠加: 螺旋被描述为 F(φ) = [φ * cos(φ), φ * sin(φ)] 计算正常 ∇F(φ) = [sin( φ) + φ * cos(φ), -cos(φ) + φ * sin(φ), φ]
在此处输入图像描述
vertsverts_normsnverts



更新 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, 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          ,  1.0 / Math.PI]);
      norms[i] = normalize3v(norms[i]);
   }
   if(revealInvisible) base[0] = [0.5, 0.0, 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[2],    sd[3], -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, slices, 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, 0, 1, 0, 0, 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.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, revealInvisibles, 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, 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, 3, gl.FLOAT, false, 0, 0);
   gl.enableVertexAttribArray (noord);

   let drawNorms = gl.getUniformLocation(prog.shaderProgram, 'isDrawNorms');
   gl.uniform1f(drawNorms, 0.0);

   gl.drawArrays(gl.TRIANGLES, 0, 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, 3, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray (coord);

      gl.drawArrays(gl.LINES, 0, 2* ( ns * 3 + ns * 6 * (nh - 1)));
      //gl.drawArrays(gl.LINE_STRIP, 0, 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,   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>
   </div>
</body>
</html>

4

0 回答 0