在 webgl 场景中使用法线应用定向光时出现问题

发布于 2024-11-16 05:58:23 字数 2599 浏览 4 评论 0原文

好的,

所以我一直在网上尝试找到使用法线和定向光正确渲染的方法(最初在learningwebgl.com 教程之一中找到)。在learningwebgl 教程中,法线全部设置在数组中。在我的程序中,我需要能够加载wavefont OBJ 文件,然后生成法线。我想知道这是否可能是我的正常生成代码,或者可能是我的着色器的问题。代码有点令人困惑(因为所有顶点/法线/索引数据都在一个数组中),但这是我的正常生成代码:(

    for(var i=0;i<d["vertices"].length;i++)d["normals"][i] = 0;     

    for(var i=0;i<d["indices"].length/3;i++){

        var a = [d["vertices"][d["indices"][(i*3)]], d["vertices"][d["indices"][(i*3)]+1], d["vertices"][d["indices"][(i*3)]+2]];
        var b = [d["vertices"][d["indices"][(i*3)+1]], d["vertices"][d["indices"][(i*3)+1]+1], d["vertices"][d["indices"][(i*3)+1]+2]];
        var c = [d["vertices"][d["indices"][(i*3)+2]], d["vertices"][d["indices"][(i*3)+2]+1], d["vertices"][d["indices"][(i*3)+2]+2]];

        var e = vec3.cross(vec3.subtract(b, a), vec3.subtract(c, a));

        d["normals"][d["indices"][(i*3)]] += -e[0];
        d["normals"][d["indices"][(i*3)]+1] += -e[1];
        d["normals"][d["indices"][(i*3)]+2] += -e[2];

        d["normals"][d["indices"][(i*3)+1]] += -e[0];
        d["normals"][d["indices"][(i*3)+1]+1] += -e[1];
        d["normals"][d["indices"][(i*3)+1]+2] += -e[2];

        d["normals"][d["indices"][(i*3)+2]] += -e[0];
        d["normals"][d["indices"][(i*3)+2]+1] += -e[1];
        d["normals"][d["indices"][(i*3)+2]+2] += -e[2];
    }

    for(var i=0;i<d["normals"].length/3;i++){
        var old = vec3.normalize([d["normals"][(i*3)],d["normals"][(i*3)+1],d["normals"][(i*3)+2]]);
        d["normals"][(i*3)] = old[0];
        d["normals"][(i*3)+1] = old[1];
        d["normals"][(i*3)+2] = old[2];
    }

顶点)着色器的重要部分:

// where uNMatrix = inverse of model view matrix
vec3 transformedNormal = uNMatrix * aVertexNormal;
// vec3 - light pos
float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 1.0);
// vec3 = light color
vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;        

我已经尝试了许多正常算法但无济于事。我还发现,如果我在最后没有对法线进行标准化,颜色/阴影实际上会发生变化,这显然是不正确的阴影。

有关当前外观的示例(带有注释的底部循环),请点击此链接,从下拉列表中选择泰迪熊,然后单击加载,然后单击“(重新)生成法线”,然后您可以通过拖动来围绕泰迪熊旋转鼠标:

http://webdesignscript.net/assignment/graphics_a3/

查看着色器它们在这里:

http://webdesignscript.net/assignment/graphics_a3/scripts/shaders。 我已经在这个问题

上坚持了好几个小时了,并且开始怀疑它是否可能与着色器相关,但是我对图形编程仍然很陌生,并且非常感谢任何帮助:)

*矩阵库使用的是 glMatrix

干杯,乔希

Okay,

