Проблемы применения направленного света с использованием нормалей в сцене webgl - PullRequest
0 голосов
/ 16 июня 2011

Хорошо,

Так что я был во всей сети, пытаясь найти способы правильного рендеринга, используя нормали и направленный свет (первоначально найденный в одном из учебных пособий learningwebgl.com). В уроках learningwebgl все нормали настроены в виде массива. В моей программе мне нужно иметь возможность загружать OBJ-файлы wavefont, а затем генерировать нормали. Мне интересно, может ли это быть мой обычный код генерации, или, возможно, проблема с моими шейдерами. Код немного сбивает с толку (так как все данные вершин / нормалей / индексов находятся в одном массиве каждый), но вот мой нормальный код генерации:

    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.js

Я застрял на этом в течение многих часов, и начинаю задумываться, может ли это быть чем-то связанным с шейдером, однако я все еще новичок в графическом программировании и буду очень признателен за любую помощь:

* используется матричная библиотека glMatrix

Ура, Джош

1 Ответ

1 голос
/ 14 сентября 2011

Я не могу загрузить вашу демонстрацию (переполнение размера выделения в строке model_engine.js 107), но я бросил ваш код шейдера в мой движок ( бесстыдный плагин: проверьте Jax, это действительно круто! ) и все работало нормально.

Затем я внимательно посмотрел на ваш код JS и ... ну, я считаю, что это в значительной степени совершенно неправильно. Похоже, первое, что вы делаете, это берете нормаль каждого лица - хорошее начало, но я не понимаю, почему вы отрицаете значение e. Вы также должны нормализовать e в этой точке, потому что сейчас это просто вектор произвольной длины. Не знаю, действительно ли это имеет значение.

Следующее, что вы делаете, берете нормаль от суммы всех e s для данной вершины. Не совсем верно: вам нужно нормализовать среднее всех 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);

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...