summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-01-11 22:26:10 +1100
committerquou <quou@disroot.org>2025-01-11 22:26:10 +1100
commit306c6318a32a9af351daaa60d2cc082e45e30dd4 (patch)
treef0f662a4c8d75e7afef30684ce13b57e30bde35a
parent64b32afb4e1fed0259b67a47e8b8ff30e4e20635 (diff)
mip the specular cube properly
-rw-r--r--c2.cpp114
-rw-r--r--intermediate/mip_spec.glsl72
-rw-r--r--todo.txt2
3 files changed, 142 insertions, 46 deletions
diff --git a/c2.cpp b/c2.cpp
index 2d4ad14..9d680e3 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -285,13 +285,36 @@ struct Env_Probe {
static constexpr int mip_count = 9;
Texture_Id cubemap[2];
Texture_Id cubemap_depth;
- Texture_Id faces[2][6][mip_count];
+ Texture_Id faces_render[6];
+ Texture_Id faces[6][mip_count];
Sampler_Id sampler;
int cubemap_res;
- int completed;
Staged_Buffer config;
+ Staged_Buffer face_cb[6][mip_count];
Shader* shader;
- int src_binding, vert_binding;
+ int src_binding, vert_binding, face_binding;
+
+ struct Face_Cbuffer {
+ float dir[3];
+ float roughness;
+ float up[3];
+ };
+ v3f face_dirs[6] = {
+ 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 face_ups[6] = {
+ 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)
+ };
void init(Device* dev, Asset_Arena* assets, int res) {
int i;
@@ -345,22 +368,28 @@ struct Env_Probe {
int j;
int w = res;
int h = res;
+ faces_render[i] = dev->alias_texture(
+ cubemap[0],
+ "env cubemap face A",
+ texture_format_rgba16f,
+ Texture_Flags::colour_target |
+ Texture_Flags::sampleable,
+ w,
+ h,
+ 1,
+ 1,
+ 1,
+ 0,
+ i
+ );
for (j = 0; j < mip_count; j++) {
- faces[0][i][j] = dev->alias_texture(
- cubemap[0],
- "env cubemap face A",
- texture_format_rgba16f,
- Texture_Flags::colour_target |
- Texture_Flags::sampleable,
- w,
- h,
- 1,
- 1,
- 1,
- j,
- i
+ face_cb[i][j].init(
+ dev,
+ "env probe mip face cbuffer",
+ sizeof(Face_Cbuffer),
+ Buffer_Flags::constant_buffer
);
- faces[1][i][j] = dev->alias_texture(
+ faces[i][j] = dev->alias_texture(
cubemap[1],
"env cubemap face B",
texture_format_rgba16f,
@@ -386,6 +415,7 @@ struct Env_Probe {
);
shader = (Shader*)assets->load("mip_spec.csh");
src_binding = shader->descriptor_binding("src");
+ face_binding = shader->descriptor_binding("c_face");
vert_binding = shader->binding_index("verts");
assert(src_binding >= 0);
assert(vert_binding >= 0);
@@ -396,9 +426,10 @@ struct Env_Probe {
for (i = 0; i < 6; i++) {
int j;
for (j = 0; j < mip_count; j++) {
- dev->destroy_texture(faces[0][i][j]);
- dev->destroy_texture(faces[1][i][j]);
+ dev->destroy_texture(faces[i][j]);
+ face_cb[i][j].destroy(dev);
}
+ dev->destroy_texture(faces_render[i]);
}
dev->destroy_texture(cubemap_depth);
dev->destroy_sampler(sampler);
@@ -417,25 +448,9 @@ struct Env_Probe {
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]);
+ m4f view = m4f::lookat(v3f(0.0f), face_dirs[i], face_ups[i]);
buf.iview = view.inverse();
buf.iprojection = iproj;
}
@@ -449,8 +464,21 @@ struct Env_Probe {
Context& ctx = dev->get_ctx();
update_cbuffer(dev);
for (i = 0; i < 6; i++) {
+ int j;
+ for (j = 0; j < mip_count; j++) {
+ Face_Cbuffer* cb = (Face_Cbuffer*)face_cb[i][j].map(dev);
+ cb->dir[0] = face_dirs[i].x;
+ cb->dir[1] = face_dirs[i].y;
+ cb->dir[2] = face_dirs[i].z;
+ cb->roughness = (float)j / (float)(mip_count - 1);
+ cb->up[0] = face_ups[i].x;
+ cb->up[1] = face_ups[i].y;
+ cb->up[2] = face_ups[i].z;
+ face_cb[i][j].unmap(dev);
+ face_cb[i][j].update(ctx);
+ }
pb.begin_rp();
- pb.rp_target(faces[0][i][0], Clear_Mode::discard);
+ pb.rp_target(faces_render[i], Clear_Mode::discard);
pb.rp_depth_target(cubemap_depth, 1.0f);
sky.render_imp(
dev,
@@ -463,20 +491,23 @@ struct Env_Probe {
cubemap_res
);
}
- completed = 0;
for (i = 0; i < 6; i++) {
int j;
for (j = 0; j < mip_count; j++) {
- Texture& t = dev->get_texture(faces[completed ^ 1][i][j]);
+ Texture& t = dev->get_texture(faces[i][j]);
pb.begin_rp();
pb.rp_target(t.id, Clear_Mode::discard);
Render_Pass& pass = pb.build_rp();
pb.begin();
pb.viewport(0, 0, t.w, t.h);
pb.scissor(0, 0, t.w, t.h);
+ pb.cbuffer(
+ face_binding,
+ face_cb[i][j].gpuonly
+ );
pb.texture(
src_binding,
- faces[completed][i][0],
+ cubemap[0],
sampler
);
pb.shader(shader->id);
@@ -495,11 +526,10 @@ struct Env_Probe {
ctx.submit(draw, pip, pass);
}
}
- completed = 1;
}
Texture_Id get_cubemap() {
- return cubemap[completed];
+ return cubemap[1];
}
};
diff --git a/intermediate/mip_spec.glsl b/intermediate/mip_spec.glsl
index bddcbb0..519fee0 100644
--- a/intermediate/mip_spec.glsl
+++ b/intermediate/mip_spec.glsl
@@ -18,10 +18,27 @@ type: vec2
name: uv
type: vec2
+[struct]
+name: Face
+[variable]
+name: dir
+type: vec3
+[variable]
+name: roughness
+type: float
+[variable]
+name: up
+type: vec3
+
+[cbuffer]
+name: c_face
+type: Face
+stage: fragment
+
[texture]
name: src
stage: fragment
-dimension: 2
+dimension: cube
[target]
name: colour
@@ -36,9 +53,58 @@ void main() {
#endif
#ifdef FRAGMENT_SHADER
+float ri(uint bits) {
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xaaaaaaaau) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xccccccccu) >> 2u);
+ bits = ((bits & 0x0f0f0f0fu) << 4u) | ((bits & 0xf0f0f0f0u) >> 4u);
+ bits = ((bits & 0x00ff00ffu) << 8u) | ((bits & 0xff00ff00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10;
+}
+
+vec2 hammersley(uint i, uint n) {
+ return vec2(float(i) / float(n), ri(i));
+}
+
+#define pi 3.14159265358979323846
+
+vec3 importance_sample_ggx(vec2 xi, float rough, vec3 n) {
+ float a = rough * rough;
+ float phi = 2 * pi * xi.x;
+ float ct = sqrt((1 - xi.y) / (1 + (a * a - 1) * xi.y));
+ float st = sqrt(1 - ct * ct);
+ vec3 h;
+ h.x = st * cos(phi);
+ h.y = st * sin(phi);
+ h.z = ct;
+ vec3 up = abs(n.z) < 0.999 ? vec3(0, 0, 1) : vec3(1, 0, 0);
+ vec3 tx = normalize(cross(up, n));
+ vec3 ty = cross(n, tx);
+ return tx * h.x + ty * h.y + n * h.z;
+}
+
+vec3 prefilter_env(float rough, vec3 n) {
+ vec3 c = 0.0.xxx;
+ int i, samples = 32;
+ float w = 1.0 / float(samples);
+ for (i = 0; i < samples; i++) {
+ vec2 coord = hammersley(i, samples);
+ vec3 s = importance_sample_ggx(coord, rough, n);
+ vec3 l = 2.0 * dot(n, s) * s - n;
+ c += (textureLod(src, l, 0.0).rgb * max(dot(n, l), 0.0)) * w;
+ }
+ return c;
+}
+
void main() {
- vec2 uv = interpolator.uv;
- colour = texture(src, uv);
+ vec2 uv = interpolator.uv * 2.0 - 1.0;
+ vec3 n = c_face.dir;
+ vec3 u = c_face.up;
+ vec3 p1 = normalize(cross(n, u));
+ vec3 p2 = normalize(cross(n, p1));
+ vec3 uvw = uv.x * p1 + uv.y * p2;
+ n = normalize(n + uvw);
+ colour = vec4(prefilter_env(c_face.roughness, n), 1.0);
}
#endif
diff --git a/todo.txt b/todo.txt
index b090b4a..984a251 100644
--- a/todo.txt
+++ b/todo.txt
@@ -17,7 +17,7 @@ todo list
- [ ] memory debug tool
- [x] material system
- [x] render a sky box
- - [ ] PBR + IBL
+ - [x] PBR + IBL
- [ ] shadows
- [ ] MSAA
- [ ] GI