So I have been all over the net trying to find ways to correctly render using normals, and directional light (origonally found in one of learningwebgl.com tutorials). In the learningwebgl tutorials the normals are all setup in an array. In my program, I need to be able to load in wavefont OBJ files and then generate normals. I am wondering if it likely to be my normal generation code, or possibly a problem with my shaders. The code is a little confusing (as all the vertex/normal/indices data are in a single array each) but here is my normal generation code:

    for(var i=0;i<d["vertices"].length;i++)d["normals"][i] = 0;     

    for(var i=0;i<d["indices"].length/3;i++){

        var a = [d["vertices"][d["indices"][(i*3)]], d["vertices"][d["indices"][(i*3)]+1], d["vertices"][d["indices"][(i*3)]+2]];
        var b = [d["vertices"][d["indices"][(i*3)+1]], d["vertices"][d["indices"][(i*3)+1]+1], d["vertices"][d["indices"][(i*3)+1]+2]];
        var c = [d["vertices"][d["indices"][(i*3)+2]], d["vertices"][d["indices"][(i*3)+2]+1], d["vertices"][d["indices"][(i*3)+2]+2]];

        var e = vec3.cross(vec3.subtract(b, a), vec3.subtract(c, a));

        d["normals"][d["indices"][(i*3)]] += -e[0];
        d["normals"][d["indices"][(i*3)]+1] += -e[1];
        d["normals"][d["indices"][(i*3)]+2] += -e[2];

        d["normals"][d["indices"][(i*3)+1]] += -e[0];
        d["normals"][d["indices"][(i*3)+1]+1] += -e[1];
        d["normals"][d["indices"][(i*3)+1]+2] += -e[2];

        d["normals"][d["indices"][(i*3)+2]] += -e[0];
        d["normals"][d["indices"][(i*3)+2]+1] += -e[1];
        d["normals"][d["indices"][(i*3)+2]+2] += -e[2];
    }

    for(var i=0;i<d["normals"].length/3;i++){
        var old = vec3.normalize([d["normals"][(i*3)],d["normals"][(i*3)+1],d["normals"][(i*3)+2]]);
        d["normals"][(i*3)] = old[0];
        d["normals"][(i*3)+1] = old[1];
        d["normals"][(i*3)+2] = old[2];
    }

Important part of the (vertex)shader:

// where uNMatrix = inverse of model view matrix
vec3 transformedNormal = uNMatrix * aVertexNormal;
// vec3 - light pos
float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 1.0);
// vec3 = light color
vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;        

I have tried many normal algorithm's to no avail. I have also found if I don't normalize the normals at the very end, the color/shades do in fact change, it is just obviously incorrect shading.

For an example of what it is currently looking like (with the bottom loop commented) follow this link, select teddy from the dropdown, then click load, then click "(re)generate normals", you can then rotate around the teddy by dragging the mouse:

http://webdesignscript.net/assignment/graphics_a3/

For a look at the shaders they are here:

http://webdesignscript.net/assignment/graphics_a3/scripts/shaders.js

I have been stuck on this for many hours, and am starting to wonder if it might be something shader related, however I am still new to graphicaly programming and would greatly appreciate any help :)

*the matrix library used is glMatrix

Cheers, Josh

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

︶ ̄淡然 2024-11-23 05:58:23

我无法加载您的演示(model_engine.js 第 107 行上的分配大小溢出),但我将您的着色器代码放入我的引擎中(无耻插件:看看 Jax,它真的很酷!)并且效果很好。

然后我仔细查看了你的 JS 代码,然后......好吧,我相信它几乎完全错误。看起来你要做的第一件事就是获取每张脸的法线——一个好的开始,但我不明白你为什么要否定 e 的值。此时您还应该对 e 进行归一化,因为现在它只是一个任意长度的向量。但不知道这是否真的重要。

您要做的下一件事是获取给定顶点的所有 e 总和的法线。不太正确:您需要标准化所有e平均值,而不是总和。

最后,这就是我的想法。它在我自己的引擎中运行得很好,而且它的运行速度似乎比原始版本的启动速度要快得多。 (免责声明:可能仍然需要进行一些优化。我编写它是为了清晰,而不是速度。)

var i, j, normals = {};

// calculate face normals. Note that each vertex will have a number of faces
// adjacent to it, so we accumulate their normals into an array. We'll take
// the average of them all when done.
var tmp1 = vec3.create(), tmp2 = vec3.create();
var a, b, c;

function pushNormal(index, normal) {
  normals[index] = normals[index] || [];
  normals[index].push(normal);
}

for (i = 0; i < d["indices"].length; i += 3) {
  // get points a, b, c
  var aIndex = d["indices"][i], bIndex = d["indices"][i+1], cIndex = d["indices"][i+2];
  var aOffsetX = aIndex * 3, aOffsetY = aIndex * 3 + 1, aOffsetZ = aIndex * 3 + 2;
  var bOffsetX = bIndex * 3, bOffsetY = bIndex * 3 + 1, bOffsetZ = bIndex * 3 + 2;
  var cOffsetX = cIndex * 3, cOffsetY = cIndex * 3 + 1, cOffsetZ = cIndex * 3 + 2;

  a = [d["vertices"][aOffsetX], d["vertices"][aOffsetY], d["vertices"][aOffsetZ]];
  b = [d["vertices"][bOffsetX], d["vertices"][bOffsetY], d["vertices"][bOffsetZ]];
  c = [d["vertices"][cOffsetX], d["vertices"][cOffsetY], d["vertices"][cOffsetZ]];

  // calculate face normal
  vec3.subtract(b, a, tmp1);
  vec3.subtract(c, a, tmp2);
  var e = vec3.normalize(vec3.cross(tmp1, tmp2, vec3.create()));

  // accumulate face normal for each of a, b, c
  pushNormal(a, vec3.create(e));
  pushNormal(b, vec3.create(e));
  pushNormal(c, vec3.create(e));
}

