Try to optimize for many draw calls
This commit is contained in:
parent
f21bc2245a
commit
b0163b1f6b
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
struct DrawCmdData {
|
struct DrawCmdData {
|
||||||
mat4 transform;
|
mat4 transform;
|
||||||
|
int materialIdx;
|
||||||
};
|
};
|
||||||
|
|
||||||
// UBOs
|
// UBOs
|
||||||
@ -18,7 +19,6 @@ layout(std140, binding = 0) uniform Matrices {
|
|||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
||||||
uint draws_count;
|
|
||||||
// Access by gl_DrawID
|
// Access by gl_DrawID
|
||||||
DrawCmdData draw_data[];
|
DrawCmdData draw_data[];
|
||||||
};
|
};
|
||||||
@ -149,13 +149,13 @@ int getCSMSplit(int lightIdx, float depth) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EvalMaterial evalMaterial() {
|
EvalMaterial evalMaterial() {
|
||||||
Material mat = materials[DrawID];
|
|
||||||
EvalMaterial result;
|
EvalMaterial result;
|
||||||
result.albedo = textureSize(mat.albedo_map, 0) == ivec2(0) ? vec4(pow(mat.albedo.rgb, vec3(2.2)), mat.albedo.a) : texture(mat.albedo_map, VertexOut.uv * mat.albedo_map_uv_scale);
|
int materialIdx = draw_data[DrawID].materialIdx;
|
||||||
float fMetallic = textureSize(mat.metallic_map, 0) == ivec2(0) ? mat.metallic : texture(mat.metallic_map, VertexOut.uv * mat.metallic_map_uv_scale).b;
|
result.albedo = textureSize(materials[materialIdx].albedo_map, 0) == ivec2(0) ? vec4(pow(materials[materialIdx].albedo.rgb, vec3(2.2)), materials[materialIdx].albedo.a) : texture(materials[materialIdx].albedo_map, VertexOut.uv * materials[materialIdx].albedo_map_uv_scale);
|
||||||
|
float fMetallic = textureSize(materials[materialIdx].metallic_map, 0) == ivec2(0) ? materials[materialIdx].metallic : texture(materials[materialIdx].metallic_map, VertexOut.uv * materials[materialIdx].metallic_map_uv_scale).b;
|
||||||
result.metallic = fMetallic > 0.1;
|
result.metallic = fMetallic > 0.1;
|
||||||
result.roughness = max(0.01, textureSize(mat.roughness_map, 0) == ivec2(0) ? mat.roughness : texture(mat.roughness_map, VertexOut.uv * mat.roughness_map_uv_scale).g);
|
result.roughness = max(0.01, textureSize(materials[materialIdx].roughness_map, 0) == ivec2(0) ? materials[materialIdx].roughness : texture(materials[materialIdx].roughness_map, VertexOut.uv * materials[materialIdx].roughness_map_uv_scale).g);
|
||||||
result.emission = textureSize(mat.emission_map, 0) == ivec2(0) ? mat.emission : texture(mat.emission_map, VertexOut.uv * mat.emission_map_uv_scale).rgb;
|
result.emission = textureSize(materials[materialIdx].emission_map, 0) == ivec2(0) ? materials[materialIdx].emission : texture(materials[materialIdx].emission_map, VertexOut.uv * materials[materialIdx].emission_map_uv_scale).rgb;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -223,21 +223,7 @@ vec3 microfacetModel(EvalMaterial mat, int light_idx, vec3 P, vec3 N) {
|
|||||||
// 0 - means directional, 1 - means point light
|
// 0 - means directional, 1 - means point light
|
||||||
bool point = subgroupAll(lights[light_idx].vPos.w == 1);
|
bool point = subgroupAll(lights[light_idx].vPos.w == 1);
|
||||||
vec3 lightI = lights[light_idx].color.rgb;
|
vec3 lightI = lights[light_idx].color.rgb;
|
||||||
float lightRadius = max(lights[light_idx].color.a, eps);
|
|
||||||
vec3 L = mix(-lights[light_idx].vPos.xyz, lights[light_idx].vPos.xyz - P, lights[light_idx].vPos.w);
|
vec3 L = mix(-lights[light_idx].vPos.xyz, lights[light_idx].vPos.xyz - P, lights[light_idx].vPos.w);
|
||||||
float dist = max(length(L), eps);
|
|
||||||
L /= dist;
|
|
||||||
|
|
||||||
// TODO: I think this is uniform control flow
|
|
||||||
// so makes sense to use `if` there for directional/point
|
|
||||||
// and don't calculate attenuation for directional at all
|
|
||||||
float att = lightAttenuation(
|
|
||||||
point,
|
|
||||||
dist,
|
|
||||||
lightRadius
|
|
||||||
);
|
|
||||||
lightI *= att;
|
|
||||||
|
|
||||||
vec3 V = normalize(-P);
|
vec3 V = normalize(-P);
|
||||||
vec3 H = normalize(V + L);
|
vec3 H = normalize(V + L);
|
||||||
|
|
||||||
@ -255,6 +241,16 @@ vec3 microfacetModel(EvalMaterial mat, int light_idx, vec3 P, vec3 N) {
|
|||||||
float shadow_mult = 1;
|
float shadow_mult = 1;
|
||||||
vec4 shadow_offset = vec4(VertexOut.wNormal * normal_offset_scale, 0);
|
vec4 shadow_offset = vec4(VertexOut.wNormal * normal_offset_scale, 0);
|
||||||
if (point) {
|
if (point) {
|
||||||
|
float dist = max(length(L), eps);
|
||||||
|
L /= dist;
|
||||||
|
float lightRadius = max(lights[light_idx].color.a, eps);
|
||||||
|
float att = lightAttenuation(
|
||||||
|
point,
|
||||||
|
dist,
|
||||||
|
lightRadius
|
||||||
|
);
|
||||||
|
lightI *= att;
|
||||||
|
|
||||||
vec2 shadow_map_texel_size = 1.0 / vec2(textureSize(cube_shadow_maps, 0));
|
vec2 shadow_map_texel_size = 1.0 / vec2(textureSize(cube_shadow_maps, 0));
|
||||||
shadow_offset *= shadow_map_texel_size.x;
|
shadow_offset *= shadow_map_texel_size.x;
|
||||||
vec3 shadow_dir = (lights[light_idx].view_mat * vec4(VertexOut.wPos, 1.0)).xyz;
|
vec3 shadow_dir = (lights[light_idx].view_mat * vec4(VertexOut.wPos, 1.0)).xyz;
|
||||||
@ -295,7 +291,7 @@ vec3 microfacetModel(EvalMaterial mat, int light_idx, vec3 P, vec3 N) {
|
|||||||
texcoord.z = shadow_map_idx + csm_split_idx;
|
texcoord.z = shadow_map_idx + csm_split_idx;
|
||||||
|
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
sum = texture(shadow_maps, vec4(texcoord.xy, texcoord.zw));
|
sum = 1.0; // texture(shadow_maps, vec4(texcoord.xy, texcoord.zw));
|
||||||
// for (float y = -0.5; y <= 0.5; y += 1) {
|
// for (float y = -0.5; y <= 0.5; y += 1) {
|
||||||
// for (float x = -0.5; x <= 0.5; x += 1) {
|
// for (float x = -0.5; x <= 0.5; x += 1) {
|
||||||
// sum += ;
|
// sum += ;
|
||||||
@ -308,14 +304,19 @@ vec3 microfacetModel(EvalMaterial mat, int light_idx, vec3 P, vec3 N) {
|
|||||||
|
|
||||||
vec3 specBrdf = geomSmith(mat, NDotL) * geomSmith(mat, NDotV) * 0.25 * ggxDistribution(mat, NDotH) * schlickFresnel(mat, LDotH);
|
vec3 specBrdf = geomSmith(mat, NDotL) * geomSmith(mat, NDotV) * 0.25 * ggxDistribution(mat, NDotH) * schlickFresnel(mat, LDotH);
|
||||||
|
|
||||||
return (PI * specBrdf + diffuseBrdf) * NDotL * shadow_mult * lightI + mat.emission;
|
vec3 vecTerm = PI * specBrdf + diffuseBrdf;
|
||||||
|
float scalarTerm = NDotL * shadow_mult;
|
||||||
|
|
||||||
|
return scalarTerm * lightI + mat.emission;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Material mat = materials[DrawID];
|
int materialIdx = draw_data[DrawID].materialIdx;
|
||||||
|
sampler2D normal_map = materials[materialIdx].normal_map;
|
||||||
|
vec2 normal_map_uv_scale = materials[materialIdx].normal_map_uv_scale;
|
||||||
EvalMaterial material = evalMaterial();
|
EvalMaterial material = evalMaterial();
|
||||||
|
|
||||||
vec3 N = textureSize(mat.normal_map, 0) == ivec2(0) ? vec3(0.5) : vec3(texture(mat.normal_map, VertexOut.uv * mat.normal_map_uv_scale).xy, 0);
|
vec3 N = textureSize(normal_map, 0) == ivec2(0) ? vec3(0.5) : vec3(texture(normal_map, VertexOut.uv * normal_map_uv_scale).xy, 0);
|
||||||
N = N * 2.0 - 1.0;
|
N = N * 2.0 - 1.0;
|
||||||
N.z = sqrt(clamp(1 - N.x * N.x - N.y * N.y, 0, 1));
|
N.z = sqrt(clamp(1 - N.x * N.x - N.y * N.y, 0, 1));
|
||||||
N = normalize(N);
|
N = normalize(N);
|
||||||
@ -324,8 +325,8 @@ void main() {
|
|||||||
vec3 finalColor = vec3(0);
|
vec3 finalColor = vec3(0);
|
||||||
|
|
||||||
// int n_lights = clamp(int(lights_count), 0, MAX_POINT_LIGHTS);
|
// int n_lights = clamp(int(lights_count), 0, MAX_POINT_LIGHTS);
|
||||||
for (int i = 0; i < lights_count; i++) {
|
for (int i = 0; i < MAX_POINT_LIGHTS; i++) {
|
||||||
// if (i >= lights_count) break;
|
if (i >= lights_count) break;
|
||||||
finalColor += microfacetModel(material, i, VertexOut.vPos, N);
|
finalColor += microfacetModel(material, i, VertexOut.vPos, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
struct DrawCmdData {
|
struct DrawCmdData {
|
||||||
mat4 transform;
|
mat4 transform;
|
||||||
|
int materialIdx;
|
||||||
};
|
};
|
||||||
|
|
||||||
// UBOs
|
// UBOs
|
||||||
@ -10,7 +11,6 @@ layout(std140, binding = 0) uniform Matrices {
|
|||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
||||||
uint draws_count;
|
|
||||||
// Access by gl_DrawID
|
// Access by gl_DrawID
|
||||||
DrawCmdData draw_data[];
|
DrawCmdData draw_data[];
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@ const a = @import("asset_manifest");
|
|||||||
const globals = @import("globals.zig");
|
const globals = @import("globals.zig");
|
||||||
pub const Material = @import("formats.zig").Material;
|
pub const Material = @import("formats.zig").Material;
|
||||||
const math = @import("math.zig");
|
const math = @import("math.zig");
|
||||||
|
const formats = @import("formats.zig");
|
||||||
|
|
||||||
const za = @import("zalgebra");
|
const za = @import("zalgebra");
|
||||||
const Vec2 = za.Vec2;
|
const Vec2 = za.Vec2;
|
||||||
@ -17,7 +18,7 @@ const Vec2_i32 = za.Vec2_i32;
|
|||||||
|
|
||||||
pub const MAX_FRAMES_QUEUED = 3;
|
pub const MAX_FRAMES_QUEUED = 3;
|
||||||
pub const MAX_LIGHTS = 8;
|
pub const MAX_LIGHTS = 8;
|
||||||
pub const MAX_DRAW_COMMANDS = 4096;
|
pub const MAX_DRAW_COMMANDS = 1024 * 16;
|
||||||
pub const MAX_LIGHT_COMMANDS = 2048;
|
pub const MAX_LIGHT_COMMANDS = 2048;
|
||||||
pub const MAX_MATERIALS = MAX_DRAW_COMMANDS;
|
pub const MAX_MATERIALS = MAX_DRAW_COMMANDS;
|
||||||
pub const CSM_SPLITS = 4;
|
pub const CSM_SPLITS = 4;
|
||||||
@ -722,20 +723,25 @@ pub fn finish(self: *Render) void {
|
|||||||
const switched_to_alpha_blend = false;
|
const switched_to_alpha_blend = false;
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
|
||||||
const draw_indirect_cmds_c: [*]u8 = @ptrCast(gl.mapNamedBuffer(
|
var draw_indirect_cmds = self.frame_arena.alloc(DrawIndirectCmd, MAX_DRAW_COMMANDS) catch @panic("OOM");
|
||||||
self.draw_indirect_buffer,
|
var draw_cmd_data = self.frame_arena.alloc(DrawCommandData, MAX_DRAW_COMMANDS) catch @panic("OOM");
|
||||||
gl.WRITE_ONLY,
|
|
||||||
) orelse {
|
var draw_indirect_buf: gl.GLuint = 0;
|
||||||
|
gl.createBuffers(1, &draw_indirect_buf);
|
||||||
checkGLError();
|
checkGLError();
|
||||||
@panic("map draw indirect buffer");
|
defer gl.deleteBuffers(1, &draw_indirect_buf);
|
||||||
});
|
|
||||||
var draw_indirect_cmds = std.mem.bytesAsSlice(DrawIndirectCmd, draw_indirect_cmds_c[0 .. @sizeOf(DrawIndirectCmd) * MAX_DRAW_COMMANDS]);
|
var draw_cmd_data_buf: gl.GLuint = 0;
|
||||||
|
gl.createBuffers(1, &draw_cmd_data_buf);
|
||||||
|
checkGLError();
|
||||||
|
defer gl.deleteBuffers(1, &draw_cmd_data_buf);
|
||||||
|
|
||||||
const materials = self.materials_pbr_ssbo.getInstance(self.tripple_buffer_index);
|
const materials = self.materials_pbr_ssbo.getInstance(self.tripple_buffer_index);
|
||||||
materials.count.* = 0;
|
materials.count.* = 0;
|
||||||
|
|
||||||
const draw_cmd_data = self.draw_cmd_data_ssbo.getInstance(self.tripple_buffer_index);
|
var material_map = std.StringHashMap(i32).init(self.frame_arena);
|
||||||
|
|
||||||
|
var materials_count: usize = 0;
|
||||||
var rendered_count: usize = 0;
|
var rendered_count: usize = 0;
|
||||||
cmds: for (self.command_buffer[0..self.command_count]) |*cmd| {
|
cmds: for (self.command_buffer[0..self.command_count]) |*cmd| {
|
||||||
const mesh = self.assetman.resolveMesh(cmd.mesh);
|
const mesh = self.assetman.resolveMesh(cmd.mesh);
|
||||||
@ -755,12 +761,20 @@ pub fn finish(self: *Render) void {
|
|||||||
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_cmd_data.data[rendered_count] = DrawCommandData{
|
const material_bytes = std.mem.asBytes(&material);
|
||||||
.transform = cmd.transform,
|
const material_copy = self.frame_arena.alloc(u8, material_bytes.len) catch @panic("OOM");
|
||||||
};
|
@memcpy(material_copy, material_bytes);
|
||||||
|
const gop = material_map.getOrPut(material_copy) catch @panic("OOM");
|
||||||
|
if (!gop.found_existing) {
|
||||||
|
gop.value_ptr.* = @intCast(materials_count);
|
||||||
|
materials.data[materials_count] = MaterialPBR.fromMaterial(self.assetman, &material);
|
||||||
|
materials_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
materials.data[rendered_count] = MaterialPBR.fromMaterial(self.assetman, &material);
|
draw_cmd_data[rendered_count] = DrawCommandData{
|
||||||
materials.count.* += 1;
|
.transform = cmd.transform,
|
||||||
|
.material_index = gop.value_ptr.*,
|
||||||
|
};
|
||||||
|
|
||||||
draw_indirect_cmds[rendered_count] = DrawIndirectCmd{
|
draw_indirect_cmds[rendered_count] = DrawIndirectCmd{
|
||||||
.count = mesh.indices.count,
|
.count = mesh.indices.count,
|
||||||
@ -774,10 +788,6 @@ pub fn finish(self: *Render) void {
|
|||||||
rendered_count += 1;
|
rendered_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = gl.unmapNamedBuffer(self.draw_indirect_buffer);
|
|
||||||
|
|
||||||
gl.bindBuffer(gl.DRAW_INDIRECT_BUFFER, self.draw_indirect_buffer);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const camera_matrix: *CameraMatrices = @alignCast(@ptrCast(self.camera_matrices[self.tripple_buffer_index * self.uboAlignedSizeOf(CameraMatrices) ..].ptr));
|
const camera_matrix: *CameraMatrices = @alignCast(@ptrCast(self.camera_matrices[self.tripple_buffer_index * self.uboAlignedSizeOf(CameraMatrices) ..].ptr));
|
||||||
camera_matrix.* = .{
|
camera_matrix.* = .{
|
||||||
@ -796,15 +806,21 @@ pub fn finish(self: *Render) void {
|
|||||||
checkGLError();
|
checkGLError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gl.namedBufferStorage(draw_indirect_buf, @intCast(@sizeOf(DrawIndirectCmd) * rendered_count), draw_indirect_cmds.ptr, 0);
|
||||||
|
gl.bindBuffer(gl.DRAW_INDIRECT_BUFFER, draw_indirect_buf);
|
||||||
|
|
||||||
|
gl.namedBufferStorage(draw_cmd_data_buf, @intCast(@sizeOf(DrawCommandData) * rendered_count), draw_cmd_data.ptr, 0);
|
||||||
|
gl.bindBufferBase(gl.SHADER_STORAGE_BUFFER, SSBO.DrawCommandData.value(), draw_cmd_data_buf);
|
||||||
|
|
||||||
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.z_prepass).program);
|
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.z_prepass).program);
|
||||||
gl.bindVertexArray(self.shadow_vao);
|
gl.bindVertexArray(self.shadow_vao);
|
||||||
|
|
||||||
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value());
|
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value(), 0);
|
||||||
checkGLError();
|
checkGLError();
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
||||||
checkGLError();
|
checkGLError();
|
||||||
|
|
||||||
gl.multiDrawElementsIndirect(gl.TRIANGLES, gl.UNSIGNED_INT, null, @intCast(rendered_count), @sizeOf(DrawIndirectCmd));
|
// gl.multiDrawElementsIndirect(gl.TRIANGLES, gl.UNSIGNED_INT, null, @intCast(rendered_count), @sizeOf(DrawIndirectCmd));
|
||||||
|
|
||||||
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.mesh).program);
|
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.mesh).program);
|
||||||
gl.bindVertexArray(self.mesh_vao);
|
gl.bindVertexArray(self.mesh_vao);
|
||||||
@ -1314,13 +1330,13 @@ pub fn BufferSSBOAlign(comptime T: type, comptime alignment: usize) type {
|
|||||||
_start: [0]T align(alignment),
|
_start: [0]T align(alignment),
|
||||||
|
|
||||||
pub fn calculateBufSize(max_count: usize, ssbo_align: usize) usize {
|
pub fn calculateBufSize(max_count: usize, ssbo_align: usize) usize {
|
||||||
return std.mem.alignForward(usize, @sizeOf(BufferInstance) + @sizeOf(T) * max_count, ssbo_align);
|
return std.mem.alignForward(usize, @sizeOf(BufferLayout) + std.mem.alignForward(usize, @sizeOf(T), alignment) * max_count, ssbo_align);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getData(self: *BufferLayout, len: usize) []T {
|
pub fn getData(self: *BufferLayout, len: usize) ([]align(alignment) T) {
|
||||||
var data_c: [*]T = @ptrFromInt(@intFromPtr(self) + @offsetOf(BufferLayout, "_start"));
|
var data_c: [*]align(alignment) T = @ptrFromInt(@intFromPtr(self) + @offsetOf(BufferLayout, "_start"));
|
||||||
|
|
||||||
return data_c[0..len];
|
return @alignCast(data_c[0..len]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1408,9 +1424,11 @@ const MaterialPBRSSBO = BufferSSBO(MaterialPBR);
|
|||||||
|
|
||||||
const DrawCommandData = extern struct {
|
const DrawCommandData = extern struct {
|
||||||
transform: Mat4,
|
transform: Mat4,
|
||||||
|
material_index: c_int,
|
||||||
|
_pad: [0]void align(16) = std.mem.zeroes([0]void),
|
||||||
};
|
};
|
||||||
|
|
||||||
const DrawCommandDataSSBO = BufferSSBOAlign(DrawCommandData, 16);
|
const DrawCommandDataSSBO = BufferSSBO(DrawCommandData);
|
||||||
|
|
||||||
const DrawIndirectCmd = extern struct {
|
const DrawIndirectCmd = extern struct {
|
||||||
count: gl.GLuint,
|
count: gl.GLuint,
|
||||||
|
60
src/game.zig
60
src/game.zig
@ -193,35 +193,35 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
.rotate = .{ .axis = Vec3.up(), .rate = -10 },
|
.rotate = .{ .axis = Vec3.up(), .rate = -10 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const light_root = globals.g_mem.world.addEntity(.{
|
// const light_root = globals.g_mem.world.addEntity(.{
|
||||||
.flags = .{ .rotate = true },
|
// .flags = .{ .rotate = true },
|
||||||
.transform = .{ .pos = Vec3.new(0, 0.1, 0) },
|
// .transform = .{ .pos = Vec3.new(0, 0.1, 0) },
|
||||||
.rotate = .{ .axis = Vec3.up(), .rate = 60 },
|
// .rotate = .{ .axis = Vec3.up(), .rate = 60 },
|
||||||
});
|
// });
|
||||||
|
|
||||||
const light1 = globals.g_mem.world.addEntity(.{
|
// const light1 = globals.g_mem.world.addEntity(.{
|
||||||
.transform = .{ .pos = Vec3.new(1.8, 1, 0) },
|
// .transform = .{ .pos = Vec3.new(1.8, 1, 0) },
|
||||||
.flags = .{ .point_light = true, .rotate = true },
|
// .flags = .{ .point_light = true, .rotate = true },
|
||||||
.light = .{ .color_intensity = Vec4.new(1.0, 0.3, 0.1, 100.0) },
|
// .light = .{ .color_intensity = Vec4.new(1.0, 0.3, 0.1, 100.0) },
|
||||||
.point_light = .{ .radius = 0.1 },
|
// .point_light = .{ .radius = 0.1 },
|
||||||
.rotate = .{ .axis = Vec3.up(), .rate = -40 },
|
// .rotate = .{ .axis = Vec3.up(), .rate = -40 },
|
||||||
});
|
// });
|
||||||
light1.ptr.setParent(light_root.handle);
|
// light1.ptr.setParent(light_root.handle);
|
||||||
|
|
||||||
const light2 = globals.g_mem.world.addEntity(.{
|
// const light2 = globals.g_mem.world.addEntity(.{
|
||||||
.transform = .{ .pos = Vec3.new(-2, 0, 0) },
|
// .transform = .{ .pos = Vec3.new(-2, 0, 0) },
|
||||||
.flags = .{ .point_light = true, .rotate = true },
|
// .flags = .{ .point_light = true, .rotate = true },
|
||||||
.light = .{ .color_intensity = Vec4.new(0.2, 0.5, 1.0, 100.0) },
|
// .light = .{ .color_intensity = Vec4.new(0.2, 0.5, 1.0, 100.0) },
|
||||||
.point_light = .{ .radius = 0.1 },
|
// .point_light = .{ .radius = 0.1 },
|
||||||
});
|
// });
|
||||||
light2.ptr.setParent(light1.handle);
|
// light2.ptr.setParent(light1.handle);
|
||||||
|
|
||||||
_ = globals.g_mem.world.addEntity(.{
|
// _ = globals.g_mem.world.addEntity(.{
|
||||||
.transform = .{ .pos = Vec3.new(1, 0.5, 4) },
|
// .transform = .{ .pos = Vec3.new(1, 0.5, 4) },
|
||||||
.flags = .{ .point_light = true },
|
// .flags = .{ .point_light = true },
|
||||||
.light = .{ .color_intensity = Vec4.new(0.2, 0.5, 1.0, 10.0) },
|
// .light = .{ .color_intensity = Vec4.new(0.2, 0.5, 1.0, 10.0) },
|
||||||
.point_light = .{ .radius = 1 },
|
// .point_light = .{ .radius = 1 },
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Plane
|
// Plane
|
||||||
_ = globals.g_mem.world.addEntity(.{
|
_ = globals.g_mem.world.addEntity(.{
|
||||||
@ -239,9 +239,10 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
|
|
||||||
// 10 dielectric bunnies
|
// 10 dielectric bunnies
|
||||||
{
|
{
|
||||||
for (0..10) |i| {
|
for (0..100) |y| {
|
||||||
|
for (0..10) |x| {
|
||||||
_ = globals.g_mem.world.addEntity(.{
|
_ = globals.g_mem.world.addEntity(.{
|
||||||
.transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0, 0) },
|
.transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(x)) * 0.3 - 0.3 * 4.5, 0, @as(f32, @floatFromInt(y)) * 0.3 - 0.3 * 4.5) },
|
||||||
|
|
||||||
.flags = .{ .mesh = true },
|
.flags = .{ .mesh = true },
|
||||||
.mesh = .{
|
.mesh = .{
|
||||||
@ -249,13 +250,14 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
.material = .{
|
.material = .{
|
||||||
.albedo_map = a.Textures.bunny_tex1,
|
.albedo_map = a.Textures.bunny_tex1,
|
||||||
// .normal_map = a.Textures.@"tile.norm",
|
// .normal_map = a.Textures.@"tile.norm",
|
||||||
.roughness = @as(f32, @floatFromInt(i)) / 10.0,
|
.roughness = @as(f32, @floatFromInt(y)) / 100.0,
|
||||||
},
|
},
|
||||||
.override_material = true,
|
.override_material = true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 10 metallic bunnies
|
// 10 metallic bunnies
|
||||||
{
|
{
|
||||||
for (0..10) |i| {
|
for (0..10) |i| {
|
||||||
|
117
src/math.zig
117
src/math.zig
@ -86,14 +86,14 @@ pub const AABB = struct {
|
|||||||
|
|
||||||
// TODO: optimize
|
// TODO: optimize
|
||||||
pub fn transform(self: *const AABB, matrix: Mat4) AABB {
|
pub fn transform(self: *const AABB, matrix: Mat4) AABB {
|
||||||
var min = Vec3.zero();
|
var min = Vec3.new(std.math.floatMax(f32), std.math.floatMax(f32), std.math.floatMax(f32));
|
||||||
var max = Vec3.zero();
|
var max = Vec3.new(std.math.floatMin(f32), std.math.floatMin(f32), std.math.floatMin(f32));
|
||||||
|
|
||||||
inline for (box_corners) |corner| {
|
inline for (box_corners) |corner| {
|
||||||
const corner_pos = matrix.mulByVec4(self.origin.add(self.extents.mul(corner)).toVec4(1));
|
const corner_pos = matrix.mulByVec4(self.origin.add(self.extents.mul(corner)).toVec4(1));
|
||||||
const corner_pos3 = corner_pos.scale(1 / corner_pos.w()).toVec3();
|
const corner_pos3 = corner_pos.toVec3();
|
||||||
min = Vec3.new(@min(corner_pos3.x(), min.x()), @min(corner_pos3.y(), min.y()), @min(corner_pos3.z(), min.z()));
|
min = corner_pos3.min(min);
|
||||||
max = Vec3.new(@max(corner_pos3.x(), max.x()), @max(corner_pos3.y(), max.y()), @max(corner_pos3.z(), max.z()));
|
max = corner_pos3.max(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AABB.fromMinMax(min, max);
|
return AABB.fromMinMax(min, max);
|
||||||
@ -118,12 +118,22 @@ pub const BoundingSphere = struct {
|
|||||||
|
|
||||||
pub const Frustum = struct {
|
pub const Frustum = struct {
|
||||||
// Plane normals
|
// Plane normals
|
||||||
top: Plane = .{},
|
// top
|
||||||
right: Plane = .{},
|
// right
|
||||||
bottom: Plane = .{},
|
// bottom
|
||||||
left: Plane = .{},
|
// left
|
||||||
near: Plane = .{},
|
// near
|
||||||
far: Plane = .{},
|
// far
|
||||||
|
planes: [6]Plane = std.mem.zeroes([6]Plane),
|
||||||
|
|
||||||
|
pub const PlaneSide = enum {
|
||||||
|
Top,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
Left,
|
||||||
|
Near,
|
||||||
|
Far,
|
||||||
|
};
|
||||||
|
|
||||||
/// Extracts frustum planes from matrices using Gribb-Hartmann method
|
/// Extracts frustum planes from matrices using Gribb-Hartmann method
|
||||||
/// If you pass in a projection matrix planes will be in view space.
|
/// If you pass in a projection matrix planes will be in view space.
|
||||||
@ -143,31 +153,36 @@ pub const Frustum = struct {
|
|||||||
const far = row4.sub(row3);
|
const far = row4.sub(row3);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.top = Plane.new(top),
|
.planes = .{
|
||||||
.right = Plane.new(right),
|
Plane.new(top),
|
||||||
.bottom = Plane.new(bottom),
|
Plane.new(right),
|
||||||
.left = Plane.new(left),
|
Plane.new(bottom),
|
||||||
.near = Plane.new(near),
|
Plane.new(left),
|
||||||
.far = Plane.new(far),
|
Plane.new(near),
|
||||||
|
Plane.new(far),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getPlane(self: *const Frustum, side: PlaneSide) *const Plane {
|
||||||
|
return &self.planes[@intFromEnum(side)];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getNearDist(self: *const Frustum) f32 {
|
pub fn getNearDist(self: *const Frustum) f32 {
|
||||||
return self.near.distance();
|
return self.getPlane(.Near).distance();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rangeZ(self: *const Frustum) f32 {
|
pub fn rangeZ(self: *const Frustum) f32 {
|
||||||
return self.far.point().sub(self.near.point()).dot(self.near.normal());
|
return self.getPLane(.Far).point().sub(self.getPlane(.Near).point()).dot(self.getPlane(.Near).normal());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform(self: *const Frustum, matrix: *const Mat4) Frustum {
|
pub fn transform(self: *const Frustum, matrix: *const Mat4) Frustum {
|
||||||
|
const new_planes = self.planes;
|
||||||
|
for (new_planes) |*plane| {
|
||||||
|
plane.* = plane.transform(matrix);
|
||||||
|
}
|
||||||
return Frustum{
|
return Frustum{
|
||||||
.top = self.top.transform(matrix),
|
.planes = new_planes,
|
||||||
.right = self.right.transform(matrix),
|
|
||||||
.bottom = self.bottom.transform(matrix),
|
|
||||||
.left = self.left.transform(matrix),
|
|
||||||
.near = self.near.transform(matrix),
|
|
||||||
.far = self.far.transform(matrix),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,26 +191,44 @@ pub const Frustum = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn intersectAABBInternal(self: *const Frustum, aabb: AABB, comptime skip_near: bool) bool {
|
fn intersectAABBInternal(self: *const Frustum, aabb: AABB, comptime skip_near: bool) bool {
|
||||||
var outside_top_plane = true;
|
for (0..6) |i| {
|
||||||
var outside_bottom_plane = true;
|
if (skip_near and i == @intFromEnum(PlaneSide.Near)) continue;
|
||||||
var outside_left_plane = true;
|
|
||||||
var outside_right_plane = true;
|
|
||||||
var outside_near_plane = !skip_near;
|
|
||||||
var outside_far_plane = true;
|
|
||||||
inline for (box_corners) |corner| {
|
|
||||||
const p = aabb.origin.add(aabb.extents.mul(corner));
|
|
||||||
|
|
||||||
outside_top_plane = outside_top_plane and self.top.isUnder(p);
|
const plane = self.planes[i];
|
||||||
outside_bottom_plane = outside_bottom_plane and self.bottom.isUnder(p);
|
const nx = plane.normal().x() > 0;
|
||||||
outside_left_plane = outside_left_plane and self.left.isUnder(p);
|
const ny = plane.normal().y() > 0;
|
||||||
outside_right_plane = outside_right_plane and self.right.isUnder(p);
|
const nz = plane.normal().z() > 0;
|
||||||
if (!skip_near) {
|
|
||||||
outside_near_plane = outside_near_plane and self.near.isUnder(p);
|
const min = aabb.origin.sub(aabb.extents);
|
||||||
}
|
const max = aabb.origin.add(aabb.extents);
|
||||||
outside_far_plane = outside_far_plane and self.far.isUnder(p);
|
|
||||||
|
// TODO: vectorize
|
||||||
|
const dot = (plane.normal().x() * if (nx) max.x() else min.x()) + (plane.normal().y() * if (ny) max.y() else min.y()) + (plane.normal().z() * if (nz) max.z() else min.z());
|
||||||
|
|
||||||
|
if (dot < plane.distance()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !(outside_left_plane or outside_right_plane or outside_bottom_plane or outside_top_plane or outside_near_plane or outside_far_plane);
|
// const dot2 = (plane.normal().x() * if (nx) min.x else max.x) + (plane.normal().y() * if (ny) min.y else max.y) + (plane.normal().z() * if (nz) min.z else max.z);
|
||||||
|
// planes have unit-length normal, offset = -dot(normal, point on plane)
|
||||||
|
// const Plane3& plane = planes[i];
|
||||||
|
// Index nx = plane.normal.x > Real(0);
|
||||||
|
// Index ny = plane.normal.y > Real(0);
|
||||||
|
// Index nz = plane.normal.z > Real(0);
|
||||||
|
//
|
||||||
|
// // getMinMax(): 0 = return min coordinate. 1 = return max.
|
||||||
|
// Real dot = (plane.normal.x*box.getMinMax(nx).x) + (plane.normal.y*box.getMinMax(ny).y) + (plane.normal.z*box.getMinMax(nz).z);
|
||||||
|
//
|
||||||
|
// if ( dot < -plane.offset )
|
||||||
|
// return OUTSIDE;
|
||||||
|
//
|
||||||
|
// Real dot2 = (plane.normal.x*box.getMinMax(1-nx).x) + (plane.normal.y*box.getMinMax(1-ny).y) + (plane.normal.z*box.getMinMax(1-nz).z);
|
||||||
|
//
|
||||||
|
// if ( dot2 <= -plane.offset )
|
||||||
|
// result = INTERSECTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn intersectAABB(self: *const Frustum, aabb: AABB) bool {
|
pub fn intersectAABB(self: *const Frustum, aabb: AABB) bool {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user