Add .obj loading and rendering

This commit is contained in:
Ben Visness
2018-05-28 17:44:35 -05:00
parent ba02e1a9c4
commit 3a382212f9
11 changed files with 10088 additions and 11 deletions

1
.gitignore vendored
View File

@@ -5,7 +5,6 @@
*.slo *.slo
*.lo *.lo
*.o *.o
*.obj
*.vs *.vs
# Precompiled Headers # Precompiled Headers

10
example/MonkeyFlat.mtl Normal file
View File

@@ -0,0 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

1512
example/MonkeyFlat.obj Normal file

File diff suppressed because it is too large Load Diff

10
example/MonkeySmooth.mtl Normal file
View File

@@ -0,0 +1,10 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl None
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

5998
example/MonkeySmooth.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
#include <string>
#include <vector>
#ifndef HMME_MESH_RENDER_COMPONENT_H
#define HMME_MESH_RENDER_COMPONENT_H
#include "tiny_obj_loader.h"
class MeshRenderComponent : public RenderComponent {
public:
bool didLoad = false;
struct Shape {
GLuint vaoID = 0;
GLuint vertexBufferID = 0;
GLuint normalBufferID = 0;
GLuint uvBufferID = 0;
GLuint colorBufferID = 0;
int numVerts = 0;
};
std::vector<Shape> renderShapes;
MeshRenderComponent(const char *filename) {
// Load the model
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename);
if (!err.empty()) { // `err` may contain warning message.
printf("Failed to load mesh: %s\n", err.c_str());
}
if (!ret) {
return;
}
for (auto shape : shapes) {
std::vector<tinyobj::real_t> vertices;
std::vector<tinyobj::real_t> normals;
std::vector<tinyobj::real_t> uvs;
std::vector<tinyobj::real_t> colors;
for (auto indices : shape.mesh.indices) {
if (indices.vertex_index > -1) {
for (int i = 0; i < 3; i++) {
int attribIndex = 3 * indices.vertex_index + i;
vertices.push_back(attrib.vertices[attribIndex]);
colors.push_back(attrib.colors[attribIndex]);
}
}
if (indices.normal_index > -1) {
for (int i = 0; i < 3; i++) {
int attribIndex = 3 * indices.normal_index + i;
normals.push_back(attrib.normals[attribIndex]);
}
}
if (indices.texcoord_index > -1) {
for (int i = 0; i < 2; i++) {
int attribIndex = 2 * indices.texcoord_index + i;
uvs.push_back(attrib.texcoords[attribIndex]);
}
}
}
Shape s; // the new shape to insert into our list
glGenVertexArrays(1, &s.vaoID);
if (!vertices.empty()) {
glGenBuffers(1, &s.vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * vertices.size(), &vertices.front(), GL_STATIC_DRAW);
glGenBuffers(1, &s.colorBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.colorBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * colors.size(), &colors.front(), GL_STATIC_DRAW);
}
if (!normals.empty()) {
glGenBuffers(1, &s.normalBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.normalBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * normals.size(), &normals.front(), GL_STATIC_DRAW);
}
if (!uvs.empty()) {
glGenBuffers(1, &s.uvBufferID);
glBindBuffer(GL_ARRAY_BUFFER, s.uvBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(tinyobj::real_t) * uvs.size(), &uvs.front(), GL_STATIC_DRAW);
}
s.numVerts = vertices.size() / 3;
renderShapes.push_back(s);
}
didLoad = true;
}
void Draw() override {
if (!didLoad) {
return;
}
for (auto s : renderShapes) {
glBindVertexArray(s.vaoID);
// 1st attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, s.vertexBufferID);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, s.colorBufferID);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
if (s.normalBufferID != 0) {
// 3rd attribute buffer : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, s.normalBufferID);
glVertexAttribPointer(
2, // must match the layout in the shader
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
}
if (s.uvBufferID != 0) {
// 4th attribute buffer : uvs
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, s.normalBufferID);
glVertexAttribPointer(
3, // must match the layout in the shader
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
}
// Shader??
// Draw the triangle!
glDrawArrays(GL_TRIANGLES, 0, s.numVerts); // Starting from vertex 0; 3 vertices total -> 1 triangle
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
if (s.normalBufferID != 0) {
glDisableVertexAttribArray(2);
}
if (s.uvBufferID != 0) {
glDisableVertexAttribArray(3);
}
}
}
};
#endif

View File

@@ -1,9 +1,16 @@
#version 330 core #version 330 core
in vec3 fragmentPosition_world;
in vec3 fragmentColor; in vec3 fragmentColor;
in vec3 fragmentNormal_world;
in vec2 fragmentUV;
out vec3 color; out vec3 color;
void main() { void main() {
color = fragmentColor; vec3 toLight_world = normalize(vec3(1, 1, 1));
float cosTheta = clamp(dot(normalize(fragmentNormal_world), toLight_world), 0.1, 1);
color = cosTheta * fragmentColor;
} }

View File

@@ -10,6 +10,7 @@
#include "Entity.h" #include "Entity.h"
#include "Cube.h" #include "Cube.h"
#include "MeshRenderComponent.h"
void TickTree(Entity *e, float deltaSeconds); void TickTree(Entity *e, float deltaSeconds);
void ComputeModelMatrices(Entity *ep, hmm_mat4 parentModelMatrix); void ComputeModelMatrices(Entity *ep, hmm_mat4 parentModelMatrix);
@@ -57,7 +58,9 @@ int main()
// Get a handle for our "MVP" uniform // Get a handle for our "MVP" uniform
// Only during the initialisation // Only during the initialisation
GLuint MatrixID = glGetUniformLocation(programID, "MVP"); GLuint uniformID_M = glGetUniformLocation(programID, "M");
GLuint uniformID_V = glGetUniformLocation(programID, "V");
GLuint uniformID_MVP = glGetUniformLocation(programID, "MVP");
// Enable depth test // Enable depth test
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@@ -66,13 +69,14 @@ int main()
Cube root = Cube(); Cube root = Cube();
Cube child = Cube(); Entity child = Entity();
child.position = HMM_Vec3(2.1f, 0.0f, 0.0f); child.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
child.renderComponent = new MeshRenderComponent("MonkeySmooth.obj");
Cube c = Cube(); // Cube c = Cube();
child.position = HMM_Vec3(2.1f, 0.0f, 0.0f); // child.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
child.AddChild(&c); // child.AddChild(&c);
root.AddChild(&child); root.AddChild(&child);
bool hasTicked = false; bool hasTicked = false;
@@ -107,8 +111,13 @@ int main()
// Use our shader // Use our shader
glUseProgram(programID); glUseProgram(programID);
// Send uniforms
glUniformMatrix4fv(uniformID_M, 1, GL_FALSE, &e->modelMatrix.Elements[0][0]);
glUniformMatrix4fv(uniformID_V, 1, GL_FALSE, &view.Elements[0][0]);
hmm_mat4 mvp = vp * e->modelMatrix; hmm_mat4 mvp = vp * e->modelMatrix;
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp.Elements[0][0]); glUniformMatrix4fv(uniformID_MVP, 1, GL_FALSE, &mvp.Elements[0][0]);
e->renderComponent->Draw(); e->renderComponent->Draw();
} }

View File

@@ -0,0 +1,2 @@
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,28 @@
#version 330 core #version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace; // These match the values in glVertexAttribPointer
// Notice that the "1" here equals the "1" in glVertexAttribPointer layout(location = 0) in vec3 vertexPosition_model;
layout(location = 1) in vec3 vertexColor; layout(location = 1) in vec3 vertexColor;
layout(location = 2) in vec3 vertexNormal_model;
layout(location = 3) in vec2 vertexUV;
uniform mat4 M;
uniform mat4 V;
uniform mat4 MVP; uniform mat4 MVP;
out vec3 fragmentPosition_world;
out vec3 fragmentColor; out vec3 fragmentColor;
out vec3 fragmentNormal_world;
out vec2 fragmentUV;
void main(){ void main(){
// Output position of the vertex, in clip space : MVP * position // Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace, 1); gl_Position = MVP * vec4(vertexPosition_model, 1);
fragmentPosition_world = (M * vec4(vertexPosition_model, 1)).xyz;
fragmentColor = vertexColor; fragmentColor = vertexColor;
fragmentNormal_world = (M * vec4(vertexNormal_model, 0)).xyz;
fragmentUV = vertexUV;
} }