Broken Models lol
9
physicaly-based-renderer/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"*.pyx": "python",
|
||||||
|
"*.js": "javascript",
|
||||||
|
"*.c": "c",
|
||||||
|
"*.scene": "yaml",
|
||||||
|
"ostream": "cpp"
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// 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.)
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
@ -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;
|
||||||
@ -111,12 +115,12 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float DistributionGGX(vec3 N, vec3 H, float roughness) {
|
float DistributionGGX(vec3 N, vec3 H, float roughness) {
|
||||||
float a = roughness * roughness;
|
float a = roughness * roughness;
|
||||||
float a2 = a * a;
|
float a2 = a * a;
|
||||||
float NdotH = max(dot(N, H), 0.0);
|
float NdotH = max(dot(N, H), 0.0);
|
||||||
float NdotH2 = NdotH * NdotH;
|
float NdotH2 = NdotH * NdotH;
|
||||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||||
denom = PI * denom * denom;
|
denom = PI * denom * denom;
|
||||||
return a2 / max(denom, 0.001);
|
return a2 / max(denom, 0.001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,19 +133,16 @@ float GeometrySchlickGGX(float NdotV, float roughness) {
|
|||||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
||||||
float NdotV = max(dot(N, V), 0.0);
|
float NdotV = max(dot(N, V), 0.0);
|
||||||
float NdotL = max(dot(N, L), 0.0);
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
float ggx1 = GeometrySchlickGGX(NdotV, roughness);
|
float ggx1 = GeometrySchlickGGX(NdotV, roughness);
|
||||||
float ggx2 = GeometrySchlickGGX(NdotL, roughness);
|
float ggx2 = GeometrySchlickGGX(NdotL, roughness);
|
||||||
return ggx1 * ggx2;
|
return ggx1 * ggx2;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -178,9 +177,9 @@ void main(){
|
|||||||
float G = GeometrySmith(N, V, L, roughnessValue);
|
float G = GeometrySmith(N, V, L, roughnessValue);
|
||||||
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||||
|
|
||||||
vec3 numerator = NDF * G * F;
|
vec3 numerator = NDF * G * F;
|
||||||
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001;
|
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001;
|
||||||
vec3 specular = numerator / denominator;
|
vec3 specular = numerator / denominator;
|
||||||
|
|
||||||
vec3 kS = F;
|
vec3 kS = F;
|
||||||
vec3 kD = vec3(1.0) - kS;
|
vec3 kD = vec3(1.0) - kS;
|
||||||
@ -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::Button("Add Sphere")) {
|
if (ImGui::CollapsingHeader("Spheres")) {
|
||||||
spheres.push_back({ glm::vec3(0.0f), 0.0f, Material() });
|
if (ImGui::Button("Add Sphere")) {
|
||||||
}
|
spheres.push_back({ glm::vec3(0.0f), 0.0f, Material() });
|
||||||
ImGui::Separator();
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
for (size_t i = 0; i < spheres.size(); i++) {
|
||||||
|
std::string header = "Sphere " + std::to_string(i);
|
||||||
|
if (ImGui::CollapsingHeader(header.c_str())) {
|
||||||
|
ImGui::DragFloat3(("Position##S" + 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::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);
|
||||||
|
|
||||||
// Global YAML material loader: set file path and add a sphere from YAML.
|
// Texture controls...
|
||||||
ImGui::InputText("YAML Material Path", yamlPathBuffer, sizeof(yamlPathBuffer));
|
ImGui::InputText(("Albedo Texture Path##S" + std::to_string(i)).c_str(),
|
||||||
if (ImGui::Button("Add Sphere from YAML Material")) {
|
spheres[i].material.albedoPath, sizeof(spheres[i].material.albedoPath));
|
||||||
Material matFromYAML = loadMaterialFromYAML(yamlPathBuffer);
|
if (ImGui::Button(("Load Albedo Texture##S" + std::to_string(i)).c_str())) {
|
||||||
spheres.push_back({ glm::vec3(0.0f), 0.0f, matFromYAML });
|
GLuint tex = LoadTexture(spheres[i].material.albedoPath);
|
||||||
}
|
if (tex != 0) {
|
||||||
ImGui::Separator();
|
spheres[i].material.albedoTex = tex;
|
||||||
|
spheres[i].material.useAlbedoMap = true;
|
||||||
// Per-sphere controls.
|
}
|
||||||
for (size_t i = 0; i < spheres.size(); i++) {
|
|
||||||
std::string header = "Sphere " + std::to_string(i);
|
|
||||||
if (ImGui::CollapsingHeader(header.c_str())) {
|
|
||||||
// Transform controls.
|
|
||||||
ImGui::DragFloat3(("Position##" + std::to_string(i)).c_str(), glm::value_ptr(spheres[i].position), 0.1f);
|
|
||||||
ImGui::DragFloat(("Rotation (radians)##" + std::to_string(i)).c_str(), &spheres[i].rotation, 0.01f);
|
|
||||||
|
|
||||||
// Material properties.
|
|
||||||
ImGui::ColorEdit3(("Albedo##" + std::to_string(i)).c_str(), glm::value_ptr(spheres[i].material.albedo));
|
|
||||||
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));
|
|
||||||
if (ImGui::Button(("Load Albedo Texture##" + std::to_string(i)).c_str())) {
|
|
||||||
GLuint tex = LoadTexture(spheres[i].material.albedoPath);
|
|
||||||
if (tex != 0) {
|
|
||||||
spheres[i].material.albedoTex = tex;
|
|
||||||
spheres[i].material.useAlbedoMap = true;
|
|
||||||
}
|
}
|
||||||
}
|
// Similar input/buttons for Metallic, Roughness, AO, and Normal...
|
||||||
ImGui::InputText(("Metallic Texture Path##" + std::to_string(i)).c_str(),
|
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##S" + std::to_string(i)).c_str(),
|
||||||
ImGui::InputText(("Roughness Texture Path##" + 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##S" + std::to_string(i)).c_str())) {
|
||||||
if (ImGui::Button(("Load Roughness Texture##" + 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##S" + std::to_string(i)).c_str(),
|
||||||
ImGui::InputText(("AO Texture Path##" + 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##S" + std::to_string(i)).c_str())) {
|
||||||
if (ImGui::Button(("Load AO Texture##" + 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##S" + std::to_string(i)).c_str(),
|
||||||
ImGui::InputText(("Normal Texture Path##" + 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##S" + std::to_string(i)).c_str())) {
|
||||||
if (ImGui::Button(("Load Normal Texture##" + 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;
|
}
|
||||||
}
|
}
|
||||||
}
|
static char sphereYAMLPath[256] = "";
|
||||||
|
ImGui::InputText(("YAML Material Path##S" + std::to_string(i)).c_str(), sphereYAMLPath, sizeof(sphereYAMLPath));
|
||||||
// YAML material reloading.
|
if (ImGui::Button(("Load Material from YAML##S" + std::to_string(i)).c_str())) {
|
||||||
static char sphereYAMLPath[256] = "";
|
Material newMat = loadMaterialFromYAML(sphereYAMLPath);
|
||||||
ImGui::InputText(("YAML Material Path##" + std::to_string(i)).c_str(), sphereYAMLPath, sizeof(sphereYAMLPath));
|
spheres[i].material = newMat;
|
||||||
if (ImGui::Button(("Load Material from YAML##" + std::to_string(i)).c_str())) {
|
}
|
||||||
Material newMat = loadMaterialFromYAML(sphereYAMLPath);
|
static char saveYAMLPath[256] = "";
|
||||||
spheres[i].material = newMat;
|
ImGui::InputText(("Save YAML Path##S" + std::to_string(i)).c_str(), saveYAMLPath, sizeof(saveYAMLPath));
|
||||||
}
|
if (ImGui::Button(("Save Material to YAML##S" + std::to_string(i)).c_str())) {
|
||||||
|
if (saveMaterialToYAML(std::string(saveYAMLPath), spheres[i].material)) {
|
||||||
// ---------------------------
|
std::cout << "Saved material for sphere " << i << " to " << saveYAMLPath << std::endl;
|
||||||
// Material Saving UI.
|
}
|
||||||
// ---------------------------
|
}
|
||||||
// We use a simple static buffer per sphere to specify a save file path.
|
if (ImGui::Button(("Remove Sphere##S" + std::to_string(i)).c_str())) {
|
||||||
static char saveYAMLPath[256] = "";
|
spheres.erase(spheres.begin() + i);
|
||||||
ImGui::InputText(("Save YAML Path##" + std::to_string(i)).c_str(), saveYAMLPath, sizeof(saveYAMLPath));
|
break;
|
||||||
if (ImGui::Button(("Save Material to YAML##" + std::to_string(i)).c_str())) {
|
|
||||||
if (saveMaterialToYAML(std::string(saveYAMLPath), spheres[i].material)) {
|
|
||||||
std::cout << "Saved material for sphere " << i << " to " << saveYAMLPath << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button(("Remove Sphere##" + std::to_string(i)).c_str())) {
|
|
||||||
spheres.erase(spheres.begin() + i);
|
|
||||||
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();
|
||||||
|
306
physicaly-based-renderer/sponza.mtl
Normal 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
|
569548
physicaly-based-renderer/sponza.obj
Normal file
BIN
physicaly-based-renderer/textures/Thumbs.db
Normal file
BIN
physicaly-based-renderer/textures/background.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/background_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/chain_texture.tga
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
physicaly-based-renderer/textures/chain_texture_ddn.tga
Normal file
After Width: | Height: | Size: 768 KiB |
BIN
physicaly-based-renderer/textures/lion.tga
Normal file
After Width: | Height: | Size: 4.0 MiB |
BIN
physicaly-based-renderer/textures/lion2_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/lion_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/spnza_bricks_a_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/spnza_bricks_a_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_arch_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_arch_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_ceiling_a_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_ceiling_a_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_column_a_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_column_a_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_column_b_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_column_b_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_column_c_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_column_c_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_curtain_blue_diff.tga
Normal file
After Width: | Height: | Size: 12 MiB |
BIN
physicaly-based-renderer/textures/sponza_curtain_ddn.tga
Normal file
After Width: | Height: | Size: 12 MiB |
BIN
physicaly-based-renderer/textures/sponza_curtain_diff.tga
Normal file
After Width: | Height: | Size: 12 MiB |
BIN
physicaly-based-renderer/textures/sponza_curtain_green_diff.tga
Normal file
After Width: | Height: | Size: 12 MiB |
BIN
physicaly-based-renderer/textures/sponza_details_ddn.tga
Normal file
After Width: | Height: | Size: 4.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_details_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_fabric_blue_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_fabric_ddn.tga
Normal file
After Width: | Height: | Size: 4.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_fabric_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_fabric_green_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_flagpole_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_flagpole_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_floor_a_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_floor_a_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_roof_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_roof_diff.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/sponza_thorn_ddn.tga
Normal file
After Width: | Height: | Size: 192 KiB |
BIN
physicaly-based-renderer/textures/sponza_thorn_diff.tga
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
physicaly-based-renderer/textures/vase_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/vase_dif.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/vase_hanging.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/vase_hanging_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/vase_plant.tga
Normal file
After Width: | Height: | Size: 4.0 MiB |
BIN
physicaly-based-renderer/textures/vase_round.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
physicaly-based-renderer/textures/vase_round_ddn.tga
Normal file
After Width: | Height: | Size: 3.0 MiB |