mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Fixing various things about shadows.
* Correcting optimal LISPSM parameter. * Figure shadows are cast when they're not visible. * Chunk shadows stay cast until you look away. * Seamless cubemaps for point lights. * Etc.
This commit is contained in:
parent
6c31e6b562
commit
2e2ab3dc1e
@ -59,7 +59,7 @@ float attenuation_strength(vec3 rpos) {
|
||||
// }
|
||||
|
||||
vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
const float LIGHT_AMBIENCE = 0.025;
|
||||
const float LIGHT_AMBIANCE = 0.025;
|
||||
|
||||
vec3 light = vec3(0);
|
||||
|
||||
@ -78,7 +78,7 @@ vec3 light_at(vec3 wpos, vec3 wnorm) {
|
||||
// Multiply the vec3 only once
|
||||
vec3 color = srgb_to_linear(L.light_col.rgb) * (strength * L.light_col.a);
|
||||
|
||||
light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIENCE);
|
||||
light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIANCE);
|
||||
}
|
||||
return light;
|
||||
}
|
||||
@ -126,7 +126,7 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve
|
||||
vec3 directed_light = vec3(0.0);
|
||||
vec3 max_light = vec3(0.0);
|
||||
|
||||
const float LIGHT_AMBIENCE = 0.0;//0.015625;
|
||||
const float LIGHT_AMBIANCE = 0.015625;
|
||||
|
||||
for (uint i = 0u; i < /*light_shadow_count.x*//*0u*/light_shadow_count.x/*32u*/; i ++) {
|
||||
|
||||
@ -183,10 +183,12 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve
|
||||
#endif
|
||||
vec3 direct_light = PI * color * strength * square_factor * light_reflection_factor(/*direct_norm_dir*/wnorm, /*cam_to_frag*/view_dir, direct_light_dir, k_d, k_s, alpha, voxel_norm, voxel_lighting);
|
||||
float computed_shadow = ShadowCalculationPoint(i, -difference, wnorm, wpos/*, light_distance*/);
|
||||
// directed_light += is_direct ? max(computed_shadow, /*LIGHT_AMBIENCE*/0.0) * direct_light * square_factor : vec3(0.0);
|
||||
directed_light += is_direct ? mix(LIGHT_AMBIENCE, 1.0, computed_shadow) * direct_light * square_factor : vec3(0.0);
|
||||
// ambient_light += is_direct ? vec3(0.0) : vec3(0.0); // direct_light * square_factor * LIGHT_AMBIENCE;
|
||||
// ambient_light += is_direct ? direct_light * (1.0 - square_factor * LIGHT_AMBIENCE) : vec3(0.0);
|
||||
// directed_light += is_direct ? max(computed_shadow, /*LIGHT_AMBIANCE*/0.0) * direct_light * square_factor : vec3(0.0);
|
||||
// directed_light += is_direct ? mix(LIGHT_AMBIANCE, 1.0, computed_shadow) * direct_light * square_factor : vec3(0.0);
|
||||
directed_light += (is_direct ? 1.0 : LIGHT_AMBIANCE) * max(computed_shadow, /*LIGHT_AMBIANCE*/0.0) * direct_light * square_factor;// : vec3(0.0);
|
||||
// directed_light += mix(LIGHT_AMBIANCE, 1.0, computed_shadow) * direct_light * square_factor;
|
||||
// ambient_light += is_direct ? vec3(0.0) : vec3(0.0); // direct_light * square_factor * LIGHT_AMBIANCE;
|
||||
// ambient_light += is_direct ? direct_light * (1.0 - square_factor * LIGHT_AMBIANCE) : vec3(0.0);
|
||||
|
||||
vec3 cam_light_diff = light_pos - focus_pos.xyz;
|
||||
float cam_distance_2 = dot(cam_light_diff, cam_light_diff);// + 0.0001;
|
||||
@ -209,12 +211,12 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve
|
||||
// float both_strength = mix(cam_strength, strength, cam_distance_2 / sqrt(cam_distance_2 + distance_2));
|
||||
max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*//*max(both_strength, 1.0) * *//*cam_strength*/computed_shadow * both_strength * square_factor * square_factor * PI * color;
|
||||
// max_light += /*max(1.0, cam_strength)*//*min(cam_strength, 1.0)*//*max*/max(cam_strength, 1.0/*, strength*//*1.0*/) * square_factor * square_factor * PI * color;
|
||||
// light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIENCE);
|
||||
// light += color * (max(0, max(dot(normalize(difference), wnorm), 0.15)) + LIGHT_AMBIANCE);
|
||||
// Compute emiittance.
|
||||
// float ambient_sides = clamp(mix(0.15, 0.0, abs(dot(wnorm, light_dir)) * 10000.0), 0.0, 0.15);
|
||||
// float ambient_sides = 0.0;// max(dot(wnorm, light_dir) - 0.15, 0.15);
|
||||
// // float ambient_sides = 0.0;
|
||||
// ambient_light += color * (ambient_sides + LIGHT_AMBIENCE);
|
||||
// ambient_light += color * (ambient_sides + LIGHT_AMBIANCE);
|
||||
}
|
||||
|
||||
// shadow = shadow_at(wpos, wnorm);
|
||||
|
@ -23,6 +23,7 @@ uniform samplerCubeShadow t_point_shadow_maps;
|
||||
|
||||
float VectorToDepth (vec3 Vec)
|
||||
{
|
||||
// return length(Vec) / screen_res.w;
|
||||
vec3 AbsVec = abs(Vec);
|
||||
float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));
|
||||
// float LocalZcomp = length(Vec);
|
||||
@ -60,14 +61,6 @@ float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /
|
||||
return 1.0;
|
||||
};
|
||||
|
||||
float shadow = 0.0;
|
||||
float bias = 0.0;//0.003;//-0.003;//-0.005;//0.001;//-1.0;//-0.001;//0.001;//0.003;//-0.05;//-0.1;//0.0;//0.1
|
||||
float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
vec3 firstDelta = vec3(0.0);///*min(viewDistance, 5.0) * *//**normalize(cam_pos - fragPos)*/fragNorm * 0.5;
|
||||
fragToLight += firstDelta;
|
||||
// viewDistance -= length(firstDelta);
|
||||
fragPos -= firstDelta;
|
||||
|
||||
{
|
||||
float currentDepth = VectorToDepth(fragToLight);// + bias;
|
||||
|
||||
@ -84,55 +77,68 @@ float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /
|
||||
/* if (visibility < 1.0) {
|
||||
return 0.0;
|
||||
} */
|
||||
return visibility == 1.0 ? 1.0 : 0.0;
|
||||
// return visibility;
|
||||
/* if (visibility == 1.0) {
|
||||
return visibility;
|
||||
} */
|
||||
return visibility;
|
||||
// return visibility == 1.0 ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
int samples = 20;
|
||||
// float lightDistance = length(fragToLight);
|
||||
// float diskRadius = 0.00001;
|
||||
// float diskRadius = 1.0;
|
||||
// float diskRadius = 0.05;
|
||||
float diskRadius = (1.0 + (/*viewDistance*/viewDistance / screen_res.w)) / 25.0;
|
||||
// float diskRadius = lightDistance;
|
||||
for(int i = 0; i < samples; ++i)
|
||||
{
|
||||
float currentDepth = VectorToDepth(fragToLight + sampleOffsetDirections[i] * diskRadius) + bias;
|
||||
// float closestDepth = texture(depthMap, fragToLight).r;
|
||||
// closestDepth *= far_plane; // Undo mapping [0;1]
|
||||
/* if(currentDepth - bias > closestDepth)
|
||||
shadow += 1.0;*/
|
||||
float visibility = texture(t_point_shadow_maps, vec4(fragToLight, currentDepth)/*, -2.5*/);
|
||||
shadow += visibility;
|
||||
// float closestDepth = texture(t_shadow_maps, vec3(fragToLight)/*, -2.5*/).r;
|
||||
// shadow += closestDepth > currentDepth ? 1.0 : 0.0;
|
||||
}
|
||||
shadow /= float(samples);
|
||||
// shadow = shadow * shadow * (3.0 - 2.0 * shadow);
|
||||
// float shadow = 0.0;
|
||||
// float bias = 0.0;//0.003;//-0.003;//-0.005;//0.001;//-1.0;//-0.001;//0.001;//0.003;//-0.05;//-0.1;//0.0;//0.1
|
||||
// float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
// vec3 firstDelta = vec3(0.0);///*min(viewDistance, 5.0) * *//**normalize(cam_pos - fragPos)*/fragNorm * 0.5;
|
||||
// fragToLight += firstDelta;
|
||||
// // viewDistance -= length(firstDelta);
|
||||
// fragPos -= firstDelta;
|
||||
|
||||
// use the light to fragment vector to sample from the depth map
|
||||
// float bias = 0.0;///*0.05*/0.01;//0.05;// 0.05;
|
||||
// float closestDepth = texture(t_shadow_maps, /*vec4*/vec3(fragToLight/*, (lightIndex + 1)*//* * 6*/)/*, 0.0*//*, 0.0*//*, bias*/).r;
|
||||
// // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// // // it is currently in linear range between [0,1]. Re-transform back to original value
|
||||
// closestDepth = (closestDepth + 0.0) * screen_res.w; // far plane
|
||||
// // // now test for shadows
|
||||
// // // float shadow = /*currentDepth*/(screen_res.w - bias) > closestDepth ? 1.0 : 0.0;
|
||||
// float shadow = currentDepth - bias < closestDepth ? 1.0 : 0.0;
|
||||
// float visibility = textureProj(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// float visibility = texture(t_shadow_maps, vec4(fragToLight, lightIndex + 1), -(currentDepth/* + screen_res.z*/) / screen_res.w);// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
// currentDepth += bias;
|
||||
// currentDepth = -1000.0 / (currentDepth + 10000.0);
|
||||
// currentDepth /= screen_res.w;
|
||||
// float currentDepth = VectorToDepth(fragToLight) + bias;
|
||||
// int samples = 20;
|
||||
// // float lightDistance = length(fragToLight);
|
||||
// // float diskRadius = 0.00001;
|
||||
// // float diskRadius = 1.0;
|
||||
// // float diskRadius = 0.05;
|
||||
// float diskRadius = 5.0 / screen_res.w;// (1.0 + (/*viewDistance*/viewDistance / screen_res.w)) / 25.0;
|
||||
// // float diskRadius = lightDistance;
|
||||
// for(int i = 0; i < samples; ++i)
|
||||
// {
|
||||
// float currentDepth = VectorToDepth(fragToLight + sampleOffsetDirections[i] * diskRadius) + bias;
|
||||
// // float closestDepth = texture(depthMap, fragToLight).r;
|
||||
// // closestDepth *= far_plane; // Undo mapping [0;1]
|
||||
// /* if(currentDepth - bias > closestDepth)
|
||||
// shadow += 1.0;*/
|
||||
// float visibility = texture(t_point_shadow_maps, vec4(fragToLight, currentDepth)/*, -2.5*/);
|
||||
// shadow += visibility;
|
||||
// // float closestDepth = texture(t_shadow_maps, vec3(fragToLight)/*, -2.5*/).r;
|
||||
// // shadow += closestDepth > currentDepth ? 1.0 : 0.0;
|
||||
// }
|
||||
// shadow /= float(samples);
|
||||
// // shadow = shadow * shadow * (3.0 - 2.0 * shadow);
|
||||
|
||||
// float visibility = texture(t_shadow_maps, vec4(fragToLight, currentDepth));// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
// return visibility == 1.0 ? 1.0 : 0.0;
|
||||
return shadow;
|
||||
// // use the light to fragment vector to sample from the depth map
|
||||
// // float bias = 0.0;///*0.05*/0.01;//0.05;// 0.05;
|
||||
// // float closestDepth = texture(t_shadow_maps, /*vec4*/vec3(fragToLight/*, (lightIndex + 1)*//* * 6*/)/*, 0.0*//*, 0.0*//*, bias*/).r;
|
||||
// // // // float closestDepth = texture(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// // // // it is currently in linear range between [0,1]. Re-transform back to original value
|
||||
// // closestDepth = (closestDepth + 0.0) * screen_res.w; // far plane
|
||||
// // // // now test for shadows
|
||||
// // // // float shadow = /*currentDepth*/(screen_res.w - bias) > closestDepth ? 1.0 : 0.0;
|
||||
// // float shadow = currentDepth - bias < closestDepth ? 1.0 : 0.0;
|
||||
// // float visibility = textureProj(t_shadow_maps, vec4(fragToLight, lightIndex), bias);
|
||||
// // float visibility = texture(t_shadow_maps, vec4(fragToLight, lightIndex + 1), -(currentDepth/* + screen_res.z*/) / screen_res.w);// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
// // currentDepth += bias;
|
||||
// // currentDepth = -1000.0 / (currentDepth + 10000.0);
|
||||
// // currentDepth /= screen_res.w;
|
||||
// // float currentDepth = VectorToDepth(fragToLight) + bias;
|
||||
|
||||
// // float visibility = texture(t_shadow_maps, vec4(fragToLight, currentDepth));// / (screen_res.w/* - screen_res.z*/)/*1.0 -bias*//*-(currentDepth - bias) / screen_res.w*//*-screen_res.w*/);
|
||||
// // return visibility == 1.0 ? 1.0 : 0.0;
|
||||
// return shadow;
|
||||
}
|
||||
|
||||
float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_pos, vec3 fragPos)
|
||||
{
|
||||
float bias = 0.000;//0.0005;//-0.0001;// 0.05 / (2.0 * view_distance.x);
|
||||
float bias = 0.001;//0.0005;//-0.0001;// 0.05 / (2.0 * view_distance.x);
|
||||
float diskRadius = 0.01;
|
||||
const vec3 sampleOffsetDirections[20] = vec3[]
|
||||
(
|
||||
@ -150,16 +156,20 @@ float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_po
|
||||
// sun_pos.z += sun_pos.w * bias;
|
||||
ShadowLocals sun_shadow = shadowMats[0];
|
||||
vec4 sun_pos = sun_shadow.texture_mat * vec4(fragPos, 1.0);
|
||||
// sun_pos.z -= sun_pos.w * bias;
|
||||
float visibility = textureProj(t_directed_shadow_maps, sun_pos);
|
||||
/* float visibilityLeft = textureProj(t_directed_shadow_maps, sun_shadow.texture_mat * vec4(fragPos + vec3(0.0, -diskRadius, 0.0), 1.0));
|
||||
float visibilityRight = textureProj(t_directed_shadow_maps, sun_shadow.texture_mat * vec4(fragPos + vec3(0.0, diskRadius, 0.0), 1.0)); */
|
||||
// float nearVisibility = textureProj(t_directed_shadow_maps + vec3(0.001, sun_pos));
|
||||
// float visibility = textureProj(t_directed_shadow_maps, vec4(fragPos.xy, /*lightIndex, */fragPos.z + bias, sun_pos.w));
|
||||
return visibility;
|
||||
// return visibility;
|
||||
// return min(visibility, min(visibilityLeft, visibilityRight));
|
||||
// return mix(visibility, 0.0, sun_pos.z < -1.0);
|
||||
// return mix(mix(0.0, 1.0, visibility == 1.0), 1.0, sign(sun_pos.w) * sun_pos.z > /*1.0*/abs(sun_pos.w));
|
||||
// return (visibility - 0.5) * (visibility - 0.5) * 2.0 * sign(visibility - 0.5) + 0.5;// visibility > 0.75 ? visibility : 0.0;// visibility > 0.9 ? 1.0 : 0.0;
|
||||
return visibility;
|
||||
// return visibility == 1.0 ? 1.0 : 0.0;
|
||||
// return abs(fragPos.y - round(fragPos.y)) <= 0.1 || abs(fragPos.x - round(fragPos.x)) <= 0.1 ? ( visibility == 1.0 ? 1.0 : 0.0) : visibility;
|
||||
/* if (visibility == 1.0) {
|
||||
return 1.0;
|
||||
} */
|
||||
@ -167,32 +177,32 @@ float ShadowCalculationDirected(in vec3 fragPos)//in vec4 /*light_pos[2]*/sun_po
|
||||
/* if (fragPos.z > 1.0) {
|
||||
return 1.0;
|
||||
} */
|
||||
vec3 snapToZ = abs(fragPos - vec3(ivec3(fragPos))); // fract(abs(fragPos));
|
||||
// snapToZ = min(snapToZ, 1.0 - snapToZ);
|
||||
const float EDGE_DIST = 0.01;
|
||||
snapToZ = mix(vec3(0.0), vec3(1.0), lessThanEqual(snapToZ, vec3(EDGE_DIST)));
|
||||
// float snapToZDist = dot(snapToZ, snapToZ);
|
||||
if (visibility <= 0.75 && /*fract(abs(fragPos.xy)), vec2(0.1)))*/ /*snapToZDist <= 0.25*//*all(lessThan(snapToZ, vec3(0.1)))(*/
|
||||
snapToZ.x + snapToZ.y + snapToZ.z >= 2.0) {
|
||||
return 0.0;
|
||||
}
|
||||
int samples = 20;
|
||||
float shadow = 0.0;
|
||||
// float bias = 0.0001;
|
||||
// float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
// float diskRadius = 0.2 * (1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// float diskRadius = 0.0003;//0.005;// / (2.0 * view_distance.x);//(1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
fragPos = sun_pos.xyz / sun_pos.w;
|
||||
for(int i = 0; i < samples; ++i)
|
||||
{
|
||||
vec3 currentDepth = fragPos + vec3(sampleOffsetDirections[i].xyz) * diskRadius + bias;
|
||||
visibility = texture(t_directed_shadow_maps, currentDepth);//vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
// visibility = texture(t_directed_shadow_maps, vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
shadow += visibility;
|
||||
// mix(visibility, 1.0, visibility >= 0.5);
|
||||
}
|
||||
shadow /= float(samples);
|
||||
return shadow;
|
||||
// vec3 snapToZ = abs(fragPos - vec3(ivec3(fragPos))); // fract(abs(fragPos));
|
||||
// // snapToZ = min(snapToZ, 1.0 - snapToZ);
|
||||
// const float EDGE_DIST = 0.01;
|
||||
// snapToZ = mix(vec3(0.0), vec3(1.0), lessThanEqual(snapToZ, vec3(EDGE_DIST)));
|
||||
// // float snapToZDist = dot(snapToZ, snapToZ);
|
||||
// if (visibility <= 0.75 && /*fract(abs(fragPos.xy)), vec2(0.1)))*/ /*snapToZDist <= 0.25*//*all(lessThan(snapToZ, vec3(0.1)))(*/
|
||||
// snapToZ.x + snapToZ.y + snapToZ.z >= 2.0) {
|
||||
// return 0.0;
|
||||
// }
|
||||
// int samples = 20;
|
||||
// float shadow = 0.0;
|
||||
// // float bias = 0.0001;
|
||||
// // float viewDistance = length(cam_pos.xyz - fragPos);
|
||||
// // float diskRadius = 0.2 * (1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// // float diskRadius = 0.0003;//0.005;// / (2.0 * view_distance.x);//(1.0 + (viewDistance / screen_res.w)) / 25.0;
|
||||
// fragPos = sun_pos.xyz / sun_pos.w;
|
||||
// for(int i = 0; i < samples; ++i)
|
||||
// {
|
||||
// vec3 currentDepth = fragPos + vec3(sampleOffsetDirections[i].xyz) * diskRadius + bias;
|
||||
// visibility = texture(t_directed_shadow_maps, currentDepth);//vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
// // visibility = texture(t_directed_shadow_maps, vec4(currentDepth.xy, lightIndex, currentDepth.z)/*, -2.5*/);
|
||||
// shadow += visibility;
|
||||
// // mix(visibility, 1.0, visibility >= 0.5);
|
||||
// }
|
||||
// shadow /= float(samples);
|
||||
// return shadow;
|
||||
}
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || SHADOW_MODE == SHADOW_MODE_CHEAP)
|
||||
float ShadowCalculationPoint(uint lightIndex, vec3 fragToLight, vec3 fragNorm, /*float currentDepth*/vec3 fragPos)
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
#define LIGHTING_DISTRIBUTION LIGHTING_DISTRIBUTION_BECKMANN
|
||||
|
||||
// // Currently, we only need globals for the far plane.
|
||||
// #include <globals.glsl>
|
||||
// Currently, we only need globals for the far plane.
|
||||
#include <globals.glsl>
|
||||
// // Currently, we only need lights for the light position
|
||||
// #include <light.glsl>
|
||||
|
||||
@ -33,16 +33,17 @@ void main()
|
||||
{
|
||||
// Only need to do anything with point lights, since sun and moon should already have nonlinear
|
||||
// distance.
|
||||
/*if (FragLayer > 0) */{
|
||||
// get distance between fragment and light source
|
||||
// float lightDistance = length(FragPos - lights[((/*FragLayer*/1 - 1) & 31)].light_pos.xyz);
|
||||
///*if (FragLayer > 0) */{
|
||||
// // get distance between fragment and light source
|
||||
// float lightDistance = length(FragPos);
|
||||
// // float lightDistance = length(FragPos - lights[((/*FragLayer*/1 - 1) & 31)].light_pos.xyz);
|
||||
|
||||
// // map to [0;1] range by dividing by far_plane
|
||||
// lightDistance = lightDistance / screen_res.w;//FragPos.w;//screen_res.w;
|
||||
// // // map to [0;1] range by dividing by far_plane
|
||||
// lightDistance = lightDistance / screen_res.w;//FragPos.w;//screen_res.w;
|
||||
|
||||
// // write this as modified depth
|
||||
// // lightDistance = -1000.0 / (lightDistance + 10000.0);
|
||||
// // lightDistance /= screen_res.w;
|
||||
// gl_FragDepth = lightDistance;// / /*FragPos.w;*/screen_res.w;//-1000.0 / (lightDistance + 1000.0);//lightDistance
|
||||
}
|
||||
// // // write this as modified depth
|
||||
// // // lightDistance = -1000.0 / (lightDistance + 10000.0);
|
||||
// // // lightDistance /= screen_res.w;
|
||||
// gl_FragDepth = lightDistance;// / /*FragPos.w;*/screen_res.w;//-1000.0 / (lightDistance + 1000.0);//lightDistance
|
||||
//}
|
||||
}
|
||||
|
@ -30,6 +30,17 @@
|
||||
// // Currently, we only need lights for the light position
|
||||
// #include <light.glsl>
|
||||
|
||||
/* struct Light {
|
||||
vec4 light_pos;
|
||||
vec4 light_col;
|
||||
// mat4 light_proj;
|
||||
};
|
||||
|
||||
layout (std140)
|
||||
uniform u_lights {
|
||||
Light lights[31];
|
||||
}; */
|
||||
|
||||
// Since our output primitive is a triangle strip, we have to render three vertices
|
||||
// each.
|
||||
#define VERTICES_PER_FACE 3
|
||||
@ -236,8 +247,8 @@ void main() {
|
||||
for(int i = 0; i < VERTICES_PER_FACE; ++i) // for each triangle vertex
|
||||
{
|
||||
// NOTE: See above, we don't make FragPos a uniform.
|
||||
vec3 FragPos = gl_in[i].gl_Position.xyz;
|
||||
// FragPos = gl_in[i].gl_Position.xyz;
|
||||
vec3 fragPos = gl_in[i].gl_Position.xyz;
|
||||
// FragPos = fragPos - (lights[((/*FragLayer*/layer - 1u) & 31u)].light_pos.xyz - focus_off.xyz);
|
||||
// FragLayer = layer;
|
||||
// float lightDistance = length(FragPos - lights[((layer - 1) & 31)].light_pos.xyz);
|
||||
// lightDistance /= screen_res.w;
|
||||
@ -250,7 +261,7 @@ void main() {
|
||||
// int face = int(((floatBitsToUint(gl_Position.w) >> 29) & 0x7u) ^ 0x1u);
|
||||
int layer_face = layer_base + face;
|
||||
gl_Layer = face;//layer_face; // built-in variable that specifies to which face we render.
|
||||
gl_Position = shadowMats[layer_face].shadowMatrices * vec4(FragPos, 1.0);
|
||||
gl_Position = shadowMats[layer_face].shadowMatrices * vec4(fragPos, 1.0);
|
||||
// gl_Position.z = -((gl_Position.z + screen_res.z) / (screen_res.w - screen_res.z)) * lightDistance;
|
||||
// gl_Position.z = gl_Position.z / screen_res.w;
|
||||
// gl_Position.z = gl_Position.z / gl_Position.w;
|
||||
|
@ -226,6 +226,7 @@ pub struct DebugInfo {
|
||||
pub ori: Option<comp::Ori>,
|
||||
pub num_chunks: u32,
|
||||
pub num_visible_chunks: u32,
|
||||
pub num_shadow_chunks: u32,
|
||||
pub num_figures: u32,
|
||||
pub num_figures_visible: u32,
|
||||
}
|
||||
@ -594,7 +595,7 @@ impl Hud {
|
||||
&mut self,
|
||||
client: &Client,
|
||||
global_state: &GlobalState,
|
||||
debug_info: DebugInfo,
|
||||
debug_info: &Option<DebugInfo>,
|
||||
dt: Duration,
|
||||
info: HudInfo,
|
||||
) -> Vec<Event> {
|
||||
@ -602,10 +603,6 @@ impl Hud {
|
||||
let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets();
|
||||
// pulse time for pulsating elements
|
||||
self.pulse = self.pulse + dt.as_secs_f32();
|
||||
self.velocity = match debug_info.velocity {
|
||||
Some(velocity) => velocity.0.magnitude(),
|
||||
None => 0.0,
|
||||
};
|
||||
|
||||
let version = format!(
|
||||
"{}-{}",
|
||||
@ -1239,7 +1236,11 @@ impl Hud {
|
||||
}
|
||||
|
||||
// Display debug window.
|
||||
if global_state.settings.gameplay.toggle_debug {
|
||||
if let Some(debug_info) = debug_info {
|
||||
self.velocity = match debug_info.velocity {
|
||||
Some(velocity) => velocity.0.magnitude(),
|
||||
None => 0.0,
|
||||
};
|
||||
// Alpha Version
|
||||
Text::new(&version)
|
||||
.top_left_with_margins_on(ui_widgets.window, 5.0, 5.0)
|
||||
@ -1345,8 +1346,8 @@ impl Hud {
|
||||
|
||||
// Number of chunks
|
||||
Text::new(&format!(
|
||||
"Chunks: {} ({} visible)",
|
||||
debug_info.num_chunks, debug_info.num_visible_chunks,
|
||||
"Chunks: {} ({} visible) & {} (shadow)",
|
||||
debug_info.num_chunks, debug_info.num_visible_chunks, debug_info.num_shadow_chunks,
|
||||
))
|
||||
.color(TEXT_COLOR)
|
||||
.down_from(self.ids.entity_count, 5.0)
|
||||
@ -2213,7 +2214,7 @@ impl Hud {
|
||||
&mut self,
|
||||
client: &Client,
|
||||
global_state: &mut GlobalState,
|
||||
debug_info: DebugInfo,
|
||||
debug_info: &Option<DebugInfo>,
|
||||
camera: &Camera,
|
||||
dt: Duration,
|
||||
info: HudInfo,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
super::{
|
||||
ColLightFmt, ColLightInfo, Pipeline, RenderError, Renderer, ShadowDepthStencilFmt,
|
||||
ColLightFmt, ColLightInfo, Light, Pipeline, RenderError, Renderer, ShadowDepthStencilFmt,
|
||||
TerrainLocals, Texture,
|
||||
},
|
||||
figure, terrain, Globals,
|
||||
@ -30,7 +30,7 @@ gfx_defines! {
|
||||
|
||||
locals: gfx::ConstantBuffer<TerrainLocals> = "u_locals",
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
// lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||
// shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
|
||||
|
||||
// map: gfx::TextureSampler<[f32; 4]> = "t_map",
|
||||
@ -42,7 +42,7 @@ gfx_defines! {
|
||||
light_shadows: gfx::ConstantBuffer<Locals> = "u_light_shadows",
|
||||
|
||||
tgt_depth_stencil: gfx::DepthTarget<ShadowDepthStencilFmt> = gfx::state::Depth {
|
||||
fun: gfx::state::Comparison::Less,
|
||||
fun: gfx::state::Comparison::LessEqual,
|
||||
write: true,
|
||||
},
|
||||
// tgt_depth_stencil: gfx::DepthTarget<ShadowDepthStencilFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))),
|
||||
@ -67,7 +67,7 @@ gfx_defines! {
|
||||
light_shadows: gfx::ConstantBuffer<Locals> = "u_light_shadows",
|
||||
|
||||
tgt_depth_stencil: gfx::DepthTarget<ShadowDepthStencilFmt> = gfx::state::Depth {
|
||||
fun: gfx::state::Comparison::Less,
|
||||
fun: gfx::state::Comparison::LessEqual,
|
||||
write: true,
|
||||
},
|
||||
// tgt_depth_stencil: gfx::DepthTarget<ShadowDepthStencilFmt> = gfx::preset::depth::LESS_WRITE,//,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))),
|
||||
|
@ -1388,8 +1388,8 @@ impl Renderer {
|
||||
globals: &Consts<Globals>,
|
||||
terrain_locals: &Consts<terrain::Locals>,
|
||||
locals: &Consts<shadow::Locals>,
|
||||
/* lights: &Consts<Light>,
|
||||
* shadows: &Consts<Shadow>,
|
||||
lights: &Consts<Light>,
|
||||
/* shadows: &Consts<Shadow>,
|
||||
* map: &Texture<LodColorFmt>,
|
||||
* horizon: &Texture<LodTextureFmt>, */
|
||||
) {
|
||||
@ -1419,7 +1419,7 @@ impl Renderer {
|
||||
vbuf: model.vbuf.clone(),
|
||||
locals: terrain_locals.buf.clone(),
|
||||
globals: globals.buf.clone(),
|
||||
// lights: lights.buf.clone(),
|
||||
lights: lights.buf.clone(),
|
||||
// shadows: shadows.buf.clone(),
|
||||
// noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
|
||||
// map: (map.srv.clone(), map.sampler.clone()),
|
||||
@ -1443,8 +1443,8 @@ impl Renderer {
|
||||
globals: &Consts<Globals>,
|
||||
terrain_locals: &Consts<terrain::Locals>,
|
||||
locals: &Consts<shadow::Locals>,
|
||||
/* lights: &Consts<Light>,
|
||||
* shadows: &Consts<Shadow>,
|
||||
lights: &Consts<Light>,
|
||||
/* shadows: &Consts<Shadow>,
|
||||
* map: &Texture<LodColorFmt>,
|
||||
* horizon: &Texture<LodTextureFmt>, */
|
||||
) {
|
||||
@ -1474,7 +1474,7 @@ impl Renderer {
|
||||
vbuf: model.vbuf.clone(),
|
||||
locals: terrain_locals.buf.clone(),
|
||||
globals: globals.buf.clone(),
|
||||
// lights: lights.buf.clone(),
|
||||
lights: lights.buf.clone(),
|
||||
// shadows: shadows.buf.clone(),
|
||||
// noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
|
||||
// map: (map.srv.clone(), map.sampler.clone()),
|
||||
@ -2089,8 +2089,8 @@ fn create_pipelines(
|
||||
)
|
||||
.unwrap(),
|
||||
&include_ctx,
|
||||
gfx::state::CullFace::Back,
|
||||
None, //Some(gfx::state::Offset(2, 10)),
|
||||
gfx::state::CullFace::Front,
|
||||
Some(gfx::state::Offset(2, /* 10 */ 0)),
|
||||
) {
|
||||
Ok(pipe) => Some(pipe),
|
||||
Err(err) => {
|
||||
@ -2108,9 +2108,10 @@ fn create_pipelines(
|
||||
&directed_shadow_frag,
|
||||
&include_ctx,
|
||||
gfx::state::CullFace::Back,
|
||||
/* None, */
|
||||
/* Some(gfx::state::Offset(4, 10)), */
|
||||
None,
|
||||
/* Some(gfx::state::Offset(4, 10)),
|
||||
* Some(gfx::state::Offset(2, 10)), */
|
||||
// Some(gfx::state::Offset(2, /*10*/1)),
|
||||
) {
|
||||
Ok(pipe) => Some(pipe),
|
||||
Err(err) => {
|
||||
@ -2131,9 +2132,10 @@ fn create_pipelines(
|
||||
&directed_shadow_frag,
|
||||
&include_ctx,
|
||||
gfx::state::CullFace::Back,
|
||||
None,
|
||||
/* Some(gfx::state::Offset(4, 10)),
|
||||
* Some(gfx::state::Offset(2, 10)), */
|
||||
/* None, */
|
||||
/* Some(gfx::state::Offset(4, 10)), */
|
||||
/*Some(gfx::state::Offset(2, 1))*/None,
|
||||
/* Some(gfx::state::Offset(2, 10)), */
|
||||
) {
|
||||
Ok(pipe) => Some(pipe),
|
||||
Err(err) => {
|
||||
|
@ -12,8 +12,8 @@ use crate::{
|
||||
RenderError, Renderer, Shadow, ShadowLocals, ShadowPipeline, Texture,
|
||||
},
|
||||
scene::{
|
||||
camera::{Camera, CameraMode},
|
||||
LodData, SceneData,
|
||||
camera::{Camera, CameraMode, Dependents},
|
||||
math, LodData, SceneData,
|
||||
},
|
||||
};
|
||||
use anim::{
|
||||
@ -221,56 +221,68 @@ impl FigureMgrStates {
|
||||
fn count_visible(&self) -> usize {
|
||||
self.character_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.quadruped_small_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.quadruped_medium_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.quadruped_low_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.bird_medium_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.critter_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.dragon_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self.dragon_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self
|
||||
.fish_medium_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.bird_small_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.fish_small_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.biped_large_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible)
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.golem_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self
|
||||
.object_states
|
||||
.iter()
|
||||
.filter(|(_, c)| c.visible())
|
||||
.count()
|
||||
+ self.golem_states.iter().filter(|(_, c)| c.visible).count()
|
||||
+ self.object_states.iter().filter(|(_, c)| c.visible).count()
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,6 +416,8 @@ impl FigureMgr {
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
scene_data: &SceneData,
|
||||
// Visible chunk data.
|
||||
visible_psr_bounds: math::Aabr<f32>,
|
||||
camera: &Camera,
|
||||
) -> Aabb<f32> {
|
||||
let state = scene_data.state;
|
||||
@ -413,6 +427,81 @@ impl FigureMgr {
|
||||
let view_distance = scene_data.view_distance;
|
||||
let dt = state.get_delta_time();
|
||||
let frustum = camera.frustum();
|
||||
|
||||
// Sun shadows--find the bounding box of the shadow map plane (i.e. the bounds
|
||||
// of the image rendered from the light). If the position projected
|
||||
// with the ray_mat matrix is valid, and shadows are otherwise enabled,
|
||||
// we mark can_shadow.
|
||||
let can_shadow_sun = {
|
||||
let ray_direction = scene_data.get_sun_dir();
|
||||
let is_daylight = ray_direction.z < 0.0/*0.6*/;
|
||||
// Are shadows enabled at all?
|
||||
let can_shadow_sun = renderer.render_mode().shadow.is_map() && is_daylight;
|
||||
let Dependents {
|
||||
proj_mat,
|
||||
view_mat,
|
||||
cam_pos,
|
||||
} = camera.dependents();
|
||||
let cam_pos = math::Vec3::from(cam_pos);
|
||||
let ray_direction = math::Vec3::from(ray_direction);
|
||||
|
||||
// Transform (semi) world space to light space.
|
||||
let ray_mat: math::Mat4<f32> =
|
||||
math::Mat4::look_at_rh(cam_pos, cam_pos + ray_direction, math::Vec3::up());
|
||||
let focus_off = math::Vec3::from(camera.get_focus_pos().map(f32::trunc));
|
||||
/* let visible_bounding_box = Aabb {
|
||||
min: visible_bounding_box.min - focus_off,
|
||||
max: visible_bounding_box.max - focus_off,
|
||||
};
|
||||
let visible_bounds_fine = math::Aabb::<f64> {
|
||||
min: math::Vec3::from(visible_bounding_box.min.map(f64::from)),
|
||||
max: math::Vec3::from(visible_bounding_box.max.map(f64::from)),
|
||||
};
|
||||
let inv_proj_view = math::Mat4::from_col_arrays(
|
||||
(proj_mat * view_mat/* * Mat4::translation_3d(-focus_off)*/).into_col_arrays(),
|
||||
)
|
||||
.map(f64::from)
|
||||
.inverted();
|
||||
let visible_light_volume = math::calc_focused_light_volume_points(
|
||||
inv_proj_view,
|
||||
ray_direction.map(f64::from),
|
||||
visible_bounds_fine,
|
||||
1e-6,
|
||||
)
|
||||
.map(|v| v.map(|e| e as f32));
|
||||
// Now that the work that requires high accuracy is done, switch from focus-relative
|
||||
// to proper world space coordinates.
|
||||
let visible_bounds = math::Aabr::from(math::fit_psr(
|
||||
ray_mat,
|
||||
/* super::aabb_to_points(visible_bounding_box).iter().copied() */
|
||||
visible_light_volume,
|
||||
|p| p, //math::Vec3::from(p), /* / p.w */
|
||||
)); */
|
||||
let ray_mat = ray_mat * math::Mat4::translation_3d(-focus_off);
|
||||
|
||||
let collides_with_aabr = |a: math::Aabr<f32>, b: math::Aabr<f32>| {
|
||||
a.min.partial_cmple(&b.max).reduce_and() && a.max.partial_cmpge(&b.min).reduce_and()
|
||||
};
|
||||
// println!("Aabr: {:?}", visible_bounds);
|
||||
move |pos: Pos, radius: f32| {
|
||||
// Short circuit when there are no shadows to cast.
|
||||
if !can_shadow_sun {
|
||||
return false;
|
||||
}
|
||||
// First project center onto shadow map.
|
||||
let center = (ray_mat * math::Vec4::new(pos.0.x, pos.0.y, pos.0.z, 1.0)).xy();
|
||||
// Then, create an approximate bounding box (± radius).
|
||||
let figure_box = math::Aabr {
|
||||
min: center - radius,
|
||||
max: center + radius,
|
||||
};
|
||||
// println!("center: {:?}, radius: {:?}", center, figure_box);
|
||||
// Quick intersection test for membership in the PSC (potential shader caster)
|
||||
// list.
|
||||
collides_with_aabr(figure_box, visible_psr_bounds)
|
||||
}
|
||||
};
|
||||
|
||||
// Get player position.
|
||||
let player_pos = ecs
|
||||
.read_storage::<Pos>()
|
||||
@ -467,6 +556,7 @@ impl FigureMgr {
|
||||
// TODO: Investigate passing the velocity into the shader so we can at least
|
||||
// interpolate motion
|
||||
const MIN_PERFECT_RATE_DIST: f32 = 50.0;
|
||||
|
||||
if (i as u64 + tick)
|
||||
% (1 + ((pos.0.distance_squared(camera.get_focus_pos()).powf(0.25)
|
||||
- MIN_PERFECT_RATE_DIST.powf(0.5))
|
||||
@ -477,6 +567,13 @@ impl FigureMgr {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether we could have been shadowing last frame.
|
||||
let mut state = self.states.get_mut(body, &entity);
|
||||
let can_shadow_prev = state
|
||||
.as_mut()
|
||||
.map(|state| state.can_shadow_sun())
|
||||
.unwrap_or(false);
|
||||
|
||||
// Don't process figures outside the vd
|
||||
let vd_frac = Vec2::from(pos.0 - player_pos)
|
||||
.map2(TerrainChunk::RECT_SIZE, |d: f32, sz| {
|
||||
@ -484,15 +581,17 @@ impl FigureMgr {
|
||||
})
|
||||
.magnitude()
|
||||
/ view_distance as f32;
|
||||
|
||||
// Keep from re-adding/removing entities on the border of the vd
|
||||
if vd_frac > 1.2 {
|
||||
self.states.remove(body, &entity);
|
||||
continue;
|
||||
} else if vd_frac > 1.0 {
|
||||
self.states
|
||||
.get_mut(body, &entity)
|
||||
.map(|state| state.visible = false);
|
||||
continue;
|
||||
state.as_mut().map(|state| state.visible = false);
|
||||
// Keep processing if this might be a shadow caster.
|
||||
if !can_shadow_prev {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't display figures outside the frustum spectrum (this is important to do
|
||||
@ -502,22 +601,25 @@ impl FigureMgr {
|
||||
// shadow correctly until their next update. For now, we treat this
|
||||
// as an acceptable tradeoff.
|
||||
let radius = scale.unwrap_or(&Scale(1.0)).0 * 2.0;
|
||||
let (in_frustum, lpindex) = if let Some(mut meta) = self.states.get_mut(body, &entity) {
|
||||
let (in_frustum, lpindex) = if let Some(mut meta) = state {
|
||||
let (in_frustum, lpindex) = BoundingSphere::new(pos.0.into_array(), radius)
|
||||
.coherent_test_against_frustum(frustum, meta.lpindex);
|
||||
meta.visible = in_frustum;
|
||||
meta.lpindex = lpindex;
|
||||
if in_frustum {
|
||||
// Update visible bounds.
|
||||
visible_aabb.expand_to_contain(Aabb {
|
||||
min: pos.0 - radius,
|
||||
max: pos.0 + radius,
|
||||
});
|
||||
} else {
|
||||
// Check whether we can shadow.
|
||||
meta.can_shadow_sun = can_shadow_sun(pos, radius);
|
||||
}
|
||||
(in_frustum, lpindex)
|
||||
} else {
|
||||
(true, 0)
|
||||
};
|
||||
if in_frustum {
|
||||
// Update visible bounds.
|
||||
visible_aabb.expand_to_contain(Aabb {
|
||||
min: pos.0 - radius,
|
||||
max: pos.0 + radius,
|
||||
});
|
||||
}
|
||||
|
||||
// Change in health as color!
|
||||
let col = stats
|
||||
@ -1839,7 +1941,7 @@ impl FigureMgr {
|
||||
false,
|
||||
pos.0,
|
||||
figure_lod_render_distance,
|
||||
|state| state.visible,
|
||||
|state| state.can_shadow_sun(),
|
||||
) {
|
||||
renderer.render_figure_shadow_directed(
|
||||
model,
|
||||
@ -1900,7 +2002,7 @@ impl FigureMgr {
|
||||
false,
|
||||
pos.0,
|
||||
figure_lod_render_distance,
|
||||
|state| state.visible,
|
||||
|state| state.visible(),
|
||||
) {
|
||||
renderer.render_figure(
|
||||
model,
|
||||
@ -1964,7 +2066,7 @@ impl FigureMgr {
|
||||
true,
|
||||
pos.0,
|
||||
figure_lod_render_distance,
|
||||
|state| state.visible,
|
||||
|state| state.visible(),
|
||||
) {
|
||||
renderer.render_player(
|
||||
model,
|
||||
@ -2160,40 +2262,46 @@ impl FigureMgr {
|
||||
.0,
|
||||
)
|
||||
}),
|
||||
Body::BirdMedium(_) => bird_medium_states.get(&entity).map(move |state| {
|
||||
(
|
||||
state.locals(),
|
||||
state.bone_consts(),
|
||||
&bird_medium_model_cache
|
||||
.get_or_create_model(
|
||||
renderer,
|
||||
col_lights,
|
||||
*body,
|
||||
loadout,
|
||||
tick,
|
||||
player_camera_mode,
|
||||
character_state,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}),
|
||||
Body::FishMedium(_) => fish_medium_states.get(&entity).map(move |state| {
|
||||
(
|
||||
state.locals(),
|
||||
state.bone_consts(),
|
||||
&fish_medium_model_cache
|
||||
.get_or_create_model(
|
||||
renderer,
|
||||
col_lights,
|
||||
*body,
|
||||
loadout,
|
||||
tick,
|
||||
player_camera_mode,
|
||||
character_state,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}),
|
||||
Body::BirdMedium(_) => bird_medium_states
|
||||
.get(&entity)
|
||||
.filter(|state| filter_state(&*state))
|
||||
.map(move |state| {
|
||||
(
|
||||
state.locals(),
|
||||
state.bone_consts(),
|
||||
&bird_medium_model_cache
|
||||
.get_or_create_model(
|
||||
renderer,
|
||||
col_lights,
|
||||
*body,
|
||||
loadout,
|
||||
tick,
|
||||
player_camera_mode,
|
||||
character_state,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}),
|
||||
Body::FishMedium(_) => fish_medium_states
|
||||
.get(&entity)
|
||||
.filter(|state| filter_state(&*state))
|
||||
.map(move |state| {
|
||||
(
|
||||
state.locals(),
|
||||
state.bone_consts(),
|
||||
&fish_medium_model_cache
|
||||
.get_or_create_model(
|
||||
renderer,
|
||||
col_lights,
|
||||
*body,
|
||||
loadout,
|
||||
tick,
|
||||
player_camera_mode,
|
||||
character_state,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}),
|
||||
Body::Critter(_) => critter_states
|
||||
.get(&entity)
|
||||
.filter(|state| filter_state(&*state))
|
||||
@ -2490,11 +2598,21 @@ pub struct FigureStateMeta {
|
||||
state_time: f64,
|
||||
last_ori: Vec3<f32>,
|
||||
lpindex: u8,
|
||||
can_shadow_sun: bool,
|
||||
visible: bool,
|
||||
last_pos: Option<Vec3<f32>>,
|
||||
avg_vel: Vec3<f32>,
|
||||
}
|
||||
|
||||
impl FigureStateMeta {
|
||||
pub fn visible(&self) -> bool { self.visible }
|
||||
|
||||
pub fn can_shadow_sun(&self) -> bool {
|
||||
// Either visible, or explicitly a shadow caster.
|
||||
self.visible || self.can_shadow_sun
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FigureState<S> {
|
||||
meta: FigureStateMeta,
|
||||
skeleton: S,
|
||||
@ -2525,6 +2643,7 @@ impl<S: Skeleton> FigureState<S> {
|
||||
last_ori: Vec3::zero(),
|
||||
lpindex: 0,
|
||||
visible: false,
|
||||
can_shadow_sun: false,
|
||||
last_pos: None,
|
||||
avg_vel: Vec3::zero(),
|
||||
},
|
||||
|
@ -41,8 +41,8 @@ const NUM_DIRECTED_LIGHTS: usize = 1;
|
||||
const LIGHT_DIST_RADIUS: f32 = 64.0; // The distance beyond which lights may not emit light from their origin
|
||||
const SHADOW_DIST_RADIUS: f32 = 8.0;
|
||||
const SHADOW_MAX_DIST: f32 = 96.0; // The distance beyond which shadows may not be visible
|
||||
/* /// The minimum sin γ we will use before switching to uniform mapping.
|
||||
const EPSILON_GAMMA: f64 = 0.25; */
|
||||
/// The minimum sin γ we will use before switching to uniform mapping.
|
||||
const EPSILON_UPSILON: f64 = -1.0;
|
||||
|
||||
// const NEAR_PLANE: f32 = 0.5;
|
||||
// const FAR_PLANE: f32 = 100000.0;
|
||||
@ -178,15 +178,37 @@ fn compute_scalar_fov<F: Float>(_near_plane: F, fov: F, aspect: F) -> F {
|
||||
/// -1 + (η_b + 1)(1 + cos(90 (γ - γ_a)/(γ_b - γ_a))) γ_a ≤ γ < γ_b
|
||||
/// η_b + (η_c - η_b) sin(90 (γ - γ_b)/(γ_c - γ_b)) γ_b ≤ γ < γ_c
|
||||
/// η_c γ_c ≤ γ
|
||||
///
|
||||
/// NOTE: Equation's described behavior is *wrong!* I have pieced together a
|
||||
/// slightly different function that seems to more closely satisfy the author's
|
||||
/// intent:
|
||||
///
|
||||
/// η =
|
||||
/// -1 γ < γ_a
|
||||
/// -1 + (η_b + 1) (γ - γ_a)/(γ_b - γ_a) γ_a ≤ γ < γ_b
|
||||
/// η_b + (η_c - η_b) sin(90 (γ - γ_b)/(γ_c - γ_b)) γ_b ≤ γ < γ_c
|
||||
/// η_c γ_c ≤ γ
|
||||
///
|
||||
/// There are other alternatives that may have more desirable properties, such
|
||||
/// as:
|
||||
///
|
||||
/// η =
|
||||
/// -1 γ < γ_a
|
||||
/// -1 + (η_b + 1)(1 - cos(90 (γ - γ_a)/(γ_b - γ_a))) γ_a ≤ γ < γ_b
|
||||
/// η_b + (η_c - η_b) sin(90 (γ - γ_b)/(γ_c - γ_b)) γ_b ≤ γ < γ_c
|
||||
/// η_c γ_c ≤ γ
|
||||
fn compute_warping_parameter<F: Float + FloatConst>(
|
||||
gamma: F,
|
||||
(gamma_a, gamma_b, gamma_c): (F, F, F),
|
||||
(eta_b, eta_c): (F, F),
|
||||
) -> F {
|
||||
if gamma < gamma_a {
|
||||
F::zero()
|
||||
-F::one()
|
||||
/* F::zero() */
|
||||
} else if gamma_a <= gamma && gamma < gamma_b {
|
||||
-F::one() + (eta_b + F::one()) * (F::one() + (F::FRAC_PI_2() * (gamma - gamma_a) / (gamma_b - gamma_a)).cos())
|
||||
/* -F::one() + (eta_b + F::one()) * (F::one() + (F::FRAC_PI_2() * (gamma - gamma_a) / (gamma_b - gamma_a)).cos()) */
|
||||
-F::one() + (eta_b + F::one()) * (F::one() - (F::FRAC_PI_2() * (gamma - gamma_a) / (gamma_b - gamma_a)).cos())
|
||||
// -F::one() + (eta_b + F::one()) * ((gamma - gamma_a) / (gamma_b - gamma_a))
|
||||
} else if gamma_b <= gamma && gamma < gamma_c {
|
||||
eta_b + (eta_c - eta_b) * (F::FRAC_PI_2() * (gamma - gamma_b) / (gamma_c - gamma_b)).sin()
|
||||
} else {
|
||||
@ -227,7 +249,7 @@ fn compute_warping_parameter_perspective<F: Float + FloatConst>(
|
||||
theta,
|
||||
theta + (three / ten) * (F::FRAC_PI_2() - theta),
|
||||
),
|
||||
(-two / ten, F::zero()),
|
||||
(-two/*F::one()*/ / ten, F::zero()),
|
||||
)
|
||||
}
|
||||
|
||||
@ -546,7 +568,11 @@ impl Scene {
|
||||
self.lod.maintain(renderer, time_of_day);
|
||||
|
||||
// Maintain the terrain.
|
||||
let (_scene_bounds, visible_bounds, _psc_bounds) = self.terrain.maintain(
|
||||
let (
|
||||
/* _scene_bounds, visible_bounds, _psc_bounds */ visible_bounds,
|
||||
visible_light_volume,
|
||||
visible_psr_bounds,
|
||||
) = self.terrain.maintain(
|
||||
renderer,
|
||||
&scene_data,
|
||||
focus_pos,
|
||||
@ -556,7 +582,9 @@ impl Scene {
|
||||
);
|
||||
|
||||
// Maintain the figures.
|
||||
let _figure_bounds = self.figure_mgr.maintain(renderer, scene_data, &self.camera);
|
||||
let _figure_bounds =
|
||||
self.figure_mgr
|
||||
.maintain(renderer, scene_data, visible_psr_bounds, &self.camera);
|
||||
|
||||
let sun_dir = scene_data.get_sun_dir();
|
||||
let is_daylight = sun_dir.z < 0.0/*0.6*/;
|
||||
@ -570,7 +598,7 @@ impl Scene {
|
||||
}; */
|
||||
|
||||
// let focus_frac = focus_pos.map(|e| e.fract());
|
||||
let visible_bounds = math::Aabb::<f32> {
|
||||
/* let visible_bounds = math::Aabb::<f32> {
|
||||
min: math::Vec3::from(visible_bounds.min - focus_off),
|
||||
max: math::Vec3::from(visible_bounds.max - focus_off),
|
||||
};
|
||||
@ -598,7 +626,7 @@ impl Scene {
|
||||
(proj_mat * view_mat/* * Mat4::translation_3d(-focus_off)*/).into_col_arrays(),
|
||||
)
|
||||
.map(f64::from)
|
||||
.inverted();
|
||||
.inverted(); */
|
||||
|
||||
let fov = self.camera.get_fov();
|
||||
let aspect_ratio = self.camera.get_aspect_ratio();
|
||||
@ -620,11 +648,11 @@ impl Scene {
|
||||
.collect::<Vec<_>>();
|
||||
// println!("light_volume: {:?}", light_volume); */
|
||||
// let visible_light_volume = light_volume.clone();
|
||||
let visible_light_volume = math::calc_focused_light_volume_points(inv_proj_view, directed_light_dir.map(f64::from), visible_bounds_fine, 1e-6)
|
||||
// .map(|e| e - focus_off)
|
||||
// NOTE: Hopefully not out of bounds.
|
||||
.map(|v| v.map(|e| e as f32))
|
||||
.collect::<Vec<_>>();
|
||||
/* let visible_light_volume = math::calc_focused_light_volume_points(inv_proj_view, directed_light_dir.map(f64::from), visible_bounds_fine, 1e-6)
|
||||
// .map(|e| e - focus_off)
|
||||
// NOTE: Hopefully not out of bounds.
|
||||
.map(|v| v.map(|e| e as f32))
|
||||
.collect::<Vec<_>>(); */
|
||||
// println!("visible_light_volume: {:?}", visible_light_volume);
|
||||
// let bounds0 = fit_psr(Mat4::identity()/* * inverse_visible*/,
|
||||
// light_volume.iter().copied(), |p| Vec3::from(p) / p.w);
|
||||
@ -695,19 +723,20 @@ impl Scene {
|
||||
// let look_at = bounds0.center();//Vec3::zero();//
|
||||
// scene_bounds.center();//Vec3::zero(); let look_at =
|
||||
// bounds0.center();
|
||||
let look_at = math::Vec3::from(cam_pos); // /*Vec3::zero()*/scene_bounds.center()/*cam_pos*/;// - focus_off;// focus_off;
|
||||
let look_at = /*Vec3::zero()*/math::Vec3::from(cam_pos); // /*Vec3::zero()*/scene_bounds.center()/*cam_pos*/;// - focus_off;// focus_off;
|
||||
let _light_scale = 1.5 * /*(directed_near + directed_far) / 2.0*/radius;
|
||||
// We upload view matrices as well, to assist in linearizing vertex positions.
|
||||
// (only for directional lights, so far).
|
||||
let mut directed_shadow_mats = Vec::with_capacity(6);
|
||||
let new_dir = math::Vec3::from(view_dir);
|
||||
// let new_dir: Vec3<f32> = light_volume/*visible_light_volume*/.iter().map(|p|
|
||||
// p - cam_pos).sum();
|
||||
// let new_dir: math::Vec3::<_> =
|
||||
// /*light_volume*/visible_light_volume.iter().copied().map(math::Vec3::from).
|
||||
// map(|p| p - look_at).sum();
|
||||
let new_dir = new_dir.normalized();
|
||||
/* let dot_prod = f64::from(directed_light_dir.dot(new_dir));
|
||||
let sin_gamma = (1.0 - dot_prod * dot_prod).sqrt();
|
||||
/* let cos_gamma = f64::from(directed_light_dir.dot(new_dir));
|
||||
let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt();
|
||||
// let sin_gamma = 0.0;
|
||||
let new_dir = if /*sin_gamma > EPISLON_GAMMA*/factor != -1.0 {
|
||||
let new_dir = if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON {
|
||||
new_dir
|
||||
} else {
|
||||
// For uniform mapping, align shadow map t axis with viewer's y axis to maximize
|
||||
@ -746,9 +775,12 @@ impl Scene {
|
||||
.scaled_3d(Vec3::new(proj_mat[(0, 0)], proj_mat[(1, 1)], 1.0));
|
||||
let focus_off = focus_pos.map(|e| e.trunc()); */
|
||||
let z_n = 1.0; //f64::from(camera::NEAR_PLANE);
|
||||
let _z_f = f64::from(camera::FAR_PLANE);
|
||||
let _scalar_fov = f64::from(fov / 2.0); // compute_scalar_fov(z_n, f64::from(fov), f64::from(aspect_ratio));
|
||||
shadow_mats.extend(directed_shadow_mats.iter().map(move |&light_view_mat| {
|
||||
let z_f = f64::from(camera::FAR_PLANE);
|
||||
let scalar_fov = /*f64::from(fov / 2.0)*/compute_scalar_fov(z_n, f64::from(fov), f64::from(aspect_ratio));
|
||||
shadow_mats.extend(directed_shadow_mats.iter().enumerate().map(move |(idx, &light_view_mat)| {
|
||||
if idx >= NUM_DIRECTED_LIGHTS {
|
||||
return ShadowLocals::new(Mat4::identity(), Mat4::identity());
|
||||
}
|
||||
/* let visible_light_volume = {
|
||||
let light_view_mat = light_view_mat.map(f64::from);
|
||||
// (See http://www.songho.ca/opengl/gl_normaltransform.html)
|
||||
@ -873,13 +905,22 @@ impl Scene {
|
||||
//
|
||||
let mut e_p: Vec3<f32> = Vec3::zero();
|
||||
v_p.z = 0.0; */
|
||||
let mut v_p = math::Vec3::from(light_view_mat * math::Vec4::from_direction(new_dir));
|
||||
v_p.normalize();
|
||||
// let dot_prod = f64::from(v_p.z);
|
||||
let dot_prod = new_dir.map(f64::from).dot(directed_light_dir.map(f64::from));
|
||||
let sin_gamma = (1.0 - dot_prod * dot_prod).sqrt();
|
||||
let gamma = sin_gamma.asin();
|
||||
let factor = compute_warping_parameter_perspective(gamma, f64::from(camera::NEAR_PLANE), f64::from(fov), f64::from(aspect_ratio));
|
||||
let v_p_orig = math::Vec3::from(light_view_mat * math::Vec4::from_direction(new_dir));
|
||||
let mut v_p = v_p_orig.normalized();
|
||||
// let cos_gamma = f64::from(v_p.z);
|
||||
let cos_gamma = new_dir.map(f64::from).dot(directed_light_dir.map(f64::from));
|
||||
let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt();
|
||||
let gamma = sin_gamma.asin()/*cos_gamma.acos()*/;
|
||||
let bounds1 = math::fit_psr(view_mat, visible_light_volume.iter().copied(), math::Vec4::homogenized);
|
||||
let n_e = f64::from(-bounds1.max.z);
|
||||
// let f_e = f64::from(-bounds1.min.z);
|
||||
// let fov = 2.0 * aspect_ratio * (fov / 2.0).tan();
|
||||
let factor = compute_warping_parameter_perspective(gamma, /*f64::from(camera::NEAR_PLANE)*/n_e, f64::from(/*fov*//*50.0.to_radians()*/fov/* / 2.0*/), f64::from(aspect_ratio));
|
||||
/* if v_p.z > 0.5 {
|
||||
-1.0
|
||||
} else {
|
||||
0.0
|
||||
}; */
|
||||
/* let factor = if factor > 0.0 {
|
||||
-1.0
|
||||
} else {
|
||||
@ -888,7 +929,7 @@ impl Scene {
|
||||
|
||||
v_p.z = 0.0;
|
||||
v_p.normalize();
|
||||
let l_r: math::Mat4<f32> = if /*v_p.magnitude_squared() > 1e-3*//*sin_gamma > EPISLON_GAMMA*/factor != -1.0 {
|
||||
let l_r: math::Mat4<f32> = if /*v_p.magnitude_squared() > 1e-3*//*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON {
|
||||
math::Mat4::look_at_rh(math::Vec3::zero(), math::Vec3::forward_rh(), v_p)
|
||||
} else {
|
||||
math::Mat4::identity()
|
||||
@ -902,8 +943,8 @@ impl Scene {
|
||||
// let l_r: Mat4<f32> = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*/Vec3::zero(), /*Vec3::from(e_p)*/-Vec3::forward_rh(), /*Vec3::up()*/-Vec3::from(v_p));
|
||||
// let l_r: Mat4<f32> = Mat4::look_at_rh(/*Vec3::from(e_p) - Vec3::from(v_p)*/Vec3::back_rh(), /*Vec3::from(e_p)*/Vec3::zero(), /*Vec3::up()*/Vec3::from(v_p));
|
||||
// let l_r: Mat4<f32> = Mat4::identity();
|
||||
let bounds0 = math::fit_psr(light_view_mat, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized);
|
||||
let directed_proj_mat = math::Mat4::orthographic_rh_no(FrustumPlanes {
|
||||
/* let bounds0 = math::fit_psr(light_view_mat, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized); */
|
||||
let directed_proj_mat = /*math::Mat4::orthographic_rh_no(FrustumPlanes {
|
||||
// TODO: Consider adjusting resolution based on view distance.
|
||||
left: bounds0.min.x,
|
||||
right: bounds0.max.x,
|
||||
@ -911,25 +952,76 @@ impl Scene {
|
||||
top: bounds0.max.y,
|
||||
near: bounds0.min.z,
|
||||
far: bounds0.max.z,
|
||||
})/* /Mat4::identity() */;
|
||||
})*//* /Mat4::identity() */math::Mat4::new(
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, -1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
);
|
||||
|
||||
let light_all_mat = l_r * directed_proj_mat * light_view_mat;
|
||||
// let bounds1 = fit_psr(light_all_mat/* * inverse_visible*/, light_volume.iter().copied(), |p| Vec3::from(p) / p.w);
|
||||
let bounds0 = math::fit_psr(/*l_r*/light_all_mat/* * inverse_visible*/, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized);
|
||||
// Vague idea: project z_n from the camera view to the light view (where it's
|
||||
// tilted by γ).
|
||||
let (z_0, z_1) = {
|
||||
let p_z = bounds1.max.z;
|
||||
let p_y = bounds0.min.y;
|
||||
let p_x = bounds0.center().x;
|
||||
// println!("p_x (light near plane, s-axis) = {:?}, p_y (light xy plane, t-axis) = {:?}, p_z (near plane, z-axis) = {:?}", p_x, p_y, p_z);
|
||||
let view_inv = view_mat.inverted();
|
||||
let light_all_inv = light_all_mat.inverted();
|
||||
|
||||
let view_point = view_inv * math::Vec4::new(0.0, 0.0, p_z, 1.0);
|
||||
let view_plane = view_inv * math::Vec4::from_direction(math::Vec3::unit_z());
|
||||
|
||||
let light_point = light_all_inv * math::Vec4::new(0.0, p_y, 0.0, 1.0);
|
||||
let light_plane = light_all_inv * math::Vec4::from_direction(math::Vec3::unit_y());
|
||||
|
||||
let shadow_point = light_all_inv * math::Vec4::new(p_x, 0.0, 0.0, 1.0);
|
||||
let shadow_plane = light_all_inv * math::Vec4::from_direction(math::Vec3::unit_x());
|
||||
|
||||
let solve_p0 = math::Mat4::new(
|
||||
view_plane.x, view_plane.y, view_plane.z, -view_plane.dot(view_point),
|
||||
light_plane.x, light_plane.y, light_plane.z, -light_plane.dot(light_point),
|
||||
shadow_plane.x, shadow_plane.y, shadow_plane.z, -shadow_plane.dot(shadow_point),
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
);
|
||||
|
||||
let w_p_arr = solve_p0.cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::<Vec<_>>();
|
||||
// println!("mat4 solve_p0 = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]);
|
||||
|
||||
let p0_world = solve_p0.inverted() * math::Vec4::unit_w();
|
||||
let p0 = light_all_mat * p0_world;
|
||||
let mut p1 = p0;
|
||||
p1.y = bounds0.max.y;
|
||||
// println!("p0 = {:?}, p1 = {:?}", p0, p1);
|
||||
|
||||
let view_from_light_mat = view_mat * light_all_inv;
|
||||
let z0 = view_from_light_mat * p0;
|
||||
let z1 = view_from_light_mat * p1;
|
||||
// println!("z0 = {:?}, z1 = {:?}", z0, z1);
|
||||
|
||||
(f64::from(z0.z), f64::from(z1.z))
|
||||
};
|
||||
|
||||
// let bounds1 = fit_psr(light_all_mat/* * inverse_visible*/, aabb_to_points(visible_bounds).iter().copied(), |p| Vec3::from(p) / p.w);
|
||||
// let mut light_focus_pos: Vec3<f32> = Vec3::from(light_all_mat * Vec4::from_point(focus_pos.map(f32::fract)));
|
||||
let mut light_focus_pos: math::Vec3<f32> = math::Vec3::zero();//bounds0.center();// l_r * directed_proj_mat * light_view_mat * Vec4::from_point(focus_pos.map(|e| e.fract()));
|
||||
let mut light_focus_pos: math::Vec3<f32> = math::Vec3::zero()/*bounds0.center()*/;// l_r * directed_proj_mat * light_view_mat * Vec4::from_point(focus_pos.map(|e| e.fract()));
|
||||
light_focus_pos.x = bounds0.center().x;
|
||||
light_focus_pos.y = bounds0.min.y/*z_0 as f32*/;
|
||||
light_focus_pos.z = bounds0.center().z;
|
||||
// let mut light_focus_pos: Vec3<f32> = bounds0.center();// l_r * directed_proj_mat * light_view_mat * Vec4::from_point(focus_pos.map(|e| e.fract()));
|
||||
// println!("cam_pos: {:?}, focus_pos: {:?}, light_focus_pos: {:?}, v_p: {:?} bounds: {:?}, l_r: {:?}, light_view_mat: {:?}, light_all_mat: {:?}", cam_pos, focus_pos - focus_off, light_focus_pos, v_p, /*bounds1*/bounds0, l_r, light_view_mat, light_all_mat);
|
||||
// let w_v = Mat4::translation_3d(-Vec3::new(xmax + xmin, ymax + ymin, /*zmax + zmin*/0.0) / 2.0);
|
||||
|
||||
// let dot_prod = /*new_dir*//*up_dir*/view_dir.map(f64::from).dot(directed_light_dir.map(f64::from));
|
||||
// let sin_gamma = (1.0 - dot_prod * dot_prod).sqrt();//.clamped(1e-1, 1.0);
|
||||
// let cos_gamma = /*new_dir*//*up_dir*/view_dir.map(f64::from).dot(directed_light_dir.map(f64::from));
|
||||
// let sin_gamma = (1.0 - cos_gamma * cos_gamma).sqrt();//.clamped(1e-1, 1.0);
|
||||
// let sin_gamma = 0.0;
|
||||
// let factor = -1.0;//1.0 / sin_gamma;
|
||||
// println!("Warp factor for γ (sin γ = {:?}, γ = {:?}, near_plane = {:?}, fov = {:?}, scalar fov = {:?}, aspect ratio = {:?}): η = {:?}", sin_gamma, gamma.to_degrees(), camera::NEAR_PLANE, fov.to_degrees(), scalar_fov.to_degrees(), aspect_ratio, factor);
|
||||
/* v ---l
|
||||
\ Θ|
|
||||
\ Θ|
|
||||
\| */
|
||||
|
||||
// let directed_near = /*0.5*//*0.25*/f64::from(camera::NEAR_PLANE);/*1.0*/;//bounds0.min.y.max(1.0);
|
||||
@ -938,13 +1030,53 @@ impl Scene {
|
||||
// let z_f = z_n + d * camera::FAR_PLANE/* / scalar_fov.cos()*/;
|
||||
// let z_0 = f64::from(bounds0.min.y);
|
||||
|
||||
// Vague idea: project z_n from the camera view to the light view (where it's
|
||||
// tilted by γ).
|
||||
let z_0 = z_n;// / sin_gamma;// / sin_gamma;
|
||||
/* let v_p_orig: math::Vec3::<f32> = math::Vec3::from(light_all_mat * math::Vec4::from_direction(new_dir));
|
||||
let n_e: f64 = /*bounds0.y.min() * scalar_fov.cos() *//*bounds0.min.y / scalar_fov.cos();*/f64::from(camera::NEAR_PLANE) * f64::from(v_p_orig.y);
|
||||
let f_e = /*bounds0.size().y / scalar_fov.cos();*//*f64::from(camera::FAR_PLANE);*//*f64::from(camera::FAR_PLANE) * v_p_orig*/
|
||||
d
|
||||
/*d * scalar_fov.cos()*/;
|
||||
|
||||
// See Lloyd's thesis, section 5.2 (p. 104-105).
|
||||
let w_e = 2.0 * n_e * scalar_fov.tan();
|
||||
|
||||
let w_n = w_e;
|
||||
// let w_f = w_n * f_e / n_e;
|
||||
let w_s = (f_e - n_e) / scalar_fov.cos();
|
||||
|
||||
let w_n_ = w_n * gamma.cos();
|
||||
let w_s_1_ = w_s * (1.0 - (scalar_fov - gamma).cos());
|
||||
let w_s_2_ = w_s * (scalar_fov - gamma).sin();
|
||||
|
||||
/* let w_l_y = w_n_ + w_s_2_ + if gamma < scalar_fov {
|
||||
w_s_1_
|
||||
} else {
|
||||
0.0
|
||||
}; */
|
||||
let v_s_1 = if gamma < scalar_fov {
|
||||
w_s_1_ / w_l_y
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let v_s_2 = v_s_1 + w_n_ / w_l_y;
|
||||
let d_e = |v: f64| n_e + (f_e - n_e) *
|
||||
(w_l_y * (v_s_1 - v) / w_s_1_)
|
||||
.max(0.0)
|
||||
.max(w_l_y * (1.0 - v) / w_s_2_); */
|
||||
|
||||
/* let w_l_x = (n_ + w_l_y) * if gamma < scalar_fov {
|
||||
w_f / n_
|
||||
} else {
|
||||
w_f / (n_ + w_s_1_)
|
||||
}; */
|
||||
|
||||
/* let z_0 = /*z_n*//*z_n*/n_e/* / sin_gamma*/;// / sin_gamma;// / sin_gamma;
|
||||
// let z_1 = z_0 + d;
|
||||
// Vague idea: project d from the light view back to the camera view (undoing the
|
||||
// tilt by γ).
|
||||
let z_1 = /*z_n*/z_0 + d * sin_gamma;
|
||||
let z_1 = /*z_n*/z_0/*n_e*/ + d * /*sin_gamma*/f64::from(v_p_orig.y)/* * sin_gamma*/;
|
||||
// 1/φ' (zn + √(zn(zn + (f - n)φ')))
|
||||
// (f-n)/φ' (zn + √(zn(zn + (f - n)φ')))
|
||||
// zn/φ' (1 + zn√(1 + (f - n)φ' / zn)) */
|
||||
let w_l_y = /* z_f - z_n */d;/*/*f64::from(camera::FAR_PLANE - camera::NEAR_PLANE)*//*(z_f - z_n)*/d * scalar_fov.cos();*/
|
||||
// let z_f = z_n + d;
|
||||
// let near_dist = directed_near;
|
||||
@ -962,6 +1094,10 @@ impl Scene {
|
||||
// Standard shadow map to LiSPSM
|
||||
(1.0 + alpha_sqrt - factor * (alpha - 1.0)) / ((alpha - 1.0) * (factor + 1.0))
|
||||
// 1+sqrt(z_f/z_n)/((z_f/z_n - 1)*2)
|
||||
//
|
||||
// η = 0:
|
||||
// (1 + √(z₁/z₀)) / (z₁ / z₀ - 1)
|
||||
// (z₀ + √(z₀z₁)) / (z₁ - z₀)
|
||||
} else {
|
||||
// LiSPSM to PSM
|
||||
((alpha_sqrt - 1.0) * (factor * alpha_sqrt + 1.0)).recip()
|
||||
@ -969,18 +1105,40 @@ impl Scene {
|
||||
// = 1 / ((√α - 1)(1))
|
||||
// = 1 / (√α - 1)
|
||||
// = (1 + √α) / (α - 1)
|
||||
// = (a + √(z_f/z_n)) / (z_f/z_n - 1)
|
||||
// = (1 + √(z₁/z₀)) / (z₁ / z₀ - 1)
|
||||
};
|
||||
// let factor = -1.0;
|
||||
// (f - n) * (1 + √(z₁/z₀) - sin γ * (z₁/z₀ - 1)) / ((z₁/z₀ - 1) * (sin γ + 1))
|
||||
//
|
||||
// (f - n) * (1 + √(z_f/z_n) - (-1 / sin γ) * (z_f/z_n - 1)) / ((z_f/z_n - 1) * ((-1 / sin γ) + 1))
|
||||
// (f - n) * (1 + √(z_f/z_n) + 1 / sin γ * (z_f/z_n - 1)) / ((z_f/z_n - 1) * (1 - 1 / sin γ))
|
||||
// (f - n) * (1 + √(z_f/z_n) + 1 / sin γ * (z_f/z_n - 1)) / ((1 / sin γ)((z_f/z_n - 1) * (sin γ - 1)))
|
||||
// (f - n)sin γ * (1 + √(z_f/z_n) + 1 / sin γ * (z_f/z_n - 1)) / ((z_f/z_n - 1) * (sin γ - 1))
|
||||
// (f - n)sin γ / sin γ * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((z_f/z_n - 1) * (sin γ - 1))
|
||||
// (f - n) * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((z_f/z_n - 1) * (sin γ - 1))
|
||||
// (f - n) * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((1 / z_n)(z_f - z_n) * (sin γ - 1))
|
||||
// (f - n)z_n * (sin γ + √(z_f/z_n)sin γ + (z_f/z_n - 1)) / ((z_f - z_n) * (sin γ - 1))
|
||||
// (f - n)z_n / z_n * (z_n sin γ + √(z_f z_n)sin γ + (z_f - z_n)) / ((z_f - z_n) * (sin γ - 1))
|
||||
// (f - n) (z_n sin γ + √(z_f z_n)sin γ + (z_f - z_n)) / ((z_f - z_n) * (sin γ - 1))
|
||||
//
|
||||
// (f - n) * (1 + √(f_e/n_e) - F * (f_e/n_e - 1)) / ((f_e/n_e - 1) * (F + 1))
|
||||
// (f - n) * n_e / n_e (n_e + √(n_e * f_e) - F * (f_e - n_e)) / ((f_e - n_e) * (F + 1))
|
||||
// (f - n) (n_e + √(n_e * f_e) - F * (f_e - n_e)) / ((f_e - n_e) * (F + 1))
|
||||
//
|
||||
// (f - n) (n_e + √(n_e * f_e) - (sin γ - 1) * (f_e - n_e)) / ((f_e - n_e) * ((sin γ - 1) + 1))
|
||||
// (f - n) (n_e + √(n_e * f_e) - (f_e - n_e) sin γ + f_e - n_e) / ((f_e - n_e) * sin γ)
|
||||
// (f - n) (√(n_e * f_e) - (f_e - n_e) sin γ + f_e) / ((f_e - n_e) * sin γ)
|
||||
|
||||
// Equation 5.14 - 5.16
|
||||
// let directed_near_normal = 1.0 / d * (z_0 + (z_0 * z_1).sqrt());
|
||||
// let directed_near = w_l_y / d * (z_0 + (z_0 * z_1).sqrt());
|
||||
/* let directed_near = directed_near_normal as f32;
|
||||
let directed_far = (directed_near_normal + d) as f32; */
|
||||
let directed_near = (w_l_y * directed_near_normal).abs() as f32;
|
||||
let directed_far = (w_l_y * (directed_near_normal + 1.0)).abs() as f32;
|
||||
let (directed_near, directed_far) = (directed_near.min(directed_far), directed_near.max(directed_far));
|
||||
let y_ = |v: f64| w_l_y * (v + directed_near_normal).abs();
|
||||
let directed_near = y_(0.0) as f32;// (w_l_y * directed_near_normal).abs() as f32;
|
||||
let directed_far = y_(1.0) as f32;// (w_l_y * (directed_near_normal + 1.0)).abs() as f32;
|
||||
/* let directed_far = (w_l_y * (directed_near_normal + 1.0)).abs() as f32;
|
||||
let (directed_near, directed_far) = (directed_near.min(directed_far), directed_near.max(directed_far)); */
|
||||
// let directed_near = w_l_y / d * (z_0 + (z_0 * z_1).sqrt());
|
||||
// println!("θ = {:?} η = {:?} z_n = {:?} z_f = {:?} γ = {:?} d = {:?} z_0 = {:?} z_1 = {:?} w_l_y: {:?} α = {:?} √α = {:?} n'₀ = {:?} n' = {:?} f' = {:?}", scalar_fov.to_degrees(), factor, z_n, z_f, gamma.to_degrees(), d, z_0, z_1, w_l_y, alpha, alpha_sqrt, directed_near_normal, directed_near, directed_far);
|
||||
|
||||
@ -990,7 +1148,7 @@ impl Scene {
|
||||
/* // let directed_near = 1.0;
|
||||
let directed_near = ((z_n + (z_f * z_n).sqrt()) / /*sin_gamma*/factor) as f32; //1.0; */
|
||||
// let directed_far = directed_near + d as f32;
|
||||
// println!("view_dir: {:?}, new_dir: {:?}, directed_light_dir: {:?}, dot_prod: {:?}, sin_gamma: {:?}, near_dist: {:?}, d: {:?}, z_n: {:?}, z_f: {:?}, directed_near: {:?}, directed_far: {:?}", view_dir, new_dir, directed_light_dir, dot_prod, sin_gamma, near_dist, d, z_n, z_f, directed_near, directed_far);
|
||||
// println!("view_dir: {:?}, new_dir: {:?}, directed_light_dir: {:?}, cos_gamma: {:?}, sin_gamma: {:?}, near_dist: {:?}, d: {:?}, z_n: {:?}, z_f: {:?}, directed_near: {:?}, directed_far: {:?}", view_dir, new_dir, directed_light_dir, cos_gamma, sin_gamma, near_dist, d, z_n, z_f, directed_near, directed_far);
|
||||
/* let size1 = bounds1.half_size();
|
||||
let center1 = bounds1.center(); */
|
||||
/* let look_at = cam_pos - (directed_near - near_dist) * up;
|
||||
@ -1001,9 +1159,9 @@ impl Scene {
|
||||
// let w_v: Mat4<f32> = Mat4::translation_3d(/*-bounds1.center()*/-center1);
|
||||
//new observer point n-1 behind eye position
|
||||
//pos = eyePos-up*(n-nearDist)
|
||||
// let directed_near = if /*sin_gamma > EPISLON_GAMMA*/factor != -1.0 { directed_near } else { near_dist/*0.0*//*-(near_dist *//*- light_focus_pos.y)*/ };
|
||||
light_focus_pos.y = if factor != -1.0 {
|
||||
/*near_dist*/z_n as f32 - directed_near
|
||||
// let directed_near = if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON { directed_near } else { near_dist/*0.0*//*-(near_dist *//*- light_focus_pos.y)*/ };
|
||||
light_focus_pos.y = if factor > EPSILON_UPSILON {
|
||||
light_focus_pos.y/* - directed_near*/+ (/*near_dist*//*z_0 as f32*/ - directed_near)
|
||||
} else {
|
||||
light_focus_pos.y
|
||||
};
|
||||
@ -1029,7 +1187,7 @@ impl Scene {
|
||||
let _bounds0 = math::fit_psr(/*l_r*/shadow_view_mat/* * inverse_visible*/, visible_light_volume.iter().copied(), /*|p| math::Vec3::from(p) / p.w*/math::Vec4::homogenized);
|
||||
// let factor = -1.0;
|
||||
let w_p: math::Mat4<f32> = {
|
||||
if /*sin_gamma > EPISLON_GAMMA*/factor != -1.0 {
|
||||
if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON {
|
||||
// Projection for y
|
||||
let n = directed_near;// - near_dist;
|
||||
let f = directed_far;
|
||||
@ -1153,7 +1311,7 @@ impl Scene {
|
||||
near: zmin,//directed_near,
|
||||
far: zmax,//directed_far,
|
||||
}); */
|
||||
let shadow_all_mat: math::Mat4<f32> = w_p * shadow_view_mat/*w_v * light_all_mat*/;
|
||||
let shadow_all_mat: math::Mat4<f32> = /*(w_v * l_r).inverted() * */w_p * shadow_view_mat/*w_v * light_all_mat*/;
|
||||
let _w_p_arr = shadow_all_mat.cols.iter().map(|e| (e.x, e.y, e.z, e.w)).collect::<Vec<_>>();
|
||||
// println!("mat4 shadow_all_mat = mat4(vec4{:?}, vec4{:?}, vec4{:?}, vec4{:?});", w_p_arr[0], w_p_arr[1], w_p_arr[2], w_p_arr[3]);
|
||||
let math::Aabb::<f32> { min: math::Vec3 { x: xmin, y: ymin, z: zmin }, max: math::Vec3 { x: xmax, y: ymax, z: zmax } } =
|
||||
@ -1173,7 +1331,7 @@ impl Scene {
|
||||
let o_x = -(xmax + xmin) / (xmax - xmin);
|
||||
let o_y = -(ymax + ymin) / (ymax - ymin);
|
||||
let o_z = -(zmax + zmin) / (zmax - zmin);
|
||||
let directed_proj_mat = if /*sin_gamma > EPISLON_GAMMA*/factor != -1.0 {
|
||||
let directed_proj_mat = if /*sin_gamma > EPISLON_GAMMA*/factor > EPSILON_UPSILON {
|
||||
// Mat4::identity()
|
||||
Mat4::new(
|
||||
s_x, 0.0, 0.0, o_x,
|
||||
@ -1283,6 +1441,7 @@ impl Scene {
|
||||
self.terrain.render_shadows(
|
||||
renderer,
|
||||
&self.globals,
|
||||
&self.lights,
|
||||
&self.shadow_mats,
|
||||
&self.light_data,
|
||||
is_daylight,
|
||||
|
@ -455,6 +455,15 @@ struct SpriteData {
|
||||
pub struct Terrain<V: RectRasterableVol> {
|
||||
atlas: AtlasAllocator,
|
||||
chunks: HashMap<Vec2<i32>, TerrainChunkData>,
|
||||
/// Temporary storage for dead chunks that might still be shadowing chunks
|
||||
/// in view. We wait until either the chunk definitely cannot be
|
||||
/// shadowing anything the player can see, the chunk comes back into
|
||||
/// view, or for daylight to end, before removing it (whichever comes
|
||||
/// first).
|
||||
///
|
||||
/// Note that these chunks are not complete; for example, they are missing
|
||||
/// texture data.
|
||||
shadow_chunks: Vec<(Vec2<i32>, TerrainChunkData)>,
|
||||
/* /// Secondary index into the terrain chunk table, used to sort through chunks by z index from
|
||||
/// the top down.
|
||||
z_index_down: BTreeSet<Vec3<i32>>,
|
||||
@ -2239,6 +2248,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
Self {
|
||||
atlas,
|
||||
chunks: HashMap::default(),
|
||||
shadow_chunks: Vec::default(),
|
||||
mesh_send_tmp: send,
|
||||
mesh_recv: recv,
|
||||
mesh_todo: HashMap::default(),
|
||||
@ -2328,7 +2338,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
Ok((atlas, texture))
|
||||
}
|
||||
|
||||
fn remove_chunk_meta(&mut self, _pos: Vec2<i32>, chunk: TerrainChunkData) {
|
||||
fn remove_chunk_meta(&mut self, _pos: Vec2<i32>, chunk: &TerrainChunkData) {
|
||||
/* println!("Terrain chunk already existed: {:?}", pos); */
|
||||
self.atlas.deallocate(chunk.col_lights);
|
||||
/* let (zmin, zmax) = chunk.z_bounds;
|
||||
@ -2338,7 +2348,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
|
||||
fn insert_chunk(&mut self, pos: Vec2<i32>, chunk: TerrainChunkData) {
|
||||
if let Some(old) = self.chunks.insert(pos, chunk) {
|
||||
self.remove_chunk_meta(pos, old);
|
||||
self.remove_chunk_meta(pos, &old);
|
||||
}
|
||||
/* let (zmin, zmax) = chunk.z_bounds;
|
||||
self.z_index_up.insert(Vec3::from(zmin, pos.x, pos.y));
|
||||
@ -2348,7 +2358,9 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
fn remove_chunk(&mut self, pos: Vec2<i32>) {
|
||||
// println!("Terrain chunk removed: {:?}", pos);
|
||||
if let Some(chunk) = self.chunks.remove(&pos) {
|
||||
self.remove_chunk_meta(pos, chunk);
|
||||
self.remove_chunk_meta(pos, &chunk);
|
||||
// Temporarily remember dead chunks for shadowing purposes.
|
||||
self.shadow_chunks.push((pos, chunk));
|
||||
}
|
||||
if let Some(_todo) = self.mesh_todo.remove(&pos) {
|
||||
/* println!("Terrain chunk was being meshed: {:?}",
|
||||
@ -2367,7 +2379,11 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
loaded_distance: f32,
|
||||
view_mat: Mat4<f32>,
|
||||
proj_mat: Mat4<f32>,
|
||||
) -> (Aabb<f32>, Aabb<f32>, Aabb<f32>) {
|
||||
) -> (
|
||||
Aabb<f32>,
|
||||
/* Aabb<f32>, Aabb<f32> */ Vec<math::Vec3<f32>>,
|
||||
math::Aabr<f32>,
|
||||
) {
|
||||
let current_tick = scene_data.tick;
|
||||
let current_time = scene_data.state.get_time();
|
||||
let mut visible_bounding_box: Option<Aabb<f32>> = None;
|
||||
@ -2855,7 +2871,9 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
let collides_with_aabr = |a: math::Aabr<f32>, b: math::Aabr<f32>| {
|
||||
a.min.partial_cmple(&b.max).reduce_and() && a.max.partial_cmpge(&b.min).reduce_and()
|
||||
};
|
||||
if ray_direction.z < 0.0 && renderer.render_mode().shadow.is_map() {
|
||||
let (visible_light_volume, visible_psr_bounds) = if ray_direction.z < 0.0
|
||||
&& renderer.render_mode().shadow.is_map()
|
||||
{
|
||||
let visible_bounding_box = Aabb {
|
||||
min: visible_bounding_box.min - focus_off,
|
||||
max: visible_bounding_box.max - focus_off,
|
||||
@ -2912,47 +2930,81 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
let visible_bounds = math::Aabr::from(math::fit_psr(
|
||||
ray_mat,
|
||||
/* super::aabb_to_points(visible_bounding_box).iter().copied() */
|
||||
visible_light_volume.into_iter(),
|
||||
visible_light_volume.iter().copied(),
|
||||
|p| p, //math::Vec3::from(p), /* / p.w */
|
||||
));
|
||||
let ray_mat = ray_mat * math::Mat4::translation_3d(-focus_off);
|
||||
/* let visible_bounds_old = Aabr::from(super::fit_psr(ray_mat, super::aabb_to_points(visible_bounding_box).iter().copied(), |p| Vec3::from(p) / p.w));
|
||||
println!("old: {:?} new: {:?}", visible_bounds_old, visible_bounds); */
|
||||
|
||||
self.chunks.iter_mut()
|
||||
// NOTE: We deliberately avoid doing this computation for chunks we already know
|
||||
// are visible, since by definition they'll always intersect the visible view
|
||||
// frustum.
|
||||
.filter(|chunk| chunk.1.visible == Visibility::InRange)
|
||||
.for_each(|(pos, chunk)| {
|
||||
let can_shadow_sun = |pos: Vec2<i32>, chunk: &TerrainChunkData| {
|
||||
let chunk_pos = pos.map(|e| e as f32 * chunk_sz);
|
||||
|
||||
// Ensure the chunk is within the view frustum
|
||||
let chunk_min = [chunk_pos.x, chunk_pos.y, chunk.z_bounds.0];
|
||||
let chunk_max = [
|
||||
chunk_pos.x + chunk_sz,
|
||||
chunk_pos.y + chunk_sz,
|
||||
chunk.z_bounds.1,
|
||||
];
|
||||
// Ensure the chunk is within the PSR set.
|
||||
let chunk_box = math::Aabb {
|
||||
min: math::Vec3::from(chunk_min) - focus_off,
|
||||
max: math::Vec3::from(chunk_max) - focus_off,
|
||||
min: math::Vec3::new(chunk_pos.x, chunk_pos.y, chunk.z_bounds.0),
|
||||
max: math::Vec3::new(
|
||||
chunk_pos.x + chunk_sz,
|
||||
chunk_pos.y + chunk_sz,
|
||||
chunk.z_bounds.1,
|
||||
),
|
||||
};
|
||||
|
||||
let chunk_from_light = math::Aabr::from(math::fit_psr(ray_mat, math::aabb_to_points(chunk_box).iter().copied(), |p| p/*math::Vec3::from(p)/* / p.w*/*/));
|
||||
let chunk_from_light = math::Aabr::from(math::fit_psr(
|
||||
ray_mat,
|
||||
math::aabb_to_points(chunk_box).iter().copied(),
|
||||
|p| p, /* math::Vec3::from(p)/* / p.w*/ */
|
||||
));
|
||||
/* let chunk_from_light = Aabr {
|
||||
min: (ray_mat * Vec4::from_point(chunk_box.min)).xy(),
|
||||
max: (ray_mat * Vec4::from_point(chunk_box.max)).xy(),
|
||||
}.made_valid(); */
|
||||
let can_shadow_sun = collides_with_aabr(chunk_from_light, visible_bounds);
|
||||
/* let can_shadow_sun = */
|
||||
collides_with_aabr(chunk_from_light, visible_bounds)
|
||||
/* let can_shadow_sun_old = collides_with_aabr(chunk_from_light, visible_bounds_old);
|
||||
if can_shadow_sun != can_shadow_sun_old {
|
||||
println!("Different results for chunk {:?} (from light = {:?}):\n\
|
||||
old = {:?} new = {:?}",
|
||||
chunk_box, chunk_from_light, can_shadow_sun_old, can_shadow_sun);
|
||||
} */
|
||||
chunk.can_shadow_sun = can_shadow_sun;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle potential shadow casters (chunks that aren't visible, but are still in
|
||||
// range) to see if they could cast shadows.
|
||||
self.chunks.iter_mut()
|
||||
// NOTE: We deliberately avoid doing this computation for chunks we already know
|
||||
// are visible, since by definition they'll always intersect the visible view
|
||||
// frustum.
|
||||
.filter(|chunk| chunk.1.visible <= Visibility::InRange)
|
||||
.for_each(|(&pos, chunk)| {
|
||||
chunk.can_shadow_sun = can_shadow_sun(pos, chunk);
|
||||
});
|
||||
|
||||
// Handle dead chunks that we kept around only to make sure shadows don't blink
|
||||
// out when a chunk disappears.
|
||||
//
|
||||
// If the sun can currently cast shadows, we retain only those shadow chunks
|
||||
// that both: 1. have not been replaced by a real chunk instance,
|
||||
// and 2. are currently potential shadow casters (as witnessed by
|
||||
// `can_shadow_sun` returning true).
|
||||
//
|
||||
// NOTE: Please make sure this runs *after* any code that could insert a chunk!
|
||||
// Otherwise we may end up with multiple instances of the chunk trying to cast
|
||||
// shadows at the same time.
|
||||
let chunks = &self.chunks;
|
||||
self.shadow_chunks
|
||||
.retain(|(pos, chunk)| !chunks.contains_key(pos) && can_shadow_sun(*pos, chunk));
|
||||
|
||||
(visible_light_volume, visible_bounds)
|
||||
} else {
|
||||
// There's no daylight or no shadows, so there's no reason to keep any
|
||||
// shadow chunks around.
|
||||
self.shadow_chunks.clear();
|
||||
(Vec::new(), math::Aabr {
|
||||
min: math::Vec2::zero(),
|
||||
max: math::Vec2::zero(),
|
||||
})
|
||||
};
|
||||
/* let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w()) + focus_off; let look_at = visible_box.center();
|
||||
let view_dir = (focus_pos - cam_pos).normalized();
|
||||
let up_vec = ray_direction.cross(view_dir).cross(light_dir).normalized();
|
||||
@ -3008,7 +3060,12 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
}
|
||||
} */
|
||||
|
||||
(scene_bounding_box, visible_bounding_box, psc_bounding_box)
|
||||
(
|
||||
/* scene_bounding_box, visible_bounding_box, psc_bounding_box */
|
||||
visible_bounding_box,
|
||||
visible_light_volume,
|
||||
visible_psr_bounds,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn chunk_count(&self) -> usize { self.chunks.len() }
|
||||
@ -3020,10 +3077,13 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn shadow_chunk_count(&self) -> usize { self.shadow_chunks.len() }
|
||||
|
||||
pub fn render_shadows(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
globals: &Consts<Globals>,
|
||||
lights: &Consts<Light>,
|
||||
shadow_mats: &Consts<ShadowLocals>,
|
||||
light_data: &[Light],
|
||||
is_daylight: bool,
|
||||
@ -3040,16 +3100,23 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
let chunk_iter = Spiral2d::new()
|
||||
.filter_map(|rpos| {
|
||||
let pos = focus_chunk + rpos;
|
||||
self.chunks.get(&pos).map(|c| (pos, c))
|
||||
self.chunks.get(&pos)
|
||||
})
|
||||
.take(self.chunks.len());
|
||||
|
||||
// let is_daylight = sun_dir.z < 0.0/*0.6*/;
|
||||
|
||||
// Directed shadows
|
||||
//
|
||||
// NOTE: We also render shadows for dead chunks that were found to still be
|
||||
// potential shadow casters, to avoid shadows suddenly disappearing at
|
||||
// very steep sun angles (e.g. sunrise / sunset).
|
||||
if is_daylight {
|
||||
for (_, chunk) in chunk_iter.clone() {
|
||||
if chunk.can_shadow_sun() {
|
||||
chunk_iter
|
||||
.clone()
|
||||
.filter(|chunk| chunk.can_shadow_sun())
|
||||
.chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk))
|
||||
.for_each(|chunk| {
|
||||
// Directed light shadows.
|
||||
renderer.render_terrain_shadow_directed(
|
||||
// &chunk.shadow_model,
|
||||
@ -3057,18 +3124,20 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
globals,
|
||||
&chunk.locals,
|
||||
shadow_mats,
|
||||
/* lights,
|
||||
* shadows,
|
||||
lights,
|
||||
/* shadows,
|
||||
* &lod.map,
|
||||
* &lod.horizon, */
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Point shadows
|
||||
for _light in light_data.iter().take(1) {
|
||||
for (_, chunk) in chunk_iter.clone() {
|
||||
//
|
||||
// NOTE: We don't bother retaining chunks unless they cast sun shadows, so we
|
||||
// don't use `shadow_chunks` here.
|
||||
light_data.iter().take(1).for_each(|_light| {
|
||||
chunk_iter.clone().for_each(|chunk| {
|
||||
if chunk.can_shadow_point {
|
||||
// shadow_vertex_count += chunk.shadow_model.vertex_range.len();
|
||||
renderer.render_shadow_point(
|
||||
@ -3077,14 +3146,14 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
globals,
|
||||
&chunk.locals,
|
||||
shadow_mats,
|
||||
/* lights,
|
||||
* shadows,
|
||||
lights,
|
||||
/* shadows,
|
||||
* &lod.map,
|
||||
* &lod.horizon, */
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
|
@ -644,11 +644,11 @@ impl PlayState for SessionState {
|
||||
self.scene
|
||||
.camera_mut()
|
||||
.compute_dependents(&*self.client.borrow().state().terrain());
|
||||
// Extract HUD events ensuring the client borrow gets dropped.
|
||||
let mut hud_events = self.hud.maintain(
|
||||
&self.client.borrow(),
|
||||
global_state,
|
||||
DebugInfo {
|
||||
|
||||
// Generate debug info, if needed (it iterates through enough data that we might
|
||||
// as well avoid it unless we need it).
|
||||
let debug_info = if global_state.settings.gameplay.toggle_debug {
|
||||
Some(DebugInfo {
|
||||
tps: clock.get_tps(),
|
||||
ping_ms: self.client.borrow().get_ping_ms_rolling_avg(),
|
||||
coordinates: self
|
||||
@ -677,9 +677,19 @@ impl PlayState for SessionState {
|
||||
.cloned(),
|
||||
num_chunks: self.scene.terrain().chunk_count() as u32,
|
||||
num_visible_chunks: self.scene.terrain().visible_chunk_count() as u32,
|
||||
num_shadow_chunks: self.scene.terrain().shadow_chunk_count() as u32,
|
||||
num_figures: self.scene.figure_mgr().figure_count() as u32,
|
||||
num_figures_visible: self.scene.figure_mgr().figure_count_visible() as u32,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Extract HUD events ensuring the client borrow gets dropped.
|
||||
let mut hud_events = self.hud.maintain(
|
||||
&self.client.borrow(),
|
||||
global_state,
|
||||
&debug_info,
|
||||
&self.scene.camera(),
|
||||
clock.get_last_delta(),
|
||||
HudInfo {
|
||||
|
Loading…
Reference in New Issue
Block a user