LumixEngine/data/pipelines/surface_base.inc
2023-09-22 13:52:15 +02:00

384 lines
10 KiB
C++

function surface_shader_ex(args)
args.vertex_preface = args.vertex_preface or ""
args.fragment_preface = args.fragment_preface or ""
args.vertex = args.vertex or ""
if args.need_local_position then
args.vertex_preface = args.vertex_preface .. "\nvec3 v_local_position;\n"
args.vertex = args.vertex .. "\nv_local_position = a_position;\n"
args.fragment_preface = args.fragment_preface .. "\nin vec3 v_local_position;\n"
end
if args.texture_slots == nil then
args.texture_slots = {
{
name = "Albedo",
default_texture = "textures/common/white.tga"
},
{
name = "Normal",
default_texture = "textures/common/default_normal.tga"
},
{
name = "Roughness",
default_texture = "textures/common/white.tga"
},
{
name = "Metallic",
define = "HAS_METALLICMAP"
},
{
name = "Ambient occlusion",
define = "HAS_AMBIENT_OCCLUSION_TEX"
}
}
end
for _, slot in ipairs(args.texture_slots) do
texture_slot(slot)
end
include "pipelines/common.glsl"
for _, v in ipairs(args.includes or {}) do
include(v)
end
define "ALPHA_CUTOUT"
------------------
function toVarName(prefix, name)
local res = prefix .. "_"
for idx = 1, #name do
local c = name:byte(idx)
if (c >= string.byte("A") and c <= string.byte("Z")) or (c >= string.byte("a") and c <= string.byte("z")) or (c >= string.byte("0") and c <= string.byte("9")) then
res = res .. string.char(c)
else
res = res .. "_"
end
end
return string.lower(res)
end
common([[
#ifdef SKINNED
layout(std140, binding = 4) uniform ModelState {
float fur_scale;
float fur_gravity;
float layers;
float padding;
mat4 matrix;
mat4 prev_matrix;
mat2x4 bones[255];
} Model;
#endif
#if !defined GRASS && !defined PARTICLES
#define HAS_LOD
#endif
]])
for idx, slot in ipairs(args.texture_slots) do
if slot.define ~= nil then
common("#ifdef " .. slot.define .. "\n")
end
common("layout (binding=" .. tostring(idx - 1) .. ") uniform sampler2D " .. toVarName("t", slot.name) .. ";\n")
if slot.define ~= nil then
common("#endif\n")
end
end
vertex_shader([[
#ifdef PARTICLES
layout(std140, binding = 4) uniform Model {
mat4 u_model;
};
#else
layout(location = 0) in vec3 a_position;
#ifdef UV0_ATTR
layout(location = UV0_ATTR) in vec2 a_uv;
#else
const vec2 a_uv = vec2(0);
#endif
layout(location = NORMAL_ATTR) in vec3 a_normal;
#ifdef TANGENT_ATTR
layout(location = TANGENT_ATTR) in vec3 a_tangent;
#else
const vec3 a_tangent = vec3(0, 1, 0);
#endif
#ifdef INDICES_ATTR
layout(location = INDICES_ATTR) in ivec4 a_indices;
layout(location = WEIGHTS_ATTR) in vec4 a_weights;
#endif
#if defined SKINNED
#elif defined INSTANCED
layout(location = INSTANCE0_ATTR) in vec4 i_rot_lod;
layout(location = INSTANCE1_ATTR) in vec4 i_pos_scale;
#elif defined AUTOINSTANCED
layout(location = INSTANCE0_ATTR) in vec4 i_rot;
layout(location = INSTANCE1_ATTR) in vec4 i_pos_lod;
layout(location = INSTANCE2_ATTR) in vec4 i_scale;
#ifdef COLOR0_ATTR
layout(location = COLOR0_ATTR) in vec4 a_color;
out vec4 v_color;
#endif
#elif defined DYNAMIC
layout(location = INSTANCE0_ATTR) in vec4 i_rot;
layout(location = INSTANCE1_ATTR) in vec4 i_pos_lod;
layout(location = INSTANCE2_ATTR) in vec4 i_scale;
layout(location = INSTANCE3_ATTR) in vec4 i_prev_rot;
layout(location = INSTANCE4_ATTR) in vec4 i_prev_pos_lod;
layout(location = INSTANCE5_ATTR) in vec4 i_prev_scale;
#ifdef COLOR0_ATTR
layout(location = COLOR0_ATTR) in vec4 a_color;
out vec4 v_color;
#endif
#elif defined GRASS
layout(location = INSTANCE0_ATTR) in vec4 i_pos_scale;
layout(location = INSTANCE1_ATTR) in vec4 i_rot;
#ifdef COLOR0_ATTR
layout(location = COLOR0_ATTR) in vec4 a_color;
out vec4 v_color;
#endif
out float v_pos_y;
#else
layout(std140, binding = 4) uniform ModelState {
mat4 matrix;
} Model;
#endif
#if defined GRASS
layout(std140, binding = 4) uniform ModelState {
vec3 u_grass_origin;
} Grass;
#endif
#ifdef HAS_LOD
out float v_lod;
#endif
#ifdef AO_ATTR
layout(location = AO_ATTR) in float a_ao;
out float v_ao;
#endif
out vec2 v_uv;
out vec3 v_normal;
out vec3 v_tangent;
out vec4 v_wpos;
#if defined DYNAMIC || defined SKINNED
out vec4 v_prev_ndcpos_no_jitter;
#endif
#ifdef FUR
out float v_fur_layer;
#endif
#endif
]] .. args.vertex_preface .. [[
void main() {
#ifndef PARTICLES
v_uv = a_uv;
#ifdef AO_ATTR
v_ao = a_ao;
#endif
#if defined INSTANCED
vec4 rot_quat = vec4(i_rot_lod.xyz, 0);
rot_quat.w = sqrt(saturate(1 - dot(rot_quat.xyz, rot_quat.xyz)));
v_normal = rotateByQuat(rot_quat, a_normal);
v_tangent = rotateByQuat(rot_quat, a_tangent);
vec3 p = a_position * i_pos_scale.w;
#ifdef HAS_LOD
v_lod = i_rot_lod.w;
#endif
v_wpos = vec4(i_pos_scale.xyz + rotateByQuat(rot_quat, p), 1);
#elif defined AUTOINSTANCED
v_normal = rotateByQuat(i_rot, a_normal);
v_tangent = rotateByQuat(i_rot, a_tangent);
vec3 p = a_position * i_scale.xyz;
#ifdef HAS_LOD
v_lod = i_pos_lod.w;
#endif
v_wpos = vec4(i_pos_lod.xyz + rotateByQuat(i_rot, p), 1);
#ifdef COLOR0_ATTR
v_color = a_color;
#endif
#elif defined DYNAMIC
v_normal = rotateByQuat(i_rot, a_normal);
v_tangent = rotateByQuat(i_rot, a_tangent);
#ifdef HAS_LOD
v_lod = i_pos_lod.w;
#endif
v_wpos = vec4(i_pos_lod.xyz + rotateByQuat(i_rot, a_position * i_scale.xyz), 1);
v_prev_ndcpos_no_jitter = vec4(i_prev_pos_lod.xyz + rotateByQuat(i_prev_rot, a_position * i_prev_scale.xyz), 1);
v_prev_ndcpos_no_jitter = Global.reprojection * Global.view_projection_no_jitter * v_prev_ndcpos_no_jitter;
#ifdef COLOR0_ATTR
v_color = a_color;
#endif
#elif defined GRASS
v_normal = rotateByQuat(i_rot, a_normal);
v_tangent = rotateByQuat(i_rot, a_tangent);
vec3 p = a_position;
v_pos_y = p.y;
v_wpos = vec4(i_pos_scale.xyz + rotateByQuat(i_rot, a_position * i_pos_scale.w), 1);
#ifdef GRASS
v_wpos.xyz += Grass.u_grass_origin;
#endif
#ifdef COLOR0_ATTR
v_color = a_color;
#endif
#elif defined SKINNED
mat2x4 dq = a_weights.x * Model.bones[a_indices.x];
float w = dot(Model.bones[a_indices.y][0], Model.bones[a_indices.x][0]) < 0 ? -a_weights.y : a_weights.y;
dq += w * Model.bones[a_indices.y];
w = dot(Model.bones[a_indices.z][0], Model.bones[a_indices.x][0]) < 0 ? -a_weights.z : a_weights.z;
dq += w * Model.bones[a_indices.z];
w = dot(Model.bones[a_indices.w][0], Model.bones[a_indices.x][0]) < 0 ? -a_weights.w : a_weights.w;
dq += w * Model.bones[a_indices.w];
dq *= 1 / length(dq[0]);
mat3 m = mat3(Model.matrix);
v_normal = m * rotateByQuat(dq[0], a_normal);
v_tangent = m * rotateByQuat(dq[0], a_tangent);
vec3 mpos;
#ifdef FUR
v_fur_layer = gl_InstanceID / Model.layers;
mpos = a_position + (a_normal + vec3(0, -Model.fur_gravity * v_fur_layer, 0)) * v_fur_layer * Model.fur_scale;
#else
mpos = a_position;
#endif
v_wpos = Model.matrix * vec4(transformByDualQuat(dq, mpos), 1);
// TODO previous frame bone positions
v_prev_ndcpos_no_jitter = Model.prev_matrix * vec4(transformByDualQuat(dq, mpos), 1);
v_prev_ndcpos_no_jitter = Global.reprojection * Global.view_projection_no_jitter * v_prev_ndcpos_no_jitter;
#else
mat4 model_mtx = Model.matrix;
v_normal = mat3(model_mtx) * a_normal;
v_tangent = mat3(model_mtx) * a_tangent;
vec3 p = a_position;
v_wpos = model_mtx * vec4(p, 1);
#endif
#endif
]] .. args.vertex .. [[
#ifndef PARTICLES
gl_Position = Pass.view_projection * v_wpos;
#endif
}
]])
---------------------
fragment_shader([[
layout (binding=5) uniform sampler2D u_shadowmap;
#if !defined DEPTH && !defined DEFERRED && !defined GRASS
layout (binding=6) uniform sampler2D u_shadow_atlas;
layout (binding=7) uniform samplerCubeArray u_reflection_probes;
layout (binding=8) uniform sampler2D u_depthbuffer;
#endif
#ifdef PARTICLES
#else
in vec2 v_uv;
in vec3 v_normal;
in vec3 v_tangent;
in vec4 v_wpos;
#if defined DYNAMIC || defined SKINNED
in vec4 v_prev_ndcpos_no_jitter;
#endif
#ifdef HAS_LOD
in float v_lod;
#endif
#ifdef COLOR0_ATTR
in vec4 v_color;
#endif
#ifdef AO_ATTR
in float v_ao;
#endif
#ifdef FUR
in float v_fur_layer;
#endif
#ifdef GRASS
in float v_pos_y;
#endif
#endif
#ifndef DEPTH
#if defined DEFERRED || defined GRASS
layout(location = 0) out vec4 o_gbuffer0;
layout(location = 1) out vec4 o_gbuffer1;
layout(location = 2) out vec4 o_gbuffer2;
layout(location = 3) out vec4 o_gbuffer3;
#else
layout(location = 0) out vec4 o_color;
#endif
#endif
]] .. args.fragment_preface .. [[
Surface getSurface()
{
#ifdef HAS_LOD
if (ditherLOD(v_lod)) discard;
#endif
Surface data;
#ifndef PARTICLES
data.wpos = v_wpos.xyz;
vec4 p = Global.view_projection_no_jitter * v_wpos;
#if defined DYNAMIC || defined SKINNED
vec2 prev_pos_projected = v_prev_ndcpos_no_jitter.xy / v_prev_ndcpos_no_jitter.w;
data.motion = prev_pos_projected.xy - p.xy / p.w;
#else
data.motion = computeStaticObjectMotionVector(v_wpos.xyz);
#endif
data.V = normalize(-data.wpos);
#endif
]] .. args.fragment .. [[
return data;
}
#ifdef DEPTH
void main()
{
#ifdef HAS_LOD
if (ditherLOD(v_lod)) discard;
#endif
#ifdef ALPHA_CUTOUT
Surface data = getSurface();
if (data.alpha < 0.5) discard;
#endif
}
#elif defined DEFERRED || defined GRASS
void main()
{
Surface data = getSurface();
#if defined ALPHA_CUTOUT
if (data.alpha < 0.5) discard;
#endif
packSurface(data, o_gbuffer0, o_gbuffer1, o_gbuffer2, o_gbuffer3);
}
#else
void main()
{
Surface data = getSurface();
float linear_depth = dot(data.wpos.xyz, Pass.view_dir.xyz);
Cluster cluster = getClusterLinearDepth(linear_depth);
o_color.rgb = computeLighting(cluster, data, Global.light_dir.xyz, Global.light_color.rgb * Global.light_intensity, u_shadowmap, u_shadow_atlas, u_reflection_probes);
#if defined ALPHA_CUTOUT
if(data.alpha < 0.5) discard;
#endif
o_color.a = data.alpha;
}
#endif
]])
end
function surface_shader(code)
surface_shader_ex({fragment = code})
end