我现在已经敲了一会儿。我有一个索引的PlaneBufferGeometry我用于GPGPU布料物理模拟,我不能在我的生活中在将模拟渲染到纹理后在最终顶点着色器中正确计算法线。
这是我当前的设置(包括相关部分),我认为它无法正常工作,因为我需要一种方法来了解当前顶点的顺序以及它在"中的邻居。面&#34 ;.只是不能说得对。
的javascript:
// get faces
const indices = geometry.index.array;
const faces = [];
for(let i = 0; i < indices.length; i += 3)
{
faces.push([indices[i + 0] * 3, indices[i + 1] * 3, indices[i + 2] * 3]);
}
const vertices = geometry.attributes.position.array;
// begin loop
// initializing data texture vertex positions
dataTexturePixels[index * 4 + 0] = vertices[index * 3 + 0];
dataTexturePixels[index * 4 + 1] = vertices[index * 3 + 1];
dataTexturePixels[index * 4 + 2] = vertices[index * 3 + 2];
dataTexturePixels[index * 4 + 3] = 0;
// storing lookup uv's in an attribute for looking up positions
positionReference[index * 3 + 0] = (index % size) / size;
positionReference[index * 3 + 1] = Math.floor(index / size) / size;
// end loop
这是我的大脑绊倒的地方。我尝试过以各种方式使用faces数组中的面部索引值,但由于索引是重复的,因此数据被覆盖。无法想到如何正确存储每个面的顶点索引信息,因此可以使用positionReference(或其他方式)在顶点着色器中查找它。
顶点着色器/模拟运行后:
// how I'd calculate the normals if I could get a proper ordered reference
vec2 coord1 = faceVert1UvReference.xy;
vec3 pos1 = texture2D(tPositions, coord1).xyz;
vec2 coord2 = faceVert2UvReference.xy;
vec3 pos2 = texture2D(tPositions, coord2).xyz;
vec2 coord3 = faceVert3UvReference.xy;
vec3 pos3 = texture2D(tPositions, coord3).xyz;
vec3 tangent = pos3 - pos2;
vec3 bitangent = pos1 - pos2;
vec3 normal = normalMatrix * normalize(cross(tangent, bitangent));
片段着色器/光照:
vec3 lightDirection = normalize(lightPosition); // also tried normalize(lightPosition - vWorldPosition);
vec3 normal = normalize(vNormal);
float lightValue = max(0.0, dot(normal, lightDirection)) * lightIntensity;
finalColor.rgb *= lightValue;
不确定我是否遗漏了一些显而易见的事情/做了一些愚蠢的事情,或者这个问题确实很难。如果没有发布我尝试过的许多失败的方式,有没有人有任何想法?
非常感谢任何帮助。
[编辑1]:我添加了几个示例,this one使用平面阴影和面法线,this one显示我当前搞砸了顶点法线进度。很难找到我的错误...
[编辑2]:这就是我在面部数据中管道到每个顶点的方式。从数据的角度来看,一切看起来都是正确的,但在视觉上完全搞砸了。我的生活不能找到我出错的地方。
的javascript
const indices = geometry.index.array;
const faces = [];
// store faces for each vertex
for(let i = 0; i < indices.length; i += 3)
{
const vertIndex1 = indices[ i + 0 ];
const vertIndex2 = indices[ i + 1 ];
const vertIndex3 = indices[ i + 2 ];
faces[ vertIndex1 ] = faces[ vertIndex1 ] || [];
faces[ vertIndex2 ] = faces[ vertIndex2 ] || [];
faces[ vertIndex3 ] = faces[ vertIndex3 ] || [];
faces[ vertIndex1 ].push([ vertIndex1, vertIndex2, vertIndex3 ]);
faces[ vertIndex2 ].push([ vertIndex1, vertIndex2, vertIndex3 ]);
faces[ vertIndex3 ].push([ vertIndex1, vertIndex2, vertIndex3 ]);
}
const size = 128;
const vertices = geometry.attributes.position;
const faceIndices = new Uint16Array( vertices.array.length );
const indices0 = gpuCompute.createTexture(size * 2, size * 2); // need 256x256 texture for all the data.
const indicesPixels0 = indices0.image.data;
let faceVertPixelIndex = 0,
faceIndexRangeStart = 0,
faceIndexRangeEnd = -1,
index;
for(let i = 0; i < size; i++)
{
for(let j = 0; j < size; j++)
{
index = j + (i * size);
// ----------------------------------------------
// writing vertex positions to data texture here
// ----------------------------------------------
if(faces[index])
{
const face = faces[index];
const fLen = face.length;
faceIndexRangeStart = faceIndexRangeEnd + 1;
faceIndexRangeEnd = faceIndexRangeStart + fLen - 1;
// face index range for looking up up all faces a single vertex is in
faceIndices[index * 3 + 0] = faceIndexRangeStart;
faceIndices[index * 3 + 1] = faceIndexRangeEnd;
faceIndices[index * 3 + 2] = 0; // unused
for(let v = 0; v < fLen; v++)
{
// store face vertex indices in each pixel rgb
indicesPixels0[faceVertPixelIndex * 4 + 0] = face[v][0]; // current face, vertex 1 index
indicesPixels0[faceVertPixelIndex * 4 + 1] = face[v][1]; // current face, vertex 2 index
indicesPixels0[faceVertPixelIndex * 4 + 2] = face[v][2]; // current face, vertex 3 index
indicesPixels0[faceVertPixelIndex * 4 + 3] = 0; // unused
faceVertPixelIndex++;
}
}
}
}
geometry.addAttribute('faceIndices', new THREE.BufferAttribute(faceIndices, 3));
uniforms.tIndices.value = indices0;
顶点着色器(相关部分)
uniform vec2 resolution;
uniform sampler2D tPositions;
uniform sampler2D tIndices;
attribute vec3 faceIndices;
varying vec3 vNormal;
vec2 getCoord(in float index, in vec2 size)
{
return vec2(mod(index, size.x) / size.x, floor(index / size.y) / size.y);
}
void addNormal(inout vec3 nrml, in float index)
{
vec2 coord = getCoord(index, resolution * 2.0); // 256x256 sized texture for faces
vec4 face = texture2D(tIndices, coord);
// get uv for each vertex index in the face and grab positions.
vec2 v1Coord = getCoord(face.x, resolution);
vec3 v1 = texture2D(tPositions, v1Coord).xyz;
vec2 v2Coord = getCoord(face.y, resolution);
vec3 v2 = texture2D(tPositions, v2Coord).xyz;
vec2 v3Coord = getCoord(face.z, resolution);
vec3 v3 = texture2D(tPositions, v3Coord).xyz;
vec3 tangent = v3 - v2;
vec3 bitangent = v1 - v2;
vec3 n = normalize(cross(tangent, bitangent));
nrml += n;
}
void main()
{
vec3 nrml = vec3(0.0);
vec2 faceIndexRange = faceIndices.xy;
float from = faceIndexRange.x;
float to = faceIndexRange.y;
float index = from;
for(int i = 0; i < 6; i++)
{
if(index <= to)
{
addNormal(nrml, index);
index += 1.0;
}
else
{
break;
}
}
vNormal = normalMatrix * normalize(nrml);
}
答案 0 :(得分:0)
我最终废弃了上面的共享方法并使用了邻居查找方法,感谢@ luigi-de-rosa的帮助。我之前尝试过这个但是使用了不正确的值来从查找纹理中抓取邻居,这让我认为它不起作用。
以下是我在顶点着色器中计算法线的方法。
float diff = 0.06; // tweak this value to yield different results.
vec2 coord = positionReference.xy;
vec3 transformed = texture2D(tPositions, coord).xyz;
vec3 neighbour1 = texture2D(tPositions, coord + vec2(diff, 0.0)).xyz;
vec3 neighbour2 = texture2D(tPositions, coord + vec2(0.0, diff)).xyz;
vec3 tangent = neighbour1 - transformed;
vec3 bitangent = neighbour2 - transformed;
vec3 nrml = cross(tangent, bitangent);
vNormal = normalMatrix * -normalize(nrml); // pass to fragment shader
更轻松的方法......叹息。