Can now load a glb model with textures embedded in the model. Further cleanup coming.
This commit is contained in:
parent
5b5e8a9fb0
commit
c6a7c42a4e
12 changed files with 323 additions and 194 deletions
Binary file not shown.
150
14-refactor/shaders/14-frag.glsl
Normal file
150
14-refactor/shaders/14-frag.glsl
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
#version 330 core
|
||||||
|
struct Material {
|
||||||
|
sampler2D diffuse;
|
||||||
|
sampler2D specular;
|
||||||
|
float shininess;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec3 FragPos;
|
||||||
|
in vec3 Normal;
|
||||||
|
in vec2 TexCoords;
|
||||||
|
|
||||||
|
uniform vec3 viewPos;
|
||||||
|
uniform Material material;
|
||||||
|
|
||||||
|
struct DirLight {
|
||||||
|
vec3 direction;
|
||||||
|
vec3 ambient;
|
||||||
|
vec3 diffuse;
|
||||||
|
vec3 specular;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointLight {
|
||||||
|
vec3 position;
|
||||||
|
vec3 ambient;
|
||||||
|
vec3 diffuse;
|
||||||
|
vec3 specular;
|
||||||
|
float constant;
|
||||||
|
float linear;
|
||||||
|
float quadratic;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpotLight {
|
||||||
|
vec3 direction;
|
||||||
|
vec3 position;
|
||||||
|
vec3 diffuse;
|
||||||
|
vec3 specular;
|
||||||
|
vec3 ambient;
|
||||||
|
|
||||||
|
float constant;
|
||||||
|
float linear;
|
||||||
|
float quadratic;
|
||||||
|
float cutOff;
|
||||||
|
float outerCutOff;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define NR_POINT_LIGHTS 4
|
||||||
|
uniform int pointLightCount;
|
||||||
|
uniform PointLight pointLights[NR_POINT_LIGHTS];
|
||||||
|
uniform DirLight dirLight;
|
||||||
|
uniform SpotLight spotLight;
|
||||||
|
|
||||||
|
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
|
||||||
|
{
|
||||||
|
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
|
||||||
|
vec3 spec_tex = vec3(texture(material.specular, TexCoords));
|
||||||
|
|
||||||
|
vec3 lightDir = normalize(-light.direction);
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
|
||||||
|
// specular shading
|
||||||
|
vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
|
|
||||||
|
vec3 ambient = light.ambient * mat_tex;
|
||||||
|
vec3 diffuse = light.diffuse * diff * mat_tex;
|
||||||
|
vec3 specular = light.specular * spec * spec_tex;
|
||||||
|
|
||||||
|
return ambient + diffuse + specular;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
|
||||||
|
{
|
||||||
|
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
|
||||||
|
vec3 spec_tex = vec3(texture(material.specular, TexCoords));
|
||||||
|
vec3 lightDir = normalize(light.position - fragPos);
|
||||||
|
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
|
||||||
|
// specular shading
|
||||||
|
vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
|
|
||||||
|
// attenuation
|
||||||
|
float distance = length(light.position - fragPos);
|
||||||
|
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
|
||||||
|
|
||||||
|
vec3 ambient = light.ambient * mat_tex;
|
||||||
|
vec3 diffuse = light.diffuse * diff * mat_tex;
|
||||||
|
vec3 specular = light.specular * spec * spec_tex;
|
||||||
|
|
||||||
|
ambient *= attenuation;
|
||||||
|
diffuse *= attenuation;
|
||||||
|
specular *= attenuation;
|
||||||
|
|
||||||
|
return ambient + diffuse + specular;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
|
||||||
|
{
|
||||||
|
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
|
||||||
|
vec3 spec_tex = vec3(texture(material.specular, TexCoords));
|
||||||
|
vec3 lightDir = normalize(light.position - fragPos);
|
||||||
|
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
|
||||||
|
// specular shading
|
||||||
|
vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
|
|
||||||
|
// attenuation
|
||||||
|
float distance = length(light.position - fragPos);
|
||||||
|
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
|
||||||
|
|
||||||
|
vec3 ambient = light.ambient * mat_tex;
|
||||||
|
vec3 diffuse = light.diffuse * diff * mat_tex;
|
||||||
|
vec3 specular = light.specular * spec * spec_tex;
|
||||||
|
|
||||||
|
float theta = dot(lightDir, normalize(-light.direction));
|
||||||
|
float epsilon = light.cutOff - light.outerCutOff;
|
||||||
|
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
|
||||||
|
diffuse *= intensity;
|
||||||
|
specular *= intensity;
|
||||||
|
|
||||||
|
ambient *= attenuation;
|
||||||
|
diffuse *= attenuation;
|
||||||
|
specular *= attenuation;
|
||||||
|
|
||||||
|
return ambient + diffuse + specular;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec3 norm = normalize(Normal);
|
||||||
|
vec3 viewDir = normalize(viewPos - FragPos);
|
||||||
|
|
||||||
|
vec3 result = CalcDirLight(dirLight, norm, viewDir);
|
||||||
|
|
||||||
|
for(int i = 0; i < pointLightCount; i++) {
|
||||||
|
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
|
||||||
|
|
||||||
|
FragColor = vec4(result, 1.0);
|
||||||
|
}
|
||||||
9
14-refactor/shaders/14-lightsource.frag.glsl
Normal file
9
14-refactor/shaders/14-lightsource.frag.glsl
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
uniform vec3 diffuse;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = vec4(diffuse, 1.0); // set all 4 vector values to 1.0
|
||||||
|
}
|
||||||
20
14-refactor/shaders/14-vert.glsl
Normal file
20
14-refactor/shaders/14-vert.glsl
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec3 aNormal;
|
||||||
|
layout (location = 2) in vec2 aTexCoords;
|
||||||
|
|
||||||
|
out vec3 FragPos;
|
||||||
|
out vec3 Normal;
|
||||||
|
out vec2 TexCoords;
|
||||||
|
|
||||||
|
uniform mat4 model;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 projection;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = projection * view * model * vec4(aPos, 1.0f);
|
||||||
|
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||||
|
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||||
|
TexCoords = aTexCoords;
|
||||||
|
}
|
||||||
|
|
@ -1,63 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#define CUBE_COUNT 10
|
#define CUBE_COUNT 9
|
||||||
|
|
||||||
float vertices[] = {
|
|
||||||
// positions // normals // texture coords
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
|
|
||||||
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
|
|
||||||
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
|
||||||
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
|
||||||
|
|
||||||
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
|
||||||
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
|
|
||||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
|
|
||||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
// positions all containers
|
// positions all containers
|
||||||
glm::vec3 cube_positions[] = {
|
glm::vec3 popcorn_positions[] = {
|
||||||
glm::vec3( 0.0f, 0.0f, 0.0f),
|
{0.0f, 0.0f, 0.0f},
|
||||||
glm::vec3( 2.0f, 5.0f, -15.0f),
|
{2.0f, 5.0f, -15.0f},
|
||||||
glm::vec3(-1.5f, -2.2f, -2.5f),
|
{-1.5f, -2.2f, -2.5f},
|
||||||
glm::vec3(-3.8f, -2.0f, -12.3f),
|
{-3.8f, -2.0f, -12.3f},
|
||||||
glm::vec3( 2.4f, -0.4f, -3.5f),
|
{ 2.4f, -0.4f, -3.5f},
|
||||||
glm::vec3(-1.7f, 3.0f, -7.5f),
|
{-1.7f, 3.0f, -7.5f},
|
||||||
glm::vec3( 1.3f, -2.0f, -2.5f),
|
{ 1.3f, -2.0f, -2.5f},
|
||||||
glm::vec3( 1.5f, 2.0f, -2.5f),
|
{ 1.5f, 2.0f, -2.5f},
|
||||||
glm::vec3( 1.5f, 0.2f, -1.5f),
|
{ 1.5f, 0.2f, -1.5f},
|
||||||
glm::vec3(-1.3f, 1.0f, -1.5f)
|
{-1.3f, 1.0f, -1.5f}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ const float AMBIENT_LEVEL = 0.25f;
|
||||||
struct Config {
|
struct Config {
|
||||||
Shader shader;
|
Shader shader;
|
||||||
Shader lightShader;
|
Shader lightShader;
|
||||||
|
std::vector<Model> models;
|
||||||
|
|
||||||
Lighting light{
|
Lighting light{
|
||||||
.directional={
|
.directional={
|
||||||
|
|
@ -86,9 +87,6 @@ struct Config {
|
||||||
.specularMap = 0,
|
.specularMap = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int cubeVAO = 0;
|
|
||||||
unsigned int lightCubeVAO = 0;
|
|
||||||
unsigned int VBO = 0;
|
|
||||||
float deltaTime = 0.0f;
|
float deltaTime = 0.0f;
|
||||||
float lastFrame = 0.0f;
|
float lastFrame = 0.0f;
|
||||||
|
|
||||||
|
|
@ -208,95 +206,27 @@ Config setup() {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
Config config{
|
Config config{
|
||||||
.shader={"shaders/13-vert.glsl", "shaders/13-frag.glsl"},
|
.shader={"shaders/14-vert.glsl", "shaders/14-frag.glsl"},
|
||||||
.lightShader={"shaders/13-vert.glsl", "shaders/13-lightsource.frag.glsl"},
|
.lightShader={"shaders/14-vert.glsl", "shaders/14-lightsource.frag.glsl"},
|
||||||
|
.models={
|
||||||
|
{"assets/popcorn_model_a.glb"}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int VBO = 0;
|
|
||||||
unsigned int lightCubeVAO = 0;
|
|
||||||
unsigned int cubeVAO = 0;
|
|
||||||
|
|
||||||
// cube vao configure, this is the light target
|
|
||||||
glGenVertexArrays(1, &cubeVAO);
|
|
||||||
glGenBuffers(1, &VBO);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glBindVertexArray(cubeVAO);
|
|
||||||
|
|
||||||
// position attribute
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
|
|
||||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
|
|
||||||
glEnableVertexAttribArray(2);
|
|
||||||
|
|
||||||
// light vao configure, this is the light source
|
|
||||||
glGenVertexArrays(1, &lightCubeVAO);
|
|
||||||
glBindVertexArray(lightCubeVAO);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
config.lightCubeVAO = lightCubeVAO;
|
|
||||||
config.cubeVAO = cubeVAO;
|
|
||||||
config.VBO = VBO;
|
|
||||||
|
|
||||||
config.cubeMaterial.diffuseMap = load_texture("resources/textures/container2.png");
|
|
||||||
config.cubeMaterial.specularMap = load_texture("resources/textures/container2_specular.png");
|
|
||||||
|
|
||||||
config.shader.use();
|
|
||||||
config.shader.setInt("material.diffuse", 0);
|
|
||||||
config.shader.setInt("material.specular", 1);
|
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_cube(size_t pos, Config& config, glm::mat4& projection, glm::mat4& view) {
|
void draw_popcorn(Config& config, size_t model_i, size_t model_pos, glm::mat4& projection, glm::mat4& view)
|
||||||
config.shader.setMat4("view", view);
|
{
|
||||||
config.shader.setMat4("projection", projection);
|
glm::vec3 objectColor = {1.0, 0.94, 0.78};
|
||||||
config.shader.setVec3("viewPos", config.camera.pos);
|
|
||||||
|
|
||||||
config.shader.applyMaterial(config.cubeMaterial);
|
config.shader.applyMaterial(config.cubeMaterial);
|
||||||
|
|
||||||
glm::mat4 model = glm::mat4(1.0f);
|
glm::mat4 model = glm::mat4(1.0f);
|
||||||
model = glm::translate(model, cube_positions[pos]);
|
model = glm::translate(model, popcorn_positions[model_pos]);
|
||||||
|
|
||||||
float angle = glfwGetTime() * (float)pos;
|
|
||||||
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
|
|
||||||
|
|
||||||
config.shader.setMat4("model", model);
|
config.shader.setMat4("model", model);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
config.models[model_i].Draw(config.shader);
|
||||||
glBindTexture(GL_TEXTURE_2D, config.cubeMaterial.diffuseMap);
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, config.cubeMaterial.specularMap);
|
|
||||||
|
|
||||||
glBindVertexArray(config.cubeVAO);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_light(Config& config, Light& light, glm::mat4& projection, glm::mat4& view) {
|
|
||||||
config.lightShader.use();
|
|
||||||
|
|
||||||
config.lightShader.setVec3("diffuse", light.diffuse);
|
|
||||||
config.lightShader.setMat4("projection", projection);
|
|
||||||
config.lightShader.setMat4("view", view);
|
|
||||||
|
|
||||||
glm::mat4 model = glm::mat4(1.0f);
|
|
||||||
model = glm::translate(model, light.position);
|
|
||||||
model = glm::scale(model, glm::vec3(0.2f));
|
|
||||||
config.lightShader.setMat4("model", model);
|
|
||||||
|
|
||||||
glBindVertexArray(config.lightCubeVAO);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(GLFWwindow* window, Config& config) {
|
void render(GLFWwindow* window, Config& config) {
|
||||||
|
|
@ -317,16 +247,16 @@ void render(GLFWwindow* window, Config& config) {
|
||||||
projection = glm::perspective(glm::radians(config.camera.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
|
projection = glm::perspective(glm::radians(config.camera.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
|
||||||
|
|
||||||
config.shader.use();
|
config.shader.use();
|
||||||
|
config.shader.setMat4("view", view);
|
||||||
|
config.shader.setMat4("projection", projection);
|
||||||
|
config.shader.setVec3("viewPos", config.camera.pos);
|
||||||
|
|
||||||
config.light.spot.position = config.camera.pos;
|
config.light.spot.position = config.camera.pos;
|
||||||
config.light.spot.direction = config.camera.front;
|
config.light.spot.direction = config.camera.front;
|
||||||
config.shader.applyLighting(config.light);
|
config.shader.applyLighting(config.light);
|
||||||
|
|
||||||
for(size_t i = 0; i < CUBE_COUNT; i++) {
|
for(size_t i = 0; i < CUBE_COUNT; i++) {
|
||||||
draw_cube(i, config, projection, view);
|
draw_popcorn(config, 0, i, projection, view);
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& light : config.light.positioned) {
|
|
||||||
draw_light(config, light, projection, view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
|
|
@ -334,9 +264,6 @@ void render(GLFWwindow* window, Config& config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup(Config& config) {
|
void cleanup(Config& config) {
|
||||||
glDeleteVertexArrays(1, &config.lightCubeVAO);
|
|
||||||
glDeleteBuffers(1, &config.lightCubeVAO);
|
|
||||||
glDeleteBuffers(1, &config.VBO);
|
|
||||||
config.shader.cleanup();
|
config.shader.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "mesh.hpp"
|
#include "mesh.hpp"
|
||||||
|
#include "dbc.hpp"
|
||||||
|
|
||||||
void Mesh::Draw(Shader &shader) {
|
void Mesh::Draw(Shader &shader) {
|
||||||
unsigned int diffuseNr = 1;
|
unsigned int diffuseNr = 1;
|
||||||
|
|
@ -8,21 +9,25 @@ void Mesh::Draw(Shader &shader) {
|
||||||
|
|
||||||
for(unsigned int i = 0; i < textures.size(); i++) {
|
for(unsigned int i = 0; i < textures.size(); i++) {
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
std::string number;
|
unsigned int number = 0;
|
||||||
std::string name = textures[i].type;
|
std::string& name = textures[i].type;
|
||||||
|
|
||||||
if(name == "texture_diffuse") {
|
if(name == "texture_diffuse") {
|
||||||
number = std::to_string(diffuseNr++);
|
number = diffuseNr++;
|
||||||
} else if(name == "texture_specular") {
|
} else if(name == "texture_specular") {
|
||||||
number = std::to_string(specularNr++);
|
number = specularNr++;
|
||||||
} else if(name == "texture_normal") {
|
} else if(name == "texture_normal") {
|
||||||
number = std::to_string(normalNr++);
|
number = normalNr++;
|
||||||
} else if(name == "texture_height") {
|
} else if(name == "texture_height") {
|
||||||
number = std::to_string(heightNr++);
|
number = heightNr++;
|
||||||
|
} else {
|
||||||
|
dbc::sentinel($F("Invalid texture type name {}", name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string target = std::format("{}{}", name, number);
|
||||||
|
|
||||||
// TODO: Get this uniform ID once and cache it?
|
// TODO: Get this uniform ID once and cache it?
|
||||||
glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);
|
glUniform1i(glGetUniformLocation(shader.ID, target.c_str()), i);
|
||||||
glBindTexture(GL_TEXTURE_2D, textures[i].id);
|
glBindTexture(GL_TEXTURE_2D, textures[i].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,6 +51,7 @@ void Mesh::setupMesh() {
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// this matches the locations in the vertex shader
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,14 @@
|
||||||
#include "model.hpp"
|
#include "model.hpp"
|
||||||
#include "dbc.hpp"
|
#include "dbc.hpp"
|
||||||
|
#include <print>
|
||||||
|
|
||||||
unsigned int TextureFromFile(const std::string& path, const std::string& directory, bool gamma)
|
unsigned int TextureFromFile(const std::string& path, const std::string& directory);
|
||||||
{
|
unsigned int TextureFromInternal(const aiScene *scene, size_t index);
|
||||||
std::string filename = path + "/" + filename;
|
|
||||||
|
|
||||||
|
unsigned int to_gl_texture(unsigned char *data, int width, int height, int nrComponents) {
|
||||||
unsigned int textureID;
|
unsigned int textureID;
|
||||||
glGenTextures(1, &textureID);
|
glGenTextures(1, &textureID);
|
||||||
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
int nrComponents = 0;
|
|
||||||
|
|
||||||
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
|
|
||||||
dbc::check(data != nullptr, $F("Failed to load texture {}", filename));
|
|
||||||
|
|
||||||
GLenum format = GL_RGB;
|
GLenum format = GL_RGB;
|
||||||
|
|
||||||
if (nrComponents == 1) {
|
if (nrComponents == 1) {
|
||||||
|
|
@ -34,6 +28,48 @@ unsigned int TextureFromFile(const std::string& path, const std::string& directo
|
||||||
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);
|
||||||
|
|
||||||
|
return textureID;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int TextureFromInternal(const aiScene *scene, size_t index) {
|
||||||
|
const aiTexture *aiTex = scene->mTextures[index];
|
||||||
|
unsigned int textureID = 0;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int nrComponents = 0;
|
||||||
|
unsigned char *data = nullptr;
|
||||||
|
const unsigned char* dataBytes = (const unsigned char*)aiTex->pcData;
|
||||||
|
|
||||||
|
if(aiTex->mHeight == 0) {
|
||||||
|
// compressed texture (PNG or JPG)
|
||||||
|
size_t dataSize = aiTex->mWidth;
|
||||||
|
data = stbi_load_from_memory(dataBytes, dataSize, &width, &height, &nrComponents, 0);
|
||||||
|
textureID = to_gl_texture(data, width, height, nrComponents);
|
||||||
|
stbi_image_free(data);
|
||||||
|
} else {
|
||||||
|
data = (unsigned char*)aiTex->pcData;
|
||||||
|
width = aiTex->mWidth;
|
||||||
|
height = aiTex->mHeight;
|
||||||
|
nrComponents = 4; // either BGRA8888 or RGBA8888
|
||||||
|
textureID = to_gl_texture(data, width, height, nrComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
return textureID;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int TextureFromFile(const std::string& path, const std::string& directory)
|
||||||
|
{
|
||||||
|
std::string filename = directory + "/" + path;
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int nrComponents = 0;
|
||||||
|
|
||||||
|
unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0);
|
||||||
|
dbc::check(data != nullptr, $F("Failed to load texture {}", filename));
|
||||||
|
|
||||||
|
unsigned int textureID = to_gl_texture(data, width, height, nrComponents);
|
||||||
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
|
|
||||||
return textureID;
|
return textureID;
|
||||||
|
|
@ -45,9 +81,14 @@ void Model::Draw(Shader &shader) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::loadModel(std::string path) {
|
void Model::loadModel(const std::string& path) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
|
|
||||||
|
const aiScene* scene = importer.ReadFile(path,
|
||||||
|
aiProcess_Triangulate |
|
||||||
|
aiProcess_GenSmoothNormals |
|
||||||
|
aiProcess_FlipUVs |
|
||||||
|
aiProcess_CalcTangentSpace);
|
||||||
|
|
||||||
dbc::check(scene != nullptr, "Assimp ReadFile return null");
|
dbc::check(scene != nullptr, "Assimp ReadFile return null");
|
||||||
dbc::check(!(scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE), "Assimp says incomplete.");
|
dbc::check(!(scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE), "Assimp says incomplete.");
|
||||||
|
|
@ -118,54 +159,53 @@ Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) {
|
||||||
// normal: texture_normalN
|
// normal: texture_normalN
|
||||||
|
|
||||||
// 1. diffuse maps
|
// 1. diffuse maps
|
||||||
std::vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
|
loadMaterialTextures(textures, scene, material, aiTextureType_DIFFUSE, "texture_diffuse");
|
||||||
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
|
|
||||||
|
|
||||||
// 2. specular maps
|
// 2. specular maps
|
||||||
std::vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
|
loadMaterialTextures(textures, scene, material, aiTextureType_SPECULAR, "texture_specular");
|
||||||
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
|
|
||||||
|
|
||||||
// 3. normal maps
|
// 3. normal maps
|
||||||
std::vector<Texture> normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal");
|
loadMaterialTextures(textures, scene, material, aiTextureType_HEIGHT, "texture_normal");
|
||||||
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
|
||||||
|
|
||||||
// 4. height maps
|
// 4. height maps
|
||||||
std::vector<Texture> heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height");
|
loadMaterialTextures(textures, scene, material, aiTextureType_AMBIENT, "texture_height");
|
||||||
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
|
|
||||||
|
|
||||||
return Mesh(vertices, indices, textures);
|
return Mesh(vertices, indices, textures);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Texture> Model::loadMaterialTextures(aiMaterial *mat, aiTextureType type, std::string typeName)
|
void Model::loadMaterialTextures(std::vector<Texture>& textures, const aiScene *scene, aiMaterial *mat, aiTextureType type, std::string typeName)
|
||||||
{
|
{
|
||||||
fmt::println("TEXTURE COUNT: {}, {}, {}", (int)type, typeName, mat->GetTextureCount(type));
|
fmt::println("TEXTURE COUNT: {}, {}, {}", (int)type, typeName, mat->GetTextureCount(type));
|
||||||
|
|
||||||
std::vector<Texture> textures;
|
|
||||||
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
|
for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) {
|
||||||
aiString str;
|
aiString str;
|
||||||
|
|
||||||
mat->GetTexture(type, i, &str);
|
mat->GetTexture(type, i, &str);
|
||||||
std::string tx_str{str.C_Str()};
|
std::string tx_str{str.C_Str()};
|
||||||
|
dbc::check(!tx_str.empty(), "Texture has empty path, should be impossible?");
|
||||||
|
|
||||||
bool skip = false;
|
if(textures_loaded.contains(tx_str)) {
|
||||||
for(unsigned int j = 0; j < textures_loaded.size(); j++) {
|
textures.push_back(textures_loaded.at(tx_str));
|
||||||
if(textures_loaded[j].path == tx_str) {
|
} else {
|
||||||
textures.push_back(textures_loaded[j]);
|
unsigned int tx_id = 0;
|
||||||
skip = true;
|
|
||||||
break;
|
// if it's a *# style path then it's internal
|
||||||
|
if(tx_str[0] == '*') {
|
||||||
|
// get the texture from the internal version
|
||||||
|
tx_id = TextureFromInternal(scene, std::stoi(tx_str.substr(1)));
|
||||||
|
} else {
|
||||||
|
// else get it from a file
|
||||||
|
tx_id = TextureFromFile(tx_str, directory);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(!skip) {
|
|
||||||
Texture texture{
|
Texture texture{
|
||||||
.id = TextureFromFile(tx_str, directory),
|
.id = tx_id,
|
||||||
.type = typeName,
|
.type = typeName,
|
||||||
.path = tx_str,
|
.path = tx_str,
|
||||||
};
|
};
|
||||||
|
|
||||||
textures.push_back(texture);
|
textures.push_back(texture);
|
||||||
textures_loaded.push_back(texture);
|
textures_loaded.try_emplace(tx_str, texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return textures;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,10 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
unsigned int TextureFromFile(const std::string& path, const std::string& directory, bool gamma = false);
|
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
std::vector<Texture> textures_loaded;
|
std::map<std::string, Texture> textures_loaded;
|
||||||
std::vector<Mesh> meshes;
|
std::vector<Mesh> meshes;
|
||||||
std::string directory;
|
std::string directory{"./"};
|
||||||
bool gammaCorrection;
|
bool gammaCorrection;
|
||||||
|
|
||||||
Model(const char *path) {
|
Model(const char *path) {
|
||||||
|
|
@ -32,9 +30,9 @@ struct Model {
|
||||||
|
|
||||||
void Draw(Shader &shader);
|
void Draw(Shader &shader);
|
||||||
|
|
||||||
void loadModel(std::string path);
|
void loadModel(const std::string& path);
|
||||||
void processNode(aiNode *node, const aiScene *scene);
|
void processNode(aiNode *node, const aiScene *scene);
|
||||||
Mesh processMesh(aiMesh *mesh, const aiScene *scene);
|
Mesh processMesh(aiMesh *mesh, const aiScene *scene);
|
||||||
|
|
||||||
std::vector<Texture> loadMaterialTextures(aiMaterial *mat, aiTextureType type, std::string typeName);
|
void loadMaterialTextures(std::vector<Texture>& textures, const aiScene *scene, aiMaterial *mat, aiTextureType type, std::string typeName);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "dbc.hpp"
|
#include "dbc.hpp"
|
||||||
|
|
||||||
TEST_SET(shader_tests);
|
TEST_SET(shader_tests);
|
||||||
|
TEST_SET(model_tests);
|
||||||
|
|
||||||
using namespace fuc2;
|
using namespace fuc2;
|
||||||
|
|
||||||
|
|
@ -31,7 +32,8 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<fuc2::Set> tests{
|
std::vector<fuc2::Set> tests{
|
||||||
shader_tests::TESTS
|
shader_tests::TESTS,
|
||||||
|
model_tests::TESTS
|
||||||
};
|
};
|
||||||
|
|
||||||
return run_tests(tests, argc, argv);
|
return run_tests(tests, argc, argv);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
fuc2_tests = files(
|
fuc2_tests = files(
|
||||||
'main.cpp',
|
'main.cpp',
|
||||||
'shader_tests.cpp',
|
'shader_tests.cpp',
|
||||||
|
'model_tests.cpp',
|
||||||
)
|
)
|
||||||
|
|
|
||||||
21
14-refactor/tests/model_tests.cpp
Normal file
21
14-refactor/tests/model_tests.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
#include <fuc2/testing.hpp>
|
||||||
|
#include "model.hpp"
|
||||||
|
|
||||||
|
using namespace fuc2;
|
||||||
|
|
||||||
|
namespace model_tests {
|
||||||
|
void test_load_textures() {
|
||||||
|
Model model{"assets/popcorn_model_a.glb"};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fuc2::Set TESTS{
|
||||||
|
.name="models",
|
||||||
|
.options={ .fail_fast=false },
|
||||||
|
.tests={
|
||||||
|
TEST(test_load_textures),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue