2016-02-13 2 views
1

EDIT: Demo, наконец, онлайн: http://bharling.github.io/deferred/index.html используйте раскрывающийся список, чтобы переключиться на модели тора, чтобы увидеть проблему вживую. ПРИМЕЧАНИЕ. Требуется расширение Webgl MRT.Анализ текстовых ошибок THREE.js json mesh

Я уже некоторое время разрабатываю свой собственный механизм отложенного рендеринга в WebGL и дошел до стадии, когда у меня есть рабочий прототип с использованием GBuffers и расширений MRT, которые делают некоторые чайники вполне удовлетворительными. Это разработано с нуля, главным образом для меня, чтобы правильно изучить WebGL без использования каких-либо фреймворков и понять отсроченный рендеринг. Для всех, кого это интересует - источник находится на github здесь: https://github.com/bharling/webgl-defer

У меня есть сцена, на которой я устал видеть только чайники и попытался реализовать загрузчик для моделей формата THREE.js JSON. Я портировал (копировал) основные части загрузчика, и я могу получить сетки, чтобы они отображались с правильными вершинами и буферами индексов, что здорово, но нормали последовательно жуткие. Я выбираю только поддержку индексированной геометрии с вершинами UVs и вершинными нормалями и одним материалом (в конечном итоге это должно быть основано на PBR), поэтому я игнорирую что-либо еще в JSON и пишу только то, что поддерживаю прямо в Float32Arrays (и т. Д.), , Ниже приведен код импорта, а также скриншот странных нормалей, которые я вижу.

parseThreeJSModel: (data) => 

    isBitSet = (value, position) -> 
     return value & (1 << position) 

    vertices = data.vertices 
    uvs = data.uvs 
    indices = [] 
    normals = data.normals 

    vertexNormals = [] 
    vertexUvs = [] 
    vertexPositions = [] 

    @vertexPositionBuffer = new DFIR.Buffer(new Float32Array(data.vertices), 3, gl.STATIC_DRAW) 
    @vertexTextureCoordBuffer = new DFIR.Buffer(new Float32Array(data.uvs[0]), 2, gl.STATIC_DRAW) 

    numUvLayers = data.uvs.length 
    faces = data.faces 

    zLength = faces.length 
    offset = 0 

    while offset < zLength 
     type = faces[offset++] 
     isQuad    = isBitSet(type, 0) 
     hasMaterial   = isBitSet(type, 1) 
     hasFaceVertexUv  = isBitSet(type, 3) 
     hasFaceNormal  = isBitSet(type, 4) 
     hasFaceVertexNormal = isBitSet(type, 5) 
     hasFaceColor  = isBitSet(type, 6) 
     hasFaceVertexColor = isBitSet(type, 7) 

     if isQuad 
     indices.push faces[ offset ] 
     indices.push faces[ offset + 1 ] 
     indices.push faces[ offset + 3 ] 
     indices.push faces[ offset + 1 ] 
     indices.push faces[ offset + 2 ] 
     indices.push faces[ offset + 3 ] 
     offset += 4 

     if hasMaterial 
      offset++ 

     if hasFaceVertexUv 
      for i in [0 ... numUvLayers] by 1 
      uvLayer = data.uvs[i] 
      for j in [0 ... 4] by 1 
       uvIndex = faces[offset++] 
       u = uvLayer[ uvIndex * 2 ] 
       v = uvLayer[ uvIndex * 2 + 1 ] 

       if j isnt 2 
       vertexUvs.push u 
       vertexUvs.push v 
       if j isnt 0 
       vertexUvs.push u 
       vertexUvs.push v 

     if hasFaceNormal 
      offset++ 

     if hasFaceVertexNormal 
      for i in [0 ... 4] by 1 
       normalIndex = faces[ offset++ ] * 3 
       normal = [ normalIndex++, normalIndex++, normalIndex ] 
       if i isnt 2 
       vertexNormals.push normals[normal[0]] 
       vertexNormals.push normals[normal[1]] 
       vertexNormals.push normals[normal[2]] 
       if i isnt 0 
       vertexNormals.push normals[normal[0]] 
       vertexNormals.push normals[normal[1]] 
       vertexNormals.push normals[normal[2]] 

     if hasFaceColor 
      offset++ 

     if hasFaceVertexColor 
      offset += 4 
     else 
     indices.push faces[offset++] 
     indices.push faces[offset++] 
     indices.push faces[offset++] 

     if hasMaterial 
      offset++ 
     if hasFaceVertexUv 
      for i in [0 ... numUvLayers] by 1 
      uvLayer = data.uvs[i] 
      for j in [0 ... 3] by 1 
       uvIndex = faces[offset++] 
       u = uvLayer[ uvIndex * 2 ] 
       v = uvLayer[ uvIndex * 2 + 1 ] 
       if j isnt 2 
       vertexUvs.push u 
       vertexUvs.push v 
       if j isnt 0 
       vertexUvs.push u 
       vertexUvs.push v 

     if hasFaceNormal 
      offset++ 

     if hasFaceVertexNormal 
      for i in [0 ... 3] by 1 
      normalIndex = faces[ offset++ ] * 3 

      vertexNormals.push normals[normalIndex++] 
      vertexNormals.push normals[normalIndex++] 
      vertexNormals.push normals[normalIndex] 

     if hasFaceColor 
      offset++ 

     if hasFaceVertexColor 
      offset +=3 

    @vertexNormalBuffer = new DFIR.Buffer(new Float32Array(vertexNormals), 3, gl.STATIC_DRAW) 
    @vertexIndexBuffer = new DFIR.Buffer(new Uint16Array(indices), 1, gl.STATIC_DRAW, gl.ELEMENT_ARRAY_BUFFER) 
    @loaded=true 

