我有一个从 3DS Max 导出的 OBJ 和 MTL 文件,它是一套完整的国际象棋。在我的最终结果中,我希望能够选择一个游戏 block ,然后选择一个正方形来移动它。我在组合时遇到问题的元素是:
- 对象选择
- 着色器
我的对象导入器以两种方式工作。
1) 将所有东西和类似的 Material 组合到一个名为 Mesh
的结构中,并循环遍历所有 model.meshes
绘制每一帧。
2) 识别棋盘、每个方 block 和每个游戏 block ,并将相关顶点、 Material 等放入名为 GroupObject
的结构中。它们放置在 model.objects
中,我循环绘制每一帧。
这是 #1 和 #2 中描述的每个选项的屏幕截图。在 SS 的顶部 1/2 中,我只是绘制了网格,所有的阴影看起来都正确,但没有什么是可选的。在底部的 1/2 中,我可以选择一个游戏 block 或一个正方形就好了,但模型看起来很垃圾。
http://img815.imageshack.us/img815/2158/chesst.png
此外,如果我将着色器与 #2 中的代码一起使用,则平移和缩放会减慢速度。它几乎完全没有反应。
这是每帧绘制对象时调用的方法。前 2 行注释是我尝试选项 1 的地方,只是绘制了我的结构 Mesh
,它看起来不错。旋转和缩放也很流畅,但我无法选择对象 b/c 我无法执行 Mesh
的 glPushName。现在,代码设置为循环遍历每个 model.objects
,因此我可以运行 glPushName( (int)object );
,这是选择/选择棋子或正方形。注释掉的部分是我尝试应用着色器的地方,它在遍历 model.objects
时非常慢(在循环 model.mesh
时没有减速)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//for (int i = 0; i < model.getNumberOfMeshes(); ++i)
//{
for ( int i = 0; i < (int)model.objects.size(); i++ )
{
ModelOBJ::GroupObject *object = model.objects[i];
glPushName( (int)object );
int faceSize = (int)object->faces.size();
for ( int j = 0; j < faceSize; j++ )
{
ModelOBJ::Face *face = object->faces[j];
pMaterial = &model.getMaterial( face->materialId );
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (GLfloat *)pMaterial->ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (GLfloat *)pMaterial->diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat *)pMaterial->specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pMaterial->shininess * 128.0f);
glDisable(GL_TEXTURE_2D);
drawFace( *face );
//if (pMaterial->bumpMapFilename.empty())
//{
// Per fragment Blinn-Phong code path.
// glUseProgram(blinnPhongShader);
// // Bind the color map texture.
// texture = nullTexture;
// if (enableTextures)
// {
// iter = modelTextures.find(pMaterial->colorMapFilename);
// if (iter != modelTextures.end())
// texture = iter->second;
// }
// glActiveTexture(GL_TEXTURE0);
// glEnable(GL_TEXTURE_2D);
// glBindTexture(GL_TEXTURE_2D, texture);
// // Update shader parameters.
// glUniform1i(glGetUniformLocation(
// blinnPhongShader, "colorMap"), 0);
// glUniform1f(glGetUniformLocation(
// blinnPhongShader, "materialAlpha"), pMaterial->alpha);
//}
}
glPopName();
}
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
glDisable(GL_BLEND);
这是相关的 drawFace 方法
void GLEngine::drawFace(ModelOBJ::Face &face)
{
if ( (int)face.numVertices <= 3 )
glBegin(GL_TRIANGLES);
else
glBegin(GL_POLYGON);
for ( int v = 0; v < (int)face.numVertices; v++ )
{
if ( (int)face.numUVWs > v && face.UVWs != NULL )
glTexCoord2f(face.UVWs[v]->x, face.UVWs[v]->y);
if ( (int)face.numNormals > v && face.normals != NULL )
glTexCoord3d(face.normals[v]->x, face.normals[v]->y, face.normals[v]->z);
if ( (int)face.numVertices > v && face.vertices != NULL )
glVertex3f(face.vertices[v]->x, face.vertices[v]->y, face.vertices[v]->z);
}
glEnd();
}
这是我正在使用的着色器
Per-fragment Blinn-Phong shader for a single directional light source.
[vert]
varying vec3 normal;
void main()
{
normal = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
[frag]
uniform sampler2D colorMap;
uniform float materialAlpha;
varying vec3 normal;
void main()
{
vec3 n = normalize(normal);
float nDotL = max(0.0, dot(n, gl_LightSource[0].position.xyz));
float nDotH = max(0.0, dot(normal, vec3(gl_LightSource[0].halfVector)));
float power = (nDotL == 0.0) ? 0.0 : pow(nDotH, gl_FrontMaterial.shininess);
vec4 ambient = gl_FrontLightProduct[0].ambient;
vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL;
vec4 specular = gl_FrontLightProduct[0].specular * power;
vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse + specular;
gl_FragColor = color * texture2D(colorMap, gl_TexCoord[0].st);
gl_FragColor.a = materialAlpha;
}
您将如何将所有这些功能合并在一起?我的第一个想法是绘制所有没有 Material 信息的 model.objects
并使它们透明。然后运行第二个循环并使用着色器绘制所有 model.meshes
并完成。但后来我想到,当我开始将游戏棋子移动到一个新方 block 时,我将如何确保将正确的阴影应用到棋子的新位置。当我选择透明的 GroupObject
并将其转换为一个新的正方形时,该 block 是否仍具有正确的阴影?
解决我遇到的问题的最佳方法是什么?
最佳答案
为什么在 GLEngine::drawFace
中将法线作为纹理坐标发送:
glTexCoord3d(face.normals[v]->x, face.normals[v]->y, face.normals[v]->z);
你的着色器期望它是一个 glNormal3d
,正如你在这里看到的:
normal = normalize(gl_NormalMatrix * gl_Normal);
关于c++ - 使用着色器绘制 3D 对象的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4650904/