Broken Models lol

This commit is contained in:
OusmBlueNinja 2025-04-08 20:13:17 -05:00
parent c36dfcd963
commit 41dcb86dbb
52 changed files with 570311 additions and 241 deletions

View File

@ -0,0 +1,9 @@
{
"files.associations": {
"*.pyx": "python",
"*.js": "javascript",
"*.c": "c",
"*.scene": "yaml",
"ostream": "cpp"
}
}

View File

@ -4,7 +4,7 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Scene Controls] [Window][Scene Controls]
Pos=121,151 Pos=7,4
Size=334,445 Size=334,466
Collapsed=0 Collapsed=0

View File

@ -1,8 +1,8 @@
// main.cpp // main.cpp
// A minimal physically based renderer with ImGui integration, // A minimal physically based renderer with ImGui integration,
// normal mapping (with per-vertex tangents), // normal mapping (with per-vertex tangents), YAML-based material loading/saving,
// YAML-based material loading and material saving via yaml-cpp. // and support for loading 3D models (OBJ files) via tinyobjloader.
// Uses OpenGL, GLFW, GLEW, GLM, ImGui (and IM_PI), stb_image, and yaml-cpp. // Uses OpenGL, GLFW, GLEW, GLM, ImGui (and IM_PI), stb_image, yaml-cpp, and tinyobjloader.
// Compile (e.g. on Linux) with: // Compile (e.g. on Linux) with:
// g++ main.cpp -lglfw -lGLEW -lGL -ldl -limgui -lyaml-cpp -o pbr_renderer // g++ main.cpp -lglfw -lGLEW -lGL -ldl -limgui -lyaml-cpp -o pbr_renderer
// (Adjust include paths and linker flags as needed.) // (Adjust include paths and linker flags as needed.)
@ -20,10 +20,11 @@
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <map>
// ImGui includes. // ImGui includes.
#include "imgui.h" #include "imgui.h"
#include "imgui_internal.h" // for IM_PI (ImGui's internal constant) #include "imgui_internal.h" // For IM_PI (ImGui's internal constant)
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
@ -31,9 +32,13 @@
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h" #include "stb_image.h"
// yaml-cpp for YAML material loading and saving. // yaml-cpp for YAML material loading/saving.
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
// tinyobjloader for OBJ file loading.
#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Shader sources // Shader sources
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -59,7 +64,7 @@ uniform mat4 projection;
void main(){ void main(){
WorldPos = vec3(model * vec4(aPos, 1.0)); WorldPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal; Normal = mat3(transpose(inverse(model))) * aNormal;
// For tangent, we simply transform with the model matrix (ignoring potential scale issues). // For tangent, we simply transform with the model matrix.
Tangent = mat3(model) * aTangent; Tangent = mat3(model) * aTangent;
TexCoords = aTexCoords; TexCoords = aTexCoords;
gl_Position = projection * view * vec4(WorldPos, 1.0); gl_Position = projection * view * vec4(WorldPos, 1.0);
@ -67,8 +72,7 @@ void main(){
)"; )";
// --- Fragment Shader --- // --- Fragment Shader ---
// Uses a uniform for PI (set from ImGui's internal IM_PI) and supports texture maps. // Supports texture maps, normal mapping (via TBN), and uses ImGui's IM_PI constant.
// It now also supports a normal map: if enabled, it uses TBN to compute a perturbed normal.
const char* fragmentShaderSource = R"( const char* fragmentShaderSource = R"(
#version 330 core #version 330 core
out vec4 FragColor; out vec4 FragColor;
@ -135,13 +139,10 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
} }
void main(){ void main(){
// Start with the geometry normal.
vec3 N = normalize(Normal); vec3 N = normalize(Normal);
// If a normal map is used, sample the normal map and compute a perturbed normal.
if (useNormalMap) { if (useNormalMap) {
vec3 tangentNormal = texture(normalMap, TexCoords).rgb; vec3 tangentNormal = texture(normalMap, TexCoords).rgb;
tangentNormal = tangentNormal * 2.0 - 1.0; // Remap from [0,1] to [-1,1] tangentNormal = tangentNormal * 2.0 - 1.0;
vec3 T = normalize(Tangent); vec3 T = normalize(Tangent);
vec3 B = normalize(cross(N, T)); vec3 B = normalize(cross(N, T));
mat3 TBN = mat3(T, B, N); mat3 TBN = mat3(T, B, N);
@ -150,7 +151,6 @@ void main(){
vec3 V = normalize(camPos - WorldPos); vec3 V = normalize(camPos - WorldPos);
// Get material parameter values from textures (if enabled) or use fallback values.
vec3 albedoValue = albedo; vec3 albedoValue = albedo;
if (useAlbedoMap) if (useAlbedoMap)
albedoValue = texture(albedoMap, TexCoords).rgb; albedoValue = texture(albedoMap, TexCoords).rgb;
@ -167,7 +167,6 @@ void main(){
if (useAOMap) if (useAOMap)
aoValue = texture(aoMap, TexCoords).r; aoValue = texture(aoMap, TexCoords).r;
// Calculate reflectance at normal incidence.
vec3 F0 = vec3(0.04); vec3 F0 = vec3(0.04);
F0 = mix(F0, albedoValue, metallicValue); F0 = mix(F0, albedoValue, metallicValue);
@ -194,7 +193,6 @@ void main(){
vec3 ambient = vec3(0.03) * albedoValue * aoValue; vec3 ambient = vec3(0.03) * albedoValue * aoValue;
color += ambient; color += ambient;
// Simple HDR tonemapping & gamma correction.
color = color / (color + vec3(1.0)); color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2)); color = pow(color, vec3(1.0/2.2));
@ -209,7 +207,6 @@ GLuint compileShader(GLenum shaderType, const char* source) {
GLuint shader = glCreateShader(shaderType); GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &source, nullptr); glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader); glCompileShader(shader);
GLint success; GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success); glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success){ if (!success){
@ -225,7 +222,6 @@ GLuint createProgram(GLuint vertexShader, GLuint fragmentShader) {
glAttachShader(program, vertexShader); glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader); glAttachShader(program, fragmentShader);
glLinkProgram(program); glLinkProgram(program);
GLint success; GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success); glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success){ if (!success){
@ -254,7 +250,6 @@ GLuint LoadTexture(const char* path) {
format = GL_RGB; format = GL_RGB;
else if(nrChannels == 4) else if(nrChannels == 4)
format = GL_RGBA; format = GL_RGBA;
GLuint textureID; GLuint textureID;
glGenTextures(1, &textureID); glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID); glBindTexture(GL_TEXTURE_2D, textureID);
@ -265,68 +260,12 @@ GLuint LoadTexture(const char* path) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data); stbi_image_free(data);
return textureID; return textureID;
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Sphere mesh generation with tangents. // Data Structures for Meshes and Models
// Produces per-vertex data: position (3), normal (3), texcoords (2), tangent (3) → 11 floats/vertex.
// --------------------------------------------------------------------------------------
void generateSphere(std::vector<float>& vertices, std::vector<unsigned int>& indices,
unsigned int X_SEGMENTS = 64, unsigned int Y_SEGMENTS = 64) {
vertices.clear();
indices.clear();
for (unsigned int y = 0; y <= Y_SEGMENTS; ++y) {
for (unsigned int x = 0; x <= X_SEGMENTS; ++x) {
float xSegment = static_cast<float>(x) / X_SEGMENTS;
float ySegment = static_cast<float>(y) / Y_SEGMENTS;
// Using ImGui's IM_PI for consistency.
float xPos = std::cos(xSegment * 2.0f * IM_PI) * std::sin(ySegment * IM_PI);
float yPos = std::cos(ySegment * IM_PI);
float zPos = std::sin(xSegment * 2.0f * IM_PI) * std::sin(ySegment * IM_PI);
// Position.
vertices.push_back(xPos);
vertices.push_back(yPos);
vertices.push_back(zPos);
// Normal (unit sphere: same as position).
vertices.push_back(xPos);
vertices.push_back(yPos);
vertices.push_back(zPos);
// Texture coordinates.
vertices.push_back(xSegment);
vertices.push_back(ySegment);
// Tangent: derivative with respect to u.
float tangentX = -std::sin(xSegment * 2.0f * IM_PI);
float tangentY = 0.0f;
float tangentZ = std::cos(xSegment * 2.0f * IM_PI);
vertices.push_back(tangentX);
vertices.push_back(tangentY);
vertices.push_back(tangentZ);
}
}
for (unsigned int y = 0; y < Y_SEGMENTS; ++y) {
for (unsigned int x = 0; x < X_SEGMENTS; ++x) {
unsigned int i0 = y * (X_SEGMENTS + 1) + x;
unsigned int i1 = i0 + 1;
unsigned int i2 = i0 + (X_SEGMENTS + 1);
unsigned int i3 = i2 + 1;
indices.push_back(i0);
indices.push_back(i2);
indices.push_back(i1);
indices.push_back(i1);
indices.push_back(i2);
indices.push_back(i3);
}
}
}
// --------------------------------------------------------------------------------------
// Material and Sphere Instance structures.
// The Material now includes a normal map.
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
struct Material { struct Material {
glm::vec3 albedo; glm::vec3 albedo;
@ -341,7 +280,7 @@ struct Material {
GLuint aoTex; GLuint aoTex;
GLuint normalTex; GLuint normalTex;
// Flags indicating if a texture map is used. // Flags indicating texture usage.
bool useAlbedoMap; bool useAlbedoMap;
bool useMetallicMap; bool useMetallicMap;
bool useRoughnessMap; bool useRoughnessMap;
@ -370,15 +309,34 @@ struct Material {
struct SphereInstance { struct SphereInstance {
glm::vec3 position; glm::vec3 position;
float rotation; // Rotation angle (in radians). float rotation; // In radians.
Material material; Material material;
}; };
// For OBJ models, we define a Vertex structure.
struct Vertex {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texcoord;
glm::vec3 tangent;
};
struct Model {
GLuint VAO;
GLuint VBO;
GLuint EBO;
unsigned int indexCount;
// Transformation.
glm::vec3 position;
float rotation; // Around Y axis.
Material material;
// Filename of the loaded model (for reference).
std::string filename;
};
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// YAML Material Loading // YAML Material Loading & Saving
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Expects a YAML file with keys: albedo (list of 3), metallic, roughness, ao,
// plus optional texture paths: albedo_texture, metallic_texture, roughness_texture, ao_texture, normal_texture.
Material loadMaterialFromYAML(const std::string& filename) { Material loadMaterialFromYAML(const std::string& filename) {
Material mat; Material mat;
try { try {
@ -446,10 +404,6 @@ Material loadMaterialFromYAML(const std::string& filename) {
return mat; return mat;
} }
// --------------------------------------------------------------------------------------
// YAML Material Saving
// --------------------------------------------------------------------------------------
// Saves a material to a YAML file with keys similar to the loader.
bool saveMaterialToYAML(const std::string& filename, const Material& mat) { bool saveMaterialToYAML(const std::string& filename, const Material& mat) {
YAML::Emitter out; YAML::Emitter out;
out << YAML::BeginMap; out << YAML::BeginMap;
@ -479,6 +433,152 @@ bool saveMaterialToYAML(const std::string& filename, const Material& mat) {
return true; return true;
} }
// --------------------------------------------------------------------------------------
// OBJ Model Loading using tinyobjloader.
// --------------------------------------------------------------------------------------
// We define a Vertex structure (see above). This function loads an OBJ file
// and outputs vertices and indices in the expected format (11 floats per vertex:
// position[3], normal[3], texcoord[2], tangent[3]). Tangents are computed after loading.
bool loadOBJModel(const std::string& filename, std::vector<Vertex>& outVertices, std::vector<unsigned int>& outIndices) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> objMaterials;
std::string warn, err;
std::cout << "tinyobjloader Loading: " << filename << std::endl;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &objMaterials, &warn, &err, filename.c_str());
if (!warn.empty())
std::cout << "tinyobjloader warning: " << warn << std::endl;
if (!err.empty()) {
std::cerr << "tinyobjloader error: " << err << std::endl;
return false;
}
if (!ret) {
std::cerr << "Failed to load/parse OBJ file: " << filename << std::endl;
return false;
}
// For simplicity, we push every vertex (no deduplication).
for (size_t s = 0; s < shapes.size(); s++) {
for (size_t f = 0; f < shapes[s].mesh.indices.size(); f++) {
tinyobj::index_t idx = shapes[s].mesh.indices[f];
Vertex vertex;
vertex.position = glm::vec3(
attrib.vertices[3 * idx.vertex_index + 0],
attrib.vertices[3 * idx.vertex_index + 1],
attrib.vertices[3 * idx.vertex_index + 2]
);
if (idx.normal_index >= 0) {
vertex.normal = glm::vec3(
attrib.normals[3 * idx.normal_index + 0],
attrib.normals[3 * idx.normal_index + 1],
attrib.normals[3 * idx.normal_index + 2]
);
} else {
vertex.normal = glm::vec3(0.0f, 1.0f, 0.0f);
}
if (idx.texcoord_index >= 0) {
vertex.texcoord = glm::vec2(
attrib.texcoords[2 * idx.texcoord_index + 0],
attrib.texcoords[2 * idx.texcoord_index + 1]
);
} else {
vertex.texcoord = glm::vec2(0.0f, 0.0f);
}
// Initialize tangent to zero; we will compute later.
vertex.tangent = glm::vec3(0.0f);
outVertices.push_back(vertex);
outIndices.push_back(static_cast<unsigned int>(outVertices.size() - 1));
}
}
// Compute tangents per triangle.
std::vector<glm::vec3> tanAccum(outVertices.size(), glm::vec3(0.0f));
for (size_t i = 0; i < outIndices.size(); i += 3) {
unsigned int i0 = outIndices[i + 0];
unsigned int i1 = outIndices[i + 1];
unsigned int i2 = outIndices[i + 2];
const glm::vec3& p0 = outVertices[i0].position;
const glm::vec3& p1 = outVertices[i1].position;
const glm::vec3& p2 = outVertices[i2].position;
const glm::vec2& uv0 = outVertices[i0].texcoord;
const glm::vec2& uv1 = outVertices[i1].texcoord;
const glm::vec2& uv2 = outVertices[i2].texcoord;
glm::vec3 deltaPos1 = p1 - p0;
glm::vec3 deltaPos2 = p2 - p0;
glm::vec2 deltaUV1 = uv1 - uv0;
glm::vec2 deltaUV2 = uv2 - uv0;
float r = 1.0f;
float denom = (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
if (fabs(denom) > 1e-6f)
r = 1.0f / denom;
glm::vec3 tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
tanAccum[i0] += tangent;
tanAccum[i1] += tangent;
tanAccum[i2] += tangent;
}
// Normalize and store tangents.
for (size_t i = 0; i < outVertices.size(); i++) {
outVertices[i].tangent = glm::normalize(tanAccum[i]);
}
return true;
}
// Create a Model from an OBJ file by loading its data and generating OpenGL buffers.
Model loadModelFromOBJ(const std::string& filename) {
Model model;
model.filename = filename;
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
if (!loadOBJModel(filename, vertices, indices)) {
std::cerr << "Failed to load model: " << filename << std::endl;
model.indexCount = 0;
return model;
}
model.indexCount = indices.size();
// Generate buffers.
glGenVertexArrays(1, &model.VAO);
glGenBuffers(1, &model.VBO);
glGenBuffers(1, &model.EBO);
glBindVertexArray(model.VAO);
glBindBuffer(GL_ARRAY_BUFFER, model.VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
// Vertex attributes: position (location 0), normal (1), texcoord (2), tangent (3).
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, tangent));
glEnableVertexAttribArray(3);
glBindVertexArray(0);
// Set default transformation.
model.position = glm::vec3(0.0f);
model.rotation = 0.0f;
// Default material.
model.material = Material();
return model;
}
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Main // Main
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -492,7 +592,7 @@ int main(){
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "PBR Renderer with ImGui, Normal Mapping & YAML Materials", nullptr, nullptr); GLFWwindow* window = glfwCreateWindow(800, 600, "PBR Renderer with OBJ Models", nullptr, nullptr);
if (!window){ if (!window){
std::cerr << "Failed to create GLFW window!" << std::endl; std::cerr << "Failed to create GLFW window!" << std::endl;
glfwTerminate(); glfwTerminate();
@ -528,53 +628,96 @@ int main(){
glDeleteShader(fragmentShader); glDeleteShader(fragmentShader);
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Generate the sphere mesh (with position, normal, texcoords, tangent). // Generate the sphere mesh.
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
std::vector<float> sphereVertices; std::vector<float> sphereVertices;
std::vector<unsigned int> sphereIndices; std::vector<unsigned int> sphereIndices;
// Reuse our earlier sphere generator that outputs: pos (3), normal (3), texcoord (2), tangent (3).
auto generateSphere = [&](std::vector<float>& vertices, std::vector<unsigned int>& indices, unsigned int X_SEGMENTS = 64, unsigned int Y_SEGMENTS = 64) {
vertices.clear();
indices.clear();
for (unsigned int y = 0; y <= Y_SEGMENTS; ++y) {
for (unsigned int x = 0; x <= X_SEGMENTS; ++x) {
float xSegment = static_cast<float>(x) / X_SEGMENTS;
float ySegment = static_cast<float>(y) / Y_SEGMENTS;
float xPos = std::cos(xSegment * 2.0f * IM_PI) * std::sin(ySegment * IM_PI);
float yPos = std::cos(ySegment * IM_PI);
float zPos = std::sin(xSegment * 2.0f * IM_PI) * std::sin(ySegment * IM_PI);
// Position.
vertices.push_back(xPos);
vertices.push_back(yPos);
vertices.push_back(zPos);
// Normal.
vertices.push_back(xPos);
vertices.push_back(yPos);
vertices.push_back(zPos);
// Texcoords.
vertices.push_back(xSegment);
vertices.push_back(ySegment);
// Tangent (simple approximation).
float tangentX = -std::sin(xSegment * 2.0f * IM_PI);
float tangentY = 0.0f;
float tangentZ = std::cos(xSegment * 2.0f * IM_PI);
vertices.push_back(tangentX);
vertices.push_back(tangentY);
vertices.push_back(tangentZ);
}
}
for (unsigned int y = 0; y < Y_SEGMENTS; ++y) {
for (unsigned int x = 0; x < X_SEGMENTS; ++x) {
unsigned int i0 = y * (X_SEGMENTS + 1) + x;
unsigned int i1 = i0 + 1;
unsigned int i2 = i0 + (X_SEGMENTS + 1);
unsigned int i3 = i2 + 1;
indices.push_back(i0);
indices.push_back(i2);
indices.push_back(i1);
indices.push_back(i1);
indices.push_back(i2);
indices.push_back(i3);
}
}
};
generateSphere(sphereVertices, sphereIndices, 64, 64); generateSphere(sphereVertices, sphereIndices, 64, 64);
unsigned int indexCount = sphereIndices.size(); unsigned int sphereIndexCount = sphereIndices.size();
GLuint VAO, VBO, EBO; GLuint sphereVAO, sphereVBO, sphereEBO;
glGenVertexArrays(1, &VAO); glGenVertexArrays(1, &sphereVAO);
glGenBuffers(1, &VBO); glGenBuffers(1, &sphereVBO);
glGenBuffers(1, &EBO); glGenBuffers(1, &sphereEBO);
glBindVertexArray(VAO); glBindVertexArray(sphereVAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ARRAY_BUFFER, sphereVBO);
glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), sphereVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphereEBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(unsigned int), sphereIndices.data(), GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(unsigned int), &sphereIndices[0], GL_STATIC_DRAW); // Layout: pos (3), normal (3), texcoords (2), tangent (3)
// Vertex attributes: 0 = position (3), 1 = normal (3), 2 = texcoords (2), 3 = tangent (3).
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float))); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float))); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float))); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float)));
glEnableVertexAttribArray(3); glEnableVertexAttribArray(3);
glBindVertexArray(0); glBindVertexArray(0);
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Prepare scene data: a list of spheres. // Prepare scene data.
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
std::vector<SphereInstance> spheres; std::vector<SphereInstance> spheres;
// Add one default sphere.
spheres.push_back({ glm::vec3(0.0f), 0.0f, Material() }); spheres.push_back({ glm::vec3(0.0f), 0.0f, Material() });
std::vector<Model> models; // For OBJ models.
// Global scene/light parameters. // Global scene/light parameters.
glm::vec3 camPos(0.0f, 0.0f, 5.0f); glm::vec3 camPos(0.0f, 0.0f, 5.0f);
glm::vec3 lightPos(0.0f, 0.0f, 10.0f); glm::vec3 lightPos(0.0f, 0.0f, 10.0f);
glm::vec3 lightColor(300.0f, 300.0f, 300.0f); glm::vec3 lightColor(300.0f, 300.0f, 300.0f);
// For YAML material loading via ImGui. // For YAML loading and OBJ model loading via ImGui.
static char yamlPathBuffer[256] = ""; static char yamlPathBuffer[256] = "";
static char objPathBuffer[256] = "";
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Main render loop. // Main render loop.
@ -587,9 +730,7 @@ int main(){
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
// ---------------------------------------------------------------------------------- // ------------------------ Global Scene Controls ------------------------
// ImGui: Global Scene Controls.
// ----------------------------------------------------------------------------------
{ {
ImGui::Begin("Scene Controls"); ImGui::Begin("Scene Controls");
@ -599,113 +740,136 @@ int main(){
ImGui::ColorEdit3("Light Color", glm::value_ptr(lightColor)); ImGui::ColorEdit3("Light Color", glm::value_ptr(lightColor));
ImGui::Separator(); ImGui::Separator();
// Button to add a new sphere. // Sphere controls.
if (ImGui::CollapsingHeader("Spheres")) {
if (ImGui::Button("Add Sphere")) { if (ImGui::Button("Add Sphere")) {
spheres.push_back({ glm::vec3(0.0f), 0.0f, Material() }); spheres.push_back({ glm::vec3(0.0f), 0.0f, Material() });
} }
ImGui::Separator(); ImGui::Separator();
// Global YAML material loader: set file path and add a sphere from YAML.
ImGui::InputText("YAML Material Path", yamlPathBuffer, sizeof(yamlPathBuffer));
if (ImGui::Button("Add Sphere from YAML Material")) {
Material matFromYAML = loadMaterialFromYAML(yamlPathBuffer);
spheres.push_back({ glm::vec3(0.0f), 0.0f, matFromYAML });
}
ImGui::Separator();
// Per-sphere controls.
for (size_t i = 0; i < spheres.size(); i++) { for (size_t i = 0; i < spheres.size(); i++) {
std::string header = "Sphere " + std::to_string(i); std::string header = "Sphere " + std::to_string(i);
if (ImGui::CollapsingHeader(header.c_str())) { if (ImGui::CollapsingHeader(header.c_str())) {
// Transform controls. ImGui::DragFloat3(("Position##S" + std::to_string(i)).c_str(), glm::value_ptr(spheres[i].position), 0.1f);
ImGui::DragFloat3(("Position##" + std::to_string(i)).c_str(), glm::value_ptr(spheres[i].position), 0.1f); ImGui::DragFloat(("Rotation (radians)##S" + std::to_string(i)).c_str(), &spheres[i].rotation, 0.01f);
ImGui::DragFloat(("Rotation (radians)##" + std::to_string(i)).c_str(), &spheres[i].rotation, 0.01f); ImGui::ColorEdit3(("Albedo##S" + std::to_string(i)).c_str(), glm::value_ptr(spheres[i].material.albedo));
ImGui::SliderFloat(("Metallic##S" + std::to_string(i)).c_str(), &spheres[i].material.metallic, 0.0f, 1.0f);
ImGui::SliderFloat(("Roughness##S" + std::to_string(i)).c_str(), &spheres[i].material.roughness, 0.05f, 1.0f);
ImGui::SliderFloat(("AO##S" + std::to_string(i)).c_str(), &spheres[i].material.ao, 0.0f, 1.0f);
// Material properties. // Texture controls...
ImGui::ColorEdit3(("Albedo##" + std::to_string(i)).c_str(), glm::value_ptr(spheres[i].material.albedo)); ImGui::InputText(("Albedo Texture Path##S" + std::to_string(i)).c_str(),
ImGui::SliderFloat(("Metallic##" + std::to_string(i)).c_str(), &spheres[i].material.metallic, 0.0f, 1.0f);
ImGui::SliderFloat(("Roughness##" + std::to_string(i)).c_str(), &spheres[i].material.roughness, 0.05f, 1.0f);
ImGui::SliderFloat(("AO##" + std::to_string(i)).c_str(), &spheres[i].material.ao, 0.0f, 1.0f);
// Texture map controls.
ImGui::InputText(("Albedo Texture Path##" + std::to_string(i)).c_str(),
spheres[i].material.albedoPath, sizeof(spheres[i].material.albedoPath)); spheres[i].material.albedoPath, sizeof(spheres[i].material.albedoPath));
if (ImGui::Button(("Load Albedo Texture##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Load Albedo Texture##S" + std::to_string(i)).c_str())) {
GLuint tex = LoadTexture(spheres[i].material.albedoPath); GLuint tex = LoadTexture(spheres[i].material.albedoPath);
if (tex != 0) { if (tex != 0) {
spheres[i].material.albedoTex = tex; spheres[i].material.albedoTex = tex;
spheres[i].material.useAlbedoMap = true; spheres[i].material.useAlbedoMap = true;
} }
} }
ImGui::InputText(("Metallic Texture Path##" + std::to_string(i)).c_str(), // Similar input/buttons for Metallic, Roughness, AO, and Normal...
ImGui::InputText(("Metallic Texture Path##S" + std::to_string(i)).c_str(),
spheres[i].material.metallicPath, sizeof(spheres[i].material.metallicPath)); spheres[i].material.metallicPath, sizeof(spheres[i].material.metallicPath));
if (ImGui::Button(("Load Metallic Texture##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Load Metallic Texture##S" + std::to_string(i)).c_str())) {
GLuint tex = LoadTexture(spheres[i].material.metallicPath); GLuint tex = LoadTexture(spheres[i].material.metallicPath);
if (tex != 0) { if (tex != 0) {
spheres[i].material.metallicTex = tex; spheres[i].material.metallicTex = tex;
spheres[i].material.useMetallicMap = true; spheres[i].material.useMetallicMap = true;
} }
} }
ImGui::InputText(("Roughness Texture Path##" + std::to_string(i)).c_str(), ImGui::InputText(("Roughness Texture Path##S" + std::to_string(i)).c_str(),
spheres[i].material.roughnessPath, sizeof(spheres[i].material.roughnessPath)); spheres[i].material.roughnessPath, sizeof(spheres[i].material.roughnessPath));
if (ImGui::Button(("Load Roughness Texture##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Load Roughness Texture##S" + std::to_string(i)).c_str())) {
GLuint tex = LoadTexture(spheres[i].material.roughnessPath); GLuint tex = LoadTexture(spheres[i].material.roughnessPath);
if (tex != 0) { if (tex != 0) {
spheres[i].material.roughnessTex = tex; spheres[i].material.roughnessTex = tex;
spheres[i].material.useRoughnessMap = true; spheres[i].material.useRoughnessMap = true;
} }
} }
ImGui::InputText(("AO Texture Path##" + std::to_string(i)).c_str(), ImGui::InputText(("AO Texture Path##S" + std::to_string(i)).c_str(),
spheres[i].material.aoPath, sizeof(spheres[i].material.aoPath)); spheres[i].material.aoPath, sizeof(spheres[i].material.aoPath));
if (ImGui::Button(("Load AO Texture##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Load AO Texture##S" + std::to_string(i)).c_str())) {
GLuint tex = LoadTexture(spheres[i].material.aoPath); GLuint tex = LoadTexture(spheres[i].material.aoPath);
if (tex != 0) { if (tex != 0) {
spheres[i].material.aoTex = tex; spheres[i].material.aoTex = tex;
spheres[i].material.useAOMap = true; spheres[i].material.useAOMap = true;
} }
} }
ImGui::InputText(("Normal Texture Path##" + std::to_string(i)).c_str(), ImGui::InputText(("Normal Texture Path##S" + std::to_string(i)).c_str(),
spheres[i].material.normalPath, sizeof(spheres[i].material.normalPath)); spheres[i].material.normalPath, sizeof(spheres[i].material.normalPath));
if (ImGui::Button(("Load Normal Texture##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Load Normal Texture##S" + std::to_string(i)).c_str())) {
GLuint tex = LoadTexture(spheres[i].material.normalPath); GLuint tex = LoadTexture(spheres[i].material.normalPath);
if (tex != 0) { if (tex != 0) {
spheres[i].material.normalTex = tex; spheres[i].material.normalTex = tex;
spheres[i].material.useNormalMap = true; spheres[i].material.useNormalMap = true;
} }
} }
// YAML material reloading.
static char sphereYAMLPath[256] = ""; static char sphereYAMLPath[256] = "";
ImGui::InputText(("YAML Material Path##" + std::to_string(i)).c_str(), sphereYAMLPath, sizeof(sphereYAMLPath)); ImGui::InputText(("YAML Material Path##S" + std::to_string(i)).c_str(), sphereYAMLPath, sizeof(sphereYAMLPath));
if (ImGui::Button(("Load Material from YAML##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Load Material from YAML##S" + std::to_string(i)).c_str())) {
Material newMat = loadMaterialFromYAML(sphereYAMLPath); Material newMat = loadMaterialFromYAML(sphereYAMLPath);
spheres[i].material = newMat; spheres[i].material = newMat;
} }
// ---------------------------
// Material Saving UI.
// ---------------------------
// We use a simple static buffer per sphere to specify a save file path.
static char saveYAMLPath[256] = ""; static char saveYAMLPath[256] = "";
ImGui::InputText(("Save YAML Path##" + std::to_string(i)).c_str(), saveYAMLPath, sizeof(saveYAMLPath)); ImGui::InputText(("Save YAML Path##S" + std::to_string(i)).c_str(), saveYAMLPath, sizeof(saveYAMLPath));
if (ImGui::Button(("Save Material to YAML##" + std::to_string(i)).c_str())) { if (ImGui::Button(("Save Material to YAML##S" + std::to_string(i)).c_str())) {
if (saveMaterialToYAML(std::string(saveYAMLPath), spheres[i].material)) { if (saveMaterialToYAML(std::string(saveYAMLPath), spheres[i].material)) {
std::cout << "Saved material for sphere " << i << " to " << saveYAMLPath << std::endl; std::cout << "Saved material for sphere " << i << " to " << saveYAMLPath << std::endl;
} }
} }
if (ImGui::Button(("Remove Sphere##S" + std::to_string(i)).c_str())) {
if (ImGui::Button(("Remove Sphere##" + std::to_string(i)).c_str())) {
spheres.erase(spheres.begin() + i); spheres.erase(spheres.begin() + i);
break; break;
} }
} }
} }
}
// Model (OBJ) controls.
if (ImGui::CollapsingHeader("3D Models (OBJ)")) {
ImGui::InputText("OBJ Model Path", objPathBuffer, sizeof(objPathBuffer));
if (ImGui::Button("Load OBJ Model")) {
Model m = loadModelFromOBJ(std::string(objPathBuffer));
if(m.indexCount > 0) {
models.push_back(m);
}
}
ImGui::Separator();
for (size_t i = 0; i < models.size(); i++) {
std::string header = "Model " + std::to_string(i) + " [" + models[i].filename + "]";
if (ImGui::CollapsingHeader(header.c_str())) {
ImGui::DragFloat3(("Position##M" + std::to_string(i)).c_str(), glm::value_ptr(models[i].position), 0.1f);
ImGui::DragFloat(("Rotation (radians)##M" + std::to_string(i)).c_str(), &models[i].rotation, 0.01f);
ImGui::ColorEdit3(("Albedo##M" + std::to_string(i)).c_str(), glm::value_ptr(models[i].material.albedo));
ImGui::SliderFloat(("Metallic##M" + std::to_string(i)).c_str(), &models[i].material.metallic, 0.0f, 1.0f);
ImGui::SliderFloat(("Roughness##M" + std::to_string(i)).c_str(), &models[i].material.roughness, 0.05f, 1.0f);
ImGui::SliderFloat(("AO##M" + std::to_string(i)).c_str(), &models[i].material.ao, 0.0f, 1.0f);
// Similar texture controls as for spheres.
ImGui::InputText(("Albedo Texture Path##M" + std::to_string(i)).c_str(),
models[i].material.albedoPath, sizeof(models[i].material.albedoPath));
if (ImGui::Button(("Load Albedo Texture##M" + std::to_string(i)).c_str())) {
GLuint tex = LoadTexture(models[i].material.albedoPath);
if (tex != 0) {
models[i].material.albedoTex = tex;
models[i].material.useAlbedoMap = true;
}
}
// ... (Repeat for other maps: Metallic, Roughness, AO, Normal)
if (ImGui::Button(("Remove Model##M" + std::to_string(i)).c_str())) {
// Delete GL buffers.
glDeleteVertexArrays(1, &models[i].VAO);
glDeleteBuffers(1, &models[i].VBO);
glDeleteBuffers(1, &models[i].EBO);
models.erase(models.begin() + i);
break;
}
}
}
}
ImGui::End(); ImGui::End();
} }
// ---------------------------------------------------------------------------------- // ---------------------- Rendering ----------------------
// Rendering.
// ----------------------------------------------------------------------------------
int width, height; int width, height;
glfwGetFramebufferSize(window, &width, &height); glfwGetFramebufferSize(window, &width, &height);
float aspect = width / static_cast<float>(height); float aspect = width / static_cast<float>(height);
@ -713,7 +877,6 @@ int main(){
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Setup camera matrices.
glm::mat4 projection = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f); glm::mat4 projection = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 100.0f);
glm::mat4 view = glm::lookAt(camPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0)); glm::mat4 view = glm::lookAt(camPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0));
@ -721,33 +884,26 @@ int main(){
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniform3fv(glGetUniformLocation(shaderProgram, "camPos"), 1, glm::value_ptr(camPos)); glUniform3fv(glGetUniformLocation(shaderProgram, "camPos"), 1, glm::value_ptr(camPos));
// Set light uniforms.
glUniform3fv(glGetUniformLocation(shaderProgram, "lightPos"), 1, glm::value_ptr(lightPos)); glUniform3fv(glGetUniformLocation(shaderProgram, "lightPos"), 1, glm::value_ptr(lightPos));
glUniform3fv(glGetUniformLocation(shaderProgram, "lightColor"), 1, glm::value_ptr(lightColor)); glUniform3fv(glGetUniformLocation(shaderProgram, "lightColor"), 1, glm::value_ptr(lightColor));
// Pass ImGui's internal PI constant.
glUniform1f(glGetUniformLocation(shaderProgram, "PI"), IM_PI); glUniform1f(glGetUniformLocation(shaderProgram, "PI"), IM_PI);
glBindVertexArray(VAO); // Render spheres.
glBindVertexArray(sphereVAO);
for (const auto& sphere : spheres) { for (const auto& sphere : spheres) {
// Compute model matrix.
glm::mat4 model = glm::translate(glm::mat4(1.0f), sphere.position); glm::mat4 model = glm::translate(glm::mat4(1.0f), sphere.position);
model = glm::rotate(model, sphere.rotation, glm::vec3(0.0f, 1.0f, 0.0f)); model = glm::rotate(model, sphere.rotation, glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
// Set fallback material uniforms.
glUniform3fv(glGetUniformLocation(shaderProgram, "albedo"), 1, glm::value_ptr(sphere.material.albedo)); glUniform3fv(glGetUniformLocation(shaderProgram, "albedo"), 1, glm::value_ptr(sphere.material.albedo));
glUniform1f(glGetUniformLocation(shaderProgram, "metallic"), sphere.material.metallic); glUniform1f(glGetUniformLocation(shaderProgram, "metallic"), sphere.material.metallic);
glUniform1f(glGetUniformLocation(shaderProgram, "roughness"), sphere.material.roughness); glUniform1f(glGetUniformLocation(shaderProgram, "roughness"), sphere.material.roughness);
glUniform1f(glGetUniformLocation(shaderProgram, "ao"), sphere.material.ao); glUniform1f(glGetUniformLocation(shaderProgram, "ao"), sphere.material.ao);
// Set texture usage flags.
glUniform1i(glGetUniformLocation(shaderProgram, "useAlbedoMap"), sphere.material.useAlbedoMap ? 1 : 0); glUniform1i(glGetUniformLocation(shaderProgram, "useAlbedoMap"), sphere.material.useAlbedoMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useMetallicMap"), sphere.material.useMetallicMap ? 1 : 0); glUniform1i(glGetUniformLocation(shaderProgram, "useMetallicMap"), sphere.material.useMetallicMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useRoughnessMap"), sphere.material.useRoughnessMap ? 1 : 0); glUniform1i(glGetUniformLocation(shaderProgram, "useRoughnessMap"), sphere.material.useRoughnessMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useAOMap"), sphere.material.useAOMap ? 1 : 0); glUniform1i(glGetUniformLocation(shaderProgram, "useAOMap"), sphere.material.useAOMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), sphere.material.useNormalMap ? 1 : 0); glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), sphere.material.useNormalMap ? 1 : 0);
// Bind textures if enabled.
if (sphere.material.useAlbedoMap) { if (sphere.material.useAlbedoMap) {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sphere.material.albedoTex); glBindTexture(GL_TEXTURE_2D, sphere.material.albedoTex);
@ -774,11 +930,57 @@ int main(){
glUniform1i(glGetUniformLocation(shaderProgram, "normalMap"), 4); glUniform1i(glGetUniformLocation(shaderProgram, "normalMap"), 4);
} }
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, sphereIndexCount, GL_UNSIGNED_INT, 0);
} }
glBindVertexArray(0); glBindVertexArray(0);
// Render ImGui over the scene. // Render OBJ models.
for (const auto& m : models) {
glm::mat4 model = glm::translate(glm::mat4(1.0f), m.position);
model = glm::rotate(model, m.rotation, glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniform3fv(glGetUniformLocation(shaderProgram, "albedo"), 1, glm::value_ptr(m.material.albedo));
glUniform1f(glGetUniformLocation(shaderProgram, "metallic"), m.material.metallic);
glUniform1f(glGetUniformLocation(shaderProgram, "roughness"), m.material.roughness);
glUniform1f(glGetUniformLocation(shaderProgram, "ao"), m.material.ao);
glUniform1i(glGetUniformLocation(shaderProgram, "useAlbedoMap"), m.material.useAlbedoMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useMetallicMap"), m.material.useMetallicMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useRoughnessMap"), m.material.useRoughnessMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useAOMap"), m.material.useAOMap ? 1 : 0);
glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), m.material.useNormalMap ? 1 : 0);
if (m.material.useAlbedoMap) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m.material.albedoTex);
glUniform1i(glGetUniformLocation(shaderProgram, "albedoMap"), 0);
}
if (m.material.useMetallicMap) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m.material.metallicTex);
glUniform1i(glGetUniformLocation(shaderProgram, "metallicMap"), 1);
}
if (m.material.useRoughnessMap) {
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, m.material.roughnessTex);
glUniform1i(glGetUniformLocation(shaderProgram, "roughnessMap"), 2);
}
if (m.material.useAOMap) {
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, m.material.aoTex);
glUniform1i(glGetUniformLocation(shaderProgram, "aoMap"), 3);
}
if (m.material.useNormalMap) {
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, m.material.normalTex);
glUniform1i(glGetUniformLocation(shaderProgram, "normalMap"), 4);
}
glBindVertexArray(m.VAO);
glDrawElements(GL_TRIANGLES, m.indexCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
// Render ImGui.
ImGui::Render(); ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
@ -788,9 +990,14 @@ int main(){
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// Cleanup. // Cleanup.
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
glDeleteVertexArrays(1, &VAO); glDeleteVertexArrays(1, &sphereVAO);
glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &sphereVBO);
glDeleteBuffers(1, &EBO); glDeleteBuffers(1, &sphereEBO);
for (auto& m : models) {
glDeleteVertexArrays(1, &m.VAO);
glDeleteBuffers(1, &m.VBO);
glDeleteBuffers(1, &m.EBO);
}
glDeleteProgram(shaderProgram); glDeleteProgram(shaderProgram);
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,306 @@
# Blender MTL File: 'None'
# Material Count: 25
newmtl Material__25
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/lion.tga
map_Disp textures/lion_ddn.tga
map_Ka textures/lion.tga
newmtl Material__298
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/background.tga
map_Disp textures/background_ddn.tga
map_Ka textures/background.tga
newmtl Material__47
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
newmtl Material__57
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/vase_plant.tga
map_d textures/vase_plant_mask.tga
map_Ka textures/vase_plant.tga
newmtl arch
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_arch_diff.tga
map_Ka textures/sponza_arch_diff.tga
map_Disp textures/sponza_arch_ddn.tga
newmtl bricks
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/spnza_bricks_a_diff.tga
map_Disp textures/spnza_bricks_a_ddn.tga
map_Ka textures/spnza_bricks_a_diff.tga
newmtl ceiling
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_ceiling_a_diff.tga
map_Ka textures/sponza_ceiling_a_diff.tga
map_Disp textures/sponza_ceiling_a_ddn.tga
newmtl chain
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/chain_texture.tga
map_d textures/chain_texture_mask.tga
map_Disp textures/chain_texture_ddn.tga
map_Ka textures/chain_texture.tga
newmtl column_a
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_a_diff.tga
map_Disp textures/sponza_column_a_ddn.tga
map_Ka textures/sponza_column_a_diff.tga
newmtl column_b
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_b_diff.tga
map_Disp textures/sponza_column_b_ddn.tga
map_Ka textures/sponza_column_b_diff.tga
newmtl column_c
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_c_diff.tga
map_Disp textures/sponza_column_c_ddn.tga
map_Ka textures/sponza_column_c_diff.tga
newmtl details
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_details_diff.tga
map_Ka textures/sponza_details_diff.tga
map_Disp textures/sponza_details_ddn.tga
newmtl fabric_a
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_diff.tga
map_Ka textures/sponza_fabric_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_c
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_diff.tga
map_Ka textures/sponza_curtain_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl fabric_d
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_blue_diff.tga
map_Ka textures/sponza_fabric_blue_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_e
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_green_diff.tga
map_Ka textures/sponza_fabric_green_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_f
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_green_diff.tga
map_Ka textures/sponza_curtain_green_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl fabric_g
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_blue_diff.tga
map_Ka textures/sponza_curtain_blue_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl flagpole
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_flagpole_diff.tga
map_Ka textures/sponza_flagpole_diff.tga
map_Disp textures/sponza_flagpole_ddn.tga
newmtl floor
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_floor_a_diff.tga
map_Ka textures/sponza_floor_a_diff.tga
map_Disp textures/sponza_floor_a_ddn.tga
newmtl leaf
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/sponza_thorn_diff.tga
map_d textures/sponza_thorn_mask.tga
map_Disp textures/sponza_thorn_ddn.tga
map_Ka textures/sponza_thorn_diff.tga
newmtl roof
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_roof_diff.tga
map_Ka textures/sponza_roof_diff.tga
map_Disp textures/sponza_roof_ddn.tga
newmtl vase
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_dif.tga
map_Ka textures/vase_dif.tga
map_Disp textures/vase_ddn.tga
newmtl vase_hanging
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_hanging.tga
map_Ka textures/vase_hanging.tga
map_Disp textures/vase_hanging_ddn.tga
newmtl vase_round
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_round.tga
map_Disp textures/vase_round_ddn.tga
map_Ka textures/vase_round.tga

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB