Add specular highlights to sunlight
This commit is contained in:
parent
924a44e94d
commit
a9c1fdf23a
15 changed files with 193 additions and 30 deletions
|
|
@ -40,6 +40,11 @@ struct HWViewpointUniforms
|
|||
|
||||
int mLightTilesWidth = 0;
|
||||
|
||||
FVector3 SunDir;
|
||||
float Padding = 0.0f;
|
||||
FVector3 SunColor;
|
||||
float SunIntensity = 0.0f;
|
||||
|
||||
FVector3 mCameraNormal;
|
||||
|
||||
void CalcDependencies()
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ void VkLightmapper::Render()
|
|||
.RenderPass(raytrace.renderPass.get())
|
||||
.RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY)
|
||||
.Framebuffer(bakeImage.raytrace.Framebuffer.get())
|
||||
.AddClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.AddClearColor(0.0f, 0.0f, 0.0f, -1.0f)
|
||||
.Execute(cmdbuffer);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
|
|
|
|||
|
|
@ -138,6 +138,9 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni
|
|||
VPUniforms.mPalLightLevels = static_cast<int>(gl_bandedswlight) | (static_cast<int>(gl_fogmode) << 8) | ((int)lightmode << 16);
|
||||
}
|
||||
VPUniforms.mClipLine.X = -10000000.0f;
|
||||
VPUniforms.SunDir = FVector3(level.SunDirection.X, level.SunDirection.Z, level.SunDirection.Y);
|
||||
VPUniforms.SunColor = level.SunColor;
|
||||
VPUniforms.SunIntensity = level.SunIntensity;
|
||||
}
|
||||
mClipper->SetViewpoint(Viewpoint);
|
||||
vClipper->SetViewpoint(Viewpoint);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ vec4 centerFragColor;
|
|||
|
||||
vec4 clampedSample(vec4 f)
|
||||
{
|
||||
return f.a != 0.0 ? f : centerFragColor;
|
||||
return f.a != -1.0 ? f : centerFragColor;
|
||||
}
|
||||
|
||||
void main()
|
||||
|
|
@ -18,7 +18,7 @@ void main()
|
|||
|
||||
centerFragColor = textureOffset(tex, texCoord, ivec2(0, 0));
|
||||
|
||||
if (centerFragColor.a != 0.0)
|
||||
if (centerFragColor.a != -1.0)
|
||||
{
|
||||
#if defined(BLUR_HORIZONTAL)
|
||||
fragcolor =
|
||||
|
|
|
|||
|
|
@ -24,11 +24,12 @@ void main()
|
|||
vec3 origin = worldpos;
|
||||
|
||||
#if defined(USE_SUNLIGHT)
|
||||
vec3 incoming = TraceSunLight(origin, normal);
|
||||
float sunAttenuation = TraceSunAttenuation(origin, normal);
|
||||
#else
|
||||
vec3 incoming = vec3(0.0);
|
||||
float sunAttenuation = 0.0;
|
||||
#endif
|
||||
|
||||
vec3 incoming = vec3(0.0);
|
||||
for (uint j = LightStart; j < LightEnd; j++)
|
||||
{
|
||||
incoming += TraceLight(origin, normal, lights[lightIndexes[j]], 0.0, false);
|
||||
|
|
@ -42,5 +43,5 @@ void main()
|
|||
incoming.rgb *= TraceAmbientOcclusion(origin, normal);
|
||||
#endif
|
||||
|
||||
fragcolor = vec4(incoming, 1.0);
|
||||
fragcolor = vec4(incoming, sunAttenuation);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,27 +4,36 @@ layout(set = 0, binding = 0) uniform sampler2DMS tex;
|
|||
layout(location = 0) in vec2 TexCoord;
|
||||
layout(location = 0) out vec4 fragcolor;
|
||||
|
||||
vec4 samplePixel(ivec2 pos, int count)
|
||||
vec4 samplePixel(ivec2 pos, int samplecount)
|
||||
{
|
||||
vec4 c = vec4(0.0);
|
||||
for (int i = 0; i < count; i++)
|
||||
float count = 0.0;
|
||||
for (int i = 0; i < samplecount; i++)
|
||||
{
|
||||
c += texelFetch(tex, pos, i);
|
||||
vec4 p = texelFetch(tex, pos, i);
|
||||
if (p.a != -1.0)
|
||||
{
|
||||
c += p;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (c.a > 0.0)
|
||||
c /= c.a;
|
||||
return c;
|
||||
if (count == 0.0)
|
||||
return vec4(0.0, 0.0, 0.0, -1.0);
|
||||
else
|
||||
return c / count;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int count = textureSamples(tex);
|
||||
int samplecount = textureSamples(tex);
|
||||
ivec2 size = textureSize(tex);
|
||||
ivec2 pos = ivec2(gl_FragCoord.xy);
|
||||
|
||||
vec4 c = samplePixel(pos, count);
|
||||
if (c.a == 0.0)
|
||||
vec4 c = samplePixel(pos, samplecount);
|
||||
if (c.a == -1.0)
|
||||
{
|
||||
float count = 0.0;
|
||||
c = vec4(0.0, 0.0, 0.0, -1.0);
|
||||
for (int y = -1; y <= 1; y++)
|
||||
{
|
||||
for (int x = -1; x <= 1; x++)
|
||||
|
|
@ -34,12 +43,17 @@ void main()
|
|||
ivec2 pos2;
|
||||
pos2.x = clamp(pos.x + x, 0, size.x - 1);
|
||||
pos2.y = clamp(pos.y + y, 0, size.y - 1);
|
||||
c += samplePixel(pos2, count);
|
||||
vec4 p = samplePixel(pos2, samplecount);
|
||||
if (p.a != -1.0)
|
||||
{
|
||||
c += p;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c.a > 0.0)
|
||||
c /= c.a;
|
||||
if (count != 0.0)
|
||||
c /= count;
|
||||
}
|
||||
|
||||
fragcolor = c;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,19 @@ vec2 GetSurfaceUV(int primitiveIndex, vec3 primitiveWeights)
|
|||
vertices[elements[index + 0]].uv * primitiveWeights.z;
|
||||
}
|
||||
|
||||
float PassAttenuationThroughSurface(SurfaceInfo surface, vec2 uv, float attentuation)
|
||||
{
|
||||
if (surface.TextureIndex == 0)
|
||||
{
|
||||
return attentuation;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec4 color = texture(textures[surface.TextureIndex], uv);
|
||||
return attentuation * (1.0 - color.a * surface.Alpha);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 PassRayThroughSurface(SurfaceInfo surface, vec2 uv, vec3 rayColor)
|
||||
{
|
||||
if (surface.TextureIndex == 0)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <shaders/lightmap/montecarlo.glsl>
|
||||
|
||||
vec3 TraceSunRay(vec3 origin, float tmin, vec3 dir, float tmax, vec3 rayColor);
|
||||
float TraceSunRayAttenuation(vec3 origin, float tmin, vec3 dir, float tmax);
|
||||
|
||||
vec3 TraceSunLight(vec3 origin, vec3 normal)
|
||||
{
|
||||
|
|
@ -41,6 +42,44 @@ vec3 TraceSunLight(vec3 origin, vec3 normal)
|
|||
return incoming * angleAttenuation;
|
||||
}
|
||||
|
||||
float TraceSunAttenuation(vec3 origin, vec3 normal)
|
||||
{
|
||||
float angleAttenuation = max(dot(normal, SunDir), 0.0);
|
||||
if (angleAttenuation == 0.0)
|
||||
return 0.0;
|
||||
|
||||
const float minDistance = 0.01;
|
||||
vec3 incoming = vec3(0.0);
|
||||
const float dist = 65536.0;
|
||||
|
||||
float attenuation = 0.0;
|
||||
|
||||
#if defined(USE_SOFTSHADOWS)
|
||||
|
||||
vec3 target = origin + SunDir * dist;
|
||||
vec3 dir = SunDir;
|
||||
vec3 v = (abs(dir.x) > abs(dir.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 xdir = normalize(cross(dir, v));
|
||||
vec3 ydir = cross(dir, xdir);
|
||||
|
||||
float lightsize = 100;
|
||||
int step_count = 10;
|
||||
for (int i = 0; i < step_count; i++)
|
||||
{
|
||||
vec2 gridoffset = getVogelDiskSample(i, step_count, gl_FragCoord.x + gl_FragCoord.y * 13.37) * lightsize;
|
||||
vec3 pos = target + xdir * gridoffset.x + ydir * gridoffset.y;
|
||||
attenuation += TraceSunRayAttenuation(origin, minDistance, normalize(pos - origin), dist) / float(step_count);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
attenuation = TraceSunRayAttenuation(origin, minDistance, SunDir, dist);
|
||||
|
||||
#endif
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
vec3 TraceSunRay(vec3 origin, float tmin, vec3 dir, float tmax, vec3 rayColor)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
|
|
@ -75,3 +114,39 @@ vec3 TraceSunRay(vec3 origin, float tmin, vec3 dir, float tmax, vec3 rayColor)
|
|||
}
|
||||
return vec3(0.0);
|
||||
}
|
||||
|
||||
float TraceSunRayAttenuation(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
float attenuation = 1.0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
TraceResult result = TraceFirstHit(origin, tmin, dir, tmax);
|
||||
|
||||
// Stop if we hit nothing. We have to hit a sky surface to hit the sky.
|
||||
if (result.primitiveIndex == -1)
|
||||
return 0.0;
|
||||
|
||||
SurfaceInfo surface = GetSurface(result.primitiveIndex);
|
||||
|
||||
// Stop if we hit the sky.
|
||||
if (surface.Sky > 0.0)
|
||||
return attenuation;
|
||||
|
||||
// Pass through surface texture
|
||||
attenuation = PassAttenuationThroughSurface(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), attenuation);
|
||||
|
||||
// Stop if there is no light left
|
||||
if (attenuation <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
// Move to surface hit point
|
||||
origin += dir * result.t;
|
||||
tmax -= result.t;
|
||||
if (tmax <= tmin)
|
||||
return 0.0;
|
||||
|
||||
// Move through the portal, if any
|
||||
TransformRay(surface.PortalIndex, origin, dir);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ layout(set = 1, binding = 0, std140) uniform readonly ViewpointUBO
|
|||
|
||||
int uLightTilesWidth; // Levelmesh light tiles
|
||||
|
||||
vec3 SunDir;
|
||||
float Padding;
|
||||
vec3 SunColor;
|
||||
float SunIntensity;
|
||||
|
||||
vec3 uCameraNormal;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -103,15 +103,18 @@ vec4 getLightColor(Material material)
|
|||
//
|
||||
// apply lightmaps
|
||||
//
|
||||
float sunlightAttenuation = 0.0;
|
||||
if (vLightmapIndex != -1)
|
||||
{
|
||||
color.rgb += texture(textures[nonuniformEXT(vLightmapIndex)], vLightmap.xy).rgb;
|
||||
vec4 lightmap = texture(textures[nonuniformEXT(vLightmapIndex)], vLightmap.xy);
|
||||
color.rgb += lightmap.rgb;
|
||||
sunlightAttenuation = lightmap.a;
|
||||
}
|
||||
|
||||
//
|
||||
// apply dynamic lights
|
||||
//
|
||||
vec4 frag = vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a);
|
||||
vec4 frag = vec4(ProcessMaterialLight(material, color.rgb, sunlightAttenuation), material.Base.a * vColor.a);
|
||||
|
||||
//
|
||||
// colored fog
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color, float sunlightAttenuation)
|
||||
{
|
||||
return material.Base.rgb * clamp(color + desaturate(uDynLightColor).rgb, 0.0, 1.4);
|
||||
vec4 dynlight = uDynLightColor;
|
||||
if (sunlightAttenuation > 0.0)
|
||||
{
|
||||
sunlightAttenuation *= clamp(dot(material.Normal, SunDir), 0.0, 1.0);
|
||||
dynlight.rgb += SunColor.rgb * SunIntensity * sunlightAttenuation;
|
||||
}
|
||||
|
||||
return material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4);
|
||||
}
|
||||
|
||||
vec3 ProcessSWLight(Material material)
|
||||
|
|
|
|||
|
|
@ -51,11 +51,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color, float sunlightAttenuation)
|
||||
{
|
||||
vec4 dynlight = uDynLightColor;
|
||||
vec3 normal = material.Normal;
|
||||
|
||||
if (sunlightAttenuation > 0.0)
|
||||
{
|
||||
sunlightAttenuation *= clamp(dot(normal, SunDir), 0.0, 1.0);
|
||||
dynlight.rgb += SunColor.rgb * SunIntensity * sunlightAttenuation;
|
||||
}
|
||||
|
||||
#ifndef UBERSHADER
|
||||
|
||||
#ifdef SHADE_VERTEX
|
||||
|
|
@ -160,7 +166,7 @@
|
|||
}
|
||||
|
||||
#else
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color, float sunlightAttenuation)
|
||||
{
|
||||
return material.Base.rgb;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const float PI = 3.14159265359;
|
||||
const float PBRBrightnessScale = 2.5; // For making non-PBR and PBR lights roughly the same intensity
|
||||
|
||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
||||
{
|
||||
|
|
@ -49,8 +50,6 @@ vec3 ProcessLight(const DynLightInfo light, vec3 albedo, float metallic, float r
|
|||
vec3 L = normalize(light.pos.xyz - pixelpos.xyz);
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
const float brightnessScale = 2.5; // For making non-PBR and PBR lights roughly the same intensity
|
||||
|
||||
float attenuation = distanceAttenuation(distance(light.pos.xyz, pixelpos.xyz), light.radius, light.strength, light.linearity);
|
||||
if ((light.flags & LIGHTINFO_SPOT) != 0)
|
||||
{
|
||||
|
|
@ -71,7 +70,7 @@ vec3 ProcessLight(const DynLightInfo light, vec3 albedo, float metallic, float r
|
|||
attenuation *= shadowAttenuation(light.pos.xyz, light.shadowIndex, light.softShadowRadius, light.flags);
|
||||
}
|
||||
|
||||
vec3 radiance = light.color.rgb * attenuation * brightnessScale;
|
||||
vec3 radiance = light.color.rgb * attenuation * PBRBrightnessScale;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
|
|
@ -91,7 +90,7 @@ vec3 ProcessLight(const DynLightInfo light, vec3 albedo, float metallic, float r
|
|||
return vec3(0.0);
|
||||
}
|
||||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
|
||||
vec3 ProcessMaterialLight(Material material, vec3 ambientLight, float sunlightAttenuation)
|
||||
{
|
||||
vec3 albedo = material.Base.rgb;
|
||||
|
||||
|
|
@ -106,6 +105,27 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight)
|
|||
|
||||
vec3 Lo = uDynLightColor.rgb;
|
||||
|
||||
if (sunlightAttenuation > 0.0)
|
||||
{
|
||||
vec3 L = SunDir;
|
||||
vec3 H = normalize(V + L);
|
||||
|
||||
sunlightAttenuation *= clamp(dot(N, L), 0.0, 1.0);
|
||||
|
||||
vec3 radiance = SunColor * SunIntensity * PBRBrightnessScale * sunlightAttenuation;
|
||||
|
||||
// cook-torrance brdf
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
|
||||
vec3 kS = F;
|
||||
vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic);
|
||||
vec3 nominator = NDF * G * F;
|
||||
float denominator = 4.0 * clamp(dot(N, V), 0.0, 1.0) * clamp(dot(N, L), 0.0, 1.0);
|
||||
vec3 specular = nominator / max(denominator, 0.001);
|
||||
Lo += (kD * albedo / PI + specular) * radiance;
|
||||
}
|
||||
|
||||
#ifndef UBERSHADER
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ vec2 lightAttenuation(DynLightInfo light, vec3 normal, vec3 viewdir, float gloss
|
|||
return vec2(attenuation, attenuation * specularLevel * pow(specAngle, phExp));
|
||||
}
|
||||
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color)
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color, float sunlightAttenuation)
|
||||
{
|
||||
vec4 dynlight = uDynLightColor;
|
||||
vec4 specular = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
|
@ -44,6 +44,17 @@ vec3 ProcessMaterialLight(Material material, vec3 color)
|
|||
vec3 normal = material.Normal;
|
||||
vec3 viewdir = normalize(uCameraPos.xyz - pixelpos.xyz);
|
||||
|
||||
if (sunlightAttenuation > 0.0)
|
||||
{
|
||||
sunlightAttenuation *= clamp(dot(normal, SunDir), 0.0, 1.0);
|
||||
vec3 color = SunColor.rgb * SunIntensity * sunlightAttenuation;
|
||||
vec3 halfdir = normalize(viewdir + SunDir);
|
||||
float specAngle = clamp(dot(halfdir, normal), 0.0f, 1.0f);
|
||||
float phExp = material.Glossiness * 4.0f;
|
||||
dynlight.rgb += color;
|
||||
specular.rgb += color * material.SpecularLevel * pow(specAngle, phExp);
|
||||
}
|
||||
|
||||
#ifndef UBERSHADER
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ struct Material
|
|||
|
||||
vec4 Process(vec4 color);
|
||||
void SetupMaterial(inout Material mat);
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color);
|
||||
vec3 ProcessMaterialLight(Material material, vec3 color, float sunlightAttenuation);
|
||||
vec3 ProcessSWLight(Material material);
|
||||
vec2 GetTexCoord();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue