Have a basic outlining thing with stencils but required a bit of hacking to make it work in Scene::render.

This commit is contained in:
Zed A. Shaw 2026-08-28 15:48:28 -04:00
parent 993f148710
commit dc973009fd
13 changed files with 101 additions and 43 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -1,21 +1,25 @@
{
"scene": {
"shader": {
"vertex_path": "shaders/17-vert.glsl",
"frag_path": "shaders/17-frag.glsl"
"vertex_path": "shaders/18-vert.glsl",
"frag_path": "shaders/18-frag.glsl"
},
"light_shader": {
"vertex_path": "shaders/17-vert.glsl",
"frag_path": "shaders/17-lightsource.frag.glsl"
"vertex_path": "shaders/18-vert.glsl",
"frag_path": "shaders/18-lightsource.frag.glsl"
},
"outline_shader": {
"vertex_path": "shaders/18-vert.glsl",
"frag_path": "shaders/18-outline.glsl"
},
"materials": {
"crate": {
"default": {
"ambient": [0.5, 0.5, 0.5],
"shininess": 32.0,
"diffuseMap": 0,
"specularMap": 0
},
"popcorn": {
"shiny": {
"ambient": [0.5, 0.25, 0.31],
"shininess": 10000.0,
"diffuseMap": 0,
@ -23,29 +27,22 @@
}
},
"models": {
"crate": {
"marble_cube": {
"directory": "assets",
"model_path": "crate.obj"
"model_path": "marble_cube.glb"
},
"popcorn": {
"metal_floor": {
"directory": "assets",
"model_path": "popcorn_model_a.glb"
"model_path": "metal_floor.glb"
}
},
"things": [
{"model": "crate", "position": [0.0, 0.0, 0.0], "material": "crate"},
{"model": "crate", "position": [2.0, 5.0, -15.0], "material": "crate"},
{"model": "crate", "position": [-1.5, -2.2, -2.5], "material": "crate"},
{"model": "popcorn", "position": [-3.8, -2.0, -12.3], "material": "popcorn"},
{"model": "crate", "position": [ 2.4, -0.4, -3.5], "material": "crate"},
{"model": "crate", "position": [-1.7, 3.0, -7.5], "material": "crate"},
{"model": "popcorn", "position": [ 1.3, -2.0, -2.5], "material": "popcorn"},
{"model": "crate", "position": [ 1.5, 2.0, -2.5], "material": "crate"},
{"model": "popcorn", "position": [ 1.5, 0.2, -1.5], "material": "popcorn"},
{"model": "crate", "position": [-1.3, 1.0, -1.5], "material": "crate"}
{"model": "marble_cube", "position": [-1.0, 0.0, -1.0], "material": "default"},
{"model": "marble_cube", "position": [2.0, 0.0, 0.0], "material": "default"},
{"model": "metal_floor", "position": [0.0, 0.0, 0.0], "material": "shiny"}
],
"camera": {
"position": [0.0, 0.0, 3.0],
"position": [0.0, 0.1, 3.0],
"front": [0.0, 0.0, -1.0],
"up": [0.0, 1.0, 0.0],
"direction": [0.0, 0.0, 0.0],

View file

@ -55,6 +55,10 @@ uniform DirLight dirLights[MAX_LIGHTS];
uniform int spotLightCount = 0;
uniform SpotLight spotLights[MAX_LIGHTS];
float near = 0.1;
float far = 100.0;
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 mat_tex = vec3(texture(material.diffuse, TexCoords));
@ -137,6 +141,13 @@ vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
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));
}
void main()
{
vec3 norm = normalize(Normal);
@ -159,4 +170,7 @@ void main()
}
FragColor = vec4(result, 1.0);
// float depth = LinearizeDepth(gl_FragCoord.z) / far;
// FragColor = vec4(vec3(depth), 1.0);
}

View file

@ -0,0 +1,6 @@
#version 330 core
out vec4 FragColor;
void main() {
FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

View file

@ -94,6 +94,7 @@ namespace components {
struct Scene {
components::Shader shader;
components::Shader light_shader;
components::Shader outline_shader;
std::map<std::string, Material> materials;
std::map<std::string, Model> models;
std::vector<Thing> things;
@ -101,5 +102,5 @@ namespace components {
Lighting light;
};
ENROLL_COMPONENT(Scene, shader, light_shader, materials, models, things, camera, light);
ENROLL_COMPONENT(Scene, shader, light_shader, outline_shader, materials, models, things, camera, light);
}

View file

@ -66,7 +66,7 @@ void process_input(GLFWwindow *window, Scene& scene) {
}
if(glfwGetKey(window, GLFW_KEY_M) == GLFW_PRESS) {
scene.spawn("popcorn", scene.camera.position);
scene.spawn("marble_cube", scene.camera.position);
}
if(glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) {
@ -84,6 +84,10 @@ void process_input(GLFWwindow *window, Scene& scene) {
Scene setup() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
components::Scene config = utils::load_scene_config("config.json");
Scene scene(config);

View file

@ -10,28 +10,22 @@ void Scene::update() {
camera.update(deltaTime);
}
void Scene::draw_model(Model& scene_model, Material& material, glm::mat4& projection, glm::mat4& view, glm::vec3& position)
void Scene::draw_model(Shader& with_shader, Model& scene_model, Material& material, glm::mat4& projection, glm::mat4& view, glm::vec3& position, float scale)
{
shader.apply_material(material);
with_shader.apply_material(material);
float time = glfwGetTime();
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, position);
model = glm::rotate(model, glm::radians(time * 10.0f), glm::vec3(1.0f, 0.3f, 0.5f));
model = glm::scale(model, glm::vec3(scale, scale, scale));
shader.setMat4("model", model);
with_shader.setMat4("model", model);
scene_model.draw(shader);
scene_model.draw(with_shader);
}
void Scene::render(GLFWwindow* window) {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.use();
// time is used for fake 3d rotation
float time = glfwGetTime();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glm::mat4 view = camera.look_at();
glm::mat4 projection = glm::mat4(1.0f);
@ -42,7 +36,6 @@ void Scene::render(GLFWwindow* window) {
shader.use();
shader.setMat4("view", view);
shader.setMat4("projection", projection);
shader.setVec3("viewPos", camera.position);
// for now just detect the camera moved and do spotlight update
if(camera.dirty) {
@ -53,10 +46,41 @@ void Scene::render(GLFWwindow* window) {
camera.dirty = false;
}
// BUG: no connection between models and positions
// ultra dumb way to draw the floor without stencil, so next move is to
// be able to tag models with specific functionality during render.
for(auto& thing : things) {
draw_model(thing.model, thing.material, projection, view, thing.position);
if(thing.name == "metal_floor") {
draw_model(shader, thing.model, thing.material, projection, view, thing.position);
}
}
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
for(auto& thing : things) {
if(thing.name != "metal_floor") {
draw_model(shader, thing.model, thing.material, projection, view, thing.position);
}
}
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
glDisable(GL_DEPTH_TEST);
outline_shader.use();
outline_shader.setMat4("view", view);
outline_shader.setMat4("projection", projection);
for(auto& thing : things) {
if(thing.name != "metal_floor") {
draw_model(outline_shader, thing.model, thing.material, projection, view, thing.position, 1.01f);
}
}
glStencilMask(0xFF);
glStencilFunc(GL_ALWAYS, 0, 0xFF);
glEnable(GL_DEPTH_TEST);
}
void Scene::cleanup() {
@ -64,8 +88,13 @@ void Scene::cleanup() {
}
void Scene::spawn(const std::string& name, components::Position& position) {
things.emplace_back(
models.at(name),
position,
materials.at(name));
if(models.contains(name)) {
things.emplace_back(
name,
models.at(name),
position,
materials.at("default"));
} else {
dbc::log($F("No model named: {}", name));
}
}

View file

@ -14,6 +14,7 @@
#include <vector>
struct Thing {
std::string name;
Model& model;
components::Position position;
Material& material;
@ -22,6 +23,8 @@ struct Thing {
struct Scene {
Shader shader;
Shader light_shader;
Shader outline_shader;
std::map<std::string, components::Material> materials;
Camera camera;
components::Lighting light;
@ -34,6 +37,7 @@ struct Scene {
Scene(components::Scene& config):
shader{config.shader.vertex_path, config.shader.frag_path},
light_shader{config.light_shader.vertex_path, config.shader.frag_path},
outline_shader{config.outline_shader.vertex_path, config.outline_shader.frag_path},
materials{config.materials},
camera{
.position=config.camera.position,
@ -50,6 +54,7 @@ struct Scene {
for(auto& thing : config.things) {
things.emplace_back(
thing.model,
models.at(thing.model),
thing.position,
materials.at(thing.material));
@ -60,7 +65,7 @@ struct Scene {
}
void update();
void draw_model(Model& scene_model, Material& material, glm::mat4& projection, glm::mat4& view, glm::vec3& position);
void draw_model(Shader& with_shader, Model& scene_model, Material& material, glm::mat4& projection, glm::mat4& view, glm::vec3& position, float scale=1.0f);
void render(GLFWwindow* window);
void cleanup();
void spawn(const std::string& name, components::Position& position);