OpenGL 3.1使用索引绘图发出渲染纹理

时间:2014-04-06 20:10:54

标签: c++ opengl glsl

我正在尝试使用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场景中的第一个网格加载到向量中,然后为几何,纹理坐标,法线和索引创建vao,vbos。然后将数据从向量加载到缓冲区中并设置顶点属性。加载完所有内容后,将创建一个包含多个GLuints的结构来返回数据。

渲染模型功能

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);
}

渲染模型的简要概述。设置着色器程序以处理渲染模型,获取相机的矩阵,将其传递给着色器,为模型生成矩阵,使其旋转,将其传递给着色器。绑定要渲染的模型的vao。绑定以前加载的文本,该文本也用于程序中显示没有问题的其他几何体,将其传递给着色器。 all设置,从当前vao的索引缓冲区中的第一个位置开始调用glDrawElements。绘图完成后,请清理以取消绑定任何缓冲区和数组

我正在使用的着色器是非常基本的 顶点着色器

#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);
}

片段着色器     #version 140

uniform sampler2D modeltext;

in vec2 fragUV;

out vec4 finalColor;

void main(){

    finalColor = texture(modeltext, fragUV);
}

所有制服都正确加载了一个函数,该函数可以验证某些内容是否已实际加载,是否使用了纹理,并在程序中的其他位置工作。该模型具有纹理坐标。几何图形正在加载并且没有问题

1 个答案:

答案 0 :(得分:1)

您将错误的值传递给采样器制服。

glBindTexture (GL_TEXTURE_2D, texture);
glUniform1i   (modeltext,     texture);

采样器制服不采用纹理对象的名称(ID),它们采用将纹理绑定到的纹理图像单元的索引。在此示例中,您似乎使用默认的纹理图像单位:GL_TEXTURE0,因此采样器制服应使用的值为 0

因为sampler2D实际上需要纹理图像单元而不是纹理的名称,所以在更改绑定纹理时,您永远不必更改此制服。 GLSL将始终采样任何绑定到相应纹理图像单元的纹理(假设它们具有兼容的类型/状态)。

这意味着您通常在初始化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是默认的活动纹理单元。