Weird Normals from simple imported cube exported from blender using THREE.s official exporter

Скриншот выше должен быть расширен мирового пространства нормалей GBuffer.

Одна большая разница в моем движке заключается в том, что я не храню информацию о лицах в классах (например, THREE.Face3), предпочитая просто записывать данные прямо в атрибуты буфера, более похожие на THREE.BufferGeometry.

До сих пор я использую только модель чайника Utah из курса «Learning WebGL», в частности эта ссылка http://learningwebgl.com/blog/?p=1658. Эта модель работает точно в моем движке и, предположительно, является ранней версией формата THREE JSON. Я загружаю эту модель, как в учебнике, написав массивы json для вершин, texcoords и т. Д. Прямо к буферам webgl, и это отлично работает в моем движке, но даже простой куб, экспортированный из последнего экспортера блендера, кажется, не работает так хорошо ,

Любые предложения с благодарностью, спасибо!

EDIT: Скриншот прохода нормалей с использованием модели чайника из учебных пособий webgl. Примечание. Я не предлагаю, чтобы ТРЕХ экспортер был сломан, скорее мой код, который анализирует его. Я много раз занимался реализацией GBuffer в этом движке за последний год или около того, и я уверен, что сейчас это правильно, у меня просто возникли проблемы с пониманием формата модели THREE json.

enter image description here

+0

Вы впервые подтвердили, что проблема заключается в импортере json mesh, а не в вашем g-буфере или в рендеринге мировых нормалей? Также вы используете гладкое или плоское затенение в блендере? –

+0

Я уверен, что проблема не в моей реализации gbuffer, так как я сказал, что могу использовать образец модели чайника на сайте webgl tutorials, и это прекрасно работает (я попытаюсь приложить скриншот этого вопроса). Что касается нормалей, я просто экспортирую куб по умолчанию прямо из блендера, поэтому нормали должны быть скорее плоскими, чем сглаженными. Я также пытался экспортировать suzanne с аналогичными результатами, сетка и индексы в порядке, нормали повсюду. – bharling

ответ

0

Это непосредственно не решение вашей проблемы, но может быть полезно в любом случае.

Если у вас есть примитивные формы, такие как коробки в приведенном выше примере, вы также можете использовать THREE.FlatShading и пропустить нормальные значения для всех. Может быть проще в некоторых случаях:

var material = new THREE.???Material({ shading: THREE.FlatShading }); 
+0

Спасибо - я фактически не использую three.js на самом деле, свой собственный движок. Действительно, я просто пытаюсь использовать формат модели three.js вместо того, чтобы писать свои собственные, в то время это казалось хорошей идеей! – bharling

