Working on the night mode
This commit is contained in:
parent
e6bfe85e2e
commit
442d3a7945
22
resources/shaders/night_fog.vertex
Normal file
22
resources/shaders/night_fog.vertex
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
uniform vec3 uPlayerEyePos;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 eyePos = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
fogDistance = length(eyePos.xyz - uPlayerEyePos);
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
|
texCoord = vTexCoord;
|
||||||
|
fragViewPos = eyePos.xyz;
|
||||||
|
fragNormal = mat3(ModelViewMatrix) * vNormal;
|
||||||
|
}
|
||||||
56
resources/shaders/night_fog_desktop.fragment
Normal file
56
resources/shaders/night_fog_desktop.fragment
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform float uAlpha;
|
||||||
|
uniform int uPointLightCount;
|
||||||
|
uniform vec3 uPointLightPos[4];
|
||||||
|
uniform vec3 uPointLightDir[4];
|
||||||
|
uniform vec3 uPointLightColor[4];
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
|
||||||
|
// cos(45 deg) = half-angle for a 90-degree full-angle spotlight
|
||||||
|
const float SPOT_COS_OUTER = 0.7071;
|
||||||
|
const float SPOT_COS_INNER = 0.82; // slightly tighter inner cone for smooth edge
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = texture2D(Texture, texCoord);
|
||||||
|
|
||||||
|
if (color.a < 0.1)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
float ambient = 0.37;
|
||||||
|
vec3 lighting = vec3(ambient);
|
||||||
|
|
||||||
|
bool hasNormal = dot(fragNormal, fragNormal) > 0.001;
|
||||||
|
vec3 N = hasNormal ? normalize(fragNormal) : vec3(0.0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (i >= uPointLightCount) break;
|
||||||
|
|
||||||
|
vec3 lightVec = uPointLightPos[i] - fragViewPos;
|
||||||
|
float dist = length(lightVec);
|
||||||
|
vec3 lightDir = normalize(lightVec);
|
||||||
|
|
||||||
|
// Spotlight cone: angle between the cone axis and the ray from light to fragment
|
||||||
|
float cosTheta = dot(-lightDir, normalize(uPointLightDir[i]));
|
||||||
|
float spotAtten = smoothstep(SPOT_COS_OUTER, SPOT_COS_INNER, cosTheta);
|
||||||
|
if (spotAtten <= 0.0) continue;
|
||||||
|
|
||||||
|
float atten = 1.0 / (1.0 + 0.35 * dist + 0.15 * dist * dist);
|
||||||
|
float diff = hasNormal ? max(dot(N, lightDir), 0.0) : 1.0;
|
||||||
|
|
||||||
|
lighting += uPointLightColor[i] * diff * atten * spotAtten;
|
||||||
|
}
|
||||||
|
|
||||||
|
color.rgb *= lighting;
|
||||||
|
|
||||||
|
vec3 fogColor = vec3(0.01, 0.01, 0.05);
|
||||||
|
float fogFactor = clamp((fogDistance - 15.0) / 8.0, 0.0, 1.0);
|
||||||
|
color.rgb = mix(color.rgb, fogColor, fogFactor);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color.rgb, color.a * uAlpha);
|
||||||
|
}
|
||||||
25
resources/shaders/night_fog_shadow.vertex
Normal file
25
resources/shaders/night_fog_shadow.vertex
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying vec4 fragPosLightSpace;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
uniform mat4 uLightFromCamera;
|
||||||
|
uniform vec3 uPlayerEyePos;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 eyePos = ModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
fogDistance = length(eyePos.xyz - uPlayerEyePos);
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
texCoord = vTexCoord;
|
||||||
|
fragViewPos = eyePos.xyz;
|
||||||
|
fragNormal = mat3(ModelViewMatrix) * vNormal;
|
||||||
|
fragPosLightSpace = uLightFromCamera * eyePos;
|
||||||
|
}
|
||||||
95
resources/shaders/night_fog_shadow_desktop.fragment
Normal file
95
resources/shaders/night_fog_shadow_desktop.fragment
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform sampler2D uShadowMap;
|
||||||
|
uniform vec3 uLightDir;
|
||||||
|
uniform float uAlpha;
|
||||||
|
uniform int uPointLightCount;
|
||||||
|
uniform vec3 uPointLightPos[4];
|
||||||
|
uniform vec3 uPointLightDir[4];
|
||||||
|
uniform vec3 uPointLightColor[4];
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying vec4 fragPosLightSpace;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
|
||||||
|
const float SPOT_COS_OUTER = 0.7071;
|
||||||
|
const float SPOT_COS_INNER = 0.82;
|
||||||
|
|
||||||
|
float computeShadow(vec4 lightSpacePos, vec3 normal)
|
||||||
|
{
|
||||||
|
vec3 projCoords = lightSpacePos.xyz / lightSpacePos.w;
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
|
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||||
|
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
||||||
|
projCoords.z > 1.0)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float currentDepth = projCoords.z;
|
||||||
|
|
||||||
|
float bias = 0.0004;
|
||||||
|
if (dot(normal, normal) > 0.001)
|
||||||
|
{
|
||||||
|
float cosTheta = dot(normalize(normal), -normalize(uLightDir));
|
||||||
|
bias = max(0.002 * (1.0 - cosTheta), 0.0002);
|
||||||
|
}
|
||||||
|
|
||||||
|
float shadow = 0.0;
|
||||||
|
float texelSize = 1.0 / 2048.0;
|
||||||
|
for (int x = -1; x <= 1; x++)
|
||||||
|
{
|
||||||
|
for (int y = -1; y <= 1; y++)
|
||||||
|
{
|
||||||
|
float pcfDepth = texture2D(uShadowMap, projCoords.xy + vec2(float(x), float(y)) * texelSize).r;
|
||||||
|
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadow /= 9.0;
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = texture2D(Texture, texCoord);
|
||||||
|
|
||||||
|
if (color.a < 0.1)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
float ambient = 0.37;
|
||||||
|
vec3 lighting = vec3(ambient);
|
||||||
|
|
||||||
|
bool hasNormal = dot(fragNormal, fragNormal) > 0.001;
|
||||||
|
vec3 N = hasNormal ? normalize(fragNormal) : vec3(0.0);
|
||||||
|
|
||||||
|
float shadow = computeShadow(fragPosLightSpace, fragNormal);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (i >= uPointLightCount) break;
|
||||||
|
|
||||||
|
vec3 lightVec = uPointLightPos[i] - fragViewPos;
|
||||||
|
float dist = length(lightVec);
|
||||||
|
vec3 lightDir = normalize(lightVec);
|
||||||
|
|
||||||
|
float cosTheta = dot(-lightDir, normalize(uPointLightDir[i]));
|
||||||
|
float spotAtten = smoothstep(SPOT_COS_OUTER, SPOT_COS_INNER, cosTheta);
|
||||||
|
if (spotAtten <= 0.0) continue;
|
||||||
|
|
||||||
|
float atten = 1.0 / (1.0 + 0.35 * dist + 0.15 * dist * dist);
|
||||||
|
float diff = hasNormal ? max(dot(N, lightDir), 0.0) : 1.0;
|
||||||
|
|
||||||
|
lighting += uPointLightColor[i] * diff * atten * spotAtten * (1.0 - shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
color.rgb *= lighting;
|
||||||
|
|
||||||
|
vec3 fogColor = vec3(0.01, 0.01, 0.05);
|
||||||
|
float fogFactor = clamp((fogDistance - 15.0) / 8.0, 0.0, 1.0);
|
||||||
|
color.rgb = mix(color.rgb, fogColor, fogFactor);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color.rgb, color.a * uAlpha);
|
||||||
|
}
|
||||||
97
resources/shaders/night_fog_shadow_web.fragment
Normal file
97
resources/shaders/night_fog_shadow_web.fragment
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform sampler2D uShadowMap;
|
||||||
|
uniform vec3 uLightDir;
|
||||||
|
uniform float uAlpha;
|
||||||
|
uniform int uPointLightCount;
|
||||||
|
uniform vec3 uPointLightPos[4];
|
||||||
|
uniform vec3 uPointLightDir[4];
|
||||||
|
uniform vec3 uPointLightColor[4];
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying vec4 fragPosLightSpace;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
|
||||||
|
const float SPOT_COS_OUTER = 0.7071;
|
||||||
|
const float SPOT_COS_INNER = 0.82;
|
||||||
|
|
||||||
|
float computeShadow(vec4 lightSpacePos, vec3 normal)
|
||||||
|
{
|
||||||
|
vec3 projCoords = lightSpacePos.xyz / lightSpacePos.w;
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
|
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||||
|
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
||||||
|
projCoords.z > 1.0)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float currentDepth = projCoords.z;
|
||||||
|
|
||||||
|
float bias = 0.0004;
|
||||||
|
if (dot(normal, normal) > 0.001)
|
||||||
|
{
|
||||||
|
float cosTheta = dot(normalize(normal), -normalize(uLightDir));
|
||||||
|
bias = max(0.002 * (1.0 - cosTheta), 0.0002);
|
||||||
|
}
|
||||||
|
|
||||||
|
float shadow = 0.0;
|
||||||
|
float texelSize = 1.0 / 2048.0;
|
||||||
|
for (int x = -1; x <= 1; x++)
|
||||||
|
{
|
||||||
|
for (int y = -1; y <= 1; y++)
|
||||||
|
{
|
||||||
|
float pcfDepth = texture2D(uShadowMap, projCoords.xy + vec2(float(x), float(y)) * texelSize).r;
|
||||||
|
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadow /= 9.0;
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = texture2D(Texture, texCoord);
|
||||||
|
|
||||||
|
if (color.a < 0.1)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
float ambient = 0.37;
|
||||||
|
vec3 lighting = vec3(ambient);
|
||||||
|
|
||||||
|
bool hasNormal = dot(fragNormal, fragNormal) > 0.001;
|
||||||
|
vec3 N = hasNormal ? normalize(fragNormal) : vec3(0.0);
|
||||||
|
|
||||||
|
float shadow = computeShadow(fragPosLightSpace, fragNormal);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (i >= uPointLightCount) break;
|
||||||
|
|
||||||
|
vec3 lightVec = uPointLightPos[i] - fragViewPos;
|
||||||
|
float dist = length(lightVec);
|
||||||
|
vec3 lightDir = normalize(lightVec);
|
||||||
|
|
||||||
|
float cosTheta = dot(-lightDir, normalize(uPointLightDir[i]));
|
||||||
|
float spotAtten = smoothstep(SPOT_COS_OUTER, SPOT_COS_INNER, cosTheta);
|
||||||
|
if (spotAtten <= 0.0) continue;
|
||||||
|
|
||||||
|
float atten = 1.0 / (1.0 + 0.35 * dist + 0.15 * dist * dist);
|
||||||
|
float diff = hasNormal ? max(dot(N, lightDir), 0.0) : 1.0;
|
||||||
|
|
||||||
|
lighting += uPointLightColor[i] * diff * atten * spotAtten * (1.0 - shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
color.rgb *= lighting;
|
||||||
|
|
||||||
|
vec3 fogColor = vec3(0.01, 0.01, 0.05);
|
||||||
|
float fogFactor = clamp((fogDistance - 15.0) / 8.0, 0.0, 1.0);
|
||||||
|
color.rgb = mix(color.rgb, fogColor, fogFactor);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color.rgb, color.a * uAlpha);
|
||||||
|
}
|
||||||
68
resources/shaders/night_fog_skinning.vertex
Normal file
68
resources/shaders/night_fog_skinning.vertex
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec4 aBoneIndices0;
|
||||||
|
attribute vec2 aBoneIndices1;
|
||||||
|
attribute vec4 aBoneWeights0;
|
||||||
|
attribute vec2 aBoneWeights1;
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
uniform mat4 uBoneMatrices[64];
|
||||||
|
uniform vec3 uPlayerEyePos;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
vec3 skinnedNormal = vec3(0.0, 0.0, 0.0);
|
||||||
|
vec4 originalPos = vec4(vPosition, 1.0);
|
||||||
|
float totalWeight = 0.0;
|
||||||
|
|
||||||
|
if (aBoneWeights0.x > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.x)]) * vNormal * aBoneWeights0.x;
|
||||||
|
totalWeight += aBoneWeights0.x;
|
||||||
|
}
|
||||||
|
if (aBoneWeights0.y > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.y)]) * vNormal * aBoneWeights0.y;
|
||||||
|
totalWeight += aBoneWeights0.y;
|
||||||
|
}
|
||||||
|
if (aBoneWeights0.z > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.z)]) * vNormal * aBoneWeights0.z;
|
||||||
|
totalWeight += aBoneWeights0.z;
|
||||||
|
}
|
||||||
|
if (aBoneWeights0.w > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.w)]) * vNormal * aBoneWeights0.w;
|
||||||
|
totalWeight += aBoneWeights0.w;
|
||||||
|
}
|
||||||
|
if (aBoneWeights1.x > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.x)]) * vNormal * aBoneWeights1.x;
|
||||||
|
totalWeight += aBoneWeights1.x;
|
||||||
|
}
|
||||||
|
if (aBoneWeights1.y > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.y)]) * vNormal * aBoneWeights1.y;
|
||||||
|
totalWeight += aBoneWeights1.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalWeight < 0.001) {
|
||||||
|
skinnedPos = originalPos;
|
||||||
|
skinnedNormal = vNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 eyePos = ModelViewMatrix * skinnedPos;
|
||||||
|
fogDistance = length(eyePos.xyz - uPlayerEyePos);
|
||||||
|
gl_Position = ProjectionModelViewMatrix * skinnedPos;
|
||||||
|
texCoord = vTexCoord;
|
||||||
|
fragViewPos = eyePos.xyz;
|
||||||
|
fragNormal = mat3(ModelViewMatrix) * skinnedNormal;
|
||||||
|
}
|
||||||
71
resources/shaders/night_fog_skinning_shadow.vertex
Normal file
71
resources/shaders/night_fog_skinning_shadow.vertex
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec4 aBoneIndices0;
|
||||||
|
attribute vec2 aBoneIndices1;
|
||||||
|
attribute vec4 aBoneWeights0;
|
||||||
|
attribute vec2 aBoneWeights1;
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying vec4 fragPosLightSpace;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
uniform mat4 uLightFromCamera;
|
||||||
|
uniform mat4 uBoneMatrices[64];
|
||||||
|
uniform vec3 uPlayerEyePos;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
vec3 skinnedNormal = vec3(0.0, 0.0, 0.0);
|
||||||
|
vec4 originalPos = vec4(vPosition, 1.0);
|
||||||
|
float totalWeight = 0.0;
|
||||||
|
|
||||||
|
if (aBoneWeights0.x > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.x)]) * vNormal * aBoneWeights0.x;
|
||||||
|
totalWeight += aBoneWeights0.x;
|
||||||
|
}
|
||||||
|
if (aBoneWeights0.y > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.y)]) * vNormal * aBoneWeights0.y;
|
||||||
|
totalWeight += aBoneWeights0.y;
|
||||||
|
}
|
||||||
|
if (aBoneWeights0.z > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.z)]) * vNormal * aBoneWeights0.z;
|
||||||
|
totalWeight += aBoneWeights0.z;
|
||||||
|
}
|
||||||
|
if (aBoneWeights0.w > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices0.w)]) * vNormal * aBoneWeights0.w;
|
||||||
|
totalWeight += aBoneWeights0.w;
|
||||||
|
}
|
||||||
|
if (aBoneWeights1.x > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.x)]) * vNormal * aBoneWeights1.x;
|
||||||
|
totalWeight += aBoneWeights1.x;
|
||||||
|
}
|
||||||
|
if (aBoneWeights1.y > 0.0) {
|
||||||
|
skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y;
|
||||||
|
skinnedNormal += mat3(uBoneMatrices[int(aBoneIndices1.y)]) * vNormal * aBoneWeights1.y;
|
||||||
|
totalWeight += aBoneWeights1.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalWeight < 0.001) {
|
||||||
|
skinnedPos = originalPos;
|
||||||
|
skinnedNormal = vNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 eyePos = ModelViewMatrix * skinnedPos;
|
||||||
|
fogDistance = length(eyePos.xyz - uPlayerEyePos);
|
||||||
|
gl_Position = ProjectionModelViewMatrix * skinnedPos;
|
||||||
|
texCoord = vTexCoord;
|
||||||
|
fragViewPos = eyePos.xyz;
|
||||||
|
fragNormal = mat3(ModelViewMatrix) * skinnedNormal;
|
||||||
|
fragPosLightSpace = uLightFromCamera * eyePos;
|
||||||
|
}
|
||||||
58
resources/shaders/night_fog_web.fragment
Normal file
58
resources/shaders/night_fog_web.fragment
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform float uAlpha;
|
||||||
|
uniform int uPointLightCount;
|
||||||
|
uniform vec3 uPointLightPos[4];
|
||||||
|
uniform vec3 uPointLightDir[4];
|
||||||
|
uniform vec3 uPointLightColor[4];
|
||||||
|
|
||||||
|
varying vec2 texCoord;
|
||||||
|
varying float fogDistance;
|
||||||
|
varying vec3 fragViewPos;
|
||||||
|
varying vec3 fragNormal;
|
||||||
|
|
||||||
|
// cos(45 deg) = half-angle for a 90-degree full-angle spotlight
|
||||||
|
const float SPOT_COS_OUTER = 0.7071;
|
||||||
|
const float SPOT_COS_INNER = 0.82; // slightly tighter inner cone for smooth edge
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = texture2D(Texture, texCoord);
|
||||||
|
|
||||||
|
if (color.a < 0.1)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
float ambient = 0.37;
|
||||||
|
vec3 lighting = vec3(ambient);
|
||||||
|
|
||||||
|
bool hasNormal = dot(fragNormal, fragNormal) > 0.001;
|
||||||
|
vec3 N = hasNormal ? normalize(fragNormal) : vec3(0.0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (i >= uPointLightCount) break;
|
||||||
|
|
||||||
|
vec3 lightVec = uPointLightPos[i] - fragViewPos;
|
||||||
|
float dist = length(lightVec);
|
||||||
|
vec3 lightDir = normalize(lightVec);
|
||||||
|
|
||||||
|
// Spotlight cone: angle between the cone axis and the ray from light to fragment
|
||||||
|
float cosTheta = dot(-lightDir, normalize(uPointLightDir[i]));
|
||||||
|
float spotAtten = smoothstep(SPOT_COS_OUTER, SPOT_COS_INNER, cosTheta);
|
||||||
|
if (spotAtten <= 0.0) continue;
|
||||||
|
|
||||||
|
float atten = 1.0 / (1.0 + 0.35 * dist + 0.15 * dist * dist);
|
||||||
|
float diff = hasNormal ? max(dot(N, lightDir), 0.0) : 1.0;
|
||||||
|
|
||||||
|
lighting += uPointLightColor[i] * diff * atten * spotAtten;
|
||||||
|
}
|
||||||
|
|
||||||
|
color.rgb *= lighting;
|
||||||
|
|
||||||
|
vec3 fogColor = vec3(0.01, 0.01, 0.05);
|
||||||
|
float fogFactor = clamp((fogDistance - 15.0) / 8.0, 0.0, 1.0);
|
||||||
|
color.rgb = mix(color.rgb, fogColor, fogFactor);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(color.rgb, color.a * uAlpha);
|
||||||
|
}
|
||||||
@ -901,6 +901,295 @@ void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matri
|
|||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== Night pass with point lights ====================
|
||||||
|
|
||||||
|
void Character::drawNight(Renderer& renderer, const float* pointLightPosEye, const float* pointLightDirEye, const float* pointLightColors, int pointLightCount) {
|
||||||
|
if (!enabled) return;
|
||||||
|
if (hitSparkEmitter.isConfigured() && hitSparkEmitter.getActiveParticleCount() > 0) {
|
||||||
|
hitSparkEmitter.draw(renderer, 1.0f, Environment::width, Environment::height, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uAlpha", 1.0f);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
if (!isPlayer && hp <= 0) return;
|
||||||
|
|
||||||
|
if (useGpuSkinning) {
|
||||||
|
drawNightGpuSkinning(renderer, pointLightPosEye, pointLightDirEye, pointLightColors, pointLightCount);
|
||||||
|
} else {
|
||||||
|
drawNightCpu(renderer, pointLightPosEye, pointLightDirEye, pointLightColors, pointLightCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::drawNightGpuSkinning(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount) {
|
||||||
|
AnimationState drawState = resolveActiveState();
|
||||||
|
auto it = animations.find(drawState);
|
||||||
|
if (it == animations.end()) return;
|
||||||
|
|
||||||
|
if (!prepareGpuSkinning()) return;
|
||||||
|
|
||||||
|
static const std::string nightSkinningShader = "night_fog_skinning";
|
||||||
|
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(nightSkinningShader);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
const float playerEyePosNight[3] = { 0.0f, 0.0f, -Environment::zoom };
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNight);
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", plCount);
|
||||||
|
if (plCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
renderer.ScaleMatrix(modelScale);
|
||||||
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
|
||||||
|
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
|
||||||
|
static_cast<int>(it->second.gpuSkinningShaderData.skinningMatrices.size()), false,
|
||||||
|
it->second.gpuSkinningShaderData.skinningMatrices[0].data());
|
||||||
|
|
||||||
|
for (const auto& name : it->second.model.meshNamesOrdered) {
|
||||||
|
auto pit = it->second.gpuSkinningShaderData.perMesh.find(name);
|
||||||
|
if (pit == it->second.gpuSkinningShaderData.perMesh.end()) continue;
|
||||||
|
auto tit = meshTextures.find(name);
|
||||||
|
if (tit == meshTextures.end() || !tit->second) continue;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tit->second->getTexID());
|
||||||
|
pit->second.RenderVBO(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader("night_fog");
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNight);
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", plCount);
|
||||||
|
if (plCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
|
||||||
|
}
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::drawNightCpu(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount) {
|
||||||
|
AnimationState drawState = resolveActiveState();
|
||||||
|
auto it = animations.find(drawState);
|
||||||
|
if (it == animations.end()) return;
|
||||||
|
|
||||||
|
static const std::string nightShader = "night_fog";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(nightShader);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
const float playerEyePosNight[3] = { 0.0f, 0.0f, -Environment::zoom };
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNight);
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", plCount);
|
||||||
|
if (plCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
renderer.ScaleMatrix(modelScale);
|
||||||
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
|
||||||
|
auto& anim = it->second;
|
||||||
|
for (const auto& name : anim.model.meshNamesOrdered) {
|
||||||
|
auto mit = anim.model.meshes.find(name);
|
||||||
|
if (mit == anim.model.meshes.end()) continue;
|
||||||
|
auto tit = meshTextures.find(name);
|
||||||
|
if (tit == meshTextures.end() || !tit->second) continue;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tit->second->getTexID());
|
||||||
|
modelMutable.AssignFrom(mit->second.mesh);
|
||||||
|
modelMutable.RefreshVBO();
|
||||||
|
renderer.DrawVertexRenderStruct(modelMutable);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNight);
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Night pass with spot-light + shadow ====================
|
||||||
|
|
||||||
|
void Character::drawNightWithShadow(Renderer& renderer,
|
||||||
|
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
|
||||||
|
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex)
|
||||||
|
{
|
||||||
|
if (!enabled) return;
|
||||||
|
if (hitSparkEmitter.isConfigured() && hitSparkEmitter.getActiveParticleCount() > 0) {
|
||||||
|
hitSparkEmitter.draw(renderer, 1.0f, Environment::width, Environment::height, false);
|
||||||
|
}
|
||||||
|
renderer.RenderUniform1f("uAlpha", 1.0f);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
if (!isPlayer && hp <= 0) return;
|
||||||
|
|
||||||
|
if (useGpuSkinning) {
|
||||||
|
drawNightGpuSkinningWithShadow(renderer, plPosEye, plDirEye, plColors, plCount, lightFromCamera, shadowMapTex);
|
||||||
|
} else {
|
||||||
|
drawNightCpuWithShadow(renderer, plPosEye, plDirEye, plColors, plCount, lightFromCamera, shadowMapTex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::drawNightGpuSkinningWithShadow(Renderer& renderer,
|
||||||
|
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
|
||||||
|
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex)
|
||||||
|
{
|
||||||
|
AnimationState drawState = resolveActiveState();
|
||||||
|
auto it = animations.find(drawState);
|
||||||
|
if (it == animations.end()) return;
|
||||||
|
if (!prepareGpuSkinning()) return;
|
||||||
|
|
||||||
|
static const std::string nightShadowSkinningShader = "night_fog_skinning_shadow";
|
||||||
|
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(nightShadowSkinningShader);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.RenderUniform1i("uShadowMap", 1);
|
||||||
|
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
|
||||||
|
// First light's eye-space direction used for shadow bias
|
||||||
|
if (plCount > 0) renderer.RenderUniform3fv("uLightDir", plDirEye);
|
||||||
|
|
||||||
|
const float playerEyePosNightShadow[3] = { 0.0f, 0.0f, -Environment::zoom };
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNightShadow);
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", plCount);
|
||||||
|
if (plCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
renderer.ScaleMatrix(modelScale);
|
||||||
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
|
||||||
|
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
|
||||||
|
static_cast<int>(it->second.gpuSkinningShaderData.skinningMatrices.size()), false,
|
||||||
|
it->second.gpuSkinningShaderData.skinningMatrices[0].data());
|
||||||
|
|
||||||
|
for (const auto& name : it->second.model.meshNamesOrdered) {
|
||||||
|
auto pit = it->second.gpuSkinningShaderData.perMesh.find(name);
|
||||||
|
if (pit == it->second.gpuSkinningShaderData.perMesh.end()) continue;
|
||||||
|
auto tit = meshTextures.find(name);
|
||||||
|
if (tit == meshTextures.end() || !tit->second) continue;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tit->second->getTexID());
|
||||||
|
pit->second.RenderVBO(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
// Weapon uses the non-skinning night shadow shader
|
||||||
|
renderer.shaderManager.PushShader("night_fog_shadow");
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.RenderUniform1i("uShadowMap", 1);
|
||||||
|
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
|
||||||
|
if (plCount > 0) renderer.RenderUniform3fv("uLightDir", plDirEye);
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNightShadow);
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", plCount);
|
||||||
|
if (plCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
|
||||||
|
}
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Character::drawNightCpuWithShadow(Renderer& renderer,
|
||||||
|
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
|
||||||
|
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex)
|
||||||
|
{
|
||||||
|
AnimationState drawState = resolveActiveState();
|
||||||
|
auto it = animations.find(drawState);
|
||||||
|
if (it == animations.end()) return;
|
||||||
|
|
||||||
|
static const std::string nightShadowShader = "night_fog_shadow";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(nightShadowShader);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.RenderUniform1i("uShadowMap", 1);
|
||||||
|
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
|
||||||
|
if (plCount > 0) renderer.RenderUniform3fv("uLightDir", plDirEye);
|
||||||
|
|
||||||
|
const float playerEyePosNightShadow[3] = { 0.0f, 0.0f, -Environment::zoom };
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNightShadow);
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", plCount);
|
||||||
|
if (plCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", plCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", plCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", plCount, plColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
renderer.ScaleMatrix(modelScale);
|
||||||
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
|
||||||
|
auto& anim = it->second;
|
||||||
|
for (const auto& name : anim.model.meshNamesOrdered) {
|
||||||
|
auto mit = anim.model.meshes.find(name);
|
||||||
|
if (mit == anim.model.meshes.end()) continue;
|
||||||
|
auto tit = meshTextures.find(name);
|
||||||
|
if (tit == meshTextures.end() || !tit->second) continue;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tit->second->getTexID());
|
||||||
|
modelMutable.AssignFrom(mit->second.mesh);
|
||||||
|
modelMutable.RefreshVBO();
|
||||||
|
renderer.DrawVertexRenderStruct(modelMutable);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePosNightShadow);
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
}
|
||||||
|
|
||||||
void Character::setupHitSparks(std::shared_ptr<Texture> sparkTexture)
|
void Character::setupHitSparks(std::shared_ptr<Texture> sparkTexture)
|
||||||
{
|
{
|
||||||
hitSparkEmitter.setTexture(sparkTexture);
|
hitSparkEmitter.setTexture(sparkTexture);
|
||||||
|
|||||||
@ -51,6 +51,10 @@ public:
|
|||||||
void draw(Renderer& renderer);
|
void draw(Renderer& renderer);
|
||||||
void drawShadowDepth(Renderer& renderer);
|
void drawShadowDepth(Renderer& renderer);
|
||||||
void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
||||||
|
void drawNight(Renderer& renderer, const float* pointLightPosEye, const float* pointLightDirEye, const float* pointLightColors, int pointLightCount);
|
||||||
|
void drawNightWithShadow(Renderer& renderer,
|
||||||
|
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
|
||||||
|
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex);
|
||||||
|
|
||||||
// Character-to-character collision (XZ-plane). Used by Location to keep
|
// Character-to-character collision (XZ-plane). Used by Location to keep
|
||||||
// player/NPCs from walking through each other.
|
// player/NPCs from walking through each other.
|
||||||
@ -201,6 +205,16 @@ private:
|
|||||||
// Shadow: draw with shadow-aware shaders
|
// Shadow: draw with shadow-aware shaders
|
||||||
void drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
void drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
||||||
void drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
void drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
|
||||||
|
// Night: draw with spot-light shaders
|
||||||
|
void drawNightGpuSkinning(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount);
|
||||||
|
void drawNightCpu(Renderer& renderer, const float* plPosEye, const float* plDirEye, const float* plColors, int plCount);
|
||||||
|
// Night: draw with spot-light + shadow shaders
|
||||||
|
void drawNightGpuSkinningWithShadow(Renderer& renderer,
|
||||||
|
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
|
||||||
|
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex);
|
||||||
|
void drawNightCpuWithShadow(Renderer& renderer,
|
||||||
|
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
|
||||||
|
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
35
src/Game.cpp
35
src/Game.cpp
@ -159,6 +159,10 @@ namespace ZL
|
|||||||
renderer.shaderManager.AddShaderFromFiles("fog_shadow", "resources/shaders/fog_shadow.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("fog_shadow", "resources/shaders/fog_shadow.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE);
|
||||||
std::cout << "Load resurces step 12x5" << std::endl;
|
std::cout << "Load resurces step 12x5" << std::endl;
|
||||||
renderer.shaderManager.AddShaderFromFiles("fog_skinning_shadow", "resources/shaders/fog_skinning_shadow.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("fog_skinning_shadow", "resources/shaders/fog_skinning_shadow.vertex", "resources/shaders/fog_shadow_web.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog", "resources/shaders/night_fog.vertex", "resources/shaders/night_fog_web.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog_skinning", "resources/shaders/night_fog_skinning.vertex", "resources/shaders/night_fog_web.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog_shadow", "resources/shaders/night_fog_shadow.vertex", "resources/shaders/night_fog_shadow_web.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog_skinning_shadow", "resources/shaders/night_fog_skinning_shadow.vertex", "resources/shaders/night_fog_shadow_web.fragment", CONST_ZIP_FILE);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE);
|
||||||
@ -181,6 +185,10 @@ namespace ZL
|
|||||||
renderer.shaderManager.AddShaderFromFiles("skinning_shadow", "resources/shaders/skinning_shadow.vertex", "resources/shaders/default_shadow_desktop.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("skinning_shadow", "resources/shaders/skinning_shadow.vertex", "resources/shaders/default_shadow_desktop.fragment", CONST_ZIP_FILE);
|
||||||
renderer.shaderManager.AddShaderFromFiles("fog_shadow", "resources/shaders/fog_shadow.vertex", "resources/shaders/fog_shadow_desktop.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("fog_shadow", "resources/shaders/fog_shadow.vertex", "resources/shaders/fog_shadow_desktop.fragment", CONST_ZIP_FILE);
|
||||||
renderer.shaderManager.AddShaderFromFiles("fog_skinning_shadow", "resources/shaders/fog_skinning_shadow.vertex", "resources/shaders/fog_shadow_desktop.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("fog_skinning_shadow", "resources/shaders/fog_skinning_shadow.vertex", "resources/shaders/fog_shadow_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog", "resources/shaders/night_fog.vertex", "resources/shaders/night_fog_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog_skinning", "resources/shaders/night_fog_skinning.vertex", "resources/shaders/night_fog_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog_shadow", "resources/shaders/night_fog_shadow.vertex", "resources/shaders/night_fog_shadow_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("night_fog_skinning_shadow", "resources/shaders/night_fog_skinning_shadow.vertex", "resources/shaders/night_fog_shadow_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -414,6 +422,18 @@ namespace ZL
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add test spotlight to every location for night-mode testing.
|
||||||
|
{
|
||||||
|
PointLight testLight;
|
||||||
|
//testLight.position = Eigen::Vector3f(-3.5951f, 3.0f, 0.280929f);
|
||||||
|
testLight.position = Eigen::Vector3f(-3.5951f, 6.0f, 0.280929f);
|
||||||
|
testLight.direction = Eigen::Vector3f(0.0f, -1.0f, 0.0f); // straight down
|
||||||
|
//testLight.color = Eigen::Vector3f(2.0f, 1.6f, 1.2f);
|
||||||
|
testLight.color = Eigen::Vector3f(4.0f, 3.2f, 2.4f);
|
||||||
|
for (auto& [name, loc] : locations)
|
||||||
|
loc->pointLights.push_back(testLight);
|
||||||
|
}
|
||||||
|
|
||||||
currentLocation = locations["location_dorm"];
|
currentLocation = locations["location_dorm"];
|
||||||
currentLocation->scriptEngine.callLocationEnterCallback();
|
currentLocation->scriptEngine.callLocationEnterCallback();
|
||||||
|
|
||||||
@ -520,13 +540,18 @@ namespace ZL
|
|||||||
{
|
{
|
||||||
if (currentLocation)
|
if (currentLocation)
|
||||||
{
|
{
|
||||||
// Sync global darklands flag so Location's raycast and draw functions see it.
|
// Sync global flags so Location's draw functions see them.
|
||||||
currentLocation->isDarklands = isDarklands;
|
currentLocation->isDarklands = isDarklands;
|
||||||
|
currentLocation->isNight = isNight;
|
||||||
|
|
||||||
if (isDarklands) {
|
if (isDarklands) {
|
||||||
currentLocation->drawGameDarklands();
|
currentLocation->drawGameDarklands();
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
else if (isNight) {
|
||||||
|
currentLocation->drawGameNight();
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
else if (currentLocation->shadowMap) {
|
else if (currentLocation->shadowMap) {
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
currentLocation->drawShadowDepthPass();
|
currentLocation->drawShadowDepthPass();
|
||||||
@ -727,6 +752,13 @@ namespace ZL
|
|||||||
|
|
||||||
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
|
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
|
||||||
switch (event.key.keysym.sym) {
|
switch (event.key.keysym.sym) {
|
||||||
|
case SDLK_9:
|
||||||
|
if (editorMode == EditorMode::InteractiveObjects && currentLocation) {
|
||||||
|
currentLocation->editor.selectInteractiveObject(9);
|
||||||
|
} else {
|
||||||
|
isNight = !isNight;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SDLK_0:
|
case SDLK_0:
|
||||||
case SDLK_1:
|
case SDLK_1:
|
||||||
case SDLK_2:
|
case SDLK_2:
|
||||||
@ -736,7 +768,6 @@ namespace ZL
|
|||||||
case SDLK_6:
|
case SDLK_6:
|
||||||
case SDLK_7:
|
case SDLK_7:
|
||||||
case SDLK_8:
|
case SDLK_8:
|
||||||
case SDLK_9:
|
|
||||||
if (editorMode == EditorMode::InteractiveObjects && currentLocation) {
|
if (editorMode == EditorMode::InteractiveObjects && currentLocation) {
|
||||||
currentLocation->editor.selectInteractiveObject(event.key.keysym.sym - SDLK_0);
|
currentLocation->editor.selectInteractiveObject(event.key.keysym.sym - SDLK_0);
|
||||||
} else if (event.key.keysym.sym == SDLK_0) {
|
} else if (event.key.keysym.sym == SDLK_0) {
|
||||||
|
|||||||
@ -52,6 +52,9 @@ namespace ZL {
|
|||||||
// Returns false if a transition is already in progress.
|
// Returns false if a transition is already in progress.
|
||||||
bool startDarklandsTransition();
|
bool startDarklandsTransition();
|
||||||
|
|
||||||
|
// Global night mode state — persists across location transitions.
|
||||||
|
bool isNight = false;
|
||||||
|
|
||||||
Inventory inventory;
|
Inventory inventory;
|
||||||
InteractiveObject* pickedUpObject = nullptr;
|
InteractiveObject* pickedUpObject = nullptr;
|
||||||
|
|
||||||
|
|||||||
180
src/Location.cpp
180
src/Location.cpp
@ -9,6 +9,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
|
#include <limits>
|
||||||
#include "GameConstants.h"
|
#include "GameConstants.h"
|
||||||
#include "Character.h"
|
#include "Character.h"
|
||||||
#include "external/nlohmann/json.hpp"
|
#include "external/nlohmann/json.hpp"
|
||||||
@ -878,6 +879,185 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Location::drawNightShadowDepthPass(const PointLight& light)
|
||||||
|
{
|
||||||
|
if (!shadowMap) return;
|
||||||
|
static constexpr float kSpotFovY = static_cast<float>(M_PI) * 0.5f; // 90°
|
||||||
|
shadowMap->updateSpotlightMatrix(light.position, light.direction, kSpotFovY, 0.1f, 20.0f);
|
||||||
|
shadowMap->bind();
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader("shadow_depth");
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(kSpotFovY, 1.0f, 0.1f, 20.0f);
|
||||||
|
renderer.PushSpecialMatrix(shadowMap->getLightViewMatrix());
|
||||||
|
|
||||||
|
for (auto& [name, gameObj] : gameObjects) {
|
||||||
|
renderer.DrawVertexRenderStruct(gameObj.mesh);
|
||||||
|
}
|
||||||
|
for (auto& intObj : interactiveObjects) {
|
||||||
|
if (intObj.isActive && intObj.loadedObject.texture) {
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix(intObj.position);
|
||||||
|
renderer.DrawVertexRenderStruct(intObj.loadedObject.mesh);
|
||||||
|
renderer.PopMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (player) player->drawShadowDepth(renderer);
|
||||||
|
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
|
||||||
|
|
||||||
|
renderer.PopMatrix(); // light view
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
shadowMap->unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Location::drawGameNight()
|
||||||
|
{
|
||||||
|
// --- Find nearest spotlight for shadow casting ---
|
||||||
|
const PointLight* shadowLight = nullptr;
|
||||||
|
if (player && !pointLights.empty()) {
|
||||||
|
float minDist = FLT_MAX;
|
||||||
|
for (const auto& pl : pointLights) {
|
||||||
|
const float d = (pl.position - player->position).norm();
|
||||||
|
if (d < minDist) { minDist = d; shadowLight = &pl; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bool hasShadows = (shadowMap != nullptr && shadowLight != nullptr);
|
||||||
|
|
||||||
|
if (hasShadows) {
|
||||||
|
drawNightShadowDepthPass(*shadowLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main render pass ---
|
||||||
|
glClearColor(0.01f, 0.01f, 0.05f, 1.0f);
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
const std::string mainShader = hasShadows ? "night_fog_shadow" : "night_fog";
|
||||||
|
renderer.shaderManager.PushShader(mainShader);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
|
||||||
|
if (hasShadows) {
|
||||||
|
renderer.RenderUniform1i("uShadowMap", 1);
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthTexture());
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float playerEyePos[3] = { 0.0f, 0.0f, -Environment::zoom };
|
||||||
|
renderer.RenderUniform3fv("uPlayerEyePos", playerEyePos);
|
||||||
|
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
renderer.PushMatrix();
|
||||||
|
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom });
|
||||||
|
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
const Eigen::Vector3f& camTarget = player ? player->position : Eigen::Vector3f::Zero();
|
||||||
|
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||||
|
|
||||||
|
cameraViewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||||
|
|
||||||
|
// Transform spot lights to eye space and build uniform arrays (max 4)
|
||||||
|
static constexpr int MAX_POINT_LIGHTS = 4;
|
||||||
|
float plPosEye[MAX_POINT_LIGHTS * 3] = {};
|
||||||
|
float plDirEye[MAX_POINT_LIGHTS * 3] = {};
|
||||||
|
float plColors[MAX_POINT_LIGHTS * 3] = {};
|
||||||
|
const Eigen::Matrix3f camRot = cameraViewMatrix.block<3, 3>(0, 0);
|
||||||
|
const int lightCount = min(static_cast<int>(pointLights.size()), MAX_POINT_LIGHTS);
|
||||||
|
for (int i = 0; i < lightCount; ++i) {
|
||||||
|
const Eigen::Vector4f worldPos(pointLights[i].position.x(), pointLights[i].position.y(), pointLights[i].position.z(), 1.0f);
|
||||||
|
const Eigen::Vector4f eyePos4 = cameraViewMatrix * worldPos;
|
||||||
|
plPosEye[i * 3 + 0] = eyePos4.x();
|
||||||
|
plPosEye[i * 3 + 1] = eyePos4.y();
|
||||||
|
plPosEye[i * 3 + 2] = eyePos4.z();
|
||||||
|
const Eigen::Vector3f eyeDir = camRot * pointLights[i].direction;
|
||||||
|
plDirEye[i * 3 + 0] = eyeDir.x();
|
||||||
|
plDirEye[i * 3 + 1] = eyeDir.y();
|
||||||
|
plDirEye[i * 3 + 2] = eyeDir.z();
|
||||||
|
plColors[i * 3 + 0] = pointLights[i].color.x();
|
||||||
|
plColors[i * 3 + 1] = pointLights[i].color.y();
|
||||||
|
plColors[i * 3 + 2] = pointLights[i].color.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute light-from-camera matrix for shadow lookup
|
||||||
|
Eigen::Matrix4f lightFromCamera = Eigen::Matrix4f::Identity();
|
||||||
|
if (hasShadows) {
|
||||||
|
lightFromCamera = shadowMap->getLightSpaceMatrix() * cameraViewMatrix.inverse();
|
||||||
|
renderer.RenderUniformMatrix4fv("uLightFromCamera", false, lightFromCamera.data());
|
||||||
|
// Pass first light's eye-space direction as uLightDir for shadow bias
|
||||||
|
renderer.RenderUniform3fv("uLightDir", plDirEye);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.RenderUniform1i("uPointLightCount", lightCount);
|
||||||
|
if (lightCount > 0) {
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightPos[0]", lightCount, plPosEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightDir[0]", lightCount, plDirEye);
|
||||||
|
renderer.RenderUniform3fvArray("uPointLightColor[0]", lightCount, plColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uAlpha", 1.0f);
|
||||||
|
for (auto& [name, gameObj] : gameObjects) {
|
||||||
|
if (!gameObj.texture) continue;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gameObj.texture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(gameObj.mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& intObj : interactiveObjects) {
|
||||||
|
if (intObj.isActive) {
|
||||||
|
intObj.draw(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uAlpha", 1.0f);
|
||||||
|
if (player) player->prepareHitSparksForDraw(cameraViewMatrix);
|
||||||
|
for (auto& npc : npcs) npc->prepareHitSparksForDraw(cameraViewMatrix);
|
||||||
|
for (auto& tz : teleportZones) tz.prepareForDraw(cameraViewMatrix);
|
||||||
|
|
||||||
|
if (hasShadows) {
|
||||||
|
if (player) player->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount, lightFromCamera, shadowMap->getDepthTexture());
|
||||||
|
for (auto& npc : npcs) npc->drawNightWithShadow(renderer, plPosEye, plDirEye, plColors, lightCount, lightFromCamera, shadowMap->getDepthTexture());
|
||||||
|
} else {
|
||||||
|
if (player) player->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount);
|
||||||
|
for (auto& npc : npcs) npc->drawNight(renderer, plPosEye, plDirEye, plColors, lightCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& tz : teleportZones) tz.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||||
|
|
||||||
|
if (editorMode == EditorMode::Navigation) {
|
||||||
|
editor.drawNavigation();
|
||||||
|
editor.drawPoints();
|
||||||
|
}
|
||||||
|
if (editorMode == EditorMode::InteractiveObjects) {
|
||||||
|
editor.drawInteractiveObjectBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
if (npcNameText) {
|
||||||
|
Eigen::Matrix4f proj = MakePerspectiveMatrix(1.0f / 1.5f,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||||
|
for (auto& npc : npcs) {
|
||||||
|
if (npc) npc->drawName(*npcNameText, cameraViewMatrix, proj);
|
||||||
|
}
|
||||||
|
if (player) player->drawHealthBar(renderer, cameraViewMatrix, proj);
|
||||||
|
for (auto& npc : npcs) {
|
||||||
|
if (npc) npc->drawHealthBar(renderer, cameraViewMatrix, proj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available)
|
bool Location::setNavigationAreaAvailable(const std::string& areaName, bool available)
|
||||||
{
|
{
|
||||||
if (!navigation) return false;
|
if (!navigation) return false;
|
||||||
|
|||||||
@ -20,6 +20,13 @@
|
|||||||
namespace ZL
|
namespace ZL
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct PointLight
|
||||||
|
{
|
||||||
|
Eigen::Vector3f position; // world space
|
||||||
|
Eigen::Vector3f direction; // world space, unit vector the cone points toward
|
||||||
|
Eigen::Vector3f color; // RGB, values > 1.0 increase intensity
|
||||||
|
};
|
||||||
|
|
||||||
struct TriggerZone
|
struct TriggerZone
|
||||||
{
|
{
|
||||||
std::string id;
|
std::string id;
|
||||||
@ -83,9 +90,12 @@ namespace ZL
|
|||||||
|
|
||||||
std::vector<TriggerZone> triggerZones;
|
std::vector<TriggerZone> triggerZones;
|
||||||
|
|
||||||
|
std::vector<PointLight> pointLights;
|
||||||
|
|
||||||
// Set by Game and kept in sync across location transitions.
|
// Set by Game and kept in sync across location transitions.
|
||||||
// Read by draw functions and raycast — do not write from Location code.
|
// Read by draw functions and raycast — do not write from Location code.
|
||||||
bool isDarklands = false;
|
bool isDarklands = false;
|
||||||
|
bool isNight = false;
|
||||||
|
|
||||||
// Called when the player successfully taps the ground and a floor walk target is set.
|
// Called when the player successfully taps the ground and a floor walk target is set.
|
||||||
// Used by the tutorial system to detect the "tap to walk" gesture.
|
// Used by the tutorial system to detect the "tap to walk" gesture.
|
||||||
@ -122,6 +132,8 @@ namespace ZL
|
|||||||
void drawShadowDepthPass();
|
void drawShadowDepthPass();
|
||||||
void drawGameWithShadows();
|
void drawGameWithShadows();
|
||||||
void drawGameDarklands();
|
void drawGameDarklands();
|
||||||
|
void drawGameNight();
|
||||||
|
void drawNightShadowDepthPass(const PointLight& light);
|
||||||
|
|
||||||
bool setNavigationAreaAvailable(const std::string& areaName, bool available);
|
bool setNavigationAreaAvailable(const std::string& areaName, bool available);
|
||||||
|
|
||||||
|
|||||||
@ -825,6 +825,16 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::RenderUniform3fvArray(const std::string& uniformName, int count, const float* value)
|
||||||
|
{
|
||||||
|
auto shader = shaderManager.GetCurrentShader();
|
||||||
|
auto uniform = shader->uniformList.find(uniformName);
|
||||||
|
if (uniform != shader->uniformList.end())
|
||||||
|
{
|
||||||
|
glUniform3fv(uniform->second, count, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::RenderUniform4fv(const std::string& uniformName, const float* value)
|
void Renderer::RenderUniform4fv(const std::string& uniformName, const float* value)
|
||||||
{
|
{
|
||||||
auto shader = shaderManager.GetCurrentShader();
|
auto shader = shaderManager.GetCurrentShader();
|
||||||
|
|||||||
@ -135,6 +135,7 @@ namespace ZL {
|
|||||||
void RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value);
|
void RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value);
|
||||||
void RenderUniform1i(const std::string& uniformName, const int value);
|
void RenderUniform1i(const std::string& uniformName, const int value);
|
||||||
void RenderUniform3fv(const std::string& uniformName, const float* value);
|
void RenderUniform3fv(const std::string& uniformName, const float* value);
|
||||||
|
void RenderUniform3fvArray(const std::string& uniformName, int count, const float* value);
|
||||||
void RenderUniform4fv(const std::string& uniformName, const float* value);
|
void RenderUniform4fv(const std::string& uniformName, const float* value);
|
||||||
void RenderUniform1f(const std::string& uniformName, float value);
|
void RenderUniform1f(const std::string& uniformName, float value);
|
||||||
|
|
||||||
|
|||||||
@ -133,6 +133,29 @@ namespace ZL {
|
|||||||
lightSpaceMatrix = lightProjectionMatrix * lightViewMatrix;
|
lightSpaceMatrix = lightProjectionMatrix * lightViewMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Eigen::Matrix4f perspective(float fovY, float aspect, float zNear, float zFar) {
|
||||||
|
float t = std::tan(fovY * 0.5f);
|
||||||
|
Eigen::Matrix4f m = Eigen::Matrix4f::Zero();
|
||||||
|
m(0, 0) = 1.0f / (aspect * t);
|
||||||
|
m(1, 1) = 1.0f / t;
|
||||||
|
m(2, 2) = -(zFar + zNear) / (zFar - zNear);
|
||||||
|
m(2, 3) = -(2.0f * zFar * zNear) / (zFar - zNear);
|
||||||
|
m(3, 2) = -1.0f;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowMap::updateSpotlightMatrix(const Eigen::Vector3f& lightPos,
|
||||||
|
const Eigen::Vector3f& lightDir,
|
||||||
|
float fovY, float nearZ, float farZ) {
|
||||||
|
Eigen::Vector3f d = lightDir.normalized();
|
||||||
|
Eigen::Vector3f up(0.f, 1.f, 0.f);
|
||||||
|
if (std::abs(d.dot(up)) > 0.99f)
|
||||||
|
up = Eigen::Vector3f(1.f, 0.f, 0.f);
|
||||||
|
lightViewMatrix = lookAt(lightPos, lightPos + d, up);
|
||||||
|
lightProjectionMatrix = perspective(fovY, 1.0f, nearZ, farZ);
|
||||||
|
lightSpaceMatrix = lightProjectionMatrix * lightViewMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
void ShadowMap::bind() {
|
void ShadowMap::bind() {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
glViewport(0, 0, resolution, resolution);
|
glViewport(0, 0, resolution, resolution);
|
||||||
|
|||||||
@ -29,6 +29,9 @@ namespace ZL {
|
|||||||
|
|
||||||
void setLightDirection(const Eigen::Vector3f& dir);
|
void setLightDirection(const Eigen::Vector3f& dir);
|
||||||
void updateLightSpaceMatrix(const Eigen::Vector3f& sceneCenter);
|
void updateLightSpaceMatrix(const Eigen::Vector3f& sceneCenter);
|
||||||
|
void updateSpotlightMatrix(const Eigen::Vector3f& lightPos,
|
||||||
|
const Eigen::Vector3f& lightDir,
|
||||||
|
float fovY, float nearZ, float farZ);
|
||||||
|
|
||||||
void bind();
|
void bind();
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user