// now calculate normalized averages for each face normal, and store the result
for (i = 0; i < d["vertices"].length; i += 3) {
  a = [d["vertices"][i], d["vertices"][i+1], d["vertices"][i+2]];
  if (normals[a]) {
    var avg = vec3.create();
    for (j = 0; j < normals[a].length; j++) {
      vec3.add(normals[a][j], avg, avg);
    }
    vec3.scale(avg, 1/normals[a].length);
    vec3.normalize(avg);

    d["normals"][i] = avg[0];
    d["normals"][i+1] = avg[1];
    d["normals"][i+2] = avg[2];
  }
}

// sanity check
if (d["normals"].length != d["vertices"].length)
  alert("ERROR "+d["normals"].length+" != "+d["vertices"].length);

希望这会有所帮助!

I can't load your demo (allocation size overflow on model_engine.js line 107), but I threw your shader code into my engine (shameless plug: check out Jax, it's really cool!) and it worked fine.

Then I took a close look at your JS code, and... well, I believe it's pretty much entirely wrong. It looks like the first thing you do is take the normal of each face -- a good start, but I don't understand why you are negating the value of e. You should also normalize e at this point, because right now it's just an arbitrary-length vector. Don't know if that really matters, though.

The next thing you're doing is taking the normal of the sum of all es for a given vertex. Not quite right: you need to normalize the average of all es, rather than the sum.

In the end, here's what I came up with. It works great in my own engine, and it seems to run considerably faster than the original version to boot. (Disclaimer: there may still be some optimizations to be made. I wrote it for clarity, not speed.)

var i, j, normals = {};

// calculate face normals. Note that each vertex will have a number of faces
// adjacent to it, so we accumulate their normals into an array. We'll take
// the average of them all when done.
var tmp1 = vec3.create(), tmp2 = vec3.create();
var a, b, c;

function pushNormal(index, normal) {
  normals[index] = normals[index] || [];
  normals[index].push(normal);
}

for (i = 0; i < d["indices"].length; i += 3) {
  // get points a, b, c
  var aIndex = d["indices"][i], bIndex = d["indices"][i+1], cIndex = d["indices"][i+2];
  var aOffsetX = aIndex * 3, aOffsetY = aIndex * 3 + 1, aOffsetZ = aIndex * 3 + 2;
  var bOffsetX = bIndex * 3, bOffsetY = bIndex * 3 + 1, bOffsetZ = bIndex * 3 + 2;
  var cOffsetX = cIndex * 3, cOffsetY = cIndex * 3 + 1, cOffsetZ = cIndex * 3 + 2;

  a = [d["vertices"][aOffsetX], d["vertices"][aOffsetY], d["vertices"][aOffsetZ]];
  b = [d["vertices"][bOffsetX], d["vertices"][bOffsetY], d["vertices"][bOffsetZ]];
  c = [d["vertices"][cOffsetX], d["vertices"][cOffsetY], d["vertices"][cOffsetZ]];

  // calculate face normal
  vec3.subtract(b, a, tmp1);
  vec3.subtract(c, a, tmp2);
  var e = vec3.normalize(vec3.cross(tmp1, tmp2, vec3.create()));

  // accumulate face normal for each of a, b, c
  pushNormal(a, vec3.create(e));
  pushNormal(b, vec3.create(e));
  pushNormal(c, vec3.create(e));
}

// now calculate normalized averages for each face normal, and store the result
for (i = 0; i < d["vertices"].length; i += 3) {
  a = [d["vertices"][i], d["vertices"][i+1], d["vertices"][i+2]];
  if (normals[a]) {
    var avg = vec3.create();
    for (j = 0; j < normals[a].length; j++) {
      vec3.add(normals[a][j], avg, avg);
    }
    vec3.scale(avg, 1/normals[a].length);
    vec3.normalize(avg);

    d["normals"][i] = avg[0];
    d["normals"][i+1] = avg[1];
    d["normals"][i+2] = avg[2];
  }
}

// sanity check
if (d["normals"].length != d["vertices"].length)
  alert("ERROR "+d["normals"].length+" != "+d["vertices"].length);

Hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文