Render Pass初始化
接下来会介绍各个子Pass的初始化。稍微看了一下,Piccolo的shader有些是OpenGL的,有些是OpenGL ES的,这种混合有点让人迷惑。
(主要内容待补充,还在学习渲染相关)
1.1. Point Light Shadow Passs初始化
void PointLightShadowPass::initialize(const RenderPassInitInfo* init_info)
{
RenderPass::initialize(nullptr);
setupAttachments();
setupRenderPass();
setupFramebuffer();
setupDescriptorSetLayout();
}
由于几乎所有的Render Pass都是相同的初始化流程,因此先对该Pass的初始化进行简单分析。
TODO
Point Light Shadow Passs用到了三个Shader:
mesh_point_light_shadow.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "structures.h"
layout(set = 0, binding = 1) readonly buffer _unused_name_per_drawcall
{
VulkanMeshInstance mesh_instances[m_mesh_per_drawcall_max_instance_count];
};
layout(set = 0, binding = 2) readonly buffer _unused_name_per_drawcall_vertex_blending
{
mat4 joint_matrices[m_mesh_vertex_blending_max_joint_count * m_mesh_per_drawcall_max_instance_count];
};
layout(set = 1, binding = 0) readonly buffer _unused_name_per_mesh_joint_binding
{
VulkanMeshVertexJointBinding indices_and_weights[];
};
layout(location = 0) in highp vec3 in_position;
layout(location = 0) out highp vec3 out_position_world_space;
void main()
{
highp mat4 model_matrix = mesh_instances[gl_InstanceIndex].model_matrix;
highp float enable_vertex_blending = mesh_instances[gl_InstanceIndex].enable_vertex_blending;
highp vec3 model_position;
if (enable_vertex_blending > 0.0)
{
highp ivec4 in_indices = indices_and_weights[gl_VertexIndex].indices;
highp vec4 in_weights = indices_and_weights[gl_VertexIndex].weights;
highp mat4 vertex_blending_matrix = mat4x4(
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0));
if (in_weights.x > 0.0 && in_indices.x > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.x] * in_weights.x;
}
if (in_weights.y > 0.0 && in_indices.y > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.y] * in_weights.y;
}
if (in_weights.z > 0.0 && in_indices.z > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.z] * in_weights.z;
}
if (in_weights.w > 0.0 && in_indices.w > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.w] * in_weights.w;
}
model_position = (vertex_blending_matrix * vec4(in_position, 1.0)).xyz;
}
else
{
model_position = in_position;
}
out_position_world_space = (model_matrix * vec4(model_position, 1.0)).xyz;
}
mesh_point_light_shadow.geom
#version 310 es
#extension GL_GOOGLE_include_directive : enable
// TODO: geometry shader is inefficient for Mali GPU
#extension GL_EXT_geometry_shader : enable
// Imagination Technologies Limited. "Dual Paraboloid Environment Mapping." Power SDK Whitepaper 2017.
// https://github.com/powervr-graphics/Native_SDK/blob/R17.1-v4.3/Documentation/Whitepapers/Dual%20Paraboloid%20Environment%20Mapping.Whitepaper.pdf
#include "constants.h"
layout(set = 0, binding = 0) readonly buffer _unused_name_global_set_per_frame_binding_buffer
{
uint point_light_count;
uint _padding_point_light_count_0;
uint _padding_point_light_count_1;
uint _padding_point_light_count_2;
highp vec4 point_lights_position_and_radius[m_max_point_light_count];
};
layout(triangles) in;
layout(triangle_strip, max_vertices = m_max_point_light_geom_vertices) out;
layout(location = 0) in highp vec3 in_positions_world_space[];
layout(location = 0) out highp float out_inv_length;
layout(location = 1) out highp vec3 out_inv_length_position_view_space;
void main()
{
for (highp int point_light_index = 0; point_light_index < int(point_light_count) && point_light_index < m_max_point_light_count; ++point_light_index)
{
vec3 point_light_position = point_lights_position_and_radius[point_light_index].xyz;
float point_light_radius = point_lights_position_and_radius[point_light_index].w;
// TODO: find more effificient ways
// we draw twice, since the gl_Layer of three vetices may not be the same
for (highp int layer_index = 0; layer_index < 2; ++layer_index)
{
for (highp int vertex_index = 0; vertex_index < 3; ++vertex_index)
{
highp vec3 position_world_space = in_positions_world_space[vertex_index];
// world space to light view space
// identity rotation
// Z - Up
// Y - Forward
// X - Right
highp vec3 position_view_space = position_world_space - point_light_position;
highp vec3 position_spherical_function_domain = normalize(position_view_space);
// z > 0
// (x_2d, y_2d, 0) + (0, 0, 1) = λ ((x_sph, y_sph, z_sph) + (0, 0, 1))
// (x_2d, y_2d) = (x_sph, y_sph) / (z_sph + 1)
// z < 0
// (x_2d, y_2d, 0) + (0, 0, -1) = λ ((x_sph, y_sph, z_sph) + (0, 0, -1))
// (x_2d, y_2d) = (x_sph, y_sph) / (-z_sph + 1)
highp float layer_position_spherical_function_domain_z[2];
layer_position_spherical_function_domain_z[0] = -position_spherical_function_domain.z;
layer_position_spherical_function_domain_z[1] = position_spherical_function_domain.z;
highp vec4 position_clip;
position_clip.xy = position_spherical_function_domain.xy;
position_clip.w = layer_position_spherical_function_domain_z[layer_index] + 1.0;
position_clip.z = 0.5 * position_clip.w; //length(position_view_space) * position_clip.w / point_light_radius;
gl_Position = position_clip;
out_inv_length = 1.0f / length(position_view_space);
out_inv_length_position_view_space = out_inv_length * position_view_space;
gl_Layer = layer_index + 2 * point_light_index;
EmitVertex();
}
EndPrimitive();
}
}
}
mesh_point_light_shadow.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
// TODO: geometry shader is inefficient for Mali GPU
#extension GL_EXT_geometry_shader : enable
#include "constants.h"
layout(set = 0, binding = 0) readonly buffer _unused_name_global_set_per_frame_binding_buffer
{
uint point_light_count;
uint _padding_point_light_count_0;
uint _padding_point_light_count_1;
uint _padding_point_light_count_2;
highp vec4 point_lights_position_and_radius[m_max_point_light_count];
};
layout(location = 0) in highp float in_inv_length;
// NOTE: we can't interpolate the length of "position_view_space" directly, otherwise the result is incorrect
layout(location = 1) in highp vec3 in_inv_length_position_view_space;
layout(location = 0) out highp float out_depth;
void main()
{
// perspective correct interpolation_
highp vec3 position_view_space = in_inv_length_position_view_space / in_inv_length;
highp float point_light_radius = point_lights_position_and_radius[gl_Layer / 2].w;
highp float ratio = length(position_view_space) / point_light_radius;
// Trick: we don't write to depth, and thus we can use early depth test
gl_FragDepth = ratio;
out_depth = ratio;
}
里面用到了两个头文件:
structures.h
struct VulkanMeshInstance
{
highp float enable_vertex_blending;
highp float _padding_enable_vertex_blending_1;
highp float _padding_enable_vertex_blending_2;
highp float _padding_enable_vertex_blending_3;
highp mat4 model_matrix;
};
struct VulkanMeshVertexJointBinding
{
highp ivec4 indices;
highp vec4 weights;
};
constants.h
#define m_max_point_light_count 15
#define m_max_point_light_geom_vertices 90 // 90 = 2 * 3 * m_max_point_light_count
#define m_mesh_per_drawcall_max_instance_count 64
#define m_mesh_vertex_blending_max_joint_count 1024
#define CHAOS_LAYOUT_MAJOR row_major
layout(CHAOS_LAYOUT_MAJOR) buffer;
layout(CHAOS_LAYOUT_MAJOR) uniform;
1.2. Directional Light Pass初始化
void DirectionalLightShadowPass::initialize(const RenderPassInitInfo* init_info)
{
RenderPass::initialize(nullptr);
setupAttachments();
setupRenderPass();
setupFramebuffer();
setupDescriptorSetLayout();
}
Directional Light Pass用到了以下两个Shader,用于向Directional Light方向正交投影,输出图像记录每个点的投影深度。
mesh_directional_light_shadow.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "structures.h"
layout(set = 0, binding = 0) readonly buffer _unused_name_global_set_per_frame_binding_buffer
{
mat4 light_proj_view;
};
layout(set = 0, binding = 1) readonly buffer _unused_name_per_drawcall
{
VulkanMeshInstance mesh_instances[m_mesh_per_drawcall_max_instance_count];
};
layout(set = 0, binding = 2) readonly buffer _unused_name_per_drawcall_vertex_blending
{
mat4 joint_matrices[m_mesh_vertex_blending_max_joint_count * m_mesh_per_drawcall_max_instance_count];
};
layout(set = 1, binding = 0) readonly buffer _unused_name_per_mesh_joint_binding
{
VulkanMeshVertexJointBinding indices_and_weights[];
};
layout(location = 0) in highp vec3 in_position;
void main()
{
highp mat4 model_matrix = mesh_instances[gl_InstanceIndex].model_matrix;
highp float enable_vertex_blending = mesh_instances[gl_InstanceIndex].enable_vertex_blending;
highp vec3 model_position;
if (enable_vertex_blending > 0.0)
{
highp ivec4 in_indices = indices_and_weights[gl_VertexIndex].indices;
highp vec4 in_weights = indices_and_weights[gl_VertexIndex].weights;
highp mat4 vertex_blending_matrix = mat4x4(
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0));
if (in_weights.x > 0.0 && in_indices.x > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.x] * in_weights.x;
}
if (in_weights.y > 0.0 && in_indices.y > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.y] * in_weights.y;
}
if (in_weights.z > 0.0 && in_indices.z > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.z] * in_weights.z;
}
if (in_weights.w > 0.0 && in_indices.w > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.w] * in_weights.w;
}
model_position = (vertex_blending_matrix * vec4(in_position, 1.0)).xyz;
}
else
{
model_position = in_position;
}
highp vec3 position_world_space = (model_matrix * vec4(model_position, 1.0)).xyz;
gl_Position = light_proj_view * vec4(position_world_space, 1.0f);
}
mesh_directional_light_shadow.frag
#version 310 es
layout(early_fragment_tests) in;
layout(location = 0) out highp float out_depth;
void main()
{
out_depth = gl_FragCoord.z;
}
1.3. Main Camera Pass初始化
axis.vert
#version 460 core
#extension GL_GOOGLE_include_directive :enable
#include "constants.h"
struct PointLight
{
vec3 position;
float radius;
vec3 intensity;
float _padding_intensity;
};
layout(set = 0, binding = 0) readonly buffer _unused_name_perframe
{
mat4 proj_view_matrix;
vec3 camera_position;
float _padding_camera_position;
vec3 ambient_light;
float _padding_ambient_light;
uint point_light_num;
uint _padding_point_light_num_1;
uint _padding_point_light_num_2;
uint _padding_point_light_num_3;
PointLight scene_point_lights[m_max_point_light_count];
};
layout(set = 0, binding = 1) readonly buffer _unused_name_axis
{
mat4 model_matrix;
uint selected_axis;
};
layout(location = 0) in vec3 in_position; // for some types as dvec3 takes 2 locations
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec3 in_tangent;
layout(location = 3) in vec2 in_texcoord;
layout(location = 0) out vec3 out_color; // output in location 0 for fragment shader
void main()
{
vec3 world_position = (model_matrix * vec4(in_position, 1.0)).xyz;
vec4 clip_position = proj_view_matrix * vec4(world_position, 1.0f);
// depth set to 0.0001 (closest)
clip_position.z = clip_position.z * 0.0001;
gl_Position = clip_position;
if(in_texcoord.x < 0.01f)
{
if(selected_axis == 0)
{
out_color = vec3(1.0, 1.0, 0.0);
}
else
{
out_color = vec3(1.0, 0.0, 0.0);
}
}
else if(in_texcoord.x < 1.01f)
{
if(selected_axis == 1)
{
out_color = vec3(1.0, 1.0, 0.0);
}
else
{
out_color = vec3(0.0, 1.0, 0.0);
}
}
else if(in_texcoord.x < 2.01f)
{
if(selected_axis == 2)
{
out_color = vec3(1.0, 1.0, 0.0);
}
else
{
out_color = vec3(0.0, 0.0, 1.0);
}
}
else
{
out_color = vec3(1.0, 1.0, 1.0);
}
}
axis.frag
#version 460
layout (location = 0) in vec3 in_color;
layout (location = 0) out vec4 outColor;
void main()
{
outColor = vec4(in_color, 1.0);
}
deferred_lighting.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(location = 0) out vec2 out_texcoord;
void main()
{
vec3 fullscreen_triangle_positions[3] = vec3[3](vec3(3.0, 1.0, 0.5), vec3(-1.0, 1.0, 0.5), vec3(-1.0, -3.0, 0.5));
vec2 fullscreen_triangle_uvs[3] = vec2[3](vec2(2.0, 1.0), vec2(0.0, 1.0), vec2(0.0, -1.0));
gl_Position = vec4(fullscreen_triangle_positions[gl_VertexIndex], 1.0);
out_texcoord = fullscreen_triangle_uvs[gl_VertexIndex];
}
gbuffer.h
struct PGBufferData
{
highp vec3 worldNormal;
highp vec3 baseColor;
highp float metallic;
highp float specular;
highp float roughness;
highp uint shadingModelID;
};
#define SHADINGMODELID_UNLIT 0U
#define SHADINGMODELID_DEFAULT_LIT 1U
highp vec3 EncodeNormal(highp vec3 N) { return N * 0.5 + 0.5; }
highp vec3 DecodeNormal(highp vec3 N) { return N * 2.0 - 1.0; }
highp vec3 EncodeBaseColor(highp vec3 baseColor)
{
// we use sRGB on the render target to give more precision to the darks
return baseColor;
}
highp vec3 DecodeBaseColor(highp vec3 baseColor)
{
// we use sRGB on the render target to give more precision to the darks
return baseColor;
}
highp float EncodeShadingModelId(highp uint ShadingModelId)
{
highp uint Value = ShadingModelId;
return (float(Value) / float(255));
}
highp uint DecodeShadingModelId(highp float InPackedChannel) { return uint(round(InPackedChannel * float(255))); }
void EncodeGBufferData(PGBufferData InGBuffer,
out highp vec4 OutGBufferA,
out highp vec4 OutGBufferB,
out highp vec4 OutGBufferC)
{
OutGBufferA.rgb = EncodeNormal(InGBuffer.worldNormal);
OutGBufferB.r = InGBuffer.metallic;
OutGBufferB.g = InGBuffer.specular;
OutGBufferB.b = InGBuffer.roughness;
OutGBufferB.a = EncodeShadingModelId(InGBuffer.shadingModelID);
OutGBufferC.rgb = EncodeBaseColor(InGBuffer.baseColor);
}
void DecodeGBufferData(out PGBufferData OutGBuffer, highp vec4 InGBufferA, highp vec4 InGBufferB, highp vec4 InGBufferC)
{
OutGBuffer.worldNormal = DecodeNormal(InGBufferA.xyz);
OutGBuffer.metallic = InGBufferB.r;
OutGBuffer.specular = InGBufferB.g;
OutGBuffer.roughness = InGBufferB.b;
OutGBuffer.shadingModelID = DecodeShadingModelId(InGBufferB.a);
OutGBuffer.baseColor = DecodeBaseColor(InGBufferC.rgb);
}
mesh_lighting.h
#define PI 3.1416
// todo: param/const
#define MAX_REFLECTION_LOD 8.0
// Normal Distribution function --------------------------------------
highp float D_GGX(highp float dotNH, highp float roughness)
{
highp float alpha = roughness * roughness;
highp float alpha2 = alpha * alpha;
highp float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
return (alpha2) / (PI * denom * denom);
}
// Geometric Shadowing function --------------------------------------
highp float G_SchlicksmithGGX(highp float dotNL, highp float dotNV, highp float roughness)
{
highp float r = (roughness + 1.0);
highp float k = (r * r) / 8.0;
highp float GL = dotNL / (dotNL * (1.0 - k) + k);
highp float GV = dotNV / (dotNV * (1.0 - k) + k);
return GL * GV;
}
// Fresnel function ----------------------------------------------------
highp float Pow5(highp float x)
{
return (x * x * x * x * x);
}
highp vec3 F_Schlick(highp float cosTheta, highp vec3 F0)
{
return F0 + (1.0 - F0) * Pow5(1.0 - cosTheta);
}
highp vec3 F_SchlickR(highp float cosTheta, highp vec3 F0, highp float roughness)
{
return F0 + (max(vec3(1.0 - roughness, 1.0 - roughness, 1.0 - roughness), F0) - F0) * Pow5(1.0 - cosTheta);
}
// Specular and diffuse BRDF composition --------------------------------------------
highp vec3 BRDF(highp vec3 L,
highp vec3 V,
highp vec3 N,
highp vec3 F0,
highp vec3 basecolor,
highp float metallic,
highp float roughness)
{
// Precalculate vectors and dot products
highp vec3 H = normalize(V + L);
highp float dotNV = clamp(dot(N, V), 0.0, 1.0);
highp float dotNL = clamp(dot(N, L), 0.0, 1.0);
highp float dotLH = clamp(dot(L, H), 0.0, 1.0);
highp float dotNH = clamp(dot(N, H), 0.0, 1.0);
// Light color fixed
// vec3 lightColor = vec3(1.0);
highp vec3 color = vec3(0.0);
highp float rroughness = max(0.05, roughness);
// D = Normal distribution (Distribution of the microfacets)
highp float D = D_GGX(dotNH, rroughness);
// G = Geometric shadowing term (Microfacets shadowing)
highp float G = G_SchlicksmithGGX(dotNL, dotNV, rroughness);
// F = Fresnel factor (Reflectance depending on angle of incidence)
highp vec3 F = F_Schlick(dotNV, F0);
highp vec3 spec = D * F * G / (4.0 * dotNL * dotNV + 0.001);
highp vec3 kD = (vec3(1.0) - F) * (1.0 - metallic);
color += (kD * basecolor / PI + (1.0 - kD) * spec);
// color += (kD * basecolor / PI + spec) * dotNL;
// color += (kD * basecolor / PI + spec) * dotNL * lightColor;
return color;
}
highp vec2 ndcxy_to_uv(highp vec2 ndcxy) { return ndcxy * vec2(0.5, 0.5) + vec2(0.5, 0.5); }
highp vec2 uv_to_ndcxy(highp vec2 uv) { return uv * vec2(2.0, 2.0) + vec2(-1.0, -1.0); }
mesh_lighting.inl
highp vec3 V = normalize(camera_position - in_world_position);
highp vec3 R = reflect(-V, N);
highp vec3 origin_samplecube_N = vec3(N.x, N.z, N.y);
highp vec3 origin_samplecube_R = vec3(R.x, R.z, R.y);
highp vec3 F0 = mix(vec3(dielectric_specular, dielectric_specular, dielectric_specular), basecolor, metallic);
// direct light specular and diffuse BRDF contribution
highp vec3 Lo = vec3(0.0, 0.0, 0.0);
for (highp int light_index = 0; light_index < int(point_light_num) && light_index < m_max_point_light_count;
++light_index)
{
highp vec3 point_light_position = scene_point_lights[light_index].position;
highp float point_light_radius = scene_point_lights[light_index].radius;
highp vec3 L = normalize(point_light_position - in_world_position);
highp float NoL = min(dot(N, L), 1.0);
// point light
highp float distance = length(point_light_position - in_world_position);
highp float distance_attenuation = 1.0 / (distance * distance + 1.0);
highp float radius_attenuation = 1.0 - ((distance * distance) / (point_light_radius * point_light_radius));
highp float light_attenuation = radius_attenuation * distance_attenuation * NoL;
if (light_attenuation > 0.0)
{
highp float shadow;
{
// world space to light view space
// identity rotation
// Z - Up
// Y - Forward
// X - Right
highp vec3 position_view_space = in_world_position - point_light_position;
highp vec3 position_spherical_function_domain = normalize(position_view_space);
// use abs to avoid divergence
// z > 0
// (x_2d, y_2d, 0) + (0, 0, 1) = λ ((x_sph, y_sph, z_sph) + (0, 0, 1))
// (x_2d, y_2d) = (x_sph, y_sph) / (z_sph + 1)
// z < 0
// (x_2d, y_2d, 0) + (0, 0, -1) = λ ((x_sph, y_sph, z_sph) + (0, 0, -1))
// (x_2d, y_2d) = (x_sph, y_sph) / (-z_sph + 1)
highp vec2 position_ndcxy =
position_spherical_function_domain.xy / (abs(position_spherical_function_domain.z) + 1.0);
// use sign to avoid divergence
// -1.0 to 0
// 1.0 to 1
highp vec2 uv = ndcxy_to_uv(position_ndcxy);
highp float layer_index =
(0.5 + 0.5 * sign(position_spherical_function_domain.z)) + 2.0 * float(light_index);
highp float depth = texture(point_lights_shadow, vec3(uv, layer_index)).r + 0.000075;
highp float closest_length = (depth)*point_light_radius;
highp float current_length = length(position_view_space);
shadow = (closest_length >= current_length) ? 1.0f : -1.0f;
}
if (shadow > 0.0f)
{
highp vec3 En = scene_point_lights[light_index].intensity * light_attenuation;
Lo += BRDF(L, V, N, F0, basecolor, metallic, roughness) * En;
}
}
};
// direct ambient contribution
highp vec3 La = vec3(0.0f, 0.0f, 0.0f);
La = basecolor * ambient_light;
// indirect environment
highp vec3 irradiance = texture(irradiance_sampler, origin_samplecube_N).rgb;
highp vec3 diffuse = irradiance * basecolor;
highp vec3 F = F_SchlickR(clamp(dot(N, V), 0.0, 1.0), F0, roughness);
highp vec2 brdfLUT = texture(brdfLUT_sampler, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg;
highp float lod = roughness * MAX_REFLECTION_LOD;
highp vec3 reflection = textureLod(specular_sampler, origin_samplecube_R, lod).rgb;
highp vec3 specular = reflection * (F * brdfLUT.x + brdfLUT.y);
highp vec3 kD = 1.0 - F;
kD *= 1.0 - metallic;
highp vec3 Libl = (kD * diffuse + specular);
// directional light
{
highp vec3 L = normalize(scene_directional_light.direction);
highp float NoL = min(dot(N, L), 1.0);
if (NoL > 0.0)
{
highp float shadow;
{
highp vec4 position_clip = directional_light_proj_view * vec4(in_world_position, 1.0);
highp vec3 position_ndc = position_clip.xyz / position_clip.w;
highp vec2 uv = ndcxy_to_uv(position_ndc.xy);
highp float closest_depth = texture(directional_light_shadow, uv).r + 0.000075;
highp float current_depth = position_ndc.z;
shadow = (closest_depth >= current_depth) ? 1.0f : -1.0f;
}
if (shadow > 0.0f)
{
highp vec3 En = scene_directional_light.color * NoL;
Lo += BRDF(L, V, N, F0, basecolor, metallic, roughness) * En;
}
}
}
// result
result_color = Lo + La + Libl;
deferred_lighting.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "gbuffer.h"
struct DirectionalLight
{
highp vec3 direction;
lowp float _padding_direction;
highp vec3 color;
lowp float _padding_color;
};
struct PointLight
{
highp vec3 position;
highp float radius;
highp vec3 intensity;
lowp float _padding_intensity;
};
layout(set = 0, binding = 0) readonly buffer _mesh_per_frame
{
highp mat4 proj_view_matrix;
highp vec3 camera_position;
lowp float _padding_camera_position;
highp vec3 ambient_light;
lowp float _padding_ambient_light;
highp uint point_light_num;
uint _padding_point_light_num_1;
uint _padding_point_light_num_2;
uint _padding_point_light_num_3;
PointLight scene_point_lights[m_max_point_light_count];
DirectionalLight scene_directional_light;
highp mat4 directional_light_proj_view;
};
layout(set = 0, binding = 3) uniform sampler2D brdfLUT_sampler;
layout(set = 0, binding = 4) uniform samplerCube irradiance_sampler;
layout(set = 0, binding = 5) uniform samplerCube specular_sampler;
layout(set = 0, binding = 6) uniform highp sampler2DArray point_lights_shadow;
layout(set = 0, binding = 7) uniform highp sampler2D directional_light_shadow;
layout(input_attachment_index = 0, set = 1, binding = 0) uniform highp subpassInput in_gbuffer_a;
layout(input_attachment_index = 1, set = 1, binding = 1) uniform highp subpassInput in_gbuffer_b;
layout(input_attachment_index = 2, set = 1, binding = 2) uniform highp subpassInput in_gbuffer_c;
layout(input_attachment_index = 3, set = 1, binding = 3) uniform highp subpassInput in_scene_depth;
layout(set = 2, binding = 1) uniform samplerCube skybox_sampler;
layout(location = 0) in highp vec2 in_texcoord;
layout(location = 0) out highp vec4 out_color;
#include "mesh_lighting.h"
void main()
{
PGBufferData gbuffer;
highp vec4 gbuffer_a = subpassLoad(in_gbuffer_a).rgba;
highp vec4 gbuffer_b = subpassLoad(in_gbuffer_b).rgba;
highp vec4 gbuffer_c = subpassLoad(in_gbuffer_c).rgba;
DecodeGBufferData(gbuffer, gbuffer_a, gbuffer_b, gbuffer_c);
highp vec3 N = gbuffer.worldNormal;
highp vec3 basecolor = gbuffer.baseColor;
highp float metallic = gbuffer.metallic;
highp float dielectric_specular = 0.08 * gbuffer.specular;
highp float roughness = gbuffer.roughness;
highp vec3 in_world_position;
{
highp float scene_depth = subpassLoad(in_scene_depth).r;
highp vec4 ndc = vec4(uv_to_ndcxy(in_texcoord), scene_depth, 1.0);
highp mat4 inverse_proj_view_matrix = inverse(proj_view_matrix);
highp vec4 in_world_position_with_w = inverse_proj_view_matrix * ndc;
in_world_position = in_world_position_with_w.xyz / in_world_position_with_w.www;
}
highp vec3 result_color = vec3(0.0, 0.0, 0.0);
if (SHADINGMODELID_UNLIT == gbuffer.shadingModelID)
{
// skybox
highp vec3 in_UVW = normalize(in_world_position - camera_position);
highp vec3 origin_sample_UVW = vec3(in_UVW.x, in_UVW.z, in_UVW.y);
result_color = textureLod(skybox_sampler, origin_sample_UVW, 0.0).rgb;
}
else if (SHADINGMODELID_DEFAULT_LIT == gbuffer.shadingModelID)
{
#include "mesh_lighting.inl"
}
out_color = vec4(result_color, 1.0f);
}
mesh.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "structures.h"
struct DirectionalLight
{
vec3 direction;
float _padding_direction;
vec3 color;
float _padding_color;
};
struct PointLight
{
vec3 position;
float radius;
vec3 intensity;
float _padding_intensity;
};
layout(set = 0, binding = 0) readonly buffer _unused_name_perframe
{
mat4 proj_view_matrix;
vec3 camera_position;
float _padding_camera_position;
vec3 ambient_light;
float _padding_ambient_light;
uint point_light_num;
uint _padding_point_light_num_1;
uint _padding_point_light_num_2;
uint _padding_point_light_num_3;
PointLight scene_point_lights[m_max_point_light_count];
DirectionalLight scene_directional_light;
highp mat4 directional_light_proj_view;
};
layout(set = 0, binding = 1) readonly buffer _unused_name_per_drawcall
{
VulkanMeshInstance mesh_instances[m_mesh_per_drawcall_max_instance_count];
};
layout(set = 0, binding = 2) readonly buffer _unused_name_per_drawcall_vertex_blending
{
highp mat4 joint_matrices[m_mesh_vertex_blending_max_joint_count * m_mesh_per_drawcall_max_instance_count];
};
layout(set = 1, binding = 0) readonly buffer _unused_name_per_mesh_joint_binding
{
VulkanMeshVertexJointBinding indices_and_weights[];
};
layout(location = 0) in vec3 in_position; // for some types as dvec3 takes 2 locations
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec3 in_tangent;
layout(location = 3) in vec2 in_texcoord;
layout(location = 0) out vec3 out_world_position; // output in framebuffer 0 for fragment shader
layout(location = 1) out vec3 out_normal;
layout(location = 2) out vec3 out_tangent;
layout(location = 3) out vec2 out_texcoord;
void main()
{
highp mat4 model_matrix = mesh_instances[gl_InstanceIndex].model_matrix;
highp float enable_vertex_blending = mesh_instances[gl_InstanceIndex].enable_vertex_blending;
highp vec3 model_position;
highp vec3 model_normal;
highp vec3 model_tangent;
if (enable_vertex_blending > 0.0)
{
highp ivec4 in_indices = indices_and_weights[gl_VertexIndex].indices;
highp vec4 in_weights = indices_and_weights[gl_VertexIndex].weights;
highp mat4 vertex_blending_matrix = mat4x4(
vec4(0.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 0.0), vec4(0.0, 0.0, 0.0, 0.0));
if (in_weights.x > 0.0 && in_indices.x > 0)
{
vertex_blending_matrix +=
joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.x] * in_weights.x;
}
if (in_weights.y > 0.0 && in_indices.y > 0)
{
vertex_blending_matrix +=
joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.y] * in_weights.y;
}
if (in_weights.z > 0.0 && in_indices.z > 0)
{
vertex_blending_matrix +=
joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.z] * in_weights.z;
}
if (in_weights.w > 0.0 && in_indices.w > 0)
{
vertex_blending_matrix +=
joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.w] * in_weights.w;
}
model_position = (vertex_blending_matrix * vec4(in_position, 1.0)).xyz;
highp mat3x3 vertex_blending_tangent_matrix =
mat3x3(vertex_blending_matrix[0].xyz, vertex_blending_matrix[1].xyz, vertex_blending_matrix[2].xyz);
model_normal = normalize(vertex_blending_tangent_matrix * in_normal);
model_tangent = normalize(vertex_blending_tangent_matrix * in_tangent);
}
else
{
model_position = in_position;
model_normal = in_normal;
model_tangent = in_tangent;
}
out_world_position = (model_matrix * vec4(model_position, 1.0)).xyz;
gl_Position = proj_view_matrix * vec4(out_world_position, 1.0f);
// TODO: normal matrix
mat3x3 tangent_matrix = mat3x3(model_matrix[0].xyz, model_matrix[1].xyz, model_matrix[2].xyz);
out_normal = normalize(tangent_matrix * model_normal);
out_tangent = normalize(tangent_matrix * model_tangent);
out_texcoord = in_texcoord;
}
mesh_gbuffer.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "gbuffer.h"
layout(set = 2, binding = 0) uniform _unused_name_permaterial
{
highp vec4 baseColorFactor;
highp float metallicFactor;
highp float roughnessFactor;
highp float normalScale;
highp float occlusionStrength;
highp vec3 emissiveFactor;
uint is_blend;
uint is_double_sided;
};
layout(set = 2, binding = 1) uniform sampler2D base_color_texture_sampler;
layout(set = 2, binding = 2) uniform sampler2D metallic_roughness_texture_sampler;
layout(set = 2, binding = 3) uniform sampler2D normal_texture_sampler;
layout(set = 2, binding = 4) uniform sampler2D occlusion_texture_sampler;
layout(set = 2, binding = 5) uniform sampler2D emissive_color_texture_sampler;
// read in fragnormal (from vertex shader)
layout(location = 0) in highp vec3 in_world_position;
layout(location = 1) in highp vec3 in_normal;
layout(location = 2) in highp vec3 in_tangent;
layout(location = 3) in highp vec2 in_texcoord;
// output screen color to location 0
layout(location = 0) out highp vec4 out_gbuffer_a;
layout(location = 1) out highp vec4 out_gbuffer_b;
layout(location = 2) out highp vec4 out_gbuffer_c;
// layout(location = 3) out highp vec4 out_scene_color;
highp vec3 getBasecolor()
{
highp vec3 basecolor = texture(base_color_texture_sampler, in_texcoord).xyz * baseColorFactor.xyz;
return basecolor;
}
highp vec3 calculateNormal()
{
highp vec3 tangent_normal = texture(normal_texture_sampler, in_texcoord).xyz * 2.0 - 1.0;
highp vec3 N = normalize(in_normal);
highp vec3 T = normalize(in_tangent.xyz);
highp vec3 B = normalize(cross(N, T));
highp mat3 TBN = mat3(T, B, N);
return normalize(TBN * tangent_normal);
}
void main()
{
PGBufferData gbuffer;
gbuffer.worldNormal = calculateNormal();
gbuffer.baseColor = getBasecolor();
gbuffer.metallic = texture(metallic_roughness_texture_sampler, in_texcoord).z * metallicFactor;
gbuffer.specular = 0.5;
gbuffer.roughness = texture(metallic_roughness_texture_sampler, in_texcoord).y * roughnessFactor;
gbuffer.shadingModelID = SHADINGMODELID_DEFAULT_LIT;
highp vec3 Le = texture(emissive_color_texture_sampler, in_texcoord).xyz * emissiveFactor;
EncodeGBufferData(gbuffer, out_gbuffer_a, out_gbuffer_b, out_gbuffer_c);
// out_scene_color.rgba = vec4(Le, 1.0);
}
mesh.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
struct DirectionalLight
{
highp vec3 direction;
lowp float _padding_direction;
highp vec3 color;
lowp float _padding_color;
};
struct PointLight
{
highp vec3 position;
highp float radius;
highp vec3 intensity;
lowp float _padding_intensity;
};
layout(set = 0, binding = 0) readonly buffer _unused_name_perframe
{
highp mat4 proj_view_matrix;
highp vec3 camera_position;
lowp float _padding_camera_position;
highp vec3 ambient_light;
lowp float _padding_ambient_light;
highp uint point_light_num;
uint _padding_point_light_num_1;
uint _padding_point_light_num_2;
uint _padding_point_light_num_3;
PointLight scene_point_lights[m_max_point_light_count];
DirectionalLight scene_directional_light;
highp mat4 directional_light_proj_view;
};
layout(set = 0, binding = 3) uniform sampler2D brdfLUT_sampler;
layout(set = 0, binding = 4) uniform samplerCube irradiance_sampler;
layout(set = 0, binding = 5) uniform samplerCube specular_sampler;
layout(set = 0, binding = 6) uniform highp sampler2DArray point_lights_shadow;
layout(set = 0, binding = 7) uniform highp sampler2D directional_light_shadow;
layout(set = 2, binding = 0) uniform _unused_name_permaterial
{
highp vec4 baseColorFactor;
highp float metallicFactor;
highp float roughnessFactor;
highp float normalScale;
highp float occlusionStrength;
highp vec3 emissiveFactor;
uint is_blend;
uint is_double_sided;
};
layout(set = 2, binding = 1) uniform sampler2D base_color_texture_sampler;
layout(set = 2, binding = 2) uniform sampler2D metallic_roughness_texture_sampler;
layout(set = 2, binding = 3) uniform sampler2D normal_texture_sampler;
layout(set = 2, binding = 4) uniform sampler2D occlusion_texture_sampler;
layout(set = 2, binding = 5) uniform sampler2D emissive_color_texture_sampler;
// read in fragnormal (from vertex shader)
layout(location = 0) in highp vec3 in_world_position;
layout(location = 1) in highp vec3 in_normal;
layout(location = 2) in highp vec3 in_tangent;
layout(location = 3) in highp vec2 in_texcoord;
layout(location = 0) out highp vec4 out_scene_color;
highp vec3 getBasecolor()
{
highp vec3 basecolor = texture(base_color_texture_sampler, in_texcoord).xyz * baseColorFactor.xyz;
return basecolor;
}
highp vec3 calculateNormal()
{
highp vec3 tangent_normal = texture(normal_texture_sampler, in_texcoord).xyz * 2.0 - 1.0;
highp vec3 N = normalize(in_normal);
highp vec3 T = normalize(in_tangent.xyz);
highp vec3 B = normalize(cross(N, T));
highp mat3 TBN = mat3(T, B, N);
return normalize(TBN * tangent_normal);
}
#include "mesh_lighting.h"
void main()
{
highp vec3 N = calculateNormal();
highp vec3 basecolor = getBasecolor();
highp float metallic = texture(metallic_roughness_texture_sampler, in_texcoord).z * metallicFactor;
highp float dielectric_specular = 0.04;
highp float roughness = texture(metallic_roughness_texture_sampler, in_texcoord).y * roughnessFactor;
highp vec3 result_color;
#include "mesh_lighting.inl"
out_scene_color = vec4(result_color, 1.0);
}
skybox.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
struct DirectionalLight
{
highp vec3 direction;
lowp float _padding_direction;
highp vec3 color;
lowp float _padding_color;
};
struct PointLight
{
highp vec3 position;
highp float radius;
highp vec3 intensity;
lowp float _padding_intensity;
};
layout(set = 0, binding = 0) readonly buffer _skybox_per_frame
{
highp mat4 proj_view_matrix;
highp vec3 camera_position;
lowp float _padding_camera_position;
highp vec3 ambient_light;
lowp float _padding_ambient_light;
highp uint point_light_num;
uint _padding_point_light_num_1;
uint _padding_point_light_num_2;
uint _padding_point_light_num_3;
PointLight scene_point_lights[m_max_point_light_count];
DirectionalLight scene_directional_light;
highp mat4 directional_light_proj_view;
};
layout(location = 0) out vec3 out_UVW;
void main()
{
const vec3 cube_corner_vertex_offsets[8] = vec3[8](vec3(1.0, 1.0, 1.0),
vec3(1.0, 1.0, -1.0),
vec3(1.0, -1.0, -1.0),
vec3(1.0, -1.0, 1.0),
vec3(-1.0, 1.0, 1.0),
vec3(-1.0, 1.0, -1.0),
vec3(-1.0, -1.0, -1.0),
vec3(-1.0, -1.0, 1.0));
const int cube_triangle_index[36] = int[36](
0,1,2,
2,3,0,
4,5,1,
1,0,4,
7,6,5,
5,4,7,
3,2,6,
6,7,3,
4,0,3,
3,7,4,
1,5,6,
6,2,1); // x+, y+, x-, y-, z+, z-
// vec3 world_position = camera_position + (camera_z_far_plane / 1.733) *
// cube_corner_vertex_offsets[cube_triangle_index[gl_VertexIndex]];
vec3 world_position = camera_position + cube_corner_vertex_offsets[cube_triangle_index[gl_VertexIndex]];
// world to NDC
vec4 clip_position = proj_view_matrix * vec4(world_position, 1.0);
// depth set to 0.99999?
clip_position.z = clip_position.w * 0.99999;
gl_Position = clip_position;
out_UVW = normalize(world_position - camera_position);
}
skybox.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "gbuffer.h"
layout(set = 0, binding = 1) uniform samplerCube specular_sampler;
layout(location = 0) in highp vec3 in_UVW;
layout(location = 0) out highp vec4 out_scene_color;
void main()
{
highp vec3 origin_sample_UVW = vec3(in_UVW.x, in_UVW.z, in_UVW.y);
highp vec3 color = textureLod(specular_sampler, origin_sample_UVW, 0.0).rgb;
out_scene_color = vec4(color, 1.0);
}
1.4. Tone Mapping Pass初始化
post_process.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
void main()
{
const vec3 fullscreen_triangle_positions[3] =
vec3[3](vec3(3.0, 1.0, 0.5), vec3(-1.0, 1.0, 0.5), vec3(-1.0, -3.0, 0.5));
gl_Position = vec4(fullscreen_triangle_positions[gl_VertexIndex], 1.0);
}
tone_mapping.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInput in_color;
layout(location = 0) out highp vec4 out_color;
highp vec3 Uncharted2Tonemap(highp vec3 x);
void main()
{
highp vec3 color = subpassLoad(in_color).rgb;
// tone mapping
color = Uncharted2Tonemap(color * 4.5f);
color = color * (1.0f / Uncharted2Tonemap(vec3(11.2f)));
// Gamma correct
// TODO: select the VK_FORMAT_B8G8R8A8_SRGB surface format,
// there is no need to do gamma correction in the fragment shader
color = vec3(pow(color.x, 1.0 / 2.2), pow(color.y, 1.0 / 2.2), pow(color.z, 1.0 / 2.2));
out_color = vec4(color, 1.0f);
}
highp vec3 Uncharted2Tonemap(highp vec3 x)
{
highp float A = 0.15;
highp float B = 0.50;
highp float C = 0.10;
highp float D = 0.20;
highp float E = 0.02;
highp float F = 0.30;
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
}
1.5. Color Grading Pass初始化
color_grading.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInput in_color;
layout(set = 0, binding = 1) uniform sampler2D color_grading_lut_texture_sampler;
layout(location = 0) out highp vec4 out_color;
void main()
{
highp ivec2 lut_tex_size = textureSize(color_grading_lut_texture_sampler, 0);
highp float _COLORS = float(lut_tex_size.y);
highp vec4 color = subpassLoad(in_color).rgba;
// texture(color_grading_lut_texture_sampler, uv)
out_color = color;
}
1.6. UI Pass初始化
1.7. Combine UI Pass初始化
combine_ui.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInput in_scene_color;
layout(input_attachment_index = 1, set = 0, binding = 1) uniform highp subpassInput in_ui_color;
layout(location = 0) out highp vec4 out_color;
void main()
{
highp vec4 scene_color = subpassLoad(in_scene_color).rgba;
highp vec4 ui_color = subpassLoad(in_ui_color).rgba;
// Gamma correct
// TODO: select the VK_FORMAT_B8G8R8A8_SRGB surface format,
// there is no need to do gamma correction in the fragment shader
if(ui_color.r<1e-6&&ui_color.g<1e-6&&ui_color.a<1e-6)
{
ui_color = vec4(pow(ui_color.r, 1.0 / 2.2), pow(ui_color.g, 1.0 / 2.2), pow(ui_color.b, 1.0 / 2.2), pow(ui_color.a, 1.0 / 2.2));
out_color = scene_color;
}
else
{
ui_color = vec4(pow(ui_color.r, 1.0 / 2.2), pow(ui_color.g, 1.0 / 2.2), pow(ui_color.b, 1.0 / 2.2), pow(ui_color.a, 1.0 / 2.2));
out_color = ui_color;
}
}
1.8. Pick Pass初始化
mesh_inefficient_pick.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "structures.h"
layout(set = 0, binding = 0) readonly buffer _unused_name_perframe
{
mat4 proj_view_matrix;
uint rt_width;
uint rt_height;
};
layout(set = 0, binding = 1) readonly buffer _unused_name_perdrawcall
{
mat4 model_matrices[m_mesh_per_drawcall_max_instance_count];
uint node_ids[m_mesh_per_drawcall_max_instance_count];
float enable_vertex_blendings[m_mesh_per_drawcall_max_instance_count];
};
layout(set = 0, binding = 2) readonly buffer _unused_name_per_drawcall_vertex_blending
{
mat4 joint_matrices[m_mesh_vertex_blending_max_joint_count * m_mesh_per_drawcall_max_instance_count];
};
layout(set = 1, binding = 0) readonly buffer _unused_name_per_mesh_joint_binding
{
VulkanMeshVertexJointBinding indices_and_weights[];
};
layout(location = 0) in vec3 in_position;
layout(location = 0) flat out highp uint out_nodeid;
void main()
{
highp mat4 model_matrix = model_matrices[gl_InstanceIndex];
highp float enable_vertex_blending = enable_vertex_blendings[gl_InstanceIndex];
highp vec3 model_position;
if (enable_vertex_blending > 0.0)
{
highp ivec4 in_indices = indices_and_weights[gl_VertexIndex].indices;
highp vec4 in_weights = indices_and_weights[gl_VertexIndex].weights;
highp mat4 vertex_blending_matrix = mat4x4(
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0));
if (in_weights.x > 0.0 && in_indices.x > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.x] * in_weights.x;
}
if (in_weights.y > 0.0 && in_indices.y > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.y] * in_weights.y;
}
if (in_weights.z > 0.0 && in_indices.z > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.z] * in_weights.z;
}
if (in_weights.w > 0.0 && in_indices.w > 0)
{
vertex_blending_matrix += joint_matrices[m_mesh_vertex_blending_max_joint_count * gl_InstanceIndex + in_indices.w] * in_weights.w;
}
model_position = (vertex_blending_matrix * vec4(in_position, 1.0)).xyz;
}
else
{
model_position = in_position;
}
gl_Position = proj_view_matrix * model_matrix * vec4(in_position, 1.0);
out_nodeid = node_ids[gl_InstanceIndex];
}
mesh_inefficient_pick.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(location = 0) flat in highp uint in_nodeid;
layout(early_fragment_tests) in;
layout (location = 0) out highp uint out_node_id;
void main()
{
out_node_id = in_nodeid;
}
1.9. FXAA Pass初始化
fxaa.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(location = 0) out vec2 out_uv;
void main()
{
const vec3 fullscreen_triangle_positions[3] =
vec3[3](vec3(3.0, 1.0, 0.5), vec3(-1.0, 1.0, 0.5), vec3(-1.0, -3.0, 0.5));
out_uv = 0.5 * (fullscreen_triangle_positions[gl_VertexIndex].xy + vec2(1.0, 1.0));
gl_Position = vec4(fullscreen_triangle_positions[gl_VertexIndex], 1.0);
}
fxaa.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
precision highp float;
precision highp int;
layout(set = 0, binding = 0) uniform sampler2D in_color;
layout(location = 0) in vec2 in_uv;
layout(location = 0) out vec4 out_color;
/* pixel index in 3*3 kernel
+---+---+---+
| 0 | 1 | 2 |
+---+---+---+
| 3 | 4 | 5 |
+---+---+---+
| 6 | 7 | 8 |
+---+---+---+
*/
#define UP_LEFT 0
#define UP 1
#define UP_RIGHT 2
#define LEFT 3
#define CENTER 4
#define RIGHT 5
#define DOWN_LEFT 6
#define DOWN 7
#define DOWN_RIGHT 8
vec2 KERNEL_STEP_MAT[] = vec2[9](
vec2(-1.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 1.0),
vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
vec2(-1.0, -1.0), vec2(0.0, -1.0), vec2(1.0, -1.0)
);
/* in order to accelerate exploring along tangent bidirectional, step by an increasing amount of pixels QUALITY(i)
the max step count is 12
+-----------------+---+---+---+---+---+---+---+---+---+---+---+---+
|step index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |
+-----------------+---+---+---+---+---+---+---+---+---+---+---+---+
|step pixels count|1.0|1.0|1.0|1.0|1.0|1.5|2.0|2.0|2.0|2.0|4.0|8.0|
+-----------------+---+---+---+---+---+---+---+---+---+---+---+---+
*/
#define STEP_COUNT_MAX 12
float QUALITY(int i) {
if (i < 5) return 1.0;
if (i == 5) return 1.5;
if (i < 10) return 2.0;
if (i == 10) return 4.0;
if (i == 11) return 8.0;
}
// L = 0.299 * R + 0.587 * G + 0.114 * B
float RGB2LUMA(vec3 color) {
return dot(vec3(0.299, 0.578, 0.114), color);
}
#define EDGE_THRESHOLD_MIN 0.0312
#define EDGE_THRESHOLD_MAX 0.125
#define SUBPIXEL_QUALITY 0.75
#define GRADIENT_SCALE 0.25
void main()
{
highp ivec2 screen_size = textureSize(in_color, 0);
highp vec2 uv_step = vec2(1.0 / float(screen_size.x), 1.0 / float(screen_size.y));
float luma_mat[9];
for (int i = 0; i < 9; i++) {
luma_mat[i] = RGB2LUMA(texture(in_color, in_uv + uv_step * KERNEL_STEP_MAT[i]).xyz);
}
// detecting where to apply FXAA, return the pixel color if not
float luma_min = min(luma_mat[CENTER], min(min(luma_mat[UP], luma_mat[DOWN]), min(luma_mat[LEFT], luma_mat[RIGHT])));
float luma_max = max(luma_mat[CENTER], max(max(luma_mat[UP], luma_mat[DOWN]), max(luma_mat[LEFT], luma_mat[RIGHT])));
float luma_range = luma_max - luma_min;
if(luma_range < max(EDGE_THRESHOLD_MIN, luma_max * EDGE_THRESHOLD_MAX)) {
out_color = texture(in_color, in_uv);
return;
}
// choosing edge tangent
// horizontal: |(upleft-left)-(left-downleft)|+2*|(up-center)-(center-down)|+|(upright-right)-(right-downright)|
// vertical: |(upright-up)-(up-upleft)|+2*|(right-center)-(center-left)|+|(downright-down)-(down-downleft)|
float luma_horizontal =
abs(luma_mat[UP_LEFT] + luma_mat[DOWN_LEFT] - 2.0 * luma_mat[LEFT])
+ 2.0 * abs(luma_mat[UP] + luma_mat[DOWN] - 2.0 * luma_mat[CENTER])
+ abs(luma_mat[UP_RIGHT] + luma_mat[DOWN_RIGHT] - 2.0 * luma_mat[RIGHT]);
float luma_vertical =
abs(luma_mat[UP_LEFT] + luma_mat[UP_RIGHT] - 2.0 * luma_mat[UP])
+ 2.0 * abs(luma_mat[LEFT] + luma_mat[RIGHT] - 2.0 * luma_mat[CENTER])
+ abs(luma_mat[DOWN_LEFT] + luma_mat[DOWN_RIGHT] - 2.0 * luma_mat[DOWN]);
bool is_horizontal = luma_horizontal > luma_vertical;
// choosing edge normal
float gradient_down_left = (is_horizontal ? luma_mat[DOWN] : luma_mat[LEFT]) - luma_mat[CENTER];
float gradient_up_right = (is_horizontal ? luma_mat[UP] : luma_mat[RIGHT]) - luma_mat[CENTER];
bool is_down_left = abs(gradient_down_left) > abs(gradient_up_right);
// get the tangent uv step vector and the normal uv step vector
vec2 step_tangent = (is_horizontal ? vec2(1.0, 0.0) : vec2(0.0, 1.0)) * uv_step;
vec2 step_normal = (is_down_left ? -1.0 : 1.0) * (is_horizontal ? vec2(0.0, 1.0) : vec2(1.0, 0.0)) * uv_step;
// get the change rate of gradient in normal per pixel
float gradient = is_down_left ? gradient_down_left : gradient_up_right;
// start at middle point of tangent edge
vec2 uv_start = in_uv + 0.5 * step_normal;
float luma_average_start = luma_mat[CENTER] + 0.5 * gradient;
//return vec4(luma_average_start, luma_average_start,luma_average_start, 1.0);
// explore along tangent bidirectional until reach the edge both
vec2 uv_pos = uv_start + step_tangent;
vec2 uv_neg = uv_start - step_tangent;
float delta_luma_pos = RGB2LUMA(texture(in_color, uv_pos).rgb) - luma_average_start;
float delta_luma_neg = RGB2LUMA(texture(in_color, uv_neg).rgb) - luma_average_start;
bool reached_pos = abs(delta_luma_pos) > GRADIENT_SCALE * abs(gradient);
bool reached_neg = abs(delta_luma_neg) > GRADIENT_SCALE * abs(gradient);
bool reached_both = reached_pos && reached_neg;
if (!reached_pos) uv_pos += step_tangent;
if (!reached_neg) uv_neg -= step_tangent;
if (!reached_both) {
for(int i = 2; i < STEP_COUNT_MAX; i++){
if(!reached_pos) delta_luma_pos = RGB2LUMA(texture(in_color, uv_pos).rgb) - luma_average_start;
if(!reached_neg) delta_luma_neg = RGB2LUMA(texture(in_color, uv_neg).rgb) - luma_average_start;
bool reached_pos = abs(delta_luma_pos) > GRADIENT_SCALE * abs(gradient);
bool reached_neg = abs(delta_luma_neg) > GRADIENT_SCALE * abs(gradient);
bool reached_both = reached_pos && reached_neg;
if (!reached_pos) uv_pos += (QUALITY(i) * step_tangent);
if (!reached_neg) uv_neg -= (QUALITY(i) * step_tangent);
if (reached_both) break;
}
}
// estimating offset
float length_pos = max(abs(uv_pos - uv_start).x, abs(uv_pos - uv_start).y);
float length_neg = max(abs(uv_neg - uv_start).x, abs(uv_neg - uv_start).y);
bool is_pos_near = length_pos < length_neg;
float pixel_offset = -1.0 * (is_pos_near ? length_pos : length_neg) / (length_pos + length_neg) + 0.5;
// no offset if the bidirectional point is too far
if(((is_pos_near ? delta_luma_pos : delta_luma_neg) < 0.0) == (luma_mat[CENTER] < luma_average_start)) pixel_offset = 0.0;
// subpixel antialiasing
float luma_average_center = 0.0;
float average_weight_mat[] = float[9](
1.0, 2.0, 1.0,
2.0, 0.0, 2.0,
1.0, 2.0, 1.0
);
for (int i = 0; i < 9; i++) luma_average_center += average_weight_mat[i] * luma_mat[i];
luma_average_center /= 12.0;
float subpixel_luma_range = clamp(abs(luma_average_center - luma_mat[CENTER]) / luma_range, 0.0, 1.0);
float subpixel_offset = (-2.0 * subpixel_luma_range + 3.0) * subpixel_luma_range * subpixel_luma_range;
subpixel_offset = subpixel_offset * subpixel_offset * SUBPIXEL_QUALITY;
// use the max offset between subpixel offset with before
pixel_offset = max(pixel_offset, subpixel_offset);
out_color = texture(in_color, in_uv + pixel_offset * step_normal);
}
1.10. Particle Pass初始化
particle_emit.comp
#version 450
#define POINT_TYPE_EMITTER 0
#define MESH_TYPE_EMITTER 1
struct Particle
{
vec3 pos;
float life;
vec3 vel;
float size_x;
vec3 acc;
float size_y;
vec4 color;
};
struct CountBuffer
{
int dead_count;
int alive_count;
int alive_count_after_sim;
int emit_count;
};
struct Argument
{
uvec4 emit_count;
uvec4 simulateCount;
int alive_flap_bit;
};
struct EmitterInfo
{
vec4 pos; // position base, variance
mat4 rotation; // rotation
vec4 vel; // velocity base, variance
vec4 acc; // acceleration base, variance
vec3 size; // size base
int emitter_type;
vec4 life; // life base, variance, accumulate time
vec4 color; // color rgba
};
layout(binding = 0) uniform UBO
{
float emit_delta;
int xemit_count;
float max_life;
float fixed_time_step;
float random0;
float random1;
float random2;
uint frameindex;
vec4 gravity;
uvec4 viewport;
vec4 extent;
}
ubo;
layout(set = 0, binding = 1) buffer Pos { Particle Particles[]; };
layout(set = 0, binding = 2) buffer Counter { CountBuffer counter; };
layout(set = 0, binding = 3) buffer indirectArgumentBuffer { Argument argument; };
layout(set = 0, binding = 4) buffer AliveBuffer { ivec4 alivelist[]; };
layout(set = 0, binding = 5) buffer DeadBuffer { ivec4 deadbuffer[]; };
layout(set = 0, binding = 6) buffer AliveBufferNext { ivec4 alivelistnext[]; };
layout(set = 0, binding = 7) buffer EmitterInfoBuffer { EmitterInfo emitterinfo; };
layout(set = 0, binding = 10) uniform sampler2D piccolotexture;
// Gold Noise ©2015 dcerisano@standard3d.com
// - based on the Golden Ratio
// - uniform normalized distribution
// - fastest static noise generator function (also runs at low precision)
// - use with indicated fractional seeding method
const float PHI = 1.61803398874989484820459; // Φ = Golden Ratio
float gold_noise(in vec2 xy, in float seed) { return fract(tan(distance(xy * PHI, xy) * seed) * xy.x); }
const float PI = 3.1415926535897932384626433832795;
layout(local_size_x = 256) in;
void main()
{
emitterinfo.life.z += 1;
uint threadId = gl_GlobalInvocationID.x;
if (emitterinfo.life.z > ubo.emit_delta)
{
emitterinfo.life.z = 1;
if (threadId < counter.emit_count)
{
bool fix = false;
Particle particle;
float rnd0 = gold_noise(vec2(threadId * ubo.random0, threadId * ubo.random1), ubo.random2);
float rnd1 = gold_noise(vec2(threadId * ubo.random0, threadId * ubo.random1), ubo.random2 + 0.2);
float rnd2 = gold_noise(vec2(threadId * ubo.random0, threadId * ubo.random1), ubo.random2 + 0.4);
if (emitterinfo.emitter_type == POINT_TYPE_EMITTER)
{
float theta = 0.15 * PI;
float phi = (2 * rnd0 - 1) * PI;
float r = 1 + rnd1;
float x = r * sin(theta) * cos(phi);
float y = r * sin(theta) * sin(phi);
float z = r * cos(theta);
particle.pos.x = 0.1 * (2 * rnd0 - 1) * emitterinfo.pos.w + emitterinfo.pos.x;
particle.pos.y = 0.1 * (2 * rnd1 - 1) * emitterinfo.pos.w + emitterinfo.pos.y;
particle.pos.z = 0.1 * (2 * rnd2 - 1) * emitterinfo.pos.w + emitterinfo.pos.z;
particle.vel.x = x * emitterinfo.vel.w + emitterinfo.vel.x;
particle.vel.y = y * emitterinfo.vel.w + emitterinfo.vel.y;
particle.vel.z = z * emitterinfo.vel.w + emitterinfo.vel.z;
particle.color = emitterinfo.color;
}
else if (emitterinfo.emitter_type == MESH_TYPE_EMITTER)
{
vec4 rotated_pos = emitterinfo.rotation * vec4(0, rnd0, rnd1, 0);
particle.pos.x = emitterinfo.pos.x + rotated_pos.x;
particle.pos.y = emitterinfo.pos.y + rotated_pos.y;
particle.pos.z = emitterinfo.pos.z + rotated_pos.z;
vec4 color = texture(piccolotexture, vec2(1.0 - rnd0, 1.0 - rnd1));
if (color.w > 0.9)
{
particle.color = color;
fix = true;
}
else
{
particle.color.x = 1.0 - rnd0;
particle.color.y = 1.0 - rnd1;
particle.color.z = 1.0 - rnd2;
particle.color.w = 0.0f;
vec4 rotated_vel =
emitterinfo.rotation * vec4((rnd0 * 2 - 1) * emitterinfo.vel.w + emitterinfo.vel.x,
(rnd1 * 2 - 1) * emitterinfo.vel.w + emitterinfo.vel.y,
(rnd2 * 2 - 1) * emitterinfo.vel.w + emitterinfo.vel.z,
1);
particle.vel.x = rotated_vel.x;
particle.vel.y = rotated_vel.y;
particle.vel.z = rotated_vel.z;
}
}
else
{
// wrong emitter type, should not happen
}
if (!fix)
{
particle.acc.x = emitterinfo.acc.x + ubo.gravity.x;
particle.acc.y = emitterinfo.acc.y + ubo.gravity.y;
particle.acc.z = emitterinfo.acc.z + ubo.gravity.z;
}
else
{
particle.acc = vec3(0, 0, 0);
particle.vel = vec3(0, 0, 0);
}
particle.life = rnd0 * emitterinfo.life.y + emitterinfo.life.x;
particle.size_x = emitterinfo.size.x;
particle.size_y = emitterinfo.size.y;
// retrieve particle from dead pool
int deadCount = atomicAdd(counter.dead_count, -1);
int index = deadbuffer[deadCount - 1].x;
// append to particle buffer
Particles[index] = particle;
// add index to alive list
if (argument.alive_flap_bit == 0)
{
int aliveIndex = atomicAdd(counter.alive_count, 1);
alivelist[aliveIndex].x = index;
}
else
{
int aliveIndex = atomicAdd(counter.alive_count, 1);
alivelistnext[aliveIndex].x = index;
}
}
}
}
particle_kickoff.comp
#version 450
struct Particle
{
vec3 pos;
float life;
vec3 vel;
float size_x;
vec3 acc;
float size_y;
vec4 color;
};
struct CountBuffer
{
int dead_count;
int alive_count;
int alive_count_after_sim;
int emit_count;
};
layout(binding = 0) uniform UBO
{
float emit_delta;
int xemit_count;
float max_life;
float fixed_time_step;
float random0;
float random1;
float random2;
uint frame_index;
vec4 gravity;
uvec4 viewport;
vec4 extent;
}
ubo;
layout(std140, binding = 2) buffer Counter { CountBuffer counter; };
struct Argument
{
uvec4 emit_count;
uvec4 simulate_count;
int alive_flap_bit;
};
layout(std140, binding = 3) buffer ArgumentBuffer { Argument argument; };
layout(local_size_x = 1) in;
void main()
{
int emitCount = min(counter.dead_count, ubo.xemit_count);
// indirect argument for emit
argument.emit_count.xyz = uvec3(ceil(float(emitCount) / float(256)), 1, 1);
// indirect argument for simulate
argument.simulate_count.xyz = uvec3(ceil(float(emitCount + counter.alive_count_after_sim) / float(256)), 1, 1);
// set new alive cnt
counter.alive_count = counter.alive_count_after_sim;
// reset particle cnt
counter.alive_count_after_sim = 0;
counter.emit_count = emitCount;
argument.alive_flap_bit = 1 - argument.alive_flap_bit;
}
particle_simulate.comp
#version 450
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
struct Particle
{
vec3 pos;
float life;
vec3 vel;
float size_x;
vec3 acc;
float size_y;
vec4 color;
};
struct CountBuffer
{
int dead_count;
int alive_count;
int alive_count_after_sim;
int emit_count;
};
struct Argument
{
uvec4 emit_count;
uvec4 simulateCount;
int alive_flap_bit;
};
layout(binding = 0) uniform UBO
{
float emit_delta;
int xemit_count;
float max_life;
float fixed_time_step;
float random0;
float random1;
float random2;
uint frameindex;
vec4 gravity;
uvec4 viewport;
vec4 extent;
}
ubo;
layout(std140, binding = 1) buffer Pos { Particle Particles[]; };
layout(std140, binding = 2) buffer Counter { CountBuffer counter; };
layout(std140, binding = 3) buffer indirectArgumentBuffer { Argument argument; };
layout(std140, binding = 4) buffer AliveBuffer { ivec4 alivelist[]; };
layout(std140, binding = 5) buffer DeadBuffer { ivec4 deadbuffer[]; };
layout(std140, binding = 6) buffer AliveBufferNext { ivec4 alivelistnext[]; };
layout(std140, binding = 8) uniform _unused_name_perframe
{
mat4 view_matrix;
mat4 proj_view_matrix;
mat4 proj_inv_matrix;
};
layout(std140, binding = 9) buffer _unsed_name_render_particle { Particle renderParticles[]; };
layout(set = 1, binding = 0, rgba8) uniform readonly image2D in_normal;
layout(set = 1, binding = 1) uniform sampler2D in_scene_depth;
layout(local_size_x = 256) in;
void main()
{
uint threadId = gl_GlobalInvocationID.x;
if (threadId < counter.alive_count)
{
float dt = ubo.fixed_time_step;
int particleId = argument.alive_flap_bit == 0 ? alivelist[threadId].x : alivelistnext[threadId].x;
Particle particle = Particles[particleId];
if (particle.life > 0)
{
particle.vel += particle.acc * dt;
particle.pos += particle.vel * dt;
// transfrom position to view space
vec3 viewSpaceParticlePosition = (view_matrix * vec4(particle.pos, 1)).xyz;
vec4 screenSpaceParticlePosition = proj_view_matrix * vec4(particle.pos, 1);
screenSpaceParticlePosition.xyz /= screenSpaceParticlePosition.w;
// on screen collision
if (screenSpaceParticlePosition.x > -1 && screenSpaceParticlePosition.x < 1 &&
screenSpaceParticlePosition.y > -1 && screenSpaceParticlePosition.y < 1)
{
vec2 uv = screenSpaceParticlePosition.xy * vec2(0.5f, 0.5f) + 0.5f;
float px = (ubo.viewport.x + uv.x * ubo.viewport.z);
float py = (ubo.viewport.y + uv.y * ubo.viewport.w);
// Fetch the depth value at this point
float depth = texture(in_scene_depth, vec2(px / ubo.extent.x, py / ubo.extent.y)).r;
vec4 viewSpacePosOfDepthBuffer;
viewSpacePosOfDepthBuffer.xy = screenSpaceParticlePosition.xy;
viewSpacePosOfDepthBuffer.z = depth;
viewSpacePosOfDepthBuffer.w = 1;
// Transform into view space using the inverse projection matrix
viewSpacePosOfDepthBuffer = proj_inv_matrix * viewSpacePosOfDepthBuffer;
viewSpacePosOfDepthBuffer.xyz /= viewSpacePosOfDepthBuffer.w;
float colliderthickness = 0.5f;
if ((viewSpaceParticlePosition.z < viewSpacePosOfDepthBuffer.z) &&
viewSpaceParticlePosition.z + colliderthickness > viewSpacePosOfDepthBuffer.z)
{
vec3 worldnormal = (imageLoad(in_normal, ivec2(px, py)).rgb) * 2 - 1;
if (dot(particle.vel, worldnormal) < 0)
{
vec3 prevd = normalize(particle.vel);
float distance =
abs(dot(prevd, (viewSpacePosOfDepthBuffer.xyz - viewSpaceParticlePosition.xyz)));
vec3 newv = 0.4f * reflect(particle.vel, worldnormal);
// stabilize
if (length(newv) < 0.3f)
{
particle.vel = vec3(0, 0, 0);
}
else
{
particle.vel = newv;
}
// push to surface, avoid multiple collision
particle.pos += -distance * prevd + particle.vel * dt;
}
}
}
}
if (particle.life < 0)
{
uint deadIndex = atomicAdd(counter.dead_count, 1);
deadbuffer[deadIndex].x = particleId;
particle.pos = vec3(0, 0, 0);
particle.life = 0;
particle.vel = vec3(0, 0, 0);
particle.size_x = 0;
particle.acc = vec3(0, 0, 0);
particle.size_y = 0;
particle.color = vec4(0, 0, 0, 0);
}
else
{
int nextAliveIndex = atomicAdd(counter.alive_count_after_sim, 1);
if (argument.alive_flap_bit == 0)
alivelistnext[nextAliveIndex].x = particleId;
else
alivelist[nextAliveIndex].x = particleId;
particle.life -= dt;
renderParticles[nextAliveIndex] = particle;
}
Particles[particleId] = particle;
}
}
particlebillboard.vert
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
layout(set = 0, binding = 0) uniform _unused_name_perframe
{
mat4 proj_view_matrix;
vec3 right_diection;
vec3 up_direction;
vec3 forward_diection;
};
struct Particle
{
vec3 pos;
float life;
vec3 vel;
float size_x;
vec3 acc;
float size_y;
vec4 color;
};
layout(set = 0, binding = 1) readonly buffer _unused_name_perdrawcall { Particle particles[]; };
layout(location = 0) out vec4 out_color;
layout(location = 1) out vec2 out_uv;
void main()
{
const vec2 vertex_buffer[4] = vec2[4](vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(0.5, -0.5));
const vec2 uv_buffer[4] = vec2[4](vec2(0, 1), vec2(1, 1), vec2(0, 0), vec2(1, 0));
vec2 model_position = vertex_buffer[gl_VertexIndex];
// Real-Time Rendering Fourth Edition
// 13.6 Billboarding
// 13.6.2 World-Oriented Billboard
Particle particle = particles[gl_InstanceIndex];
vec3 anchor_location = particle.pos;
// viewport-oriented
vec3 vel_dir = particle.vel;
float projectvel_x = dot(vel_dir, right_diection);
float projectvel_y = dot(vel_dir, up_direction);
float size_x = particle.size_x;
float size_y = particle.size_y;
vec3 world_position;
if (abs(projectvel_x) < size_x || abs(projectvel_y) < size_y)
{
world_position =
size_x * right_diection * model_position.x + size_y * up_direction * model_position.y + anchor_location;
}
else
{
vec3 project_dir = normalize(projectvel_x * right_diection + projectvel_y * up_direction);
vec3 side_dir = normalize(cross(forward_diection, project_dir));
world_position =
size_x * side_dir * model_position.x + size_y * project_dir * model_position.y + anchor_location;
}
// world to NDC
gl_Position = proj_view_matrix * vec4(world_position, 1.0);
out_color = particle.color;
out_uv = uv_buffer[gl_VertexIndex];
}
particlebillboard.frag
#version 310 es
#extension GL_GOOGLE_include_directive : enable
#include "constants.h"
#include "gbuffer.h"
layout(location = 0) in highp vec4 in_color;
layout(location = 1) in highp vec2 in_uv;
layout(set = 0, binding = 2) uniform sampler2D sparktexture;
layout(location = 0) out highp vec4 out_scene_color;
void main() {
out_scene_color.xyz = 4.0f * texture(sparktexture, in_uv).r * in_color.xyz;
out_scene_color.w = texture(sparktexture, in_uv).r;
}
2. Debug Draw Manager初始化
debugdraw.vert
#version 450
#extension GL_GOOGLE_include_directive :enable
#include "constants.h"
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec4 inColor;
layout(location = 2) in vec2 texcoord;
layout(set = 0, binding = 0) uniform UniformBufferObject {
mat4 proj_view_matrix;
} ubo;
layout(set = 0, binding = 1) uniform UniformDynamicBufferObject {
mat4 model;
vec4 color;
} dynamic_ubo;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec2 fragTexCoord;
void main() {
if(texcoord.x<0)
{
gl_Position = ubo.proj_view_matrix * dynamic_ubo.model * vec4(inPosition,1.0);
}
else
{
gl_Position = vec4(inPosition,1.0);
}
gl_PointSize = 2;
if(dynamic_ubo.color.a>0.000001)
{
fragColor = dynamic_ubo.color;
}
else
{
fragColor = inColor;
}
fragTexCoord = texcoord;
}
debugdraw.frag
#version 450
#extension GL_GOOGLE_include_directive :enable
layout(location = 0) in vec4 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 0) out vec4 outColor;
layout(set = 0, binding = 2) uniform sampler2D texSampler;
void main(){
outColor = fragColor;
if(fragTexCoord.x >= 0.0f && fragTexCoord.y >= 0.0f)
{
vec4 tex = texture(texSampler, fragTexCoord);
float xi = tex.r;
outColor = vec4(fragColor.r*xi,fragColor.g*xi,fragColor.b*xi,fragColor.a*xi);
}
}