+0

@bharling Любая удача в решении вашей проблемы? – Wilt

+0

Пока что, к сожалению, на данный момент я не работал над другими аспектами движка (и игнорируя тот факт, что он может загружать только чайники :), сейчас они красиво выглядят чайники). Думая о попытке загрузчика .obj вместо этого на данный момент, есть примеры ванильных webgl из тех, что вокруг – bharling

0

Не уверен, что ваш перевод между тремя. Face3 в буферы правилен. Вот мой собственный синтаксический анализатор Json, который я использую для загрузки анимированной скелетной сетки из блендера, которая может вам помочь. Аналогичным образом поддерживаются только частичные функции. Он возвращает индексированные буферы, которые будут использоваться с .drawElements, а не .drawArrays.

function parsePackedArrayHelper(outArray, index, dataArray, componentSize){ 
    for (var c = 0; c<componentSize; c++){ 
     outArray.push(dataArray[index*componentSize + c]); 
    } 
} 

function parseThreeJson(geometry){ 
    if (isString(geometry)){ 
     geometry = JSON.parse(geometry); 
    } 

    var faces = geometry["faces"]; 
    faces = convertQuadToTrig(faces); // can use the triangulate modifer in blender to skip this 
    // and others data etc... 

    var seenVertices = new Map(); 
    var currentIndex = 0; 
    var maxIndex = 0; 

    var c = 0; // current index into the .faces array 
    while (c < faces.length){ 
     var bitInfo = faces[c]; 
     var hasMaterials = (bitInfo &(1<<1)) !== 0; 
     var hasVertexUvs = (bitInfo &(1<<3)) !== 0; 
     var hasVertexNormals = (bitInfo &(1<<5)) !== 0; 
     var faceIndex = c+1; 

     c += (
      4 + //1 for the bitflag and 3 for vertex positions 
      (hasMaterials? 1: 0) + 
      (hasVertexUvs? 3: 0) + 
      (hasVertexNormals ? 3: 0) 
     ); 

     for (var v = 0;v<3;v++){ 
      var s = 0; 
      var vertIndex = faces[faceIndex+v]; 
      var uvIndex = -1; 
      var normalIndex = -1; 
      var materialIndex = -1; 
      if (hasMaterials){ 
       s += 1; 
       materialIndex = faces[faceIndex+3]; 
      } 
      if (hasVertexUvs){ 
       s += 3; 
       uvIndex = faces[faceIndex+s+v]; 
      } 
      if (hasVertexNormals){ 
       s += 3; 
       normalIndex = faces[faceIndex+s+v]; 
      } 

      var hash = ""+vertIndex+","+uvIndex+","+normalIndex; 
      if (seenVertices.has(hash)){ 
       indices[currentIndex++] = seenVertices.get(hash); 
      } else { 
       seenVertices.set(hash, maxIndex); 
       indices[currentIndex++] = maxIndex++; 
       parsePackedArrayHelper(verticesOut, vertIndex, verticesData, 3); 
       if (boneInfluences > 1){ 
        // skinning data skipped 
       } 
       if (hasVertexUvs){ 
        parsePackedArrayHelper(uvsOut, uvIndex, uvsData[0], 2); 

        // flip uv vertically; may or may not be needed 
        var lastV = uvsOut[uvsOut.length-1]; 
        uvsOut[uvsOut.length-1] = 1.0 - lastV; 

       } 
       if (hasVertexNormals){ 
        parsePackedArrayHelper(normalsOut, normalIndex, normalsData, 3); 
       } 

       if (hasMaterials){ 
        materialIndexOut.push(materialIndex); 
       } 
      } 
     } 
    } 
} 
+0

Спасибо за это - очень похоже на то, что мне нужно, хотя я думаю, что бит, который мне действительно нужен, - это метод parsePackedArrayHelper() - будет вы не согласны с этим? Спасибо! – bharling

+0

ой жаль - пропустил это наверху! попробует – bharling

+0

У меня это получилось, но я, должно быть, не интерпретировал его так хорошо, как мне удалось значительно уменьшить мои индексные буферы (это сказало, что нормали выглядели немного лучше). Будем продолжать пытаться, спасибо! – bharling

Смежные вопросы