我正在尝试使用 glDrawElements 绘制从 assimp 加载的模型,几何显示正常但纹理没有显示在模型上,我只是得到了我加载的模型的黑色版本。
加载模型函数
ModelInfo LoadModel(const std::string& modelPath){
printf( "Loading model: %s\n", modelPath.c_str());
//verify that file exists first
std::ifstream fin(modelPath.c_str());
if(!fin.fail()){
fin.close();
}else{
throw std::runtime_error("could not open file" + modelPath);
}
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile( modelPath,
aiProcessPreset_TargetRealtime_Fast |
//aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_GenSmoothNormals |
aiProcess_FlipUVs
//aiProcess_JoinIdenticalVertices |
//aiProcess_SortByPType);
);
if(!scene){
throw std::runtime_error(importer.GetErrorString());
}
printf("imported %s\n",modelPath.c_str());
fflush(stdout);
std::vector<unsigned int> indices;
std::vector<float> vertices;
std::vector<float> uvs;
std::vector<float> normals;
aiMesh* mesh = scene->mMeshes[0];
int numOfFaces = mesh->mNumFaces;
int numOfIndices = numOfFaces * 3;
indices.resize(numOfIndices);
for (unsigned int i =0; i < mesh->mNumFaces; ++i){
const aiFace &face = mesh->mFaces[i];
assert(face.mNumIndices == 3);
indices[i * 3 + 0] = face.mIndices[0];
indices[i * 3 + 1] = face.mIndices[1];
indices[i * 3 + 2] = face.mIndices[2];
}
int numOfVertices = mesh->mNumVertices;
vertices.resize(numOfVertices * 3);
normals.resize(numOfVertices * 3);
uvs.resize(numOfVertices * 2);
for( unsigned int i = 0; i < mesh->mNumVertices; ++i){
if(mesh->HasPositions()){
vertices[i * 3 + 0] = mesh->mVertices[i].x;
vertices[i * 3 + 1] = mesh->mVertices[i].y;
vertices[i * 3 + 2] = mesh->mVertices[i].z;
//printf("[ %f, %f, %f]\n",vertices[i*3+0],vertices[i*3+1],vertices[i*3+2]);
}
if( mesh->HasNormals()){
normals[i * 3 + 0] = mesh->mNormals[i].x;
normals[i * 3 + 1] = mesh->mNormals[i].x;
normals[i * 3 + 2] = mesh->mNormals[i].x;
}
if(mesh->HasTextureCoords(0)){
uvs[i * 2 + 0] = mesh->mTextureCoords[0][i].x;
uvs[i * 2 + 1] = mesh->mTextureCoords[0][i].y;
printf("[ %f, %f]\n",uvs[i*2+0],uvs[i*2+1]);
}
}
//create voa
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//create element buffer
GLuint elementBuffer;
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
//create vertex buffer
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(aiVector3D), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
printf("vertices.size is %lu\n", vertices.size());
printf("uvs.size is %lu\n", uvs.size());
GLuint uvBuffer;
glGenBuffers(1, &uvBuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(aiVector2D), &uvs[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0);
GLuint normalBuffer;
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(aiVector3D), &normals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
ModelInfo retval;
retval.vao = vao;
retval.index = elementBuffer;
retval.vertex = vertexBuffer;
retval.uv = uvBuffer;
retval.normal = normalBuffer;
retval.count = numOfIndices;
return retval;
加载模型的简短概述,使用 assimp 加载模型,然后将 assimp 场景中第一个网格的数据加载到 vector 中,然后为几何、纹理坐标、法线和索引创建 vao、vbos。然后将数据从 vector 加载到缓冲区中,并设置顶点属性。一旦全部加载完毕,就会创建一个包含多个 GLuint 的结构来返回数据。
渲染模型函数
void render_model(ModelInfo info){
cleanup();
//set program
glUseProgram(modelprogram);
//set uniforms
glm::mat4 view = camera.matrix();
glUniformMatrix4fv(modelcamera, 1, GL_FALSE, &view[0][0]);
glm::mat4 model = glm::mat4();
model = glm::rotate(model, degree, glm::vec3(0,1,1));
glUniformMatrix4fv(modelmodel, 1, GL_FALSE, &model[0][0]);
glBindVertexArray(info.vao);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(modeltext, texture);
glDrawElements(GL_TRIANGLES, info.count, GL_UNSIGNED_INT, (void*)0);
}
渲染模型的简要概述。设置着色器程序来处理渲染模型,获取相机矩阵,将其传递给着色器,为模型生成矩阵,使其旋转,将其传递给着色器。绑定(bind)要渲染的模型的vao。绑定(bind)一个先前加载的文本,该文本也用于程序中显示没有问题的其他几何体,将其传递给着色器。全部设置好,从当前vao的索引缓冲区的第一个位置开始调用glDrawElements。绘制完成后,清理以取消绑定(bind)任何缓冲区和数组
我为此使用的着色器非常基础 顶点着色器
#version 140
uniform mat4 camera;
uniform mat4 model;
in vec3 position;
in vec2 uv;
out vec2 fragUV;
void main(){
//pass variables on to fragment shader
fragUV = uv;
//vertex to draw
gl_Position = camera * model * vec4(position,1);
}
片段着色器 #版本 140
uniform sampler2D modeltext;
in vec2 fragUV;
out vec4 finalColor;
void main(){
finalColor = texture(modeltext, fragUV);
}
所有制服都正确加载了一个函数,该函数验证某些东西确实被加载,纹理被使用并且在程序的其他地方工作。该模型具有纹理坐标。几何正在加载和渲染没有问题
最佳答案
您将错误的值传递给采样器制服。
glBindTexture (GL_TEXTURE_2D, texture);
glUniform1i (modeltext, texture);
采样器制服不采用纹理对象的名称 (ID),它们采用您将纹理绑定(bind)到的纹理图像单元的索引。在此示例中,您似乎正在使用默认的纹理图像单元:GL_TEXTURE0
,因此您的采样器制服应使用的值是0。
因为 sampler2D
实际上需要纹理图像单元而不是纹理名称,所以当您更改绑定(bind)纹理时,您永远不必更改此制服。 GLSL 将始终对绑定(bind)到相应纹理图像单元的任何纹理进行采样(假设它们具有兼容的类型/状态)。
这意味着通常您在初始化 GLSL 程序时设置一次采样器制服,并且永远不会再碰它。在较新版本的 GLSL (4.20) 中,您甚至可以对采样器在着色器本身中使用的纹理图像单元进行硬编码,但由于您使用的是 GLSL 1.40,因此您没有此选项,除非扩展名:GL_ARB_shading_language_420pack
受支持。
考虑以下代码,它正确演示了如何使用采样器制服:
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture);
glUniform1i (modeltext, 0);
我已经包含了对 glActiveTexture (...)
的冗余调用,只是为了演示统一采样器和事件纹理单元是如何相关的...您没有传递常量 GL_TEXTURE0
到采样器,而不是使用整数索引。 GL_TEXTURE0
是默认的事件纹理单元。
关于c++ - OpenGL 3.1 使用索引绘图发布渲染纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22899382/