mirror of
https://github.com/HandmadeMath/HandmadeMath.git
synced 2025-09-10 12:18:16 +00:00
Add .obj loading and rendering
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,7 +5,6 @@
|
|||||||
*.slo
|
*.slo
|
||||||
*.lo
|
*.lo
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
|
||||||
*.vs
|
*.vs
|
||||||
|
|
||||||
# Precompiled Headers
|
# Precompiled Headers
|
||||||
|
10
example/MonkeyFlat.mtl
Normal file
10
example/MonkeyFlat.mtl
Normal 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
1512
example/MonkeyFlat.obj
Normal file
File diff suppressed because it is too large
Load Diff
10
example/MonkeySmooth.mtl
Normal file
10
example/MonkeySmooth.mtl
Normal 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
5998
example/MonkeySmooth.obj
Normal file
File diff suppressed because it is too large
Load Diff
179
example/src/MeshRenderComponent.h
Normal file
179
example/src/MeshRenderComponent.h
Normal 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
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
2
example/src/tiny_obj_loader.cpp
Normal file
2
example/src/tiny_obj_loader.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define TINYOBJLOADER_IMPLEMENTATION
|
||||||
|
#include "tiny_obj_loader.h"
|
2338
example/src/tiny_obj_loader.h
Normal file
2338
example/src/tiny_obj_loader.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user