Proper multi draw indirect for all meshes!
Also refactoring for SSBO to more easily create them
This commit is contained in:
parent
a39fdad1a0
commit
c27e1cecc3
@ -21,6 +21,27 @@ struct Light {
|
|||||||
vec4 csm_split_points; // TODO: Maybe increase to 8, though it's probably too many
|
vec4 csm_split_points; // TODO: Maybe increase to 8, though it's probably too many
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
vec4 albedo;
|
||||||
|
sampler2D albedo_map;
|
||||||
|
vec2 albedo_map_uv_scale;
|
||||||
|
sampler2D normal_map;
|
||||||
|
vec2 normal_map_uv_scale;
|
||||||
|
float metallic;
|
||||||
|
sampler2D metallic_map;
|
||||||
|
vec2 metallic_map_uv_scale;
|
||||||
|
float roughness;
|
||||||
|
sampler2D roughness_map;
|
||||||
|
vec2 roughness_map_uv_scale;
|
||||||
|
vec3 emission;
|
||||||
|
sampler2D emission_map;
|
||||||
|
vec2 emission_map_uv_scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DrawCmdData {
|
||||||
|
mat4 transform;
|
||||||
|
};
|
||||||
|
|
||||||
// UBOs
|
// UBOs
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
layout(std140, binding = 0) uniform Matrices {
|
||||||
mat4 projection;
|
mat4 projection;
|
||||||
@ -32,6 +53,17 @@ layout(std430, binding = 1) readonly buffer Lights {
|
|||||||
Light lights[];
|
Light lights[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) readonly buffer Materials {
|
||||||
|
uint materials_count;
|
||||||
|
Material materials[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
||||||
|
uint draws_count;
|
||||||
|
// Access by gl_DrawID
|
||||||
|
DrawCmdData draw_data[];
|
||||||
|
};
|
||||||
|
|
||||||
int getShadowMapIndex(int lightIdx) {
|
int getShadowMapIndex(int lightIdx) {
|
||||||
return int(lights[lightIdx].params.z);
|
return int(lights[lightIdx].params.z);
|
||||||
}
|
}
|
||||||
@ -52,28 +84,6 @@ int getCSMSplit(int lightIdx, float depth) {
|
|||||||
return totalSplits - 1;
|
return totalSplits - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uniforms
|
|
||||||
layout(location = 1) uniform mat4 model;
|
|
||||||
|
|
||||||
layout(location = 2) uniform vec4 color;
|
|
||||||
layout(location = 3, bindless_sampler) uniform sampler2D albedo_map;
|
|
||||||
layout(location = 4) uniform vec2 albedo_map_uv_scale = vec2(1);
|
|
||||||
|
|
||||||
layout(location = 5, bindless_sampler) uniform sampler2D normal_map;
|
|
||||||
layout(location = 6) uniform vec2 normal_map_uv_scale = vec2(1);
|
|
||||||
|
|
||||||
layout(location = 7) uniform float metallic;
|
|
||||||
layout(location = 8, bindless_sampler) uniform sampler2D metallic_map;
|
|
||||||
layout(location = 9) uniform vec2 metallic_map_uv_scale = vec2(1);
|
|
||||||
|
|
||||||
layout(location = 10) uniform float roughness;
|
|
||||||
layout(location = 11, bindless_sampler) uniform sampler2D roughness_map;
|
|
||||||
layout(location = 12) uniform vec2 roughness_map_uv_scale = vec2(1);
|
|
||||||
|
|
||||||
layout(location = 13) uniform vec3 emission;
|
|
||||||
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 = 16, bindless_sampler) uniform sampler2DArrayShadow shadow_maps;
|
||||||
layout(location = 17, bindless_sampler) uniform samplerCubeArrayShadow cube_shadow_maps;
|
layout(location = 17, bindless_sampler) uniform samplerCubeArrayShadow cube_shadow_maps;
|
||||||
|
|
||||||
@ -88,6 +98,8 @@ VERTEX_EXPORT VertexData {
|
|||||||
vec3 wNormal;
|
vec3 wNormal;
|
||||||
} VertexOut;
|
} VertexOut;
|
||||||
|
|
||||||
|
VERTEX_EXPORT flat int DrawID;
|
||||||
|
|
||||||
float random(vec4 seed4) {
|
float random(vec4 seed4) {
|
||||||
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
|
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
|
||||||
return fract(sin(dot_product) * 43758.5453);
|
return fract(sin(dot_product) * 43758.5453);
|
||||||
@ -101,6 +113,8 @@ layout(location = 2) in vec2 aUV;
|
|||||||
layout(location = 3) in vec3 aTangent;
|
layout(location = 3) in vec3 aTangent;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
DrawID = gl_DrawID;
|
||||||
|
mat4 model = draw_data[DrawID].transform;
|
||||||
vec4 vPos = view * model * vec4(aPos.xyz, 1.0);
|
vec4 vPos = view * model * vec4(aPos.xyz, 1.0);
|
||||||
gl_Position = projection * vPos;
|
gl_Position = projection * vPos;
|
||||||
|
|
||||||
@ -121,25 +135,26 @@ void main() {
|
|||||||
|
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
struct Material {
|
struct EvalMaterial {
|
||||||
vec4 albedo;
|
vec4 albedo;
|
||||||
bool metallic;
|
bool metallic;
|
||||||
float roughness;
|
float roughness;
|
||||||
vec3 emission;
|
vec3 emission;
|
||||||
};
|
};
|
||||||
|
|
||||||
Material evalMaterial() {
|
EvalMaterial evalMaterial() {
|
||||||
Material result;
|
Material mat = materials[DrawID];
|
||||||
result.albedo = textureSize(albedo_map, 0) == ivec2(0) ? vec4(pow(color.rgb, vec3(2.2)), color.a) : texture(albedo_map, VertexOut.uv * albedo_map_uv_scale);
|
EvalMaterial result;
|
||||||
float fMetallic = textureSize(metallic_map, 0) == ivec2(0) ? metallic : texture(metallic_map, VertexOut.uv * metallic_map_uv_scale).b;
|
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);
|
||||||
|
float fMetallic = textureSize(mat.metallic_map, 0) == ivec2(0) ? mat.metallic : texture(mat.metallic_map, VertexOut.uv * mat.metallic_map_uv_scale).b;
|
||||||
result.metallic = fMetallic > 0.1;
|
result.metallic = fMetallic > 0.1;
|
||||||
result.roughness = max(0.01, textureSize(roughness_map, 0) == ivec2(0) ? roughness : texture(roughness_map, VertexOut.uv * roughness_map_uv_scale).g);
|
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.emission = textureSize(emission_map, 0) == ivec2(0) ? emission : texture(emission_map, VertexOut.uv * emission_map_uv_scale).rgb;
|
result.emission = textureSize(mat.emission_map, 0) == ivec2(0) ? mat.emission : texture(mat.emission_map, VertexOut.uv * mat.emission_map_uv_scale).rgb;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 schlickFresnel(Material mat, float LDotH) {
|
vec3 schlickFresnel(EvalMaterial mat, float LDotH) {
|
||||||
vec3 f0 = vec3(0.04); // dielectric
|
vec3 f0 = vec3(0.04); // dielectric
|
||||||
if (mat.metallic) {
|
if (mat.metallic) {
|
||||||
f0 = mat.albedo.rgb;
|
f0 = mat.albedo.rgb;
|
||||||
@ -150,13 +165,13 @@ vec3 schlickFresnel(Material mat, float LDotH) {
|
|||||||
|
|
||||||
const float eps = 0.0000001;
|
const float eps = 0.0000001;
|
||||||
|
|
||||||
float geomSmith(Material mat, float DotVal) {
|
float geomSmith(EvalMaterial mat, float DotVal) {
|
||||||
float k = (mat.roughness + 1.0) * (mat.roughness + 1.0) / 8.0;
|
float k = (mat.roughness + 1.0) * (mat.roughness + 1.0) / 8.0;
|
||||||
float denom = DotVal * (1 - k) + k;
|
float denom = DotVal * (1 - k) + k;
|
||||||
return 1.0 / max(denom, eps);
|
return 1.0 / max(denom, eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
float ggxDistribution(Material mat, float NDotH) {
|
float ggxDistribution(EvalMaterial mat, float NDotH) {
|
||||||
float alpha2 = mat.roughness * mat.roughness * mat.roughness * mat.roughness;
|
float alpha2 = mat.roughness * mat.roughness * mat.roughness * mat.roughness;
|
||||||
float d = (NDotH * NDotH) * (alpha2 - 1) + 1;
|
float d = (NDotH * NDotH) * (alpha2 - 1) + 1;
|
||||||
return alpha2 / max((PI * d * d), eps);
|
return alpha2 / max((PI * d * d), eps);
|
||||||
@ -191,7 +206,7 @@ float map(float value, float min1, float max1, float min2, float max2) {
|
|||||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 microfacetModel(Material mat, int light_idx, Light light, vec3 P, vec3 N) {
|
vec3 microfacetModel(EvalMaterial mat, int light_idx, Light light, vec3 P, vec3 N) {
|
||||||
int csm_split_idx = getCSMSplit(light_idx, P.z);
|
int csm_split_idx = getCSMSplit(light_idx, P.z);
|
||||||
// Visualize CSM splits
|
// Visualize CSM splits
|
||||||
//mat.albedo = vec4(mix(mat.albedo.rgb, csm_split_colors[csm_split_idx], 0.8), mat.albedo.a);
|
//mat.albedo = vec4(mix(mat.albedo.rgb, csm_split_colors[csm_split_idx], 0.8), mat.albedo.a);
|
||||||
@ -290,9 +305,10 @@ vec3 microfacetModel(Material mat, int light_idx, Light light, vec3 P, vec3 N) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Material material = evalMaterial();
|
Material mat = materials[DrawID];
|
||||||
|
EvalMaterial material = evalMaterial();
|
||||||
|
|
||||||
vec3 N = textureSize(normal_map, 0) == ivec2(0) ? vec3(0.5) : vec3(texture(normal_map, VertexOut.uv * normal_map_uv_scale).xy, 0);
|
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);
|
||||||
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);
|
||||||
|
@ -323,17 +323,17 @@ fn loadMeshErr(self: *AssetManager, id: AssetId) !LoadedMesh {
|
|||||||
|
|
||||||
const vertex_offset = allocation.vertex.offset;
|
const vertex_offset = allocation.vertex.offset;
|
||||||
|
|
||||||
gl.namedBufferSubData(self.vertex_heap.vertices, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.vertices.ptr));
|
gl.namedBufferSubData(self.vertex_heap.vertices.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.vertices.ptr));
|
||||||
checkGLError();
|
checkGLError();
|
||||||
gl.namedBufferSubData(self.vertex_heap.normals, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.normals.ptr));
|
gl.namedBufferSubData(self.vertex_heap.normals.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.normals.ptr));
|
||||||
checkGLError();
|
checkGLError();
|
||||||
gl.namedBufferSubData(self.vertex_heap.tangents, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.tangents.ptr));
|
gl.namedBufferSubData(self.vertex_heap.tangents.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.tangents.ptr));
|
||||||
checkGLError();
|
checkGLError();
|
||||||
gl.namedBufferSubData(self.vertex_heap.uvs, @intCast(vertex_offset * @sizeOf(formats.Vector2)), @intCast(vertices_len * @sizeOf(formats.Vector2)), @ptrCast(mesh.uvs.ptr));
|
gl.namedBufferSubData(self.vertex_heap.uvs.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector2)), @intCast(vertices_len * @sizeOf(formats.Vector2)), @ptrCast(mesh.uvs.ptr));
|
||||||
checkGLError();
|
checkGLError();
|
||||||
|
|
||||||
const index_offset = allocation.index.offset;
|
const index_offset = allocation.index.offset;
|
||||||
gl.namedBufferSubData(self.vertex_heap.indices, @intCast(index_offset * @sizeOf(formats.Index)), @intCast(mesh.indices.len * @sizeOf(formats.Index)), @ptrCast(mesh.indices.ptr));
|
gl.namedBufferSubData(self.vertex_heap.indices.buffer, @intCast(index_offset * @sizeOf(formats.Index)), @intCast(mesh.indices.len * @sizeOf(formats.Index)), @ptrCast(mesh.indices.ptr));
|
||||||
|
|
||||||
const loaded_mesh = LoadedMesh{
|
const loaded_mesh = LoadedMesh{
|
||||||
.aabb = .{
|
.aabb = .{
|
||||||
@ -343,27 +343,27 @@ fn loadMeshErr(self: *AssetManager, id: AssetId) !LoadedMesh {
|
|||||||
.heap_handle = allocation,
|
.heap_handle = allocation,
|
||||||
.material = mesh.material,
|
.material = mesh.material,
|
||||||
.positions = .{
|
.positions = .{
|
||||||
.buffer = self.vertex_heap.vertices,
|
.buffer = self.vertex_heap.vertices.buffer,
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
||||||
.stride = @sizeOf(formats.Vector3),
|
.stride = @sizeOf(formats.Vector3),
|
||||||
},
|
},
|
||||||
.normals = .{
|
.normals = .{
|
||||||
.buffer = self.vertex_heap.normals,
|
.buffer = self.vertex_heap.normals.buffer,
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
||||||
.stride = @sizeOf(formats.Vector3),
|
.stride = @sizeOf(formats.Vector3),
|
||||||
},
|
},
|
||||||
.tangents = .{
|
.tangents = .{
|
||||||
.buffer = self.vertex_heap.tangents,
|
.buffer = self.vertex_heap.tangents.buffer,
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)),
|
||||||
.stride = @sizeOf(formats.Vector3),
|
.stride = @sizeOf(formats.Vector3),
|
||||||
},
|
},
|
||||||
.uvs = .{
|
.uvs = .{
|
||||||
.buffer = self.vertex_heap.uvs,
|
.buffer = self.vertex_heap.uvs.buffer,
|
||||||
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector2)),
|
.offset = @intCast(vertex_offset * @sizeOf(formats.Vector2)),
|
||||||
.stride = @sizeOf(formats.Vector2),
|
.stride = @sizeOf(formats.Vector2),
|
||||||
},
|
},
|
||||||
.indices = .{
|
.indices = .{
|
||||||
.buffer = self.vertex_heap.indices,
|
.buffer = self.vertex_heap.indices.buffer,
|
||||||
.offset = @intCast(index_offset * @sizeOf(formats.Index)),
|
.offset = @intCast(index_offset * @sizeOf(formats.Index)),
|
||||||
.count = @intCast(mesh.indices.len),
|
.count = @intCast(mesh.indices.len),
|
||||||
.type = gl.UNSIGNED_INT,
|
.type = gl.UNSIGNED_INT,
|
||||||
@ -567,7 +567,7 @@ pub const BufferSlice = struct {
|
|||||||
pub const IndexSlice = struct {
|
pub const IndexSlice = struct {
|
||||||
buffer: gl.GLuint,
|
buffer: gl.GLuint,
|
||||||
offset: gl.GLuint,
|
offset: gl.GLuint,
|
||||||
count: gl.GLsizei,
|
count: gl.GLuint,
|
||||||
type: gl.GLenum,
|
type: gl.GLenum,
|
||||||
base_vertex: gl.GLint,
|
base_vertex: gl.GLint,
|
||||||
|
|
||||||
@ -587,8 +587,8 @@ pub const ShaderType = enum {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERTEX_DEFINES = "#version 450 core\n#define VERTEX_SHADER 1\n#define VERTEX_EXPORT out\n";
|
const VERTEX_DEFINES = "#version 460 core\n#define VERTEX_SHADER 1\n#define VERTEX_EXPORT out\n";
|
||||||
const FRAGMENT_DEFINES = "#version 450 core\n#define FRAGMENT_SHADER 1\n#define VERTEX_EXPORT in\n";
|
const FRAGMENT_DEFINES = "#version 460 core\n#define FRAGMENT_SHADER 1\n#define VERTEX_EXPORT in\n";
|
||||||
pub fn getDefines(self: ShaderType) []const u8 {
|
pub fn getDefines(self: ShaderType) []const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.vertex => VERTEX_DEFINES,
|
.vertex => VERTEX_DEFINES,
|
||||||
@ -729,13 +729,29 @@ const VertexBufferHeap = struct {
|
|||||||
index: BuddyAllocator.Alloc = .{},
|
index: BuddyAllocator.Alloc = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Buffer = struct {
|
||||||
|
buffer: gl.GLuint,
|
||||||
|
stride: gl.GLsizei,
|
||||||
|
|
||||||
|
pub fn init(name: gl.GLuint, stride: usize) Buffer {
|
||||||
|
return .{
|
||||||
|
.buffer = name,
|
||||||
|
.stride = @intCast(stride),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind(self: *const Buffer, index: gl.GLuint) void {
|
||||||
|
gl.bindVertexBuffer(index, self.buffer, 0, self.stride);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
vertex_buddy: BuddyAllocator,
|
vertex_buddy: BuddyAllocator,
|
||||||
index_buddy: BuddyAllocator,
|
index_buddy: BuddyAllocator,
|
||||||
vertices: gl.GLuint,
|
vertices: Buffer,
|
||||||
normals: gl.GLuint,
|
normals: Buffer,
|
||||||
tangents: gl.GLuint,
|
tangents: Buffer,
|
||||||
uvs: gl.GLuint,
|
uvs: Buffer,
|
||||||
indices: gl.GLuint,
|
indices: Buffer,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !Self {
|
pub fn init(allocator: std.mem.Allocator) !Self {
|
||||||
// 256 mega vertices :)
|
// 256 mega vertices :)
|
||||||
@ -760,38 +776,38 @@ const VertexBufferHeap = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const vertices = bufs[0];
|
const vertices = Buffer.init(bufs[0], @sizeOf(formats.Vector3));
|
||||||
const normals = bufs[1];
|
const normals = Buffer.init(bufs[1], @sizeOf(formats.Vector3));
|
||||||
const tangents = bufs[2];
|
const tangents = Buffer.init(bufs[2], @sizeOf(formats.Vector3));
|
||||||
const uvs = bufs[3];
|
const uvs = Buffer.init(bufs[3], @sizeOf(formats.Vector2));
|
||||||
const indices = bufs[4];
|
const indices = Buffer.init(bufs[4], @sizeOf(formats.Index));
|
||||||
|
|
||||||
gl.namedBufferStorage(
|
gl.namedBufferStorage(
|
||||||
vertices,
|
vertices.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
||||||
null,
|
null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
);
|
||||||
gl.namedBufferStorage(
|
gl.namedBufferStorage(
|
||||||
normals,
|
normals.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
||||||
null,
|
null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
);
|
||||||
gl.namedBufferStorage(
|
gl.namedBufferStorage(
|
||||||
tangents,
|
tangents.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
||||||
null,
|
null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
);
|
||||||
gl.namedBufferStorage(
|
gl.namedBufferStorage(
|
||||||
uvs,
|
uvs.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector2)),
|
@intCast(vertex_buf_size * @sizeOf(formats.Vector2)),
|
||||||
null,
|
null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
);
|
||||||
gl.namedBufferStorage(
|
gl.namedBufferStorage(
|
||||||
indices,
|
indices.buffer,
|
||||||
@intCast(index_buf_size * @sizeOf(formats.Index)),
|
@intCast(index_buf_size * @sizeOf(formats.Index)),
|
||||||
null,
|
null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
gl.DYNAMIC_STORAGE_BIT,
|
||||||
|
466
src/Render.zig
466
src/Render.zig
@ -19,6 +19,7 @@ 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 = 4096;
|
||||||
pub const MAX_LIGHT_COMMANDS = 2048;
|
pub const MAX_LIGHT_COMMANDS = 2048;
|
||||||
|
pub const MAX_MATERIALS = MAX_DRAW_COMMANDS;
|
||||||
pub const CSM_SPLITS = 4;
|
pub const CSM_SPLITS = 4;
|
||||||
pub const DIRECTIONAL_SHADOW_MAP_SIZE = 2048;
|
pub const DIRECTIONAL_SHADOW_MAP_SIZE = 2048;
|
||||||
// affects how cascades are split
|
// affects how cascades are split
|
||||||
@ -40,12 +41,16 @@ tripple_buffer_index: usize = MAX_FRAMES_QUEUED - 1,
|
|||||||
gl_fences: [MAX_FRAMES_QUEUED]?gl.GLsync = [_]?gl.GLsync{null} ** MAX_FRAMES_QUEUED,
|
gl_fences: [MAX_FRAMES_QUEUED]?gl.GLsync = [_]?gl.GLsync{null} ** MAX_FRAMES_QUEUED,
|
||||||
camera_ubo: gl.GLuint = 0,
|
camera_ubo: gl.GLuint = 0,
|
||||||
camera_matrices: []u8 = &.{},
|
camera_matrices: []u8 = &.{},
|
||||||
point_lights_ssbo: gl.GLuint = 0,
|
|
||||||
point_lights: []u8 = &.{}, // TODO: remove
|
|
||||||
lights: [MAX_LIGHT_COMMANDS]LightCommand = undefined,
|
lights: [MAX_LIGHT_COMMANDS]LightCommand = undefined,
|
||||||
light_count: usize = 0,
|
light_count: usize = 0,
|
||||||
|
|
||||||
|
lights_ssbo: LightSSBO = .{},
|
||||||
|
materials_pbr_ssbo: MaterialPBRSSBO = .{},
|
||||||
|
draw_cmd_data_ssbo: DrawCommandDataSSBO = .{},
|
||||||
|
|
||||||
command_buffer: [MAX_DRAW_COMMANDS]DrawCommand = undefined,
|
command_buffer: [MAX_DRAW_COMMANDS]DrawCommand = undefined,
|
||||||
command_count: usize = 0,
|
command_count: usize = 0,
|
||||||
|
|
||||||
ubo_align: usize = 0,
|
ubo_align: usize = 0,
|
||||||
ssbo_align: usize = 0,
|
ssbo_align: usize = 0,
|
||||||
shadow_vao: gl.GLuint = 0,
|
shadow_vao: gl.GLuint = 0,
|
||||||
@ -68,6 +73,8 @@ screen_mip_count: usize = 1,
|
|||||||
// VAO for post processing shaders
|
// VAO for post processing shaders
|
||||||
post_process_vao: gl.GLuint = 0,
|
post_process_vao: gl.GLuint = 0,
|
||||||
|
|
||||||
|
draw_indirect_buffer: gl.GLuint = 0,
|
||||||
|
|
||||||
// Bloom
|
// Bloom
|
||||||
screen_bloom_sampler: gl.GLuint = 0,
|
screen_bloom_sampler: gl.GLuint = 0,
|
||||||
|
|
||||||
@ -154,28 +161,11 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
|||||||
render.camera_matrices = camera_matrices_c[0..buf_size];
|
render.camera_matrices = camera_matrices_c[0..buf_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Point lights ubo
|
// SSBOs
|
||||||
{
|
{
|
||||||
gl.createBuffers(1, &render.point_lights_ssbo);
|
render.lights_ssbo = LightSSBO.init(render.ssbo_align, MAX_LIGHTS, MAX_FRAMES_QUEUED) catch @panic("LightSSBO.init()");
|
||||||
std.debug.assert(render.camera_ubo != 0);
|
render.materials_pbr_ssbo = MaterialPBRSSBO.init(render.ssbo_align, MAX_MATERIALS, MAX_FRAMES_QUEUED) catch @panic("MaterialPBRSSBO.init()");
|
||||||
|
render.draw_cmd_data_ssbo = DrawCommandDataSSBO.init(render.ssbo_align, MAX_DRAW_COMMANDS, MAX_FRAMES_QUEUED) catch @panic("DrawCommandDataSSBO.init()");
|
||||||
const buf_size = render.ssboAlign(@sizeOf(LightArraySSBO) + Light.sizeOfStd430() * MAX_LIGHTS) * MAX_FRAMES_QUEUED;
|
|
||||||
gl.namedBufferStorage(
|
|
||||||
render.point_lights_ssbo,
|
|
||||||
@intCast(buf_size),
|
|
||||||
null,
|
|
||||||
PERSISTENT_BUFFER_FLAGS,
|
|
||||||
);
|
|
||||||
const point_lights_c: [*]u8 = @ptrCast(gl.mapNamedBufferRange(
|
|
||||||
render.point_lights_ssbo,
|
|
||||||
0,
|
|
||||||
@intCast(buf_size),
|
|
||||||
PERSISTENT_BUFFER_FLAGS,
|
|
||||||
) orelse {
|
|
||||||
checkGLError();
|
|
||||||
@panic("bind point_lights_ssbo");
|
|
||||||
});
|
|
||||||
render.point_lights = point_lights_c[0..buf_size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -329,6 +319,14 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
|||||||
gl.vertexArrayAttribFormat(vao, Attrib.Position.value(), 3, gl.FLOAT, gl.FALSE, 0);
|
gl.vertexArrayAttribFormat(vao, Attrib.Position.value(), 3, gl.FLOAT, gl.FALSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw indirect buffer
|
||||||
|
{
|
||||||
|
gl.createBuffers(1, &render.draw_indirect_buffer);
|
||||||
|
std.debug.assert(render.draw_indirect_buffer != 0);
|
||||||
|
|
||||||
|
gl.namedBufferStorage(render.draw_indirect_buffer, @sizeOf(DrawIndirectCmd) * MAX_DRAW_COMMANDS, null, gl.MAP_WRITE_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
return render;
|
return render;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,24 +397,13 @@ pub fn begin(self: *Render) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getLightBuffer(self: *Render) *LightArraySSBO {
|
|
||||||
return @alignCast(@ptrCast(self.point_lights[self.tripple_buffer_index * self.ssboAlign(@sizeOf(LightArraySSBO) + Light.sizeOfStd430() * MAX_LIGHTS) ..].ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: get rid of this
|
// TODO: get rid of this
|
||||||
pub fn flushUBOs(self: *Render) void {
|
pub fn flushUBOs(self: *Render) void {
|
||||||
const idx = self.tripple_buffer_index;
|
const idx = self.tripple_buffer_index;
|
||||||
|
|
||||||
const light_array_size = self.ssboAlign(@sizeOf(LightArraySSBO) + Light.sizeOfStd430() * MAX_LIGHTS);
|
self.lights_ssbo.bind(idx, SSBO.PointLights);
|
||||||
// gl.flushMappedNamedBufferRange(self.point_lights_ssbo, idx * @sizeOf(PointLightArray), @sizeOf(PointLightArray));
|
self.materials_pbr_ssbo.bind(idx, SSBO.Materials);
|
||||||
gl.bindBufferRange(
|
self.draw_cmd_data_ssbo.bind(idx, SSBO.DrawCommandData);
|
||||||
gl.SHADER_STORAGE_BUFFER,
|
|
||||||
SSBO.PointLights.value(),
|
|
||||||
self.point_lights_ssbo,
|
|
||||||
idx * light_array_size,
|
|
||||||
@intCast(light_array_size),
|
|
||||||
);
|
|
||||||
checkGLError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LightKind = enum {
|
pub const LightKind = enum {
|
||||||
@ -504,9 +491,8 @@ pub fn finish(self: *Render) void {
|
|||||||
}.lessThan);
|
}.lessThan);
|
||||||
}
|
}
|
||||||
|
|
||||||
const lights_buf = self.getLightBuffer();
|
const lights_buf = self.lights_ssbo.getInstance(self.tripple_buffer_index);
|
||||||
lights_buf.count = 0;
|
lights_buf.count.* = 0;
|
||||||
const lights_buf_lights = lights_buf.getLights();
|
|
||||||
|
|
||||||
var dir_view_proj_mat: [CSM_SPLITS]Mat4 = undefined;
|
var dir_view_proj_mat: [CSM_SPLITS]Mat4 = undefined;
|
||||||
|
|
||||||
@ -522,11 +508,11 @@ pub fn finish(self: *Render) void {
|
|||||||
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.shadow).program);
|
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.shadow).program);
|
||||||
|
|
||||||
for (lights) |light_cmd| {
|
for (lights) |light_cmd| {
|
||||||
const i = lights_buf.count;
|
const i = lights_buf.count.*;
|
||||||
if (i == lights_buf_lights.len) break;
|
if (i == lights_buf.data.len) break;
|
||||||
|
|
||||||
const light = &lights_buf_lights[i];
|
const light = &lights_buf.data[i];
|
||||||
lights_buf.count += 1;
|
lights_buf.count.* += 1;
|
||||||
|
|
||||||
switch (light_cmd) {
|
switch (light_cmd) {
|
||||||
.directional => |dir_light| {
|
.directional => |dir_light| {
|
||||||
@ -707,7 +693,7 @@ pub fn finish(self: *Render) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Light world space to view space
|
// Light world space to view space
|
||||||
for (lights_buf_lights[0..lights_buf.count]) |*light| {
|
for (lights_buf.data[0..lights_buf.count.*]) |*light| {
|
||||||
light.pos = self.camera.view_mat.mulByVec4(light.pos);
|
light.pos = self.camera.view_mat.mulByVec4(light.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,102 +740,81 @@ pub fn finish(self: *Render) void {
|
|||||||
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);
|
||||||
|
|
||||||
var switched_to_alpha_blend = false;
|
const switched_to_alpha_blend = false;
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
|
||||||
|
self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value());
|
||||||
|
checkGLError();
|
||||||
|
self.assetman.vertex_heap.normals.bind(Render.Attrib.Normal.value());
|
||||||
|
checkGLError();
|
||||||
|
self.assetman.vertex_heap.tangents.bind(Render.Attrib.Tangent.value());
|
||||||
|
checkGLError();
|
||||||
|
self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value());
|
||||||
|
checkGLError();
|
||||||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer);
|
||||||
|
checkGLError();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
const draw_indirect_cmds_c: [*]u8 = @ptrCast(gl.mapNamedBuffer(
|
||||||
|
self.draw_indirect_buffer,
|
||||||
|
gl.WRITE_ONLY,
|
||||||
|
) orelse {
|
||||||
|
checkGLError();
|
||||||
|
@panic("map draw indirect buffer");
|
||||||
|
});
|
||||||
|
var draw_indirect_cmds = std.mem.bytesAsSlice(DrawIndirectCmd, draw_indirect_cmds_c[0 .. @sizeOf(DrawIndirectCmd) * MAX_DRAW_COMMANDS]);
|
||||||
|
|
||||||
|
const materials = self.materials_pbr_ssbo.getInstance(self.tripple_buffer_index);
|
||||||
|
materials.count.* = 0;
|
||||||
|
|
||||||
|
const draw_cmd_data = self.draw_cmd_data_ssbo.getInstance(self.tripple_buffer_index);
|
||||||
|
|
||||||
var rendered_count: usize = 0;
|
var rendered_count: usize = 0;
|
||||||
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);
|
||||||
const aabb = math.AABB.fromMinMax(mesh.aabb.min, mesh.aabb.max);
|
const aabb = math.AABB.fromMinMax(mesh.aabb.min, mesh.aabb.max);
|
||||||
|
|
||||||
if (!self.world_camera_frustum.intersectAABB(aabb.transform(cmd.transform))) {
|
if (!self.world_camera_frustum.intersectAABB(aabb.transform(cmd.transform))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rendered_count += 1;
|
|
||||||
|
|
||||||
const material: Material = if (cmd.material_override) |mat| mat else mesh.material;
|
const material: Material = if (cmd.material_override) |mat| mat else mesh.material;
|
||||||
|
|
||||||
// Opaque objects are drawn, start rendering alpha blended objects
|
// Opaque objects are drawn, start rendering alpha blended objects
|
||||||
{
|
if (material.blend_mode == .AlphaBlend and !switched_to_alpha_blend) {
|
||||||
if (material.blend_mode == .AlphaBlend and !switched_to_alpha_blend) {
|
break :cmds;
|
||||||
switched_to_alpha_blend = true;
|
// switched_to_alpha_blend = true;
|
||||||
gl.enable(gl.BLEND);
|
// gl.enable(gl.BLEND);
|
||||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data));
|
draw_cmd_data.data[rendered_count] = DrawCommandData{
|
||||||
{
|
.transform = cmd.transform,
|
||||||
gl.uniform4fv(Uniform.Color.value(), 1, @ptrCast(&material.albedo.data));
|
};
|
||||||
|
|
||||||
const albedo_map = self.assetman.resolveTexture(material.albedo_map);
|
materials.data[rendered_count] = MaterialPBR.fromMaterial(self.assetman, &material);
|
||||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(
|
materials.count.* += 1;
|
||||||
Uniform.AlbedoMap.value(),
|
|
||||||
albedo_map.handle,
|
|
||||||
);
|
|
||||||
gl.uniform2fv(Uniform.AlbedoMapUVScale.value(), 1, @ptrCast(&albedo_map.uv_scale.data));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const normal_map = self.assetman.resolveTexture(material.normal_map);
|
|
||||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(
|
|
||||||
Uniform.NormalMap.value(),
|
|
||||||
normal_map.handle,
|
|
||||||
);
|
|
||||||
gl.uniform2fv(Uniform.NormalMapUVScale.value(), 1, @ptrCast(&normal_map.uv_scale.data));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
gl.uniform1fv(Uniform.Metallic.value(), 1, &material.metallic);
|
|
||||||
|
|
||||||
const metallic_map = self.assetman.resolveTexture(material.metallic_map);
|
draw_indirect_cmds[rendered_count] = DrawIndirectCmd{
|
||||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(
|
.count = mesh.indices.count,
|
||||||
Uniform.MetallicMap.value(),
|
.instance_count = 1,
|
||||||
metallic_map.handle,
|
.first_index = mesh.indices.offset / 4,
|
||||||
);
|
.base_vertex = mesh.indices.base_vertex,
|
||||||
gl.uniform2fv(Uniform.MetallicMapUVScale.value(), 1, @ptrCast(&metallic_map.uv_scale.data));
|
.base_instance = 0,
|
||||||
}
|
.transform = cmd.transform,
|
||||||
{
|
};
|
||||||
gl.uniform1fv(Uniform.Roughness.value(), 1, &material.roughness);
|
|
||||||
|
|
||||||
const roughness_map = self.assetman.resolveTexture(material.roughness_map);
|
rendered_count += 1;
|
||||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(
|
|
||||||
Uniform.RoughnessMap.value(),
|
|
||||||
roughness_map.handle,
|
|
||||||
);
|
|
||||||
gl.uniform2fv(Uniform.RoughnessMapUVScale.value(), 1, @ptrCast(&roughness_map.uv_scale.data));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
gl.uniform3fv(Uniform.Emission.value(), 1, @ptrCast(&material.emission.data));
|
|
||||||
|
|
||||||
const emission_map = self.assetman.resolveTexture(material.emission_map);
|
|
||||||
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(
|
|
||||||
Uniform.EmissionMap.value(),
|
|
||||||
emission_map.handle,
|
|
||||||
);
|
|
||||||
gl.uniform2fv(Uniform.EmissionMapUVScale.value(), 1, @ptrCast(&emission_map.uv_scale.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());
|
|
||||||
checkGLError();
|
|
||||||
mesh.normals.bind(Render.Attrib.Normal.value());
|
|
||||||
checkGLError();
|
|
||||||
mesh.tangents.bind(Render.Attrib.Tangent.value());
|
|
||||||
checkGLError();
|
|
||||||
mesh.uvs.bind(Render.Attrib.UV.value());
|
|
||||||
checkGLError();
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices.buffer);
|
|
||||||
checkGLError();
|
|
||||||
gl.drawElementsBaseVertex(
|
|
||||||
gl.TRIANGLES,
|
|
||||||
mesh.indices.count,
|
|
||||||
mesh.indices.type,
|
|
||||||
@ptrFromInt(mesh.indices.offset),
|
|
||||||
mesh.indices.base_vertex,
|
|
||||||
);
|
|
||||||
checkGLError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = gl.unmapNamedBuffer(self.draw_indirect_buffer);
|
||||||
|
|
||||||
|
gl.bindBuffer(gl.DRAW_INDIRECT_BUFFER, self.draw_indirect_buffer);
|
||||||
|
|
||||||
|
gl.multiDrawElementsIndirect(gl.TRIANGLES, gl.UNSIGNED_INT, null, @intCast(rendered_count), @sizeOf(DrawIndirectCmd));
|
||||||
|
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
|
||||||
// Debug stuff
|
// Debug stuff
|
||||||
@ -882,7 +847,7 @@ pub fn finish(self: *Render) void {
|
|||||||
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&frustum_model_mat.data));
|
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&frustum_model_mat.data));
|
||||||
gl.drawElementsBaseVertex(
|
gl.drawElementsBaseVertex(
|
||||||
gl.TRIANGLES,
|
gl.TRIANGLES,
|
||||||
mesh.indices.count,
|
@intCast(mesh.indices.count),
|
||||||
mesh.indices.type,
|
mesh.indices.type,
|
||||||
@ptrFromInt(mesh.indices.offset),
|
@ptrFromInt(mesh.indices.offset),
|
||||||
mesh.indices.base_vertex,
|
mesh.indices.base_vertex,
|
||||||
@ -901,7 +866,7 @@ pub fn finish(self: *Render) void {
|
|||||||
for (self.world_view_frustum_corners[split_idx]) |corner| {
|
for (self.world_view_frustum_corners[split_idx]) |corner| {
|
||||||
const model = Mat4.fromTranslate(corner);
|
const model = Mat4.fromTranslate(corner);
|
||||||
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&model.data));
|
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&model.data));
|
||||||
gl.drawElementsBaseVertex(gl.TRIANGLES, mesh.indices.count, mesh.indices.type, @ptrFromInt(mesh.indices.offset), mesh.indices.base_vertex);
|
gl.drawElementsBaseVertex(gl.TRIANGLES, @intCast(mesh.indices.count), mesh.indices.type, @ptrFromInt(mesh.indices.offset), mesh.indices.base_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -941,7 +906,7 @@ pub fn finish(self: *Render) void {
|
|||||||
|
|
||||||
gl.drawElementsBaseVertex(
|
gl.drawElementsBaseVertex(
|
||||||
gl.TRIANGLES,
|
gl.TRIANGLES,
|
||||||
quad.indices.count,
|
@intCast(quad.indices.count),
|
||||||
quad.indices.type,
|
quad.indices.type,
|
||||||
@ptrFromInt(quad.indices.offset),
|
@ptrFromInt(quad.indices.offset),
|
||||||
quad.indices.base_vertex,
|
quad.indices.base_vertex,
|
||||||
@ -968,7 +933,7 @@ pub fn finish(self: *Render) void {
|
|||||||
|
|
||||||
gl.drawElementsBaseVertex(
|
gl.drawElementsBaseVertex(
|
||||||
gl.TRIANGLES,
|
gl.TRIANGLES,
|
||||||
quad.indices.count,
|
@intCast(quad.indices.count),
|
||||||
quad.indices.type,
|
quad.indices.type,
|
||||||
@ptrFromInt(quad.indices.offset),
|
@ptrFromInt(quad.indices.offset),
|
||||||
quad.indices.base_vertex,
|
quad.indices.base_vertex,
|
||||||
@ -988,7 +953,7 @@ pub fn finish(self: *Render) void {
|
|||||||
gl.bindTextureUnit(0, self.screen_color_texture);
|
gl.bindTextureUnit(0, self.screen_color_texture);
|
||||||
defer gl.bindTextureUnit(0, 0);
|
defer gl.bindTextureUnit(0, 0);
|
||||||
|
|
||||||
gl.drawElementsBaseVertex(gl.TRIANGLES, quad.indices.count, quad.indices.type, @ptrFromInt(quad.indices.offset), quad.indices.base_vertex);
|
gl.drawElementsBaseVertex(gl.TRIANGLES, @intCast(quad.indices.count), quad.indices.type, @ptrFromInt(quad.indices.offset), quad.indices.base_vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.gl_fences[self.tripple_buffer_index] = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
self.gl_fences[self.tripple_buffer_index] = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
@ -1058,7 +1023,7 @@ fn renderShadow(self: *Render, frustum: *const math.Frustum) void {
|
|||||||
|
|
||||||
gl.drawElementsBaseVertex(
|
gl.drawElementsBaseVertex(
|
||||||
gl.TRIANGLES,
|
gl.TRIANGLES,
|
||||||
mesh.indices.count,
|
@intCast(mesh.indices.count),
|
||||||
mesh.indices.type,
|
mesh.indices.type,
|
||||||
@ptrFromInt(mesh.indices.offset),
|
@ptrFromInt(mesh.indices.offset),
|
||||||
mesh.indices.base_vertex,
|
mesh.indices.base_vertex,
|
||||||
@ -1116,12 +1081,59 @@ pub const UBO = enum(gl.GLuint) {
|
|||||||
};
|
};
|
||||||
pub const SSBO = enum(gl.GLuint) {
|
pub const SSBO = enum(gl.GLuint) {
|
||||||
PointLights = 1,
|
PointLights = 1,
|
||||||
|
Materials = 2,
|
||||||
|
DrawCommandData = 3,
|
||||||
|
|
||||||
pub inline fn value(self: SSBO) gl.GLuint {
|
pub inline fn value(self: SSBO) gl.GLuint {
|
||||||
return @intFromEnum(self);
|
return @intFromEnum(self);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn getStd430Align(comptime T: type) usize {
|
||||||
|
switch (T) {
|
||||||
|
Vec2, Vec2_i32 => {
|
||||||
|
return 8;
|
||||||
|
},
|
||||||
|
Vec3, Vec4 => {
|
||||||
|
return 16;
|
||||||
|
},
|
||||||
|
Mat4 => {
|
||||||
|
return 16;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const info = @typeInfo(T);
|
||||||
|
switch (info) {
|
||||||
|
.Int => |int| {
|
||||||
|
if (int.bits & (int.bits - 1) != 0) {
|
||||||
|
@compileError("Non power of two bit size of int");
|
||||||
|
}
|
||||||
|
const byte_size = int.bits / 8;
|
||||||
|
|
||||||
|
return @intCast(byte_size);
|
||||||
|
},
|
||||||
|
.Float => |float| {
|
||||||
|
if (float.bits & (float.bits - 1) != 0) {
|
||||||
|
@compileError("Non power of two bit size of float");
|
||||||
|
}
|
||||||
|
const byte_size = float.bits / 8;
|
||||||
|
|
||||||
|
return @intCast(byte_size);
|
||||||
|
},
|
||||||
|
.Struct => |str| {
|
||||||
|
if (str.layout != .@"extern") {
|
||||||
|
@compileError("Structs should be extern for std430");
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline for (str.fields) |field| {
|
||||||
|
// field.
|
||||||
|
// }
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
_ => @compileError("Unknown type for std430 " ++ @typeName(T)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const Uniform = enum(gl.GLint) {
|
pub const Uniform = enum(gl.GLint) {
|
||||||
ModelMatrix = 1,
|
ModelMatrix = 1,
|
||||||
Color = 2,
|
Color = 2,
|
||||||
@ -1194,25 +1206,205 @@ pub const Light = extern struct {
|
|||||||
|
|
||||||
/// Alignment of this struct if it was in a std430 array
|
/// Alignment of this struct if it was in a std430 array
|
||||||
pub fn alignStd430() usize {
|
pub fn alignStd430() usize {
|
||||||
return 16;
|
return @alignOf(Light);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Aligned size of this struct if it was in a std430 array
|
/// Aligned size of this struct if it was in a std430 array
|
||||||
pub fn sizeOfStd430() usize {
|
pub fn sizeOfStd430() usize {
|
||||||
return std.mem.alignForward(usize, @sizeOf(Light), Light.alignStd430());
|
return @sizeOf(Light);
|
||||||
|
// return std.mem.alignForward(usize, @sizeOf(Light), Light.alignStd430());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: rename
|
const LightSSBO = BufferSSBO(Light);
|
||||||
pub const LightArraySSBO = extern struct {
|
|
||||||
count: c_uint,
|
|
||||||
// Zero sized field that just has the right alignment
|
|
||||||
_lights_start: [0]Light align(Light.alignStd430()),
|
|
||||||
|
|
||||||
pub fn getLights(self: *LightArraySSBO) []align(Light.alignStd430()) Light {
|
// Shader struct for material data
|
||||||
var lights_c: [*]align(Light.alignStd430()) Light = @ptrFromInt(@intFromPtr(self) + @offsetOf(LightArraySSBO, "_lights_start"));
|
pub const MaterialPBR = extern struct {
|
||||||
return lights_c[0..MAX_LIGHTS];
|
albedo: Vec4,
|
||||||
|
albedo_map: gl.GLuint64,
|
||||||
|
albedo_map_uv_scale: Vec2,
|
||||||
|
normal_map: gl.GLuint64,
|
||||||
|
normal_map_uv_scale: Vec2,
|
||||||
|
metallic: f32,
|
||||||
|
metallic_map: gl.GLuint64,
|
||||||
|
metallic_map_uv_scale: Vec2,
|
||||||
|
roughness: f32,
|
||||||
|
roughness_map: gl.GLuint64,
|
||||||
|
roughness_map_uv_scale: Vec2,
|
||||||
|
emission: Vec3 align(16),
|
||||||
|
emission_map: gl.GLuint64,
|
||||||
|
emission_map_uv_scale: Vec2,
|
||||||
|
|
||||||
|
pub fn fromMaterial(assetman: *AssetManager, mat: *const Material) MaterialPBR {
|
||||||
|
const albedo_map = assetman.resolveTexture(mat.albedo_map);
|
||||||
|
const normal_map = assetman.resolveTexture(mat.normal_map);
|
||||||
|
const metallic_map = assetman.resolveTexture(mat.metallic_map);
|
||||||
|
const roughness_map = assetman.resolveTexture(mat.roughness_map);
|
||||||
|
const emission_map = assetman.resolveTexture(mat.emission_map);
|
||||||
|
return .{
|
||||||
|
.albedo = mat.albedo,
|
||||||
|
.albedo_map = albedo_map.handle,
|
||||||
|
.albedo_map_uv_scale = albedo_map.uv_scale,
|
||||||
|
.normal_map = normal_map.handle,
|
||||||
|
.normal_map_uv_scale = normal_map.uv_scale,
|
||||||
|
.metallic = mat.metallic,
|
||||||
|
.metallic_map = metallic_map.handle,
|
||||||
|
.metallic_map_uv_scale = metallic_map.uv_scale,
|
||||||
|
.roughness = mat.roughness,
|
||||||
|
.roughness_map = roughness_map.handle,
|
||||||
|
.roughness_map_uv_scale = roughness_map.uv_scale,
|
||||||
|
.emission = mat.emission,
|
||||||
|
.emission_map = emission_map.handle,
|
||||||
|
.emission_map_uv_scale = emission_map.uv_scale,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Alignment of this struct if it was in a std430 array
|
||||||
|
pub fn alignStd430() usize {
|
||||||
|
return @alignOf(MaterialPBR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Aligned size of this struct if it was in a std430 array
|
||||||
|
pub fn sizeOfStd430() usize {
|
||||||
|
return @sizeOf(MaterialPBR);
|
||||||
|
//return std.mem.alignForward(usize, @sizeOf(MaterialPBR), MaterialPBR.alignStd430());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn BufferSSBO(comptime T: type) type {
|
||||||
|
return BufferSSBOAlign(T, @alignOf(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper struct for using ssbo arrays with count
|
||||||
|
// It provides a coherent always mapped buffer
|
||||||
|
pub fn BufferSSBOAlign(comptime T: type, comptime alignment: usize) type {
|
||||||
|
switch (@typeInfo(T)) {
|
||||||
|
.Struct => |str| {
|
||||||
|
if (str.layout != .@"extern") {
|
||||||
|
@compileError("Use extern layout for SSBO structs");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
return struct {
|
||||||
|
pub const BufferInstance = struct {
|
||||||
|
count: *c_uint,
|
||||||
|
data: []T align(alignment),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper struct to calculate buffer sizes
|
||||||
|
// not actually used
|
||||||
|
const BufferLayout = extern struct {
|
||||||
|
count: c_uint,
|
||||||
|
_start: [0]T align(alignment),
|
||||||
|
|
||||||
|
pub fn calculateBufSize(max_count: usize, ssbo_align: usize) usize {
|
||||||
|
return std.mem.alignForward(usize, @sizeOf(BufferInstance) + @sizeOf(T) * max_count, ssbo_align);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getData(self: *BufferLayout, len: usize) []T {
|
||||||
|
var data_c: [*]T = @ptrFromInt(@intFromPtr(self) + @offsetOf(BufferLayout, "_start"));
|
||||||
|
|
||||||
|
return data_c[0..len];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
len: usize = 0,
|
||||||
|
/// How many buffer instances of length `len` are in a single GL buffer
|
||||||
|
len_buffers: usize = 0,
|
||||||
|
buffer: gl.GLuint = 0,
|
||||||
|
data: []u8 = &.{},
|
||||||
|
|
||||||
|
// Don't like duplicating it here, but don't have a better idea
|
||||||
|
ssbo_align: usize = 0,
|
||||||
|
|
||||||
|
pub fn init(ssbo_align: usize, len: usize, num_buffers: usize) !Self {
|
||||||
|
var result = Self{
|
||||||
|
.len = len,
|
||||||
|
.len_buffers = num_buffers,
|
||||||
|
.ssbo_align = ssbo_align,
|
||||||
|
};
|
||||||
|
|
||||||
|
gl.createBuffers(1, &result.buffer);
|
||||||
|
if (result.buffer == 0) {
|
||||||
|
checkGLError();
|
||||||
|
return error.CreateBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PERSISTENT_BUFFER_FLAGS: gl.GLbitfield = gl.MAP_PERSISTENT_BIT | gl.MAP_WRITE_BIT | gl.MAP_COHERENT_BIT;
|
||||||
|
|
||||||
|
const buf_size = BufferLayout.calculateBufSize(len, ssbo_align) * num_buffers;
|
||||||
|
gl.namedBufferStorage(
|
||||||
|
result.buffer,
|
||||||
|
@intCast(buf_size),
|
||||||
|
null,
|
||||||
|
PERSISTENT_BUFFER_FLAGS,
|
||||||
|
);
|
||||||
|
const data_c: [*]u8 = @ptrCast(gl.mapNamedBufferRange(
|
||||||
|
result.buffer,
|
||||||
|
0,
|
||||||
|
@intCast(buf_size),
|
||||||
|
PERSISTENT_BUFFER_FLAGS,
|
||||||
|
) orelse {
|
||||||
|
checkGLError();
|
||||||
|
@panic("bind point_lights_ssbo");
|
||||||
|
});
|
||||||
|
|
||||||
|
result.data = data_c[0..buf_size];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
gl.deleteBuffers(1, &self.buffer);
|
||||||
|
self.buffer = 0;
|
||||||
|
self.data = &.{};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getInstance(self: *Self, index: usize) BufferInstance {
|
||||||
|
std.debug.assert(index < self.len_buffers);
|
||||||
|
|
||||||
|
const layout: *BufferLayout = @alignCast(@ptrCast(self.data[index * BufferLayout.calculateBufSize(self.len, self.ssbo_align) ..].ptr));
|
||||||
|
|
||||||
|
return BufferInstance{
|
||||||
|
.count = &layout.count,
|
||||||
|
.data = layout.getData(self.len),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind(self: *const Self, idx: usize, binding: SSBO) void {
|
||||||
|
std.debug.assert(idx < self.len_buffers);
|
||||||
|
|
||||||
|
const size = BufferLayout.calculateBufSize(self.len, self.ssbo_align);
|
||||||
|
gl.bindBufferRange(
|
||||||
|
gl.SHADER_STORAGE_BUFFER,
|
||||||
|
binding.value(),
|
||||||
|
self.buffer,
|
||||||
|
idx * size,
|
||||||
|
@intCast(size),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const MaterialPBRSSBO = BufferSSBO(MaterialPBR);
|
||||||
|
|
||||||
|
const DrawCommandData = extern struct {
|
||||||
|
transform: Mat4,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DrawCommandDataSSBO = BufferSSBOAlign(DrawCommandData, 16);
|
||||||
|
|
||||||
|
const DrawIndirectCmd = extern struct {
|
||||||
|
count: gl.GLuint,
|
||||||
|
instance_count: gl.GLuint,
|
||||||
|
first_index: gl.GLuint,
|
||||||
|
base_vertex: gl.GLint,
|
||||||
|
base_instance: gl.GLuint,
|
||||||
|
transform: Mat4,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn uboAlignedSizeOf(self: *const Render, comptime T: type) usize {
|
fn uboAlignedSizeOf(self: *const Render, comptime T: type) usize {
|
||||||
|
52
src/game.zig
52
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(.{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user