summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-01-06 22:05:05 +1100
committerquou <quou@disroot.org>2025-01-06 22:07:10 +1100
commitce6efd3b28b5cec813c715a57a884199fa3b3ce1 (patch)
tree239e6e9b4b376f9b2cc294d564f69ae0e501e778
parent1006ccf490c473447498a5c1a290e4dd9b55b7c2 (diff)
environment mapping
-rw-r--r--c2.cpp176
-rw-r--r--intermediate/surface.glsl17
-rw-r--r--model.cpp11
-rw-r--r--model.hpp3
4 files changed, 198 insertions, 9 deletions
diff --git a/c2.cpp b/c2.cpp
index 0c231eb..5268117 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -230,10 +230,34 @@ struct Sky {
Sampler_Id sampler,
const Camera& cam
) {
+ Texture_Id backbuffer_id = d->get_backbuffer();
+ Texture& backbuffer = d->get_texture(backbuffer_id);
Cbuffer* cb = (Cbuffer*)config.map(d);
cb->iview = cam.get_view().inverse();
cb->iprojection = cam.get_proj().inverse();
config.unmap(d);
+ render_imp(
+ d,
+ a,
+ pass,
+ sampler,
+ config.gpuonly,
+ 0,
+ backbuffer.w,
+ backbuffer.h
+ );
+ }
+
+ void render_imp(
+ Device* d,
+ Arena* a,
+ Render_Pass& pass,
+ Sampler_Id sampler,
+ Buffer_Id cbuffer,
+ int offset,
+ int w,
+ int h
+ ) {
Context& ctx = d->get_ctx();
Pipeline_Builder pb(a, d);
pb.begin();
@@ -244,7 +268,9 @@ struct Sky {
texture,
sampler
);
- pb.cbuffer(cfg_binding, config.gpuonly);
+ pb.viewport(0, 0, w, h);
+ pb.scissor(0, 0, w, h);
+ pb.cbuffer(cfg_binding, cbuffer, offset, sizeof(Cbuffer));
pb.depth(true, false, Depth_Mode::equal);
Pipeline& pip = pb.build();
@@ -263,6 +289,143 @@ struct Sky {
}
};
+struct Env_Probe {
+ Texture_Id cubemap;
+ Texture_Id cubemap_depth;
+ Texture_Id faces[6];
+ Sampler_Id sampler;
+ int cubemap_res;
+ Staged_Buffer config;
+
+ void init(Device* dev, Asset_Arena* assets, int res) {
+ int i;
+ Sampler_State s{};
+ cubemap_res = res;
+ s.min = Filter_Mode::linear;
+ s.mag = Filter_Mode::linear;
+ s.address_u = Address_Mode::repeat;
+ s.address_v = Address_Mode::repeat;
+ sampler = dev->create_sampler("env probe sampler", s);
+ cubemap_depth = dev->create_texture(
+ "env cubemap depth",
+ texture_format_d16,
+ Texture_Flags::sampleable | Texture_Flags::depth_stencil_target,
+ res,
+ res,
+ 1,
+ 1,
+ 1,
+ 0
+ );
+ cubemap = dev->create_texture(
+ "env cubemap",
+ texture_format_rgba16f,
+ Texture_Flags::cubemap |
+ Texture_Flags::colour_target |
+ Texture_Flags::sampleable,
+ res,
+ res,
+ 1,
+ 1,
+ 1,
+ Buffer_Id(0)
+ );
+ for (i = 0; i < 6; i++) {
+ faces[i] = dev->alias_texture(
+ cubemap,
+ "env cubemap face",
+ texture_format_rgba16f,
+ Texture_Flags::colour_target |
+ Texture_Flags::sampleable,
+ res,
+ res,
+ 1,
+ 1,
+ 1,
+ 0,
+ i
+ );
+ }
+ config.init(
+ dev,
+ "env probe sky cbuffer",
+ sizeof(Sky::Cbuffer) * 6,
+ Buffer_Flags::constant_buffer
+ );
+ }
+
+ void destroy(Device* dev) {
+ int i;
+ for (i = 0; i < 6; i++) {
+ dev->destroy_texture(faces[i]);
+ }
+ dev->destroy_texture(cubemap_depth);
+ dev->destroy_sampler(sampler);
+ dev->destroy_texture(cubemap);
+ config.destroy(dev);
+ }
+
+ void update_cbuffer(Device* dev) {
+ int i;
+ Context& ctx = dev->get_ctx();
+ Sky::Cbuffer* bufs = (Sky::Cbuffer*)config.map(dev);
+ m4f iproj = m4f::pers(
+ 90.0f,
+ 1.0f,
+ 0.1f,
+ 1000.0f
+ ).inverse();
+ v3f dirs[] = {
+ v3f( 1.0f, 0.0f, 0.0f),
+ v3f(-1.0f, 0.0f, 0.0f),
+ v3f( 0.0f, 1.0f, 0.0f),
+ v3f( 0.0f, -1.0f, 0.0f),
+ v3f( 0.0f, 0.0f, -1.0f),
+ v3f( 0.0f, 0.0f, 1.0f)
+ };
+ v3f ups[] = {
+ v3f(0.0f, 1.0f, 0.0f),
+ v3f(0.0f, 1.0f, 0.0f),
+ v3f(0.0f, 0.0f, 1.0f),
+ v3f(0.0f, 0.0f, -1.0f),
+ v3f(0.0f, 1.0f, 0.0f),
+ v3f(0.0f, 1.0f, 0.0f)
+ };
+ for (i = 0; i < 6; i++) {
+ Sky::Cbuffer& buf = bufs[i];
+ m4f view = m4f::lookat(v3f(0.0f), dirs[i], ups[i]);
+ buf.iview = view.inverse();
+ buf.iprojection = iproj;
+ }
+ config.unmap(dev);
+ config.update(ctx);
+ }
+
+ void render(Device* dev, Arena* a, Sky& sky) {
+ int i;
+ Pipeline_Builder pb(a, dev);
+ Context& ctx = dev->get_ctx();
+ update_cbuffer(dev);
+ for (i = 0; i < 6; i++) {
+ ctx.transition(faces[i], Resource_State::render_target);
+ pb.begin_rp();
+ pb.rp_target(faces[i], Clear_Mode::discard);
+ pb.rp_depth_target(cubemap_depth, 1.0f);
+ sky.render_imp(
+ dev,
+ a,
+ pb.build_rp(),
+ sampler,
+ config.gpuonly,
+ i * sizeof(Sky::Cbuffer),
+ cubemap_res,
+ cubemap_res
+ );
+ ctx.transition(faces[i], Resource_State::shader_read);
+ }
+ }
+};
+
struct Config_Buffer {
float offset[2];
};
@@ -286,6 +449,7 @@ extern "C" int entrypoint() {
Model_Scene scene;
Orbit_Cam camera;
Sky sky;
+ Env_Probe eprobe;
Buffer_Id vbo, cbuf;
Sampler_Id clamped_linear;
C2* app = App::create<C2>("c2");
@@ -350,6 +514,7 @@ extern "C" int entrypoint() {
(Model*)assets.load("monkey.mdl")
);
sky.init(dev, &assets);
+ eprobe.init(dev, &assets, 256);
camera.init();
while (app->running) {
Arena frame_arena;
@@ -428,6 +593,10 @@ extern "C" int entrypoint() {
pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore);
Render_Pass& sky_pass = pb.build_rp();
+ ctx.debug_push("environment cube");
+ eprobe.render(dev, &frame_arena, sky);
+ ctx.debug_pop();
+
Texture& bb = dev->get_texture(dev->get_backbuffer());
monkey->transform = m4f::translate(
m4f::identity(),
@@ -450,10 +619,10 @@ extern "C" int entrypoint() {
scene.update(camera, dev);
ctx.debug_push("scene");
ctx.debug_push("depth prepass");
- scene.render(dev, &frame_arena, depth_prepass, clamped_linear);
+ scene.render(dev, &frame_arena, depth_prepass, 0, clamped_linear);
ctx.debug_pop();
ctx.debug_push("forward");
- scene.render(dev, &frame_arena, pass2, clamped_linear);
+ scene.render(dev, &frame_arena, pass2, eprobe.cubemap, clamped_linear);
ctx.debug_pop();
ctx.debug_pop();
@@ -479,6 +648,7 @@ extern "C" int entrypoint() {
}
scene.destroy(dev);
sky.destroy(dev);
+ eprobe.destroy(dev);
ui->destroy();
assets.destroy();
dev->destroy_texture(default_texture);
diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl
index 5feb09f..8ec24f0 100644
--- a/intermediate/surface.glsl
+++ b/intermediate/surface.glsl
@@ -87,6 +87,10 @@ dimension: 2
name: normal
stage: fragment
dimension: 2
+[texture]
+name: env_cube
+stage: fragment
+dimension: cube
[target]
name: colour
@@ -126,10 +130,9 @@ float specular_G1(float a, vec3 v, vec3 n) {
return ndv / (ndv * (1.0 - k) + k);
}
-float specular_brdf(vec2 uv, vec3 l, vec3 v, vec3 n) {
+float specular_brdf(vec2 uv, vec3 ref, vec3 l, vec3 v, vec3 n) {
float ndl = max(dot(n, l), 0.0);
float ndv = max(dot(n, v), 0.0);
- vec3 ref = reflect(-l, n);
float a = texture(rough, uv).r * material.roughness;
float a2 = a * a;
float ndr = max(dot(n, ref), 0.0);
@@ -161,16 +164,20 @@ void main() {
vec3 view_dir = normalize(material.camera_pos - p);
float met = texture(metal, uv).r * material.metalness;
+ vec3 ref = reflect(-view_dir, nrm);
+ vec3 spec_col = texture(env_cube, ref).rgb;
+ vec3 amb_col = texture(env_cube, nrm).rgb;
+
vec3 diffuse =
diffuse_brdf(uv) *
(1.0 - met) *
cos_theta_i;
vec3 spec =
- mix(1.0.xxx, col, met) *
- specular_brdf(uv, light_dir, view_dir, nrm) *
+ mix(spec_col, col, met) *
+ specular_brdf(uv, ref, light_dir, view_dir, nrm) *
cos_theta_i;
vec3 ambient =
- min(col, 0.05) *
+ min(amb_col, 0.05) *
texture(ao, uv).r;
colour = vec4(ambient + diffuse + spec, 1.0);
diff --git a/model.cpp b/model.cpp
index 778d945..dac6538 100644
--- a/model.cpp
+++ b/model.cpp
@@ -128,10 +128,12 @@ Asset* Model_Loader::load(
mesh.mvp_binding = shader->descriptor_binding("c_mvp");
mesh.mvp_binding_depth = depth_shader->descriptor_binding("c_mvp");
mesh.mat_binding = shader->descriptor_binding("material");
+ mesh.env_cube_binding = shader->descriptor_binding("env_cube");
mesh.mesh_binding = shader->binding_index("mesh");
assert(mesh.mvp_binding >= 0);
assert(mesh.mat_binding >= 0);
assert(mesh.mesh_binding >= 0);
+ assert(mesh.env_cube_binding >= 0);
pack_read(f, &vertex_size, 4);
pack_read(f, &mesh.count, 4);
pack_read(f, &vertex_count, 4);
@@ -330,6 +332,7 @@ void Model_Instance::render(
Device* dev,
Arena* a,
Render_Pass& pass,
+ Texture_Id env_cubemap,
Sampler_Id sampler
) {
int i, c = m->mesh_count;
@@ -382,6 +385,11 @@ void Model_Instance::render(
i * sizeof(MVP_Cbuffer),
sizeof(MVP_Cbuffer)
);
+ pb.texture(
+ mesh.env_cube_binding,
+ env_cubemap,
+ sampler
+ );
}
pb.cull(Cull_Mode::back);
pb.vertex_format(shader.vf);
@@ -433,12 +441,13 @@ void Model_Scene::render(
Device* dev,
Arena* a,
Render_Pass& pass,
+ Texture_Id env_cubemap,
Sampler_Id sampler
) {
int i;
Model_Instance* instance = instances;
for (i = 0; i < count; i++, instance++)
- instance->render(dev, a, pass, sampler);
+ instance->render(dev, a, pass, env_cubemap, sampler);
}
void Model_Scene::destroy(Device* dev) {
diff --git a/model.hpp b/model.hpp
index 7b8f4fb..f21c35e 100644
--- a/model.hpp
+++ b/model.hpp
@@ -26,6 +26,7 @@ struct Model;
struct Mesh {
int offset, vbo_offset, count;
int parent, mesh_binding, mvp_binding, mat_binding;
+ int env_cube_binding;
int mvp_binding_depth;
bool world_dirty;
m4f world, local;
@@ -99,6 +100,7 @@ struct Model_Instance {
Device* dev,
Arena* a,
Render_Pass& pass,
+ Texture_Id env_cubemap,
Sampler_Id sampler
);
};
@@ -118,6 +120,7 @@ struct Model_Scene {
Device* dev,
Arena* a,
Render_Pass& pass,
+ Texture_Id env_cubemap,
Sampler_Id sampler
);
};