Alpha blending!

This commit is contained in:
sergeypdev 2024-03-14 19:20:26 +04:00
parent a865ea4ab7
commit b4a2b1d728
5 changed files with 66 additions and 13 deletions

View File

@ -55,7 +55,7 @@ int getCSMSplit(int lightIdx, float depth) {
// Uniforms
layout(location = 1) uniform mat4 model;
layout(location = 2) uniform vec3 color;
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);
@ -122,7 +122,7 @@ void main() {
out vec4 FragColor;
struct Material {
vec3 albedo;
vec4 albedo;
bool metallic;
float roughness;
vec3 emission;
@ -130,7 +130,7 @@ struct Material {
Material evalMaterial() {
Material result;
result.albedo = textureSize(albedo_map, 0) == ivec2(0) ? pow(color, vec3(2.2)) : texture(albedo_map, VertexOut.uv * albedo_map_uv_scale).rgb;
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);
float fMetallic = textureSize(metallic_map, 0) == ivec2(0) ? metallic : texture(metallic_map, VertexOut.uv * metallic_map_uv_scale).b;
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);
@ -142,7 +142,7 @@ Material evalMaterial() {
vec3 schlickFresnel(Material mat, float LDotH) {
vec3 f0 = vec3(0.04); // dielectric
if (mat.metallic) {
f0 = mat.albedo;
f0 = mat.albedo.rgb;
}
return f0 + (1 - f0) * pow(1.0 - LDotH, 5);
@ -193,11 +193,11 @@ float map(float value, float min1, float max1, float min2, float max2) {
vec3 microfacetModel(Material mat, int light_idx, Light light, vec3 P, vec3 N) {
int csm_split_idx = getCSMSplit(light_idx, P.z);
mat.albedo = mix(mat.albedo, csm_split_colors[csm_split_idx], 0.8);
mat.albedo = vec4(mix(mat.albedo.rgb, csm_split_colors[csm_split_idx], 0.8), mat.albedo.a);
vec3 diffuseBrdf = vec3(0); // metallic
if (!mat.metallic) {
diffuseBrdf = mat.albedo;
diffuseBrdf = mat.albedo.rgb;
}
// 0 - means directional, 1 - means point light
@ -303,7 +303,7 @@ void main() {
finalColor += microfacetModel(material, i, lights[i], VertexOut.vPos, N);
}
FragColor = vec4(finalColor, 1.0f);
FragColor = vec4(finalColor, material.albedo.a);
}

View File

@ -445,6 +445,35 @@ pub fn finish(self: *Render) void {
const camera_projection = self.camera.projection();
const view_proj = camera_projection.mul(self.camera.view_mat);
// Sort draw calls: opaque -> blended
{
const cmds = self.command_buffer[0..self.command_count];
std.mem.sortUnstable(DrawCommand, cmds, self, struct {
pub fn lessThan(render: *const Render, lhs: DrawCommand, rhs: DrawCommand) bool {
const lhs_mesh = render.assetman.resolveMesh(lhs.mesh);
const rhs_mesh = render.assetman.resolveMesh(rhs.mesh);
const lhs_material: Material = if (lhs.material_override) |mat| mat else lhs_mesh.material;
const rhs_material: Material = if (rhs.material_override) |mat| mat else rhs_mesh.material;
return switch (lhs_material.blend_mode) {
.Opaque => switch (rhs_material.blend_mode) {
.AlphaBlend => true,
.Opaque => false,
},
.AlphaBlend => switch (rhs_material.blend_mode) {
.Opaque => false,
.AlphaBlend => {
const lhs_view_pos = render.camera.view_mat.mulByVec4(lhs.transform.extractTranslation().toVec4(1));
const rhs_view_pos = render.camera.view_mat.mulByVec4(rhs.transform.extractTranslation().toVec4(1));
// Back to front sorting. View pos has negative Z
return lhs_view_pos.z() < rhs_view_pos.z();
},
},
};
}
}.lessThan);
}
if (self.update_view_frustum) {
self.camera_view_proj = view_proj;
self.world_camera_frustum = math.Frustum.new(view_proj);
@ -698,6 +727,9 @@ pub fn finish(self: *Render) void {
gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.mesh).program);
gl.bindVertexArray(self.mesh_vao);
var switched_to_alpha_blend = false;
gl.disable(gl.BLEND);
var rendered_count: usize = 0;
for (self.command_buffer[0..self.command_count]) |*cmd| {
const mesh = self.assetman.resolveMesh(cmd.mesh);
@ -710,9 +742,18 @@ pub fn finish(self: *Render) void {
const material: Material = if (cmd.material_override) |mat| mat else mesh.material;
// Opaque objects are drawn, start rendering alpha blended objects
{
if (material.blend_mode == .AlphaBlend and !switched_to_alpha_blend) {
switched_to_alpha_blend = true;
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
}
}
gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data));
{
gl.uniform3fv(Uniform.Color.value(), 1, @ptrCast(&material.albedo.data));
gl.uniform4fv(Uniform.Color.value(), 1, @ptrCast(&material.albedo.data));
const albedo_map = self.assetman.resolveTexture(material.albedo_map);
gl.GL_ARB_bindless_texture.uniformHandleui64ARB(
@ -775,6 +816,8 @@ pub fn finish(self: *Render) void {
);
}
gl.disable(gl.BLEND);
// Debug stuff
{
gl.polygonMode(gl.FRONT_AND_BACK, gl.LINE);

View File

@ -3,6 +3,7 @@ const builtin = @import("builtin");
const Handle = @import("assets").Handle;
const za = @import("zalgebra");
const Vec3 = za.Vec3;
const Vec4 = za.Vec4;
pub const Entity = @import("entity.zig").Entity;
pub const native_endian = builtin.cpu.arch.endian();
@ -366,8 +367,12 @@ test "write and read scene" {
}
pub const Material = extern struct {
// TODO: rgba
albedo: Vec3 = Vec3.one(),
pub const BlendMode = enum(u8) {
Opaque,
AlphaBlend,
};
albedo: Vec4 = Vec4.one(),
albedo_map: Handle.Texture = .{},
normal_map: Handle.Texture = .{},
metallic: f32 = 0,
@ -376,6 +381,7 @@ pub const Material = extern struct {
roughness_map: Handle.Texture = .{},
emission: Vec3 = Vec3.zero(),
emission_map: Handle.Texture = .{},
blend_mode: BlendMode = .Opaque,
pub fn fromBuffer(buf: []const u8) Material {
const mat: *align(1) const Material = @ptrCast(buf);

View File

@ -230,6 +230,8 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
.mesh = .{
.handle = a.Meshes.plane.Plane,
.material = .{
.blend_mode = .AlphaBlend,
.albedo = Vec4.new(1, 1, 1, 0.5),
.normal_map = a.Textures.@"tile.norm",
},
.override_material = true,
@ -265,7 +267,8 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
.mesh = .{
.handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1,
.material = .{
.albedo = Vec3.new(1.000, 0.766, 0.336),
.blend_mode = .AlphaBlend,
.albedo = Vec4.new(1.000, 0.766, 0.336, 0.5),
// .albedo_map = a.Textures.bunny_tex1,
// .normal_map = a.Textures.@"tile.norm",
.roughness = @as(f32, @floatFromInt(i + 1)) / 10.0,
@ -464,7 +467,7 @@ export fn game_update() bool {
} else if (ent.data.flags.point_light) {
gmem.render.draw(.{
.mesh = a.Meshes.sphere.Icosphere,
.material_override = .{ .albedo = Vec3.zero(), .emission = ent.data.light.premultipliedColor() },
.material_override = .{ .albedo = Vec4.new(0, 0, 0, 1), .emission = ent.data.light.premultipliedColor() },
.transform = ent.globalMatrix(&gmem.world).*,
});
}

View File

@ -9,6 +9,7 @@ const Vector2 = formats.Vector2;
const Vector3 = formats.Vector3;
const za = @import("zalgebra");
const Vec3 = za.Vec3;
const Vec4 = za.Vec4;
const Mat4 = za.Mat4;
const c = @cImport({
@cInclude("assimp/cimport.h");
@ -203,7 +204,7 @@ fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std
var base_color: c.aiColor4D = .{};
if (c.aiGetMaterialColor(material, AI_MATKEY_BASE_COLOR, 0, 0, &base_color) == c.aiReturn_SUCCESS) {
// TODO: rgba
mat_output.albedo = Vec3.new(base_color.r, base_color.g, base_color.b);
mat_output.albedo = Vec4.new(base_color.r, base_color.g, base_color.b, base_color.a);
}
if (c.aiGetMaterialTextureCount(material, c.aiTextureType_BASE_COLOR) > 0) {