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
Скриншот выше должен быть расширен мирового пространства нормалей GBuffer.
Одна большая разница в моем движке заключается в том, что я не храню информацию о лицах в классах (например, THREE.Face3), предпочитая просто записывать данные прямо в атрибуты буфера, более похожие на THREE.BufferGeometry.
До сих пор я использую только модель чайника Utah из курса «Learning WebGL», в частности эта ссылка http://learningwebgl.com/blog/?p=1658. Эта модель работает точно в моем движке и, предположительно, является ранней версией формата THREE JSON. Я загружаю эту модель, как в учебнике, написав массивы json для вершин, texcoords и т. Д. Прямо к буферам webgl, и это отлично работает в моем движке, но даже простой куб, экспортированный из последнего экспортера блендера, кажется, не работает так хорошо ,
Любые предложения с благодарностью, спасибо!
EDIT: Скриншот прохода нормалей с использованием модели чайника из учебных пособий webgl. Примечание. Я не предлагаю, чтобы ТРЕХ экспортер был сломан, скорее мой код, который анализирует его. Я много раз занимался реализацией GBuffer в этом движке за последний год или около того, и я уверен, что сейчас это правильно, у меня просто возникли проблемы с пониманием формата модели THREE json.
Вы впервые подтвердили, что проблема заключается в импортере json mesh, а не в вашем g-буфере или в рендеринге мировых нормалей? Также вы используете гладкое или плоское затенение в блендере? –
Я уверен, что проблема не в моей реализации gbuffer, так как я сказал, что могу использовать образец модели чайника на сайте webgl tutorials, и это прекрасно работает (я попытаюсь приложить скриншот этого вопроса). Что касается нормалей, я просто экспортирую куб по умолчанию прямо из блендера, поэтому нормали должны быть скорее плоскими, чем сглаженными. Я также пытался экспортировать suzanne с аналогичными результатами, сетка и индексы в порядке, нормали повсюду. – bharling