feat: complete native client rendering parity updates
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
#version 450
|
||||
layout(location = 0) in vec3 in_position;
|
||||
layout(location = 1) in vec3 in_normal;
|
||||
layout(location = 2) in vec2 in_uv;
|
||||
layout(location = 3) in vec4 in_color;
|
||||
layout(location = 4) in uvec4 in_joints;
|
||||
layout(location = 5) in vec4 in_weights;
|
||||
layout(location = 6) in vec2 in_mask_uv;
|
||||
layout(location = 7) in float in_rhw;
|
||||
|
||||
layout(location = 0) out vec4 out_color;
|
||||
layout(location = 1) out vec2 out_uv;
|
||||
layout(location = 2) out vec2 out_mask_uv;
|
||||
layout(location = 3) out float out_fog;
|
||||
|
||||
layout(set = 1, binding = 0, std430) readonly buffer BonePalette {
|
||||
mat4 bones[];
|
||||
} bone_palette;
|
||||
|
||||
layout(push_constant) uniform DrawConstants {
|
||||
mat4 mvp;
|
||||
vec4 tint_color;
|
||||
vec4 ambient_emissive;
|
||||
vec4 light_dir;
|
||||
vec4 light_diffuse;
|
||||
} draw;
|
||||
|
||||
layout(set = 1, binding = 1, std430) readonly buffer FixedFunctionState {
|
||||
uvec4 stage0_color;
|
||||
uvec4 stage0_alpha;
|
||||
uvec4 stage1_color;
|
||||
uvec4 stage1_alpha;
|
||||
vec4 fog_color;
|
||||
vec4 fog_params;
|
||||
vec4 texture_factor;
|
||||
mat4 world_view;
|
||||
uvec4 flags;
|
||||
mat4 world;
|
||||
uvec4 lighting_flags;
|
||||
vec4 material_ambient;
|
||||
vec4 material_emissive;
|
||||
vec4 global_ambient;
|
||||
vec4 light_position_type[2];
|
||||
vec4 light_direction_range[2];
|
||||
vec4 light_diffuse[2];
|
||||
vec4 light_ambient[2];
|
||||
vec4 light_attenuation[2];
|
||||
vec4 light_spot[2];
|
||||
} fixed_state;
|
||||
|
||||
void main() {
|
||||
vec3 pos = in_position;
|
||||
vec3 nrm = in_normal;
|
||||
if (draw.light_diffuse.w > 0.5) {
|
||||
uint bone_base = uint(draw.light_diffuse.w - 0.5);
|
||||
vec3 skinned_pos = vec3(0.0);
|
||||
vec3 skinned_nrm = vec3(0.0);
|
||||
float total_w = 0.0;
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
float w = in_weights[k];
|
||||
if (w > 0.0) {
|
||||
mat4 B = bone_palette.bones[bone_base + in_joints[k]];
|
||||
skinned_pos += w * (B * vec4(pos, 1.0)).xyz;
|
||||
skinned_nrm += w * (mat3(B) * nrm);
|
||||
total_w += w;
|
||||
}
|
||||
}
|
||||
if (total_w > 0.0) {
|
||||
pos = skinned_pos;
|
||||
nrm = skinned_nrm;
|
||||
}
|
||||
}
|
||||
// D3D row-vector matrices are uploaded row-major. GLSL reads the bytes as their transpose.
|
||||
gl_Position = draw.mvp * vec4(pos, 1.0);
|
||||
if (draw.light_diffuse.w < -0.5) {
|
||||
float clip_w = in_rhw > 0.0 ? 1.0 / in_rhw : 1.0;
|
||||
gl_Position.xyz *= clip_w;
|
||||
gl_Position.w = clip_w;
|
||||
}
|
||||
gl_Position.y = -gl_Position.y;
|
||||
vec3 n = length(nrm) > 1e-4 ? normalize(nrm) : vec3(0.0, 0.0, 1.0);
|
||||
out_color = in_color;
|
||||
if (fixed_state.lighting_flags.x != 0u) {
|
||||
vec3 world_pos = (fixed_state.world * vec4(pos, 1.0)).xyz;
|
||||
vec3 world_normal = normalize(mat3(fixed_state.world) * n);
|
||||
vec3 mat_diffuse = (fixed_state.lighting_flags.y != 0u && fixed_state.lighting_flags.w == 1u)
|
||||
? in_color.rgb : draw.tint_color.rgb;
|
||||
vec3 mat_ambient = (fixed_state.lighting_flags.y != 0u && fixed_state.lighting_flags.z == 1u)
|
||||
? in_color.rgb : fixed_state.material_ambient.rgb;
|
||||
vec3 ambient_sum = fixed_state.global_ambient.rgb;
|
||||
vec3 diffuse_sum = vec3(0.0);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int type = int(fixed_state.light_position_type[i].w + 0.5);
|
||||
if (type == 0) continue;
|
||||
vec3 L;
|
||||
float strength = 1.0;
|
||||
if (type == 3) {
|
||||
L = normalize(-fixed_state.light_direction_range[i].xyz);
|
||||
} else {
|
||||
vec3 to_light = fixed_state.light_position_type[i].xyz - world_pos;
|
||||
float distance_to_light = length(to_light);
|
||||
if (distance_to_light > fixed_state.light_direction_range[i].w || distance_to_light < 0.0001)
|
||||
continue;
|
||||
L = to_light / distance_to_light;
|
||||
vec4 attenuation = fixed_state.light_attenuation[i];
|
||||
float denominator = attenuation.x + attenuation.y * distance_to_light +
|
||||
attenuation.z * distance_to_light * distance_to_light;
|
||||
strength = denominator > 0.0001 ? min(1.0 / denominator, 1.0) : 1.0;
|
||||
if (type == 2) {
|
||||
vec3 spot_dir = normalize(fixed_state.light_direction_range[i].xyz);
|
||||
float cosine = dot(-L, spot_dir);
|
||||
float inner = cos(fixed_state.light_spot[i].x * 0.5);
|
||||
float outer = cos(fixed_state.light_spot[i].y * 0.5);
|
||||
float cone = clamp((cosine - outer) / max(inner - outer, 0.0001), 0.0, 1.0);
|
||||
strength *= pow(cone, max(attenuation.w, 0.0001));
|
||||
}
|
||||
}
|
||||
ambient_sum += fixed_state.light_ambient[i].rgb * strength;
|
||||
diffuse_sum += fixed_state.light_diffuse[i].rgb * max(dot(world_normal, L), 0.0) * strength;
|
||||
}
|
||||
vec3 lit = fixed_state.material_emissive.rgb + mat_ambient * ambient_sum + mat_diffuse * diffuse_sum;
|
||||
float alpha = (fixed_state.lighting_flags.y != 0u && fixed_state.lighting_flags.w == 1u)
|
||||
? in_color.a : draw.tint_color.a;
|
||||
out_color = vec4(clamp(lit, 0.0, 1.0), alpha);
|
||||
}
|
||||
out_uv = in_uv;
|
||||
if (draw.light_dir.w > 1.001) {
|
||||
vec3 view_normal = normalize(mat3(fixed_state.world_view) * n);
|
||||
vec3 view_pos = (fixed_state.world_view * vec4(pos, 1.0)).xyz;
|
||||
vec3 view_dir = normalize(-view_pos);
|
||||
vec3 reflected = reflect(-view_dir, view_normal);
|
||||
out_mask_uv = reflected.xy * vec2(0.5, -0.5) + vec2(0.5);
|
||||
} else {
|
||||
out_mask_uv = in_mask_uv;
|
||||
}
|
||||
out_fog = 1.0;
|
||||
if (fixed_state.flags.x != 0u && fixed_state.flags.w != 0u && draw.light_diffuse.w >= -0.5) {
|
||||
vec3 eye = (fixed_state.world_view * vec4(pos, 1.0)).xyz;
|
||||
float distance_to_eye = fixed_state.fog_params.w > 0.5 ? length(eye) : abs(eye.z);
|
||||
if (fixed_state.flags.w == 3u) {
|
||||
float span = fixed_state.fog_params.y - fixed_state.fog_params.x;
|
||||
if (span > 0.0001)
|
||||
out_fog = clamp((fixed_state.fog_params.y - distance_to_eye) / span, 0.0, 1.0);
|
||||
} else if (fixed_state.flags.w == 1u) {
|
||||
out_fog = clamp(exp(-fixed_state.fog_params.z * distance_to_eye), 0.0, 1.0);
|
||||
} else if (fixed_state.flags.w == 2u) {
|
||||
float fog_distance = fixed_state.fog_params.z * distance_to_eye;
|
||||
out_fog = clamp(exp(-fog_distance * fog_distance), 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user