collada_scene: rough ssao implementation

This commit is contained in:
Zack Buhman 2026-02-28 21:58:43 +00:00
parent ba777fbf3c
commit 64b0d8fab9
14 changed files with 2228 additions and 2144 deletions

View File

@ -743,6 +743,15 @@ vec3 = {
return result return result
end, end,
multiply_scalar = function(v1, s)
local result = vec3(
v1.f[0] * s,
v1.f[1] * s,
v1.f[2] * s
)
return result
end,
multiply_add = function(v1, v2, v3) multiply_add = function(v1, v2, v3)
local result = vec3( local result = vec3(
v1.f[0] * v2.f[0] + v3.f[0], v1.f[0] * v2.f[0] + v3.f[0],

View File

@ -5,6 +5,7 @@ local vec4 = _math.vec4
local scalar = _math.scalar local scalar = _math.scalar
local collada_types = require 'collada_types' local collada_types = require 'collada_types'
local random_data = require 'random_data'
local pixel_color_data = love.filesystem.newFileData("pixel_color.glsl") local pixel_color_data = love.filesystem.newFileData("pixel_color.glsl")
local pixel_shadow_data = love.filesystem.newFileData("pixel_shadow.glsl") local pixel_shadow_data = love.filesystem.newFileData("pixel_shadow.glsl")
@ -15,6 +16,16 @@ local shader_color_skinned = love.graphics.newShader(pixel_color_data, vertex_sk
local shader_shadow_static = love.graphics.newShader(pixel_shadow_data, vertex_static_data) local shader_shadow_static = love.graphics.newShader(pixel_shadow_data, vertex_static_data)
local shader_shadow_skinned = love.graphics.newShader(pixel_shadow_data, vertex_skinned_data) local shader_shadow_skinned = love.graphics.newShader(pixel_shadow_data, vertex_skinned_data)
local vertex_screen = love.filesystem.newFileData("vertex_screen.glsl")
local pixel_ssao = love.filesystem.newFileData("pixel_ssao.glsl")
local shader_ssao = love.graphics.newShader(pixel_ssao, vertex_screen)
local pixel_clear = love.filesystem.newFileData("pixel_clear.glsl")
local shader_clear = love.graphics.newShader(pixel_clear, vertex_screen)
local noise_texture = random_data.generate_noise_texture(4, 4)
local ssao_kernel_shaderstorage_buffer = random_data.generate_ssao_kernel(64)
local shader_set = { local shader_set = {
shadow = { shadow = {
static = shader_shadow_static, static = shader_shadow_static,
@ -205,7 +216,7 @@ collada_scene = {
end end
end, end,
draw_node = function(node_state, transform, light_transform, node, node_instance) draw_node = function(node_state, projection, view, light_transform, node, node_instance)
if node.type ~= collada_types.node_type.NODE then if node.type ~= collada_types.node_type.NODE then
return return
end end
@ -215,12 +226,15 @@ collada_scene = {
end end
local world = node_instance.world local world = node_instance.world
transform = world * transform view_transform = world * view
transform = view_transform * projection
light_transform = world * light_transform light_transform = world * light_transform
if node.instance_geometries_count > 0 then if node.instance_geometries_count > 0 then
current_shader = current_shader_set.static current_shader = current_shader_set.static
love.graphics.setShader(current_shader) love.graphics.setShader(current_shader)
--current_shader:send("projection", "column", projection.data)
current_shader:send("view_transform", "column", view_transform.data)
current_shader:send("world_transform", "column", world.data) current_shader:send("world_transform", "column", world.data)
current_shader:send("light_transform", "column", light_transform.data) current_shader:send("light_transform", "column", light_transform.data)
current_shader:send("transform", "column", transform.data) current_shader:send("transform", "column", transform.data)
@ -237,11 +251,11 @@ collada_scene = {
end end
end, end,
draw_nodes = function(node_state, transform, light_transform) draw_nodes = function(node_state, projection, view, light_transform)
local node_index = 0 local node_index = 0
for _, node in ipairs(node_state.nodes) do for _, node in ipairs(node_state.nodes) do
local node_instance = node_state.node_instances[node_index] local node_instance = node_state.node_instances[node_index]
collada_scene.draw_node(node_state, transform, light_transform, node, node_instance) collada_scene.draw_node(node_state, projection, view, light_transform, node, node_instance)
node_index = node_index + 1 node_index = node_index + 1
end end
end, end,
@ -268,11 +282,14 @@ collada_scene = {
-- shadow -- shadow
---------------------------------------------------------------------- ----------------------------------------------------------------------
love.graphics.setCanvas({g_shadow_canvas, depth=true}) if false then
love.graphics.clear({0.0, 0.0, 0.0, 1.0}) love.graphics.setCanvas({g_shadow_canvas, depth=true})
current_shader_set = shader_set.shadow love.graphics.clear({0.0, 0.0, 0.0, 1.0})
send_material = false current_shader_set = shader_set.shadow
collada_scene.draw_nodes(node_state, light_transform, light_transform) send_material = false
love.graphics.setDepthMode("less", true)
collada_scene.draw_nodes(node_state, light_transform, light_transform)
end
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- color -- color
@ -280,17 +297,41 @@ collada_scene = {
shader_color_static:send("view_position", view_position.data) shader_color_static:send("view_position", view_position.data)
shader_color_static:send("light_position", light_position.data) shader_color_static:send("light_position", light_position.data)
shader_color_static:send("shadow_sampler", g_shadow_canvas) --shader_color_static:send("shadow_sampler", g_shadow_canvas)
shader_color_skinned:send("view_position", view_position.data) shader_color_skinned:send("view_position", view_position.data)
shader_color_skinned:send("light_position", light_position.data) shader_color_skinned:send("light_position", light_position.data)
shader_color_skinned:send("shadow_sampler", g_shadow_canvas) --shader_color_skinned:send("shadow_sampler", g_shadow_canvas)
love.graphics.setCanvas({g_color_canvas, g_position_canvas, g_normal_canvas, depth=true})
--love.graphics.setCanvas()
--love.graphics.clear({0.0, 0.0, 0.0, 1.0})
--love.graphics.clear({0, 0, 0, 1.0}, {0, 0, 0, 1.0}, {0, 0, 0, 1.0}, 255, 0)
love.graphics.setDepthMode("always", true)
love.graphics.setShader(shader_clear)
love.graphics.drawFromShader(screen_index_buffer, 3 * 2, 1, 1)
love.graphics.setCanvas()
love.graphics.clear({0.0, 0.0, 0.0, 1.0})
current_shader_set = shader_set.color current_shader_set = shader_set.color
send_material = true send_material = true
collada_scene.draw_nodes(node_state, transform, light_transform) love.graphics.setDepthMode("greater", true)
collada_scene.draw_nodes(node_state, perspective_projection, view, light_transform)
----------------------------------------------------------------------
-- ssao
----------------------------------------------------------------------
if true then
love.graphics.setCanvas()
love.graphics.setShader(shader_ssao)
shader_ssao:send("projection2", "column", perspective_projection.data)
shader_ssao:send("g_color_sampler", g_color_canvas)
shader_ssao:send("g_position_sampler", g_position_canvas)
shader_ssao:send("g_normal_sampler", g_normal_canvas)
shader_ssao:send("noise_sampler", noise_texture)
shader_ssao:send("SSAOKernelLayout", ssao_kernel_shaderstorage_buffer)
love.graphics.setDepthMode("always", false)
love.graphics.drawFromShader(screen_index_buffer, 3 * 2, 1, 1)
end
end, end,
} }

View File

@ -35,7 +35,7 @@ local scenes = {
local node_state local node_state
local screen_index_buffer --local screen_index_buffer
local screen_shader local screen_shader
local load_screen_index_buffer = function() local load_screen_index_buffer = function()
@ -62,7 +62,7 @@ end
function love.load(args) function love.load(args)
love.window.setMode(1024, 1024, {depth=true, resizable=false}) love.window.setMode(1024, 1024, {depth=true, resizable=false})
local scene = scenes.shadow_test local scene = scenes.sci_fi_ship
collada_scene.load_buffers(scene.idx_path, scene.vtx_path, scene.vjw_path) collada_scene.load_buffers(scene.idx_path, scene.vtx_path, scene.vjw_path)
collada_scene.load_images(scene.image_path, scene.descriptor.images) collada_scene.load_images(scene.image_path, scene.descriptor.images)
node_state = collada_scene_node_state(scene.descriptor.nodes) node_state = collada_scene_node_state(scene.descriptor.nodes)
@ -94,8 +94,10 @@ function love.draw()
local aspect_ratio = width / height local aspect_ratio = width / height
local perspective_projection = mat4.perspective_fov_rh(scalar.convert_to_radians(45 * 0.5), local perspective_projection = mat4.perspective_fov_rh(scalar.convert_to_radians(45 * 0.5),
aspect_ratio, aspect_ratio,
0.1, 1,
10000.0) 0.1)
--0.1,
--10000.0)
local orthographic_projection = mat4.orthographic_rh(300, 300, 200, 400.0) local orthographic_projection = mat4.orthographic_rh(300, 300, 200, 400.0)
@ -108,7 +110,6 @@ function love.draw()
t = t + 0.016 * 0.1 t = t + 0.016 * 0.1
love.graphics.setBlendMode("replace", "premultiplied") love.graphics.setBlendMode("replace", "premultiplied")
love.graphics.setDepthMode("less", true)
collada_scene.draw_scene(node_state, perspective_projection, orthographic_projection) collada_scene.draw_scene(node_state, perspective_projection, orthographic_projection)
-- love.graphics.setCanvas({ -- love.graphics.setCanvas({

10
pixel_clear.glsl Normal file
View File

@ -0,0 +1,10 @@
layout (location = 0) out vec4 g_color;
layout (location = 1) out vec4 g_position;
layout (location = 2) out vec4 g_normal;
void pixelmain()
{
g_color = vec4(0.0, 0.0, 0.0, 1.0);
g_position = vec4(0.0, 0.0, 0.0, 1.0);
g_normal = vec4(0.0, 0.0, 0.0, 1.0);
}

View File

@ -2,6 +2,7 @@
varying vec4 PixelNormal; varying vec4 PixelNormal;
varying vec4 PixelTexture; varying vec4 PixelTexture;
varying vec4 PixelViewPosition;
varying vec4 PixelWorldPosition; varying vec4 PixelWorldPosition;
varying vec4 PixelLightPosition; varying vec4 PixelLightPosition;
@ -70,7 +71,8 @@ void pixelmain()
specular = specular_color; specular = specular_color;
} }
float diffuse_intensity = max(dot(normal, light_direction), 0.0); //float diffuse_intensity = max(dot(normal, light_direction), 0.0);
float diffuse_intensity = 0.7;
float specular_intensity = pow(max(dot(view_direction, reflect_light_direction), 0.0), shininess); float specular_intensity = pow(max(dot(view_direction, reflect_light_direction), 0.0), shininess);
vec3 color = emission.xyz * 0; vec3 color = emission.xyz * 0;
@ -78,11 +80,9 @@ void pixelmain()
color += diffuse.xyz * diffuse_intensity; color += diffuse.xyz * diffuse_intensity;
color += specular.xyz * specular_intensity * 0.3; color += specular.xyz * specular_intensity * 0.3;
color *= Shadow(normal, light_direction); //color *= Shadow(normal, light_direction);
g_color = vec4(color, 1.0); g_color = vec4(color, 1.0);
//float s = Shadow(); g_position = PixelViewPosition;
//g_color = vec4(s, s, s, 1.0);
g_position = vec4(PixelWorldPosition.xyz, 1.0);
g_normal = vec4(normal, 0.0); g_normal = vec4(normal, 0.0);
} }

64
pixel_ssao.glsl Normal file
View File

@ -0,0 +1,64 @@
#pragma language glsl4
uniform sampler2D g_color_sampler;
uniform sampler2D g_position_sampler;
uniform sampler2D g_normal_sampler;
uniform sampler2D noise_sampler;
uniform mat4 projection2;
uniform vec3 sample_kernel[64];
const vec2 noise_scale = vec2(1024.0 / 4.0, 1024 / 4.0);
const float bias = 0.05;
const float radius = 0.5;
const int samples = 64;
varying vec4 PixelTexture;
out vec4 out_color;
layout (std430) readonly buffer SSAOKernelLayout
{
vec4 SSAOKernel[];
};
void pixelmain()
{
vec3 color = texture(g_color_sampler, PixelTexture.xy).xyz;
vec3 position = texture(g_position_sampler, PixelTexture.xy).xyz;
vec3 normal = normalize(texture(g_normal_sampler, PixelTexture.xy).xyz);
vec3 noise = normalize(vec3(texture(noise_sampler, PixelTexture.xy * noise_scale).xy, 0));
vec3 tangent = normalize(noise - normal * dot(noise, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
for (int i = 0; i < samples; i++) {
vec3 sample_position = TBN * SSAOKernel[i].xyz;
sample_position = sample_position * radius + position;
vec4 offset = vec4(sample_position, 1.0);
offset = projection2 * offset;
offset.xyz = offset.xyz / offset.w;
offset.xyz = offset.xyz * vec3(0.5, -0.5, 0.5) + 0.5;
float sample_depth = texture(g_position_sampler, offset.xy).z;
float range_check = smoothstep(0.0, 1.0, radius / abs(position.z - sample_depth));
occlusion += (sample_depth >= sample_position.z + bias ? 1.0 : 0.0) * range_check;
}
occlusion = 1.0 - (occlusion / samples);
out_color = vec4(color * vec3(pow(occlusion, 20) + 0.75), 1.0);
//out_color = vec4(vec3(-position.z * 0.0001), 1.0);
//out_color = vec4(vec3(-position.z * 0.0001), 1.0);
//vec4 foo = projection2 * vec4(position, 1.0);
//foo.xyz = foo.xyz / foo.w;
//out_color = vec4(foo.xy * 0.5 + 0.5, 0.0, 1.0);
//out_color = vec4(normal, 1);
//out_color = vec4(SSAOKernel[].xyz * 8, 1.0);
}

52
random_data.lua Normal file
View File

@ -0,0 +1,52 @@
local ffi = require 'ffi'
local _math = require '_math'
local vec3 = _math.vec3
local generate_noise_texture = function(width, height)
local noise_data = love.data.newByteData(width * height * 2 * 4)
local noise_data_ptr = ffi.cast('float*', noise_data:getFFIPointer())
for i = 0, (width * height - 1) do
noise_data_ptr[i * 2 + 0] = love.math.random() * 2 - 1
noise_data_ptr[i * 2 + 1] = love.math.random() * 2 - 1
end
local noise_image_data = love.image.newImageData(width, height, "rg32f", noise_data)
local noise_texture = love.graphics.newTexture(noise_image_data)
noise_texture:setWrap("repeat", "repeat")
return noise_texture
end
local lerp = function(a, b, t)
return a + t * (b - a)
end
local generate_ssao_kernel = function(kernel_samples)
local ssao_kernel_data = love.data.newByteData(kernel_samples * 4 * 4)
local ssao_kernel_data_ptr = ffi.cast('float*', ssao_kernel_data:getFFIPointer())
for i = 0, (kernel_samples - 1) do
local v = vec3(love.math.random() * 2.0 - 1.0,
love.math.random() * 2.0 - 1.0,
love.math.random())
v = vec3.normalize(v)
local scale = i / kernel_samples
scale = lerp(0.1, 1.0, scale * scale)
v = vec3.multiply_scalar(v, love.math.random() * scale)
ssao_kernel_data_ptr[i * 4 + 0] = v.f[0]
ssao_kernel_data_ptr[i * 4 + 1] = v.f[1]
ssao_kernel_data_ptr[i * 4 + 2] = v.f[2]
--ssao_kernel_data_ptr[i * 4 + 3] = 0
end
local ssao_kernel_format = {
{ format = 'floatvec4' },
}
local ssao_kernel_shaderstorage_buffer = love.graphics.newBuffer(ssao_kernel_format, ssao_kernel_data, { shaderstorage = true, usage = "static" })
return ssao_kernel_shaderstorage_buffer
end
return {
generate_noise_texture = generate_noise_texture,
generate_ssao_kernel = generate_ssao_kernel,
}

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -13,5 +13,5 @@ void vertexmain()
PixelTexture = vec4(vertex.xy * vec2(0.5, -0.5) + 0.5, 0, 0); PixelTexture = vec4(vertex.xy * vec2(0.5, -0.5) + 0.5, 0, 0);
love_Position = vertex; love_Position = vec4(vertex.xy, -1.0, 1.0);
} }

View File

@ -34,6 +34,7 @@ varying vec4 PixelNormal;
varying vec4 PixelTexture; varying vec4 PixelTexture;
varying vec4 PixelWorldPosition; varying vec4 PixelWorldPosition;
varying vec4 PixelLightPosition; varying vec4 PixelLightPosition;
varying vec4 PixelViewPosition;
void vertexmain() void vertexmain()
{ {

View File

@ -13,6 +13,7 @@ layout (std430) readonly buffer VertexPNTLayout
uniform int VertexPNTOffset; uniform int VertexPNTOffset;
uniform mat4 view_transform;
uniform mat4 world_transform; uniform mat4 world_transform;
uniform mat4 light_transform; uniform mat4 light_transform;
uniform mat4 transform; uniform mat4 transform;
@ -21,6 +22,7 @@ varying vec4 PixelNormal;
varying vec4 PixelTexture; varying vec4 PixelTexture;
varying vec4 PixelWorldPosition; varying vec4 PixelWorldPosition;
varying vec4 PixelLightPosition; varying vec4 PixelLightPosition;
varying vec4 PixelViewPosition;
void vertexmain() void vertexmain()
{ {
@ -31,6 +33,7 @@ void vertexmain()
vec4 Position = vec4(VertexPNT.Position.xyz, 1); vec4 Position = vec4(VertexPNT.Position.xyz, 1);
PixelViewPosition = view_transform * Position;
PixelWorldPosition = world_transform * Position; PixelWorldPosition = world_transform * Position;
PixelLightPosition = light_transform * Position; PixelLightPosition = light_transform * Position;
love_Position = transform * Position; love_Position = transform * Position;