안녕하세요 저는 3D 모델링 앱을 작성 중이며 OpenGL에서 렌더링 속도를 높이고 싶습니다. 현재 내가 사용하는 glBegin/glEnd는 정말 느리고 비추천입니다. 나는 매우 빠른 평면 음영 모델을 그릴 필요가있다. 모든 단일 프레임 CPU에서 법선을 생성합니다. 이것은 매우 느립니다. glDrawElements를 인덱스 된 지오메트리와 함께 사용하려고 시도했지만 법선이 삼각형 수준이 아닌 정점에 지정되어 있기 때문에 정상 생성시 문제가 있습니다.
또 다른 아이디어는 GLSL을 사용하여 기하학 쉐이더에서 GPU의 법선을 생성하는 것이 었습니다. 정상 생성을 위해이 코드를 작성했습니다 :GLSL 셰이더 법선 생성
#version 120
#extension GL_EXT_geometry_shader4 : enable
vec3 NormalFromTriangleVertices(vec3 triangleVertices[3])
{
// now is same as RedBook (OpenGL Programming Guide)
vec3 u = triangleVertices[0] - triangleVertices[1];
vec3 v = triangleVertices[1] - triangleVertices[2];
return cross(v, u);
}
void main()
{
// no change of position
// computes normal from input triangle and front color for that triangle
vec3 triangleVertices[3];
vec3 computedNormal;
vec3 normal, lightDir;
vec4 diffuse;
float NdotL;
vec4 finalColor;
for(int i = 0; i < gl_VerticesIn; i += 3)
{
for (int j = 0; j < 3; j++)
{
triangleVertices[j] = gl_PositionIn[i + j].xyz;
}
computedNormal = NormalFromTriangleVertices(triangleVertices);
normal = normalize(gl_NormalMatrix * computedNormal);
// hardcoded light direction
vec4 light = gl_ModelViewMatrix * vec4(0.0, 0.0, 1.0, 0.0);
lightDir = normalize(light.xyz);
NdotL = max(dot(normal, lightDir), 0.0);
// hardcoded
diffuse = vec4(0.5, 0.5, 0.9, 1.0);
finalColor = NdotL * diffuse;
finalColor.a = 1.0; // final color ignores everything, except lighting
for (int j = 0; j < 3; j++)
{
gl_FrontColor = finalColor;
gl_Position = gl_PositionIn[i + j];
EmitVertex();
}
}
EndPrimitive();
}
쉐이더를 응용 프로그램에 통합하면 속도가 향상되지 않습니다. 그것은 이전보다 더 나빴다. 나는 GLSL과 쉐이더 전체에서 초보자이기 때문에 내가 뭘 잘못했는지 모른다. Geforce 9400M이 장착 된 MacBook에서이 코드를 사용해 보았습니다.
- (void)drawAsCommandsWithScale:(Vector3D)scale
{
float frontDiffuse[4] = { 0.4, 0.4, 0.4, 1 };
CGFloat components[4];
[color getComponents:components];
float backDiffuse[4];
float selectedDiffuse[4] = { 1.0f, 0.0f, 0.0f, 1 };
for (uint i = 0; i < 4; i++)
backDiffuse[i] = components[i];
glMaterialfv(GL_BACK, GL_DIFFUSE, backDiffuse);
glMaterialfv(GL_FRONT, GL_DIFFUSE, frontDiffuse);
Vector3D triangleVertices[3];
float *lastDiffuse = frontDiffuse;
BOOL flip = scale.x < 0.0f || scale.y < 0.0f || scale.z < 0.0f;
glBegin(GL_TRIANGLES);
for (uint i = 0; i < triangles->size(); i++)
{
if (selectionMode == MeshSelectionModeTriangles)
{
if (selected->at(i))
{
if (lastDiffuse == frontDiffuse)
{
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, selectedDiffuse);
lastDiffuse = selectedDiffuse;
}
}
else if (lastDiffuse == selectedDiffuse)
{
glMaterialfv(GL_BACK, GL_DIFFUSE, backDiffuse);
glMaterialfv(GL_FRONT, GL_DIFFUSE, frontDiffuse);
lastDiffuse = frontDiffuse;
}
}
Triangle currentTriangle = [self triangleAtIndex:i];
if (flip)
currentTriangle = FlipTriangle(currentTriangle);
[self getTriangleVertices:triangleVertices fromTriangle:currentTriangle];
for (uint j = 0; j < 3; j++)
{
for (uint k = 0; k < 3; k++)
{
triangleVertices[j][k] *= scale[k];
}
}
Vector3D n = NormalFromTriangleVertices(triangleVertices);
n.Normalize();
for (uint j = 0; j < 3; j++)
{
glNormal3f(n.x, n.y, n.z);
glVertex3f(triangleVertices[j].x, triangleVertices[j].y, triangleVertices[j].z);
}
}
glEnd();
}
당신이 매우 비효율적하지만 작업입니다 볼 수 있듯이 :
이 내가 대체 할 코드, 더 명확합니다.triangles
은
vertices
배열에 대한 인덱스 배열입니다.
그리기 위해이 코드를 사용하려고했지만 두 개가 아닌 하나의 인덱스 배열 만 가질 수는 없습니다 (정점 및 법선에 대해 하나씩). 일부 정점이 다른 삼각형에 의해 공유 될 때 이제
glEnableClientState(GL_VERTEX_ARRAY);
uint *trianglePtr = (uint *)(&(*triangles)[0]);
float *vertexPtr = (float *)(&(*vertices)[0]);
glVertexPointer(3, GL_FLOAT, 0, vertexPtr);
glDrawElements(GL_TRIANGLES, triangles->size() * 3, GL_UNSIGNED_INT, trianglePtr);
glDisableClientState(GL_VERTEX_ARRAY);
, 어떻게 그들을 위해 너무 다른 노멀, 노멀 포인터를 지정할 수 있습니다?
glDrawElements와 협력하여 glVertexPointer의 문제점은 무엇입니까? 모든 정점에 대한 법선을 계산할 vertex normal 알고리즘을 사용할 수 있습니다. – pmr
btw 이제 모든 삼각형에 대해 쉐이더가 사용됩니다. 이것은 주 병목이 될 것입니다. 귀하의 그것의 탈출구는 glDrawElements 또는 VBOs입니다. – pmr
까다로운 것은 모든 정점에 대해 일반을 생성하는 것이 아니라 모든 삼각형에 대해 일반을 생성하고 싶다는 것입니다. –