Add lightmap and dynamic lights
This commit is contained in:
parent
23a5b05e45
commit
3dbb4d7b9c
3 changed files with 139 additions and 7 deletions
|
|
@ -237,7 +237,7 @@ void VkTextureManager::CreateGamePalette()
|
|||
{
|
||||
GamePalette = ImageBuilder()
|
||||
.Format(VK_FORMAT_B8G8R8A8_UNORM)
|
||||
.Size(256, 1)
|
||||
.Size(512, 512)
|
||||
.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||
.DebugName("VkDescriptorSetManager.GamePalette")
|
||||
.Create(fb->GetDevice());
|
||||
|
|
@ -250,6 +250,25 @@ void VkTextureManager::CreateGamePalette()
|
|||
|
||||
void VkTextureManager::SetGamePalette()
|
||||
{
|
||||
std::shared_ptr<void> data(new uint32_t[512 * 512], [](void* p) { delete[](uint32_t*)p; });
|
||||
uint8_t* lut = (uint8_t*)data.get();
|
||||
for (int r = 0; r < 64; r++)
|
||||
{
|
||||
for (int g = 0; g < 64; g++)
|
||||
{
|
||||
for (int b = 0; b < 64; b++)
|
||||
{
|
||||
// Do not tonemap this. Must match the RGB666 lookup table from the software renderer exactly.
|
||||
PalEntry color = GPalette.BaseColors[ColorMatcher.Pick((r << 2) | (r >> 4), (g << 2) | (g >> 4), (b << 2) | (b >> 4))];
|
||||
int index = ((r * 64 + g) * 64 + b) * 4;
|
||||
lut[index] = color.b;
|
||||
lut[index + 1] = color.g;
|
||||
lut[index + 2] = color.r;
|
||||
lut[index + 3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
PipelineBarrier()
|
||||
|
|
@ -257,21 +276,21 @@ void VkTextureManager::SetGamePalette()
|
|||
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
|
||||
auto stagingBuffer = BufferBuilder()
|
||||
.Size(256 * 4)
|
||||
.Size(512 * 512 * 4)
|
||||
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
|
||||
.DebugName("VkDescriptorSetManager.GamePaletteStagingBuffer")
|
||||
.Create(fb->GetDevice());
|
||||
|
||||
void* data = stagingBuffer->Map(0, 256 * 4);
|
||||
memcpy(data, GPalette.BaseColors, 256 * 4);
|
||||
void* dest = stagingBuffer->Map(0, 512 * 512 * 4);
|
||||
memcpy(dest, data.get(), 512 * 512 * 4);
|
||||
stagingBuffer->Unmap();
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageExtent.width = 256;
|
||||
region.imageExtent.height = 1;
|
||||
region.imageExtent.width = 512;
|
||||
region.imageExtent.height = 512;
|
||||
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, GamePalette->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#endif
|
||||
|
||||
#define BrdfLUT 1 // the BRDF convoluted texture is always in this texture slot
|
||||
#define PaletteLUT 2 // the RGB666 lookup table from a color to the game palette is always in this texture slot
|
||||
|
||||
#define uObjectColor data[uDataIndex].uObjectColor
|
||||
#define uObjectColor2 data[uDataIndex].uObjectColor2
|
||||
|
|
|
|||
|
|
@ -6,6 +6,23 @@
|
|||
#include "shaders/scene/material.glsl"
|
||||
#include "shaders/scene/fogball.glsl"
|
||||
|
||||
#ifndef SIMPLE3D
|
||||
vec3 swLightContribution(DynLightInfo light, vec3 normal);
|
||||
float distanceAttenuation(float dist, float radius, float strength, float linearity);
|
||||
float spotLightAttenuation(vec3 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle);
|
||||
float traceSun(vec3 SunDir);
|
||||
float shadowAttenuation(vec3 lightpos, int shadowIndex, float softShadowRadius, int flags);
|
||||
#endif
|
||||
|
||||
vec3 PickGamePaletteColor(vec3 color)
|
||||
{
|
||||
ivec3 c = ivec3(clamp(color.rgb, vec3(0.0), vec3(1.0)) * 63.0 + 0.5);
|
||||
int index = (c.r * 64 + c.g) * 64 + c.b;
|
||||
int tx = index % 512;
|
||||
int ty = index / 512;
|
||||
return texelFetch(textures[PaletteLUT], ivec2(tx, ty), 0).rgb;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Calculate light
|
||||
|
|
@ -38,7 +55,49 @@ vec4 getLightColor(Material material)
|
|||
float shade = 2.0 - (L + 12.0) / 128.0;
|
||||
int light = max(int((shade - vis) * 32), 0);
|
||||
|
||||
return vec4(texelFetch(textures[uColormapIndex], ivec2(color, light), 0).rgb, 1.0);
|
||||
vec3 matColor = texelFetch(textures[uColormapIndex], ivec2(color, 0), 0).rgb;
|
||||
vec4 frag = vec4(texelFetch(textures[uColormapIndex], ivec2(color, light), 0).rgb, 1.0);
|
||||
|
||||
vec4 dynlight = uDynLightColor;
|
||||
|
||||
if (vLightmap.z >= 0.0)
|
||||
{
|
||||
dynlight.rgb += texture(LightMap, vLightmap).rgb;
|
||||
}
|
||||
|
||||
vec3 normal = material.Normal;
|
||||
|
||||
#ifndef SIMPLE3D
|
||||
#ifndef UBERSHADER
|
||||
#ifdef SHADE_VERTEX
|
||||
dynlight.rgb += vLightColor;
|
||||
#else
|
||||
if (uLightIndex >= 0)
|
||||
{
|
||||
ivec4 lightRange = getLightRange();
|
||||
|
||||
if (lightRange.z > lightRange.x)
|
||||
{
|
||||
// modulated lights
|
||||
for(int i=lightRange.x; i<lightRange.y; i++)
|
||||
{
|
||||
dynlight.rgb += swLightContribution(getLights()[i], normal);
|
||||
}
|
||||
|
||||
// subtractive lights
|
||||
for(int i=lightRange.y; i<lightRange.z; i++)
|
||||
{
|
||||
dynlight.rgb -= swLightContribution(getLights()[i], normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
dynlight = desaturate(dynlight);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
frag.rgb = PickGamePaletteColor(frag.rgb + matColor * dynlight.rgb);
|
||||
return frag;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -179,3 +238,56 @@ vec4 ProcessLightMode(Material material)
|
|||
return getLightColor(material);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SIMPLE3D
|
||||
vec3 swLightContribution(DynLightInfo light, vec3 normal)
|
||||
{
|
||||
float lightdistance = distance(light.pos.xyz, pixelpos.xyz);
|
||||
|
||||
if (light.radius < lightdistance)
|
||||
return vec3(0.0); // Early out lights touching surface but not this fragment
|
||||
|
||||
vec3 lightdir = normalize(light.pos.xyz - pixelpos.xyz);
|
||||
|
||||
float dotprod;
|
||||
|
||||
if (!LIGHT_NONORMALS)
|
||||
{
|
||||
dotprod = dot(normal, lightdir);
|
||||
if (dotprod < -0.0001) return vec3(0.0); // light hits from the backside. This can happen with full sector light lists and must be rejected for all cases. Note that this can cause precision issues.
|
||||
}
|
||||
|
||||
float attenuation = distanceAttenuation(lightdistance, light.radius, light.strength, light.linearity);
|
||||
|
||||
if ((light.flags & LIGHTINFO_SPOT) != 0)
|
||||
{
|
||||
attenuation *= spotLightAttenuation(light.pos.xyz, light.spotDir.xyz, light.spotInnerAngle, light.spotOuterAngle);
|
||||
}
|
||||
|
||||
if (!LIGHT_NONORMALS)
|
||||
{
|
||||
if ((light.flags & LIGHTINFO_ATTENUATED) != 0)
|
||||
{
|
||||
attenuation *= clamp(dotprod, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (attenuation > 0.0) // Skip shadow map test if possible
|
||||
{
|
||||
if((light.flags & (LIGHTINFO_SUN | LIGHTINFO_TRACE)) == (LIGHTINFO_SUN | LIGHTINFO_TRACE))
|
||||
{
|
||||
attenuation *= traceSun(lightdir);
|
||||
}
|
||||
else if((light.flags & (LIGHTINFO_SHADOWMAPPED | LIGHTINFO_SUN)) == LIGHTINFO_SHADOWMAPPED)
|
||||
{
|
||||
attenuation *= shadowAttenuation(light.pos.xyz, light.shadowIndex, light.softShadowRadius, light.flags);
|
||||
}
|
||||
|
||||
return light.color.rgb * attenuation;
|
||||
}
|
||||
else
|
||||
{
|
||||
return vec3(0.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue