나는 잠시 동안 내 머리를 두드렸다. GPGPU cloth physics 시뮬레이션에 사용하는 인덱스 된 PlaneBufferGeometry가 있습니다. 시뮬레이션을 텍스처에 렌더링 한 후 최종 버텍스 쉐이더에서 법선을 올바르게 계산할 수 없습니다.Three.js/이동 후 정점 셰이더에서 인덱싱 된 PlaneBufferGeometry의 정점 법선 계산
이것은 현재의 설정 (관련 부분 포함)이며, 현재의 vert의 순서와 "얼굴"의 이웃을 알 수있는 방법이 필요하기 때문에 작동하지 않는다고 생각합니다. 그냥 제대로 할 수는 없습니다.
자바 스크립트 :
// 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
내 머리가 트립되는 곳입니다. 여러 가지 방법으로 얼굴 배열에서 얼굴 인덱스 값을 사용하여 시도했지만 인덱스가 중복되어 있기 때문에 데이터를 덮어 씁니다. 각면에 대한 정점 인덱스 정보를 올바르게 저장하는 방법을 생각할 수 없으므로 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;
나는 분명 뭔가/바보 같은 일을하고를 누락하는 경우 확인 또는이되지 않음 문제는 실제로 어렵다. 시도한 많은 실패한 방법을 게시하지 않고도 누구나 아이디어가 있습니까?
도움을 주시면 대단히 감사하겠습니다. 내 현재 엉망 부드러운 정점 법선의 진행 상황을 보여주는 나는 몇 가지 예제를 추가 한, 얼굴 법선 평면 음영을 사용 this one 및 this one :
[편집 1]. ... 내 오류를 발견
[편집 2] 힘든 시간을 보내고 : 것은 이것은 내가 각 정점에 얼굴 데이터의 배관 해요 방법이다. 모든 것이 데이터 관점에서 나에게 맞지만 시각적으로 엉망입니다. 나 인생이 잘못 될 곳을 찾을 수는 없지.
자바 스크립트
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);
}
[flat shading] (https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderChunk/normal_fragment)이 포함 된 라이브 예제를 처음으로 시연하면 더 도움이 될 수 있습니다. .glsl # L5-L7). 이 경우 법선은 필요하지 않습니다. 또한 uv는 픽셀 중심으로 인덱스되어야하므로 텍스처가 4x4이면 uv는 1/8, 3/8, 5/8, 7/8이됩니다. – WestLangley
@WestLangley 현재 진행 상황을 보여주는 몇 가지 코드를 추가했습니다. 평면 쉐이딩 - [link] (https://codepen.io/mystaticself/pen/WjYRRm) 및 현재의 법선 진행이 꽤 엉망입니다. [link] (https://codepen.io/mystaticself/pen/oWQaZg) – mystaticself
당신은 분명히 이것을 디버깅 할 기술이 있습니다. :) 디버깅을 위해 크기를 4로 설정했습니다. BTW, 더 이상 유니폼을 지정할 때'type'을 설정할 필요가 없습니다. – WestLangley