diff options
author | quou <quou@disroot.org> | 2025-01-06 22:05:05 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-01-06 22:07:10 +1100 |
commit | ce6efd3b28b5cec813c715a57a884199fa3b3ce1 (patch) | |
tree | 239e6e9b4b376f9b2cc294d564f69ae0e501e778 | |
parent | 1006ccf490c473447498a5c1a290e4dd9b55b7c2 (diff) |
environment mapping
-rw-r--r-- | c2.cpp | 176 | ||||
-rw-r--r-- | intermediate/surface.glsl | 17 | ||||
-rw-r--r-- | model.cpp | 11 | ||||
-rw-r--r-- | model.hpp | 3 |
4 files changed, 198 insertions, 9 deletions
@@ -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); @@ -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) { @@ -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 ); }; |