Shadows working but look dumb. The issue so far was that framebuffer.cpp interferes with the framebuffer used to create the shadow map.

This commit is contained in:
Zed A. Shaw 2026-09-19 15:09:46 -04:00
parent a29494325b
commit 482ec07fb3
19 changed files with 261 additions and 206 deletions

View file

@ -43,9 +43,9 @@
}
},
"models": {
"marble_cube": {
"directory": "assets",
"model_path": "marble_cube.glb"
"backpack": {
"directory": "../assets/backpack/",
"model_path": "backpack.obj"
},
"metal_floor": {
"directory": "assets",
@ -61,14 +61,10 @@
}
},
"things": [
{"model": "marble_cube", "position": [1.5, 0.0, -1.0],
{"model": "backpack", "position": [1.5, 0.0, -1.0],
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
"scale": 3.0,
"material": "default"},
{"model": "marble_cube", "position": [1.5, 0.25, 0.0],
"rotation": {"angle": 90.0, "axes": [1.0,0.0,0.0]},
"scale": 1.0,
"material": "shiny"}
"material": "default"}
],
"camera": {
"position": [0.0, 0.1, 3.0],

View file

@ -81,7 +81,11 @@
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
"scale": 1.0,
"material": "default"},
{"model": "human", "position": [-0.032, 0.0, 0.11],
{"model": "marble_cube", "position": [1.28, 0.0, 1.85],
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
"scale": 1.0,
"material": "shiny"},
{"model": "human", "position": [3.13, 0.80, 3.04],
"rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]},
"scale": 1.0,
"material": "shiny"},
@ -92,11 +96,7 @@
{"model": "window", "position": [1.75, 0.25, 0.25],
"rotation": {"angle": 90.0, "axes": [1.0,0.0,0.0]},
"scale": 1.0,
"material": "shiny"},
{"model": "light_bulb", "position": [3.84, 3.45, 4.73],
"rotation": {"angle": 0.0, "axes": [1.0,1.0,1.0]},
"scale": 0.03,
"material": "default"}
"material": "shiny"}
],
"camera": {
"position": [0.0, 0.1, 3.0],
@ -110,8 +110,8 @@
],
"positioned": [
{
"position": [3.84, 3.45, 4.73],
"direction":[-0.5, -1.0, -0.3],
"position": [-2.0, 4.0, -1.0],
"direction":[0.0, 0.0, 0.0],
"ambient":[0.3, 0.3, 0.3],
"diffuse":[0.9, 0.9, 0.9],
"specular":[1.0, 1.0, 1.0],

View file

@ -0,0 +1,6 @@
#version 330 core
void main()
{
// gl_FragDepth = gl_FragCoord.z;
}

View file

@ -0,0 +1,10 @@
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 lightSpaceMatrix;
uniform mat4 model;
void main()
{
gl_Position = lightSpaceMatrix * model * vec4(aPos, 1.0);
}

View file

@ -1,168 +1,58 @@
#version 330 core
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
in vec4 FragPosLightSpace;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform Material material;
uniform sampler2D shadowMap;
uniform sampler2D texture_diffuse1;
uniform sampler2D texture_specular1;
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 cut_off;
float outer_cut_off;
};
#define MAX_LIGHTS 4
uniform int pointLightCount = 0;
uniform PointLight pointLights[MAX_LIGHTS];
uniform int dirLightCount = 0;
uniform DirLight dirLights[MAX_LIGHTS];
uniform int spotLightCount = 0;
uniform SpotLight spotLights[MAX_LIGHTS];
float near = 0.1;
float far = 100.0;
vec4 CalcDirLight(vec4 mat_tex, vec4 spec_tex, DirLight light, vec3 normal, vec3 viewDir)
float ShadowCalculation(vec4 fragPosLightSpace, float bias)
{
vec3 lightDir = normalize(-light.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(shadowMap, projCoords.xy).r;
// get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// check whether current frag pos is in shadow
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
vec4 ambient = vec4(light.ambient, 1.0) * mat_tex;
vec4 diffuse = vec4(light.diffuse, 1.0) * diff * mat_tex;
vec4 specular = vec4(light.specular, 1.0) * spec * spec_tex;
return ambient + diffuse + specular;
}
vec4 CalcPointLight(vec4 mat_tex, vec4 spec_tex, PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
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));
vec4 ambient = vec4(light.ambient, 1.0) * mat_tex;
vec4 diffuse = vec4(light.diffuse, 1.0) * diff * mat_tex;
vec4 specular = vec4(light.specular, 1.0) * spec * spec_tex;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return ambient + diffuse + specular;
}
vec4 CalcSpotLight(vec4 mat_tex, vec4 spec_tex, SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
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));
vec4 ambient = vec4(light.ambient, 1.0) * mat_tex;
vec4 diffuse = vec4(light.diffuse, 1.0) * diff * mat_tex;
vec4 specular = vec4(light.specular, 1.0) * spec * spec_tex;
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cut_off - light.outer_cut_off;
float intensity = clamp((theta - light.outer_cut_off) / epsilon, 0.0, 1.0);
diffuse *= intensity;
specular *= intensity;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return ambient + diffuse + specular;
}
float LinearizeDepth(float depth)
{
float ndc = depth * 2.0 - 1.0;
return (2.0 * near * far) / (far + near - ndc * (far - near));
return shadow;
}
void main()
{
vec4 mat_tex = texture(material.diffuse, TexCoords);
vec4 spec_tex = texture(material.specular, TexCoords);
vec3 norm = normalize(Normal);
vec3 color = texture(texture_diffuse1, TexCoords).rgb;
vec3 normal = normalize(Normal);
vec3 lightColor = vec3(0.7);
// ambient
vec3 ambient = 0.3 * lightColor;
// diffuse
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor;
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = 0.0;
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor;
// calculate shadow
// kick it off with the first dirlight
vec4 result = CalcDirLight(mat_tex, spec_tex, dirLights[0], norm, viewDir);
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
float shadow = ShadowCalculation(FragPosLightSpace, bias);
// then augment with more (off by one)
for(int i = 1; i < dirLightCount; i++) {
result += CalcDirLight(mat_tex, spec_tex, dirLights[i], norm, viewDir);
}
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;
for(int i = 0; i < pointLightCount; i++) {
result += CalcPointLight(mat_tex, spec_tex, pointLights[i], norm, FragPos, viewDir);
}
for(int i = 0; i < spotLightCount; i++) {
result += CalcSpotLight(mat_tex, spec_tex, spotLights[i], norm, FragPos, viewDir);
}
FragColor = result;
FragColor = vec4(lighting, 1.0);
}

View file

@ -6,16 +6,18 @@ layout (location = 2) in vec2 aTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
out vec4 FragPosLightSpace;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;
void main()
{
vec4 pos = vec4(aPos, 1.0);
gl_Position = projection * view * model * pos;
FragPos = vec3(model * pos);
Normal = transpose(inverse(mat3(model))) * aNormal;
TexCoords = aTexCoords;
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = transpose(inverse(mat3(model))) * aNormal;
TexCoords = aTexCoords;
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
gl_Position = projection * view * model * vec4(aPos, 1.0);
}

View file

@ -0,0 +1,22 @@
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D shadowMap;
uniform float near_plane;
uniform float far_plane;
// required when using a perspective projection matrix
float LinearizeDepth(float depth)
{
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane));
}
void main()
{
float depthValue = texture(shadowMap, TexCoords).r;
// FragColor = vec4(vec3(LinearizeDepth(depthValue) / far_plane), 1.0); // perspective
FragColor = vec4(vec3(depthValue), 1.0); // orthographic
}

View file

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos, 1.0);
}

View file

@ -1 +0,0 @@
#version 330 core

View file

@ -1,4 +0,0 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

View file

@ -12,11 +12,9 @@ namespace components {
struct Material {
glm::vec3 ambient{0.1f,0.1f,0.1f};
float shininess{32.0f};
unsigned int diffuseMap = 0;
unsigned int specularMap = 0;
};
ENROLL_COMPONENT(Material, ambient, shininess, diffuseMap, specularMap);
ENROLL_COMPONENT(Material, ambient, shininess);
struct Light {
glm::vec3 position{0.0f, 0.0f, 0.0f};

View file

@ -60,7 +60,7 @@ void FrameBuffer::commit() {
}
void FrameBuffer::draw(Screen& screen) {
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);

View file

@ -4,8 +4,10 @@
#include "utils.hpp"
#include <print>
#include <format>
#include "text.hpp"
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
std::string text_content{""};
void init_glfw() {
@ -77,6 +79,10 @@ void process_input(GLFWwindow *window, Scene& scene) {
scene.reflect_on = !scene.reflect_on;
}
if(glfwGetKey(window, GLFW_KEY_J) == GLFW_PRESS) {
scene.debug_on = !scene.debug_on;
}
if(glfwGetKey(window, GLFW_KEY_H) == GLFW_PRESS) {
scene.spawn("human");
glm::vec3 pos = scene.camera.position;
@ -127,10 +133,9 @@ void update(GLFWwindow* window, Scene& scene) {
scene.update();
}
void render(GLFWwindow* window, Scene& scene, Text& text) {
void render(GLFWwindow* window, Scene& scene, Text &text) {
scene.render(window);
text.render(text_content, 25.0f, 25.0f, 1.0f, glm::vec3(1.0, 0.0f, 0.0f));
glfwSwapBuffers(window);
}

View file

@ -10,19 +10,20 @@ void Mesh::draw(Shader &shader, bool with_textures) {
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE0);
}
void Mesh::apply_textures(const Shader& shader) {
for(unsigned int i = 0; i < textures.size(); i++) {
Texture& texture = textures[i];
int texture_i = 1;
for(auto& texture : textures) {
texture.uniform_id = glGetUniformLocation(shader.ID, texture.target.c_str());
glActiveTexture(GL_TEXTURE0 + i);
if(texture.uniform_id == -1) continue;
// move this to setup_mesh
glUniform1i(texture.uniform_id, i);
glActiveTexture(GL_TEXTURE0 + texture_i);
glBindTexture(GL_TEXTURE_2D, texture.id);
glUniform1i(texture.uniform_id, texture_i);
texture_i++;
}
}

View file

@ -36,32 +36,94 @@ void Scene::draw_thing(Shader& with_shader, Thing& thing)
thing.model.draw(with_shader, !reflect_on);
}
void Scene::render(GLFWwindow* window) {
void Scene::render_scene(GLFWwindow* window, Shader& with_shader) {
glm::mat4 view = camera.look_at();
glm::mat4 projection = glm::mat4(1.0f);
auto& with_shader = reflect_on ? reflect_shader : shader;
// fov, aspect, near plane, far plane
projection = glm::perspective(glm::radians(camera.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
framebuffer.begin();
projection = glm::perspective(glm::radians(camera.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, near_plane, far_plane);
// render the scene
with_shader.use();
with_shader.setMat4("view", view);
with_shader.setMat4("projection", projection);
with_shader.setVec3("cameraPos", camera.position);
with_shader.setFloat("time", glfwGetTime());
for(auto& thing : things) {
draw_thing(with_shader, thing);
}
}
render_skybox(projection);
void Scene::render_shadows(GLFWwindow* window) {
// temporarily use the config.json positioned even though this is doing a directional
auto& light_pos = light.positioned.at(0).position;
framebuffer.commit();
glm::mat4 proj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, depth_near_plane, depth_far_plane);
glm::mat4 view = glm::lookAt(light_pos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
framebuffer.draw(screen);
light_space = proj * view;
depth_shader.use();
depth_shader.setMat4("lightSpaceMatrix", light_space);
depth_shader.setFloat("near_plane", depth_near_plane);
depth_shader.setFloat("far_plane", depth_far_plane);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depth_FBO);
glClear(GL_DEPTH_BUFFER_BIT);
render_scene(window, depth_shader);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Scene::render(GLFWwindow* window) {
auto& with_shader = reflect_on ? reflect_shader : shader;
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
render_shadows(window);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depth_map);
with_shader.use();
with_shader.setInt("shadowMap", 0);
// NOTE: in the shader is it viewPos or cameraPos?
with_shader.setVec3("viewPos", camera.position);
with_shader.setVec3("lightPos", light.positioned.at(0).position);
with_shader.setMat4("lightSpaceMatrix", light_space);
if(debug_on) {
render_debug(window);
} else {
render_scene(window, with_shader);
}
}
void Scene::render_debug(GLFWwindow* window) {
depth_dbg_shader.use();
depth_dbg_shader.setInt("shadowMap", 0);
depth_dbg_shader.setFloat("near_plane", depth_near_plane);
depth_dbg_shader.setFloat("far_plane", depth_far_plane);
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
}
void Scene::init_debug() {
// setup plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
}
void Scene::cleanup() {
@ -70,7 +132,28 @@ void Scene::cleanup() {
skybox_shader.cleanup();
}
void Scene::init_shadows() {
glGenFramebuffers(1, &depth_FBO);
glGenTextures(1, &depth_map);
glBindTexture(GL_TEXTURE_2D, depth_map);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindFramebuffer(GL_FRAMEBUFFER, depth_FBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
dbc::check(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame buffer not complete.");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Scene::init_skybox() {
dbc::sentinel("DISABLED, do not run me.");
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
@ -122,7 +205,8 @@ void Scene::load_skybox_textures() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
void Scene::render_skybox(const glm::mat4& projection) {
void Scene::render_skybox() {
dbc::sentinel("DISABLED, do not run me.");
glDepthFunc(GL_LEQUAL);
skybox_shader.use();
glm::mat4 view = glm::mat4(glm::mat3(camera.look_at()));

View file

@ -15,7 +15,6 @@
#include <vector>
#include <unordered_map>
#include "config.hpp"
#include "text.hpp"
struct Thing {
std::string name;
@ -45,8 +44,36 @@ struct Scene {
unsigned int skyboxVAO = UINT_MAX;
unsigned int skyboxVBO = UINT_MAX;
unsigned int skybox_texture_id = UINT_MAX;
glm::mat4 projection = glm::mat4(1.0f);
bool reflect_on = false;
// shadow stuff
Shader depth_shader{{"shaders/33-depth.vert.glsl", "shaders/33-depth.frag.glsl", ""}};
Shader depth_dbg_shader{{"shaders/33-shadow_dbg.vert.glsl", "shaders/33-shadow_dbg.frag.glsl", ""}};
unsigned int depth_FBO = UINT_MAX;
unsigned int depth_map = UINT_MAX;
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
float near_plane = 1.0f;
float far_plane = 100.0f;
float depth_near_plane = 1.0f;
float depth_far_plane = 7.5f;
glm::mat4 light_space;
bool debug_on = false;
float quadVertices[20] = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
unsigned int quadVAO = UINT_MAX;
unsigned int quadVBO = UINT_MAX;
Scene(components::Scene& config):
shader{config.shader},
reflect_shader{config.reflect_shader},
@ -90,7 +117,9 @@ struct Scene {
framebuffer.init();
screen.init();
init_skybox();
// init_skybox();
init_shadows();
init_debug();
}
void update();
@ -98,7 +127,12 @@ struct Scene {
void render(GLFWwindow* window);
void cleanup();
void init_skybox();
void init_shadows();
void init_debug();
void load_skybox_textures();
void render_skybox(const glm::mat4& projection);
void render_skybox();
void spawn(const std::string& name);
void render_scene(GLFWwindow* window, Shader& with_shader);
void render_shadows(GLFWwindow* window);
void render_debug(GLFWwindow* window);
};

View file

@ -62,7 +62,7 @@ unsigned int Shader::load_shader(const std::string& filename, GLenum shader_type
}
Shader::Shader(components::Shader config) {
Shader::Shader(components::Shader c) : config(c) {
dbc::log($F("Loading shaders vert={}, frag={}, geom={}", config.vertex_path, config.frag_path, config.geometry_path));
unsigned int vertex = load_shader(config.vertex_path, GL_VERTEX_SHADER);

View file

@ -15,6 +15,7 @@ class Shader
{
public:
unsigned int ID = UINT_MAX;
components::Shader config;
Shader(components::Shader config);

View file

@ -11,7 +11,7 @@ using namespace fuc2;
*/
namespace model_tests {
void test_load_textures() {
Shader shader({"shaders/14-vert.glsl", "shaders/14-frag.glsl", ""});
Shader shader({"shaders/33-framebuffers.vert.glsl", "shaders/33-framebuffers.frag.glsl", ""});
Model popcorn{"assets", "popcorn_model_a.glb"};
popcorn.draw(shader, true);