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
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
*.vs
|
||||
|
||||
# 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
|
||||
|
||||
in vec3 fragmentPosition_world;
|
||||
in vec3 fragmentColor;
|
||||
in vec3 fragmentNormal_world;
|
||||
in vec2 fragmentUV;
|
||||
|
||||
out vec3 color;
|
||||
|
||||
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 "Cube.h"
|
||||
#include "MeshRenderComponent.h"
|
||||
|
||||
void TickTree(Entity *e, float deltaSeconds);
|
||||
void ComputeModelMatrices(Entity *ep, hmm_mat4 parentModelMatrix);
|
||||
@@ -57,7 +58,9 @@ int main()
|
||||
|
||||
// Get a handle for our "MVP" uniform
|
||||
// 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
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
@@ -66,13 +69,14 @@ int main()
|
||||
|
||||
Cube root = Cube();
|
||||
|
||||
Cube child = Cube();
|
||||
Entity child = Entity();
|
||||
child.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
|
||||
child.renderComponent = new MeshRenderComponent("MonkeySmooth.obj");
|
||||
|
||||
Cube c = Cube();
|
||||
child.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
|
||||
// Cube c = Cube();
|
||||
// child.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
|
||||
|
||||
child.AddChild(&c);
|
||||
// child.AddChild(&c);
|
||||
root.AddChild(&child);
|
||||
|
||||
bool hasTicked = false;
|
||||
@@ -107,8 +111,13 @@ int main()
|
||||
// Use our shader
|
||||
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;
|
||||
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp.Elements[0][0]);
|
||||
glUniformMatrix4fv(uniformID_MVP, 1, GL_FALSE, &mvp.Elements[0][0]);
|
||||
|
||||
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
|
||||
|
||||
layout(location = 0) in vec3 vertexPosition_modelspace;
|
||||
// Notice that the "1" here equals the "1" in glVertexAttribPointer
|
||||
// These match the values in glVertexAttribPointer
|
||||
layout(location = 0) in vec3 vertexPosition_model;
|
||||
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;
|
||||
|
||||
out vec3 fragmentPosition_world;
|
||||
out vec3 fragmentColor;
|
||||
out vec3 fragmentNormal_world;
|
||||
out vec2 fragmentUV;
|
||||
|
||||
void main(){
|
||||
// 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;
|
||||
|
||||
fragmentNormal_world = (M * vec4(vertexNormal_model, 0)).xyz;
|
||||
|
||||
fragmentUV = vertexUV;
|
||||
}
|
||||
|
Reference in New Issue
Block a user