我正在尝试使用openGL渲染一些东西。它“有效”,但是我的模型渲染不正确。我查看了几个参考文献,并且无法分辨出错误。也许一个openGL大师可以指出我的错误?
我正在使用几个库,例如tinyobjloader,GLM,GLFW,GLEW等。这里仅介绍与渲染相关的部分。有些代码只是为了渲染单个模型而开发的。
shader.vs
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 norm;
layout (location = 2) in vec2 texCoord;
out vec3 normal;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(position, 2.0f);
TexCoord = texCoord;
normal = norm;
}
shader.frag
#version 330 core
in vec3 normal;
in vec2 TexCoord;
out vec4 color;
uniform sampler2D ourTexture1;
void main()
{
color = texture(ourTexture1, TexCoord);
}
graphics.h中
#include <string>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Shader;
class Graphics{
public:
Graphics(std::string, uint, uint);
~Graphics();
void render();
void clearScreen();
void draw();
void loadTexture(std::string);
private:
GLFWwindow* window = NULL;
};
class Shader{
public:
Shader(std::string, std::string);
void useShader();
GLuint shaderprogram;
};
class Mesh{
public:
Mesh(std::vector<glm::vec3>, std::vector<glm::vec3>, std::vector<glm::vec2>, std::vector<uint>);
void draw();
private:
GLuint VBO = 0;
GLuint VBO_tex = 0;
GLuint VBO_normal = 0;
GLuint VAO = 0;
GLuint EBO = 0;
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> normals;
std::vector<uint> indices;
std::vector<glm::vec2> textures;
};
Mesh loadModel(std::string);
graphics.cpp
#include <glog/logging.h>
#include "graphics.h"
#include <SOIL/SOIL.h>
#include "tiny_obj_loader.h"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
Graphics::Graphics(std::string name, uint w, uint h){
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(w, h, name.c_str(), NULL, NULL);
if(window == NULL){
LOG(ERROR) << "Failed to create GLFW window";
glfwTerminate();
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK){
LOG(ERROR) << "Failed to initialize GLEW";
}
glViewport(0, 0, w, h);
};
Graphics::~Graphics(){
glfwTerminate();
};
void Graphics::render(){
glfwSwapBuffers(window);
};
void Graphics::clearScreen(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
};
GLuint texture;
void Graphics::loadTexture(std::string path){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
int width, height;
unsigned char* image = SOIL_load_image(path.c_str(), &width, &height, 0, SOIL_LOAD_RGB);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//SOIL_free_image_data(image);
//glBindTexture(GL_TEXTURE_2D, 0);
}
Shader::Shader(std::string vertexstring, std::string fragmentstring){
GLuint vertexshaderid = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentshaderid = glCreateShader(GL_FRAGMENT_SHADER);
const char* vertercstring = vertexstring.c_str();
const char* fragmentcstring = fragmentstring.c_str();
GLint success; GLchar errordata[512];
glShaderSource(vertexshaderid, 1, &vertercstring, NULL);
glCompileShader(vertexshaderid);
glGetShaderiv(vertexshaderid, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(vertexshaderid, 1024, NULL, errordata);
LOG(ERROR) << "Vertex Shader Error: " << errordata;
};
glShaderSource(fragmentshaderid, 1, &fragmentcstring, NULL);
glCompileShader(fragmentshaderid);
glGetShaderiv(fragmentshaderid, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(fragmentshaderid, 1024, NULL, errordata);
LOG(ERROR) << "fragment Shader Error: " << errordata;
};
shaderprogram = glCreateProgram();
glAttachShader(shaderprogram, vertexshaderid);
glAttachShader(shaderprogram, fragmentshaderid);
glLinkProgram(shaderprogram);
glDeleteShader(vertexshaderid);
glDeleteShader(fragmentshaderid);
};
void Shader::useShader(){
glUseProgram(shaderprogram);
};
Mesh::Mesh(std::vector<glm::vec3> v, std::vector<glm::vec3> n, std::vector<glm::vec2> t, std::vector<uint> i){
vertices = v;
textures = t;
normals = n;
indices = i;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &VBO_tex);
glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * textures.size(), &textures[0], GL_STATIC_DRAW);
glGenBuffers(1, &VBO_normal);
glBindBuffer(GL_ARRAY_BUFFER, VBO_normal);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * normals.size(), &normals[0], GL_STATIC_DRAW);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint) * indices.size(), &indices[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, VBO_normal);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
};
void Mesh::draw(){
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture);
//glDrawArrays(GL_TRIANGLES, 0, vertices.size());
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
};
#include <iostream>
Mesh loadModel(std::string path){
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, path.c_str());
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textures;
std::vector<uint> indices;
for(auto shape : shapes){
std::cout << shape.name << std::endl;
for(uint i = 0; i < shape.mesh.positions.size(); i+=3){
glm::vec3 vertex;
vertex.x = shape.mesh.positions[i];
vertex.y = shape.mesh.positions[i+1];
vertex.z = shape.mesh.positions[i+2];
vertices.push_back(vertex);
}
for(uint i = 0; i < shape.mesh.normals.size(); i+=3){
glm::vec3 vertex;
vertex.x = shape.mesh.normals[i];
vertex.y = shape.mesh.normals[i+1];
vertex.z = shape.mesh.normals[i+2];
normals.push_back(vertex);
}
for(uint i = 0; i < shape.mesh.indices.size(); i++){
indices.push_back(shape.mesh.indices[i]);
}
for(uint i = 0; i < shape.mesh.texcoords.size(); i+=2){
glm::vec2 vertex;
vertex.x = shape.mesh.texcoords[i];
vertex.y = shape.mesh.texcoords[i+1];
textures.push_back(vertex);
}
}
return Mesh(vertices, normals, textures, indices);
};
主要 - 削减
#include "graphics.h"
Graphics graphics("hai", 640, 480);
Shader shader(readFile("shader.vs"), readFile("shader.frag"));
shader.useShader();
graphics.loadTexture("tempTexture.jpg");
Mesh m = loadModel("treeStump.obj");
graphics.clearScreen();
shader.useShader();
m.draw();
graphics.render();
正如您所看到的那样,纹理没有正确地绘制在模型上,但它在混合器中工作,而其他程序我已将其加载到其中。下一张照片是一个不同的角度(在搅拌机中),但它应该是它的样子。
如果我需要提供更多信息,请告诉我!谢谢!
答案 0 :(得分:2)
纹理坐标有2个组件,这是典型的:
glm::vec2 vertex;
vertex.x = shape.mesh.texcoords[i];
vertex.y = shape.mesh.texcoords[i+1];
textures.push_back(vertex);
但这与您指定属性的方式不符:
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, VBO_tex);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glVertexAttribPointer()
的第二个参数指定属性中的组件数。在这种情况下,匹配数据应为2:
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, NULL);
此外,如果您完全关心性能或电源使用情况,则应避免不必要地复制数据。我只在你的代码中计算了4个顶点数据副本。在OBJ解析器中添加副本,以及由OpenGL驱动程序创建的副本,并且在渲染之前,您最终将整个顶点数据复制大约7次。这是很多浪费的电子......