Point light shadow maps with filtering, improve bias with normal offset
This commit is contained in:
parent
daf85fc614
commit
95d30aacda
38
assets/shaders/cube_shadow.glsl
Normal file
38
assets/shaders/cube_shadow.glsl
Normal file
@ -0,0 +1,38 @@
|
||||
// UBOs
|
||||
layout(std140, binding = 0) uniform Matrices {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
};
|
||||
|
||||
// Uniforms
|
||||
layout(location = 1) uniform mat4 model;
|
||||
layout(location = 18) uniform vec2 near_far;
|
||||
|
||||
// Input, output blocks
|
||||
VERTEX_EXPORT VertexData {
|
||||
vec3 vPos;
|
||||
} VertexOut;
|
||||
|
||||
#if VERTEX_SHADER
|
||||
|
||||
layout(location = 0) in vec3 aPos;
|
||||
|
||||
void main() {
|
||||
vec4 vPos = view * model * vec4(aPos.xyz, 1.0);
|
||||
gl_Position = projection * vPos;
|
||||
VertexOut.vPos = vPos.xyz;
|
||||
}
|
||||
#endif // VERTEX_SHADER
|
||||
|
||||
#if FRAGMENT_SHADER
|
||||
|
||||
float map(float value, float min1, float max1, float min2, float max2) {
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
void main() {
|
||||
gl_FragDepth = map(length(VertexOut.vPos), near_far.x, near_far.y, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif // FRAGMNET_SHADER
|
6
assets/shaders/cube_shadow.prog
Normal file
6
assets/shaders/cube_shadow.prog
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
{
|
||||
"shader": "cube_shadow.glsl",
|
||||
"vertex": true,
|
||||
"fragment": true
|
||||
}
|
@ -7,6 +7,8 @@
|
||||
struct Light {
|
||||
vec4 vPos;
|
||||
vec4 color;
|
||||
mat4 shadow_vp; // for spot and dir lights
|
||||
vec2 near_far; // for point lights
|
||||
};
|
||||
|
||||
// UBOs
|
||||
@ -44,7 +46,7 @@ layout(location = 14, bindless_sampler) uniform sampler2D emission_map;
|
||||
layout(location = 15) uniform vec2 emission_map_uv_scale = vec2(1);
|
||||
|
||||
layout(location = 16, bindless_sampler) uniform sampler2DArrayShadow shadow_maps;
|
||||
layout(location = 17) uniform mat4 shadow_map_vp;
|
||||
layout(location = 17, bindless_sampler) uniform samplerCubeArrayShadow cube_shadow_maps;
|
||||
|
||||
|
||||
// Input, output blocks
|
||||
@ -54,6 +56,7 @@ VERTEX_EXPORT VertexData {
|
||||
vec2 uv;
|
||||
mat3 vTBN;
|
||||
vec3 wPos;
|
||||
vec3 wNormal;
|
||||
} VertexOut;
|
||||
|
||||
float random(vec4 seed4) {
|
||||
@ -81,6 +84,7 @@ void main() {
|
||||
VertexOut.vTBN = mat3(T, B, N);
|
||||
vec4 wPos = model * vec4(aPos.xyz, 1.0);
|
||||
VertexOut.wPos = wPos.xyz / wPos.w;
|
||||
VertexOut.wNormal = normalize(model * vec4(aNormal, 0.0)).xyz;
|
||||
}
|
||||
#endif // VERTEX_SHADER
|
||||
|
||||
@ -145,7 +149,11 @@ vec2 poissonDisk[4] = vec2[](
|
||||
vec2( 0.34495938, 0.29387760 )
|
||||
);
|
||||
|
||||
vec3 microfacetModel(Material mat, Light light, vec3 P, vec3 N) {
|
||||
float map(float value, float min1, float max1, float min2, float max2) {
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
vec3 microfacetModel(Material mat, int light_idx, Light light, vec3 P, vec3 N) {
|
||||
vec3 diffuseBrdf = vec3(0); // metallic
|
||||
if (!mat.metallic) {
|
||||
diffuseBrdf = mat.albedo;
|
||||
@ -177,37 +185,60 @@ vec3 microfacetModel(Material mat, Light light, vec3 P, vec3 N) {
|
||||
float NDotL = max(dot(N, L), 0);
|
||||
float NDotV = dot(N, V);
|
||||
|
||||
float normal_offset_scale = clamp(1 - NDotL, 0, 1);
|
||||
normal_offset_scale *= 10; // constant
|
||||
|
||||
float constant_bias = 0.001;
|
||||
float shadow_mult = 1;
|
||||
//// TODO: Shadows for directional light only for now
|
||||
if (point == 0) {
|
||||
vec4 shadow_pos = shadow_map_vp * vec4(VertexOut.wPos, 1.0);
|
||||
vec4 shadow_offset = vec4(VertexOut.wNormal * normal_offset_scale, 0);
|
||||
if (point == 1) {
|
||||
vec2 shadow_map_texel_size = 1.0 / vec2(textureSize(cube_shadow_maps, 0));
|
||||
shadow_offset *= shadow_map_texel_size.x;
|
||||
vec3 shadow_dir = (light.shadow_vp * vec4(VertexOut.wPos, 1.0)).xyz;
|
||||
float world_depth = length(shadow_dir.xyz);
|
||||
shadow_dir = normalize((light.shadow_vp * (vec4(VertexOut.wPos, 1.0) + shadow_offset)).xyz);
|
||||
float mapped_depth = map(world_depth, light.near_far.x, light.near_far.y, 0, 1);
|
||||
|
||||
vec4 texcoord;
|
||||
texcoord.xyz = shadow_dir;
|
||||
texcoord.w = float(light_idx);
|
||||
|
||||
float sum = 0;
|
||||
for (float z = -1; z <= 1; z += 1) {
|
||||
for (float y = -1; y <= 1; y += 1) {
|
||||
for (float x = -1; x <= 1; x += 1) {
|
||||
sum += texture(cube_shadow_maps, vec4(normalize(texcoord.xyz + vec3(x, y, z) * shadow_map_texel_size.x), texcoord.w), mapped_depth - constant_bias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadow_mult = sum / 27;
|
||||
} else {
|
||||
vec2 shadow_map_texel_size = 1.0 / vec2(textureSize(shadow_maps, 0));
|
||||
shadow_offset *= shadow_map_texel_size.x;
|
||||
// Directional shadow
|
||||
vec4 shadow_pos = light.shadow_vp * vec4(VertexOut.wPos, 1.0);
|
||||
shadow_pos.xy = (light.shadow_vp * (vec4(VertexOut.wPos, 1.0) + shadow_offset)).xy;
|
||||
shadow_pos /= shadow_pos.w;
|
||||
shadow_pos.xyz = shadow_pos.xyz * 0.5 + 0.5; // [-1, 1] to [0, 1]
|
||||
float bias = 0.005 * tan(acos(NDotL));
|
||||
shadow_pos.z -= bias;
|
||||
shadow_pos.z -= constant_bias;
|
||||
|
||||
|
||||
vec4 texcoord;
|
||||
texcoord.xyw = shadow_pos.xyz; // sampler2DArrayShadow strange texcoord mapping
|
||||
texcoord.z = 0; // First shadow map
|
||||
|
||||
float sum = 0;
|
||||
vec2 tex_scale = 1.0 / vec2(textureSize(shadow_maps, 0));
|
||||
|
||||
for (float y = -1.5; y <= 1.5; y += 1) {
|
||||
for (float x = -1.5; x <= 1.5; x += 1) {
|
||||
sum += texture(shadow_maps, vec4(texcoord.xy + vec2(x, y) * tex_scale, texcoord.zw));
|
||||
sum += texture(shadow_maps, vec4(texcoord.xy + vec2(x, y) * shadow_map_texel_size, texcoord.zw));
|
||||
}
|
||||
}
|
||||
|
||||
shadow_mult = sum / 16.0;
|
||||
|
||||
// for (int i=0; i<4; i++){
|
||||
// int index = int(16.0 * random(vec4(VertexOut.wPos.xyz * 1000.0, i))) % 4;
|
||||
// float depth_test = texture(shadow_maps, vec4(texcoord.xy + poissonDisk[index]/700.0, texcoord.zw));
|
||||
// shadow_mult -= 0.25 * (1 - depth_test);
|
||||
// }
|
||||
//shadow_mult = texture(shadow_maps, texcoord);
|
||||
}
|
||||
shadow_mult = clamp(shadow_mult, 0, 1);
|
||||
|
||||
vec3 specBrdf = 0.25 * ggxDistribution(mat, NDotH) * schlickFresnel(mat, LDotH) * geomSmith(mat, NDotL) * geomSmith(mat, NDotV);
|
||||
|
||||
@ -226,7 +257,7 @@ void main() {
|
||||
vec3 finalColor = vec3(0);
|
||||
|
||||
for (int i = 0; i < lights_count; i++) {
|
||||
finalColor += microfacetModel(material, lights[i], VertexOut.vPos, N);
|
||||
finalColor += microfacetModel(material, i, lights[i], VertexOut.vPos, N);
|
||||
}
|
||||
|
||||
FragColor = vec4(finalColor, 1.0f);
|
||||
|
@ -20,8 +20,9 @@ void main() {
|
||||
|
||||
#if FRAGMENT_SHADER
|
||||
|
||||
|
||||
void main() {
|
||||
gl_FragDepth = gl_FragCoord.z / gl_FragCoord.w;
|
||||
//gl_FragDepth = gl_FragCoord.z / gl_FragCoord.w;
|
||||
}
|
||||
|
||||
|
||||
|
272
src/Render.zig
272
src/Render.zig
@ -36,11 +36,14 @@ command_buffer: [MAX_DRAW_COMMANDS]DrawCommand = undefined,
|
||||
command_count: usize = 0,
|
||||
ubo_align: usize = 0,
|
||||
shadow_vao: gl.GLuint = 0,
|
||||
shadow_texture_arrray: gl.GLuint = 0,
|
||||
shadow_texture_array: gl.GLuint = 0,
|
||||
shadow_texture_handle: gl.GLuint64 = 0,
|
||||
shadow_framebuffer: gl.GLuint = 0,
|
||||
shadow_matrices_buffer: gl.GLuint = 0,
|
||||
shadow_matrices: CameraMatrices = .{},
|
||||
cube_shadow_texture_array: gl.GLuint = 0,
|
||||
cube_shadow_texture_handle: gl.GLuint64 = 0,
|
||||
cube_shadow_framebuffer: gl.GLuint = 0,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetman: *AssetManager) Render {
|
||||
var render = Render{
|
||||
@ -136,34 +139,68 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
||||
}
|
||||
|
||||
{
|
||||
// Shadow texture array
|
||||
gl.createTextures(gl.TEXTURE_2D_ARRAY, 1, &render.shadow_texture_arrray);
|
||||
checkGLError();
|
||||
std.debug.assert(render.shadow_texture_arrray != 0);
|
||||
// 2D Shadow texture array
|
||||
{
|
||||
gl.createTextures(gl.TEXTURE_2D_ARRAY, 1, &render.shadow_texture_array);
|
||||
checkGLError();
|
||||
std.debug.assert(render.shadow_texture_array != 0);
|
||||
|
||||
gl.textureStorage3D(render.shadow_texture_arrray, 1, gl.DEPTH_COMPONENT16, 2048, 2048, 1);
|
||||
checkGLError();
|
||||
gl.textureStorage3D(render.shadow_texture_array, 1, gl.DEPTH_COMPONENT16, 2048, 2048, 1);
|
||||
checkGLError();
|
||||
|
||||
gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
|
||||
gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_COMPARE_FUNC, gl.LESS);
|
||||
gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER);
|
||||
gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER);
|
||||
gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.textureParameterfv(render.shadow_texture_arrray, gl.TEXTURE_BORDER_COLOR, @ptrCast(&Vec4.one().data));
|
||||
gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
|
||||
gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_COMPARE_FUNC, gl.LESS);
|
||||
gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER);
|
||||
gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER);
|
||||
gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.textureParameterfv(render.shadow_texture_array, gl.TEXTURE_BORDER_COLOR, @ptrCast(&Vec4.one().data));
|
||||
}
|
||||
|
||||
// First shadow texture handle
|
||||
render.shadow_texture_handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(render.shadow_texture_arrray);
|
||||
checkGLError();
|
||||
gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(render.shadow_texture_handle);
|
||||
checkGLError();
|
||||
{
|
||||
render.shadow_texture_handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(render.shadow_texture_array);
|
||||
checkGLError();
|
||||
std.debug.assert(render.shadow_texture_handle != 0);
|
||||
gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(render.shadow_texture_handle);
|
||||
checkGLError();
|
||||
}
|
||||
|
||||
// Cube Shadow texture array
|
||||
{
|
||||
gl.createTextures(gl.TEXTURE_CUBE_MAP_ARRAY, 1, &render.cube_shadow_texture_array);
|
||||
checkGLError();
|
||||
std.debug.assert(render.cube_shadow_texture_array != 0);
|
||||
|
||||
gl.textureStorage3D(render.cube_shadow_texture_array, 1, gl.DEPTH_COMPONENT16, 512, 512, MAX_POINT_LIGHTS * 6);
|
||||
checkGLError();
|
||||
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_COMPARE_FUNC, gl.LESS);
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
// Cube Shadow array handle
|
||||
{
|
||||
render.cube_shadow_texture_handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(render.cube_shadow_texture_array);
|
||||
checkGLError();
|
||||
std.debug.assert(render.cube_shadow_texture_handle != 0);
|
||||
gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(render.cube_shadow_texture_handle);
|
||||
checkGLError();
|
||||
}
|
||||
|
||||
// Shadow FBO
|
||||
gl.createFramebuffers(1, &render.shadow_framebuffer);
|
||||
checkGLError();
|
||||
std.debug.assert(render.shadow_framebuffer != 0);
|
||||
{
|
||||
gl.createFramebuffers(1, &render.shadow_framebuffer);
|
||||
checkGLError();
|
||||
std.debug.assert(render.shadow_framebuffer != 0);
|
||||
}
|
||||
|
||||
gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.shadow_texture_arrray, 0, 0);
|
||||
gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.shadow_texture_array, 0, 0);
|
||||
const check_fbo_status = gl.checkNamedFramebufferStatus(render.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
||||
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
||||
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
||||
@ -251,61 +288,88 @@ pub fn draw(self: *Render, cmd: DrawCommand) void {
|
||||
pub fn finish(self: *Render) void {
|
||||
const ginit = globals.g_init;
|
||||
|
||||
var dir_light: ?PointLight = null;
|
||||
var dir_light_vp: ?Mat4 = null;
|
||||
const lights = self.getPointLights();
|
||||
|
||||
// Find directional light
|
||||
// Light shadow maps
|
||||
{
|
||||
const lights = self.getPointLights();
|
||||
gl.bindVertexArray(self.shadow_vao);
|
||||
|
||||
for (lights.lights[0..lights.count]) |*light| {
|
||||
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, self.shadow_framebuffer);
|
||||
|
||||
for (lights.lights[0..lights.count], 0..) |*light, i| {
|
||||
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.shadow).program);
|
||||
// Directional light
|
||||
if (std.math.approxEqAbs(f32, light.pos.w(), 0, std.math.floatEps(f32))) {
|
||||
dir_light = light.*;
|
||||
}
|
||||
gl.namedFramebufferTextureLayer(self.shadow_framebuffer, gl.DEPTH_ATTACHMENT, self.shadow_texture_array, 0, 0);
|
||||
const check_fbo_status = gl.checkNamedFramebufferStatus(self.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
||||
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
||||
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
||||
}
|
||||
|
||||
// Transform view to camera view space
|
||||
light.pos = self.camera.view_mat.mulByVec4(light.pos);
|
||||
gl.viewport(0, 0, 2048, 2048);
|
||||
|
||||
const camera_matrix = &self.shadow_matrices;
|
||||
camera_matrix.* = .{
|
||||
.projection = Mat4.orthographic(-2, 2, -2, 2, -5, 5),
|
||||
.view = Mat4.lookAt(
|
||||
Vec3.new(light.pos.x(), light.pos.y(), light.pos.z()).scale(-1),
|
||||
Vec3.zero(),
|
||||
Vec3.up(),
|
||||
),
|
||||
};
|
||||
light.shadow_vp = camera_matrix.projection.mul(camera_matrix.view);
|
||||
|
||||
gl.namedBufferSubData(self.shadow_matrices_buffer, 0, @sizeOf(CameraMatrices), std.mem.asBytes(&self.shadow_matrices));
|
||||
checkGLError();
|
||||
|
||||
gl.clear(gl.DEPTH_BUFFER_BIT);
|
||||
gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO.CameraMatrices.value(), self.shadow_matrices_buffer);
|
||||
|
||||
self.renderShadow();
|
||||
} else {
|
||||
// Point Light
|
||||
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.cube_shadow).program);
|
||||
|
||||
const pos = Vec3.new(light.pos.x(), light.pos.y(), light.pos.z());
|
||||
light.shadow_vp = Mat4.fromTranslate(pos.negate());
|
||||
// For each cube face
|
||||
for (cube_camera_dirs, 0..) |cam_dir, face| {
|
||||
gl.namedFramebufferTextureLayer(self.shadow_framebuffer, gl.DEPTH_ATTACHMENT, self.cube_shadow_texture_array, 0, @intCast(i * 6 + face));
|
||||
const check_fbo_status = gl.checkNamedFramebufferStatus(self.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
||||
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
||||
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
||||
}
|
||||
|
||||
gl.viewport(0, 0, 512, 512);
|
||||
|
||||
const near_far = Vec2.new(0.1, 10);
|
||||
const camera_matrix = &self.shadow_matrices;
|
||||
camera_matrix.* = .{
|
||||
.projection = Mat4.perspective(90, 1, near_far.x(), near_far.y()),
|
||||
.view = Mat4.lookAt(
|
||||
pos,
|
||||
pos.add(cam_dir.target),
|
||||
cam_dir.up,
|
||||
),
|
||||
};
|
||||
light.near_far = near_far;
|
||||
gl.uniform2f(Uniform.NearFarPlanes.value(), near_far.x(), near_far.y());
|
||||
|
||||
gl.namedBufferSubData(self.shadow_matrices_buffer, 0, @sizeOf(CameraMatrices), std.mem.asBytes(&self.shadow_matrices));
|
||||
checkGLError();
|
||||
|
||||
gl.clear(gl.DEPTH_BUFFER_BIT);
|
||||
gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO.CameraMatrices.value(), self.shadow_matrices_buffer);
|
||||
|
||||
self.renderShadow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Directional Light shadow map
|
||||
if (dir_light) |light| {
|
||||
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, self.shadow_framebuffer);
|
||||
gl.viewport(0, 0, 2048, 2048);
|
||||
gl.clear(gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.shadow).program);
|
||||
gl.bindVertexArray(self.shadow_vao);
|
||||
|
||||
const camera_matrix = &self.shadow_matrices;
|
||||
camera_matrix.* = .{
|
||||
.projection = Mat4.orthographic(-2, 2, -2, 2, -5, 5),
|
||||
.view = Mat4.lookAt(
|
||||
Vec3.new(light.pos.x(), light.pos.y(), light.pos.z()).scale(-1),
|
||||
Vec3.zero(),
|
||||
Vec3.up(),
|
||||
),
|
||||
};
|
||||
dir_light_vp = camera_matrix.projection.mul(camera_matrix.view);
|
||||
// TODO: use multiple buffers for this in the future
|
||||
gl.namedBufferSubData(self.shadow_matrices_buffer, 0, @sizeOf(CameraMatrices), std.mem.asBytes(camera_matrix));
|
||||
checkGLError();
|
||||
gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO.CameraMatrices.value(), self.shadow_matrices_buffer);
|
||||
|
||||
for (self.command_buffer[0..self.command_count]) |*cmd| {
|
||||
const mesh = self.assetman.resolveMesh(cmd.mesh);
|
||||
|
||||
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data));
|
||||
mesh.positions.bind(Render.Attrib.Position.value());
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices.buffer);
|
||||
|
||||
gl.drawElements(
|
||||
gl.TRIANGLES,
|
||||
mesh.indices.count,
|
||||
mesh.indices.type,
|
||||
@ptrFromInt(mesh.indices.offset),
|
||||
);
|
||||
}
|
||||
// Light world space to view space
|
||||
for (lights.lights[0..lights.count]) |*light| {
|
||||
light.pos = self.camera.view_mat.mulByVec4(light.pos);
|
||||
}
|
||||
|
||||
var width: c_int = 0;
|
||||
@ -393,10 +457,8 @@ pub fn finish(self: *Render) void {
|
||||
);
|
||||
gl.uniform2fv(Uniform.EmissionMapUVScale.value(), 1, @ptrCast(&emission_map.uv_scale.data));
|
||||
}
|
||||
if (dir_light != null) {
|
||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(Uniform.ShadowMap.value(), self.shadow_texture_handle);
|
||||
gl.uniformMatrix4fv(Uniform.ShadowMapVP.value(), 1, gl.FALSE, @ptrCast(&dir_light_vp.?.data));
|
||||
}
|
||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(Uniform.ShadowMap2D.value(), self.shadow_texture_handle);
|
||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(Uniform.ShadowMapCube.value(), self.cube_shadow_texture_handle);
|
||||
|
||||
mesh.positions.bind(Render.Attrib.Position.value());
|
||||
mesh.normals.bind(Render.Attrib.Normal.value());
|
||||
@ -416,6 +478,62 @@ pub fn finish(self: *Render) void {
|
||||
c.SDL_Delay(1);
|
||||
}
|
||||
|
||||
const CubeCameraDir = struct {
|
||||
face: gl.GLenum,
|
||||
target: Vec3,
|
||||
up: Vec3,
|
||||
};
|
||||
|
||||
const cube_camera_dirs = [6]CubeCameraDir{
|
||||
.{
|
||||
.face = gl.TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
.target = Vec3.right(),
|
||||
.up = Vec3.down(),
|
||||
},
|
||||
.{
|
||||
.face = gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
|
||||
.target = Vec3.left(),
|
||||
.up = Vec3.down(),
|
||||
},
|
||||
.{
|
||||
.face = gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
|
||||
.target = Vec3.up(),
|
||||
.up = Vec3.forward(),
|
||||
},
|
||||
.{
|
||||
.face = gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
||||
.target = Vec3.down(),
|
||||
.up = Vec3.back(),
|
||||
},
|
||||
.{
|
||||
.face = gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
|
||||
.target = Vec3.forward(),
|
||||
.up = Vec3.down(),
|
||||
},
|
||||
.{
|
||||
.face = gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
||||
.target = Vec3.back(),
|
||||
.up = Vec3.down(),
|
||||
},
|
||||
};
|
||||
|
||||
fn renderShadow(self: *Render) void {
|
||||
for (self.command_buffer[0..self.command_count]) |*cmd| {
|
||||
const mesh = self.assetman.resolveMesh(cmd.mesh);
|
||||
|
||||
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data));
|
||||
mesh.positions.bind(Render.Attrib.Position.value());
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices.buffer);
|
||||
|
||||
gl.drawElements(
|
||||
gl.TRIANGLES,
|
||||
mesh.indices.count,
|
||||
mesh.indices.type,
|
||||
@ptrFromInt(mesh.indices.offset),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkGLError() void {
|
||||
var err = gl.getError();
|
||||
if (err == gl.NO_ERROR) return;
|
||||
@ -483,8 +601,10 @@ pub const Uniform = enum(gl.GLint) {
|
||||
EmissionMap = 14,
|
||||
EmissionMapUVScale = 15,
|
||||
|
||||
ShadowMap = 16,
|
||||
ShadowMapVP = 17,
|
||||
ShadowMap2D = 16,
|
||||
ShadowMapCube = 17,
|
||||
|
||||
NearFarPlanes = 18, // vec2 stores near and far planes for perspective projection
|
||||
|
||||
pub inline fn value(self: Uniform) gl.GLint {
|
||||
return @intFromEnum(self);
|
||||
@ -513,6 +633,8 @@ const CameraMatrices = extern struct {
|
||||
pub const PointLight = extern struct {
|
||||
pos: Vec4, // x, y, z, w - vPos
|
||||
color_radius: Vec4, // x, y, z - color, w - radius
|
||||
shadow_vp: Mat4 = Mat4.identity(),
|
||||
near_far: Vec2 = Vec2.zero(),
|
||||
};
|
||||
|
||||
// TODO: rename
|
||||
|
@ -114,6 +114,7 @@ fn loadGL() void {
|
||||
};
|
||||
gl.debugMessageCallback(glDebugCallback, null);
|
||||
// gl.enable(gl.DEBUG_OUTPUT);
|
||||
gl.enable(gl.DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
|
||||
fn glDebugCallback(source: gl.GLenum, _type: gl.GLenum, id: gl.GLuint, severity: gl.GLenum, length: gl.GLsizei, message: [*:0]const u8, userParam: ?*anyopaque) callconv(.C) void {
|
||||
@ -188,7 +189,7 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
||||
_ = globals.g_mem.world.addEntity(.{
|
||||
.flags = .{ .dir_light = true, .rotate = true },
|
||||
.transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(60, 15, 0)) },
|
||||
.light = .{ .color_intensity = Vec4.new(1, 1, 0.83, 1) },
|
||||
.light = .{ .color_intensity = Vec4.new(1, 1, 0.83, 0.7) },
|
||||
});
|
||||
|
||||
const light_root = globals.g_mem.world.addEntity(.{
|
||||
|
Loading…
x
Reference in New Issue
Block a user