mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-20 11:35:54 +00:00
Merge 3f96e6c7ee
into 5ed8b7bc9d
This commit is contained in:
commit
5832a1d4c2
7 changed files with 170 additions and 126 deletions
|
@ -218,22 +218,24 @@ static float CalculateLightAttn(const LightPointer* light, Vec3* _ldir, const Ve
|
|||
switch (chan.attnfunc)
|
||||
{
|
||||
case AttenuationFunc::None:
|
||||
{
|
||||
PanicAlertFmt("None lighting in use!");
|
||||
ldir = ldir.Normalized();
|
||||
break;
|
||||
}
|
||||
case AttenuationFunc::Dir:
|
||||
{
|
||||
ldir = ldir.Normalized();
|
||||
if (ldir == Vec3(0.0f, 0.0f, 0.0f))
|
||||
ldir = normal;
|
||||
break;
|
||||
}
|
||||
case AttenuationFunc::Spec:
|
||||
{
|
||||
PanicAlertFmt("Specular lighting in use!");
|
||||
ldir = ldir.Normalized();
|
||||
attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0;
|
||||
Vec3 attLen = Vec3(1.0, attn, attn * attn);
|
||||
Vec3 cosAttn = light->cosatt;
|
||||
Vec3 distAttn = light->distatt;
|
||||
if (chan.diffusefunc != DiffuseFunc::None)
|
||||
distAttn = distAttn.Normalized();
|
||||
|
||||
attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn);
|
||||
break;
|
||||
|
|
|
@ -11,69 +11,97 @@
|
|||
#include "VideoCommon/XFMemory.h"
|
||||
|
||||
static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_data, int index,
|
||||
int litchan_index, bool alpha)
|
||||
AttenuationFunc attn_func, DiffuseFunc diffuse_func, bool alpha)
|
||||
{
|
||||
object.Write(" {{ // {} light {}\n", alpha ? "Alpha" : "Color", index);
|
||||
const char* swizzle = alpha ? "a" : "rgb";
|
||||
const char* swizzle_components = (alpha) ? "" : "3";
|
||||
|
||||
const auto attnfunc =
|
||||
static_cast<AttenuationFunc>((uid_data.attnfunc >> (2 * litchan_index)) & 0x3);
|
||||
const auto diffusefunc =
|
||||
static_cast<DiffuseFunc>((uid_data.diffusefunc >> (2 * litchan_index)) & 0x3);
|
||||
// Create a normalized vector pointing from the light to the current position. We manualy
|
||||
// normalize instead of using normalize() because the raw distance is needed for spot lights.
|
||||
object.Write(" float3 ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index));
|
||||
object.Write(" float dist2 = dot(ldir, ldir);\n"
|
||||
" float dist = sqrt(dist2);\n"
|
||||
" ldir = ldir / dist;\n");
|
||||
|
||||
switch (attnfunc)
|
||||
switch (attn_func)
|
||||
{
|
||||
case AttenuationFunc::None:
|
||||
// This logic correctly reproduces the behavior (if diffuse > 0, then lacc is 255, if it's < 0
|
||||
// lacc is 0, and if it's equal to 0 lacc is unchanged, but with DiffuseFunc::None lacc instead
|
||||
// has the light's color added to it), but may be an overly jank implementation (and might give
|
||||
// incorrect results for a light value of 1/256, for instance; testing is needed)
|
||||
if (diffuse_func == DiffuseFunc::None)
|
||||
object.Write(" float attn = 1.0;\n");
|
||||
else
|
||||
object.Write(" float attn = 1024.0;\n");
|
||||
break;
|
||||
case AttenuationFunc::Dir:
|
||||
object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
|
||||
object.Write("attn = 1.0;\n");
|
||||
object.Write("if (length(ldir) == 0.0)\n\t ldir = _normal;\n");
|
||||
object.Write(" float attn = 1.0;\n");
|
||||
break;
|
||||
case AttenuationFunc::Spec:
|
||||
object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
|
||||
object.Write("attn = (dot(_normal, ldir) >= 0.0) ? max(0.0, dot(_normal, " LIGHT_DIR
|
||||
".xyz)) : 0.0;\n",
|
||||
object.Write(" float cosine = 0.0;\n"
|
||||
" // Ensure that the object is facing the light\n"
|
||||
" if (dot(_normal, ldir) >= 0.0) {{\n"
|
||||
" // Compute the cosine of the angle between the object normal\n"
|
||||
" // and the half-angle direction for the viewer\n"
|
||||
" // (assuming the half-angle direction is a unit vector)\n"
|
||||
" cosine = max(0.0, dot(_normal, " LIGHT_DIR ".xyz));\n",
|
||||
LIGHT_DIR_PARAMS(index));
|
||||
object.Write("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index));
|
||||
object.Write("distAttn = {}(" LIGHT_DISTATT ".xyz);\n",
|
||||
(diffusefunc == DiffuseFunc::None) ? "" : "normalize",
|
||||
LIGHT_DISTATT_PARAMS(index));
|
||||
object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
|
||||
"float3(1.0, attn, attn*attn));\n");
|
||||
object.Write(" }}\n"
|
||||
" // Specular lights use the angle for the denominator as well\n"
|
||||
" dist = cosine;\n"
|
||||
" dist2 = dist * dist;\n");
|
||||
break;
|
||||
case AttenuationFunc::Spot:
|
||||
object.Write("ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index));
|
||||
object.Write("dist2 = dot(ldir, ldir);\n"
|
||||
"dist = sqrt(dist2);\n"
|
||||
"ldir = ldir / dist;\n"
|
||||
"attn = max(0.0, dot(ldir, " LIGHT_DIR ".xyz));\n",
|
||||
object.Write(" // Compute the cosine of the angle between the vector to the object\n"
|
||||
" // and the light's direction (assuming the direction is a unit vector)\n"
|
||||
" float cosine = max(0.0, dot(ldir, " LIGHT_DIR ".xyz));\n",
|
||||
LIGHT_DIR_PARAMS(index));
|
||||
// attn*attn may overflow
|
||||
object.Write("attn = max(0.0, " LIGHT_COSATT ".x + " LIGHT_COSATT ".y*attn + " LIGHT_COSATT
|
||||
".z*attn*attn) / dot(" LIGHT_DISTATT ".xyz, float3(1.0,dist,dist2));\n",
|
||||
LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index),
|
||||
LIGHT_DISTATT_PARAMS(index));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (diffusefunc)
|
||||
if (attn_func == AttenuationFunc::Spot || attn_func == AttenuationFunc::Spec)
|
||||
{
|
||||
object.Write(" float3 cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index));
|
||||
object.Write(" float3 distAttn = " LIGHT_DISTATT ".xyz;\n", LIGHT_DISTATT_PARAMS(index));
|
||||
object.Write(" float cosine2 = cosine * cosine;\n"
|
||||
""
|
||||
" // This is equivalent to dot(cosAttn, float3(1.0, attn, attn*attn)),\n"
|
||||
" // except with spot lights games often don't set the direction value,\n"
|
||||
" // as they configure cosAttn to (1, 0, 0). GX light objects are often\n"
|
||||
" // stack-allocated, so those values are uninitialized and may be\n"
|
||||
" // arbitrary garbage, including NaN or Inf, or become Inf when squared.\n"
|
||||
" float numerator = cosAttn.x; // constant term\n"
|
||||
" if (cosAttn.y != 0.0) numerator += cosAttn.y * cosine; // linear term\n"
|
||||
" if (cosAttn.z != 0.0) numerator += cosAttn.z * cosine2; // quadratic term\n"
|
||||
" // Same with the denominator, though this generally is not garbage\n"
|
||||
" // Note that VertexShaderManager ensures that distAttn is not zero, which\n"
|
||||
" // should prevent division by zero (TODO: what does real hardware do?)\n"
|
||||
" float denominator = distAttn.x; // constant term\n"
|
||||
" if (distAttn.y != 0.0) denominator += distAttn.y * dist; // linear term\n"
|
||||
" if (distAttn.z != 0.0) denominator += distAttn.z * dist2; // quadratic term\n"
|
||||
""
|
||||
" float attn = max(0.0f, numerator / denominator);\n");
|
||||
}
|
||||
|
||||
switch (diffuse_func)
|
||||
{
|
||||
case DiffuseFunc::None:
|
||||
object.Write("lacc.{} += int{}(round(attn * float{}(" LIGHT_COL ")));\n", swizzle,
|
||||
swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
|
||||
object.Write(" float diffuse = 1.0;\n");
|
||||
break;
|
||||
case DiffuseFunc::Sign:
|
||||
case DiffuseFunc::Clamp:
|
||||
object.Write("lacc.{} += int{}(round(attn * {}dot(ldir, _normal)) * float{}(" LIGHT_COL
|
||||
")));\n",
|
||||
swizzle, swizzle_components, diffusefunc != DiffuseFunc::Sign ? "max(0.0," : "(",
|
||||
swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
|
||||
default: // Confirmed by hardware testing that invalid values use this
|
||||
object.Write(" float diffuse = dot(ldir, _normal);\n");
|
||||
break;
|
||||
case DiffuseFunc::Clamp:
|
||||
object.Write(" float diffuse = max(0.0, dot(ldir, _normal));\n");
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
object.Write("\n");
|
||||
object.Write(" lacc.{} += int{}(round(attn * diffuse * float{}(" LIGHT_COL ")));\n", swizzle,
|
||||
swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
|
||||
object.Write(" }}\n");
|
||||
}
|
||||
|
||||
// vertex shader
|
||||
|
@ -84,94 +112,133 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d
|
|||
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data,
|
||||
std::string_view in_color_name, std::string_view dest)
|
||||
{
|
||||
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
|
||||
for (u32 chan = 0; chan < NUM_XF_COLOR_CHANNELS; chan++)
|
||||
{
|
||||
object.Write("{{\n");
|
||||
// Data for alpha is stored after all colors
|
||||
const u32 chan_a = chan + NUM_XF_COLOR_CHANNELS;
|
||||
|
||||
const bool colormatsource = !!(uid_data.matsource & (1 << j));
|
||||
if (colormatsource) // from vertex
|
||||
object.Write("int4 mat = int4(round({}{} * 255.0));\n", in_color_name, j);
|
||||
else // from color
|
||||
object.Write("int4 mat = {}[{}];\n", I_MATERIALS, j + 2);
|
||||
const auto color_matsource = static_cast<MatSource>((uid_data.matsource >> chan) & 1);
|
||||
const auto color_ambsource = static_cast<AmbSource>((uid_data.ambsource >> chan) & 1);
|
||||
const bool color_enable = ((uid_data.enablelighting >> chan) & 1) != 0;
|
||||
const auto alpha_matsource = static_cast<MatSource>((uid_data.matsource >> chan_a) & 1);
|
||||
const auto alpha_ambsource = static_cast<AmbSource>((uid_data.ambsource >> chan_a) & 1);
|
||||
const bool alpha_enable = ((uid_data.enablelighting >> chan_a) & 1) != 0;
|
||||
|
||||
if ((uid_data.enablelighting & (1 << j)) != 0)
|
||||
object.Write("{{\n"
|
||||
" // Lighting for channel {}:\n"
|
||||
" // Color material source: {}\n"
|
||||
" // Color ambient source: {}\n"
|
||||
" // Color lighting enabled: {}\n"
|
||||
" // Alpha material source: {}\n"
|
||||
" // Alpha ambient source: {}\n"
|
||||
" // Alpha lighting enabled: {}\n",
|
||||
chan, color_matsource, color_ambsource, color_enable, alpha_matsource,
|
||||
alpha_ambsource, alpha_enable);
|
||||
|
||||
if (color_matsource == MatSource::Vertex)
|
||||
object.Write(" int4 mat = int4(round({}{} * 255.0));\n", in_color_name, chan);
|
||||
else // from material color register
|
||||
object.Write(" int4 mat = {}[{}];\n", I_MATERIALS, chan + 2);
|
||||
|
||||
if (color_enable)
|
||||
{
|
||||
if ((uid_data.ambsource & (1 << j)) != 0) // from vertex
|
||||
object.Write("lacc = int4(round({}{} * 255.0));\n", in_color_name, j);
|
||||
else // from color
|
||||
object.Write("lacc = {}[{}];\n", I_MATERIALS, j);
|
||||
if (color_ambsource == AmbSource::Vertex)
|
||||
object.Write(" int4 lacc = int4(round({}{} * 255.0));\n", in_color_name, chan);
|
||||
else // from ambient color register
|
||||
object.Write(" int4 lacc = {}[{}];\n", I_MATERIALS, chan);
|
||||
}
|
||||
else
|
||||
{
|
||||
object.Write("lacc = int4(255, 255, 255, 255);\n");
|
||||
object.Write(" int4 lacc = int4(255, 255, 255, 255);\n");
|
||||
}
|
||||
|
||||
// check if alpha is different
|
||||
const bool alphamatsource = !!(uid_data.matsource & (1 << (j + 2)));
|
||||
if (alphamatsource != colormatsource)
|
||||
if (color_matsource != alpha_matsource)
|
||||
{
|
||||
if (alphamatsource) // from vertex
|
||||
object.Write("mat.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
|
||||
else // from color
|
||||
object.Write("mat.w = {}[{}].w;\n", I_MATERIALS, j + 2);
|
||||
if (alpha_matsource == MatSource::Vertex)
|
||||
object.Write(" mat.w = int(round({}{}.w * 255.0));\n", in_color_name, chan);
|
||||
else // from material color register
|
||||
object.Write(" mat.w = {}[{}].w;\n", I_MATERIALS, chan + 2);
|
||||
}
|
||||
|
||||
if ((uid_data.enablelighting & (1 << (j + 2))) != 0)
|
||||
if (alpha_enable)
|
||||
{
|
||||
if ((uid_data.ambsource & (1 << (j + 2))) != 0) // from vertex
|
||||
object.Write("lacc.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
|
||||
else // from color
|
||||
object.Write("lacc.w = {}[{}].w;\n", I_MATERIALS, j);
|
||||
if (alpha_ambsource == AmbSource::Vertex) // from vertex
|
||||
object.Write(" lacc.w = int(round({}{}.w * 255.0));\n", in_color_name, chan);
|
||||
else // from ambient color register
|
||||
object.Write(" lacc.w = {}[{}].w;\n", I_MATERIALS, chan);
|
||||
}
|
||||
else
|
||||
{
|
||||
object.Write("lacc.w = 255;\n");
|
||||
object.Write(" lacc.w = 255;\n");
|
||||
}
|
||||
|
||||
if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights
|
||||
if (color_enable)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
const auto attnfunc = static_cast<AttenuationFunc>((uid_data.attnfunc >> (2 * chan)) & 3);
|
||||
const auto diffusefunc = static_cast<DiffuseFunc>((uid_data.diffusefunc >> (2 * chan)) & 3);
|
||||
const u32 light_mask =
|
||||
(uid_data.light_mask >> (NUM_XF_LIGHTS * chan)) & ((1 << NUM_XF_LIGHTS) - 1);
|
||||
object.Write(" // Color attenuation function: {}\n", attnfunc);
|
||||
object.Write(" // Color diffuse function: {}\n", diffusefunc);
|
||||
object.Write(" // Color light mask: {:08b}\n", light_mask);
|
||||
for (u32 light = 0; light < NUM_XF_LIGHTS; light++)
|
||||
{
|
||||
if ((uid_data.light_mask & (1 << (i + 8 * j))) != 0)
|
||||
GenerateLightShader(object, uid_data, i, j, false);
|
||||
if ((light_mask & (1 << light)) != 0)
|
||||
{
|
||||
GenerateLightShader(object, uid_data, light, attnfunc, diffusefunc, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((uid_data.enablelighting & (1 << (j + 2))) != 0) // Alpha lights
|
||||
if (alpha_enable)
|
||||
{
|
||||
for (int i = 0; i < 8; ++i)
|
||||
const auto attnfunc = static_cast<AttenuationFunc>((uid_data.attnfunc >> (2 * chan_a)) & 3);
|
||||
const auto diffusefunc = static_cast<DiffuseFunc>((uid_data.diffusefunc >> (2 * chan_a)) & 3);
|
||||
const u32 light_mask =
|
||||
(uid_data.light_mask >> (NUM_XF_LIGHTS * chan_a)) & ((1 << NUM_XF_LIGHTS) - 1);
|
||||
object.Write(" // Alpha attenuation function: {}\n", attnfunc);
|
||||
object.Write(" // Alpha diffuse function: {}\n", diffusefunc);
|
||||
object.Write(" // Alpha light mask function: {:08b}\n", light_mask);
|
||||
for (u32 light = 0; light < NUM_XF_LIGHTS; light++)
|
||||
{
|
||||
if ((uid_data.light_mask & (1 << (i + 8 * (j + 2)))) != 0)
|
||||
GenerateLightShader(object, uid_data, i, j + 2, true);
|
||||
if ((light_mask & (1 << light)) != 0)
|
||||
{
|
||||
GenerateLightShader(object, uid_data, light, attnfunc, diffusefunc, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
object.Write("lacc = clamp(lacc, 0, 255);\n");
|
||||
object.Write("{}{} = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, j);
|
||||
object.Write(" lacc = clamp(lacc, 0, 255);\n");
|
||||
object.Write(" {}{} = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, chan);
|
||||
object.Write("}}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void GetLightingShaderUid(LightingUidData& uid_data)
|
||||
{
|
||||
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
|
||||
for (u32 chan = 0; chan < NUM_XF_COLOR_CHANNELS; chan++)
|
||||
{
|
||||
uid_data.matsource |= static_cast<u32>(xfmem.color[j].matsource.Value()) << j;
|
||||
uid_data.matsource |= static_cast<u32>(xfmem.alpha[j].matsource.Value()) << (j + 2);
|
||||
uid_data.enablelighting |= xfmem.color[j].enablelighting << j;
|
||||
uid_data.enablelighting |= xfmem.alpha[j].enablelighting << (j + 2);
|
||||
// Data for alpha is stored after all colors
|
||||
const u32 chan_a = chan + NUM_XF_COLOR_CHANNELS;
|
||||
|
||||
if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights
|
||||
uid_data.matsource |= static_cast<u32>(xfmem.color[chan].matsource.Value()) << chan;
|
||||
uid_data.matsource |= static_cast<u32>(xfmem.alpha[chan].matsource.Value()) << chan_a;
|
||||
uid_data.enablelighting |= xfmem.color[chan].enablelighting << chan;
|
||||
uid_data.enablelighting |= xfmem.alpha[chan].enablelighting << chan_a;
|
||||
|
||||
if ((uid_data.enablelighting & (1 << chan)) != 0) // Color lights
|
||||
{
|
||||
uid_data.ambsource |= static_cast<u32>(xfmem.color[j].ambsource.Value()) << j;
|
||||
uid_data.attnfunc |= static_cast<u32>(xfmem.color[j].attnfunc.Value()) << (2 * j);
|
||||
uid_data.diffusefunc |= static_cast<u32>(xfmem.color[j].diffusefunc.Value()) << (2 * j);
|
||||
uid_data.light_mask |= xfmem.color[j].GetFullLightMask() << (8 * j);
|
||||
uid_data.ambsource |= static_cast<u32>(xfmem.color[chan].ambsource.Value()) << chan;
|
||||
uid_data.attnfunc |= static_cast<u32>(xfmem.color[chan].attnfunc.Value()) << (2 * chan);
|
||||
uid_data.diffusefunc |= static_cast<u32>(xfmem.color[chan].diffusefunc.Value()) << (2 * chan);
|
||||
uid_data.light_mask |= xfmem.color[chan].GetFullLightMask() << (NUM_XF_LIGHTS * chan);
|
||||
}
|
||||
if ((uid_data.enablelighting & (1 << (j + 2))) != 0) // Alpha lights
|
||||
if ((uid_data.enablelighting & (1 << chan_a)) != 0) // Alpha lights
|
||||
{
|
||||
uid_data.ambsource |= static_cast<u32>(xfmem.alpha[j].ambsource.Value()) << (j + 2);
|
||||
uid_data.attnfunc |= static_cast<u32>(xfmem.alpha[j].attnfunc.Value()) << (2 * (j + 2));
|
||||
uid_data.diffusefunc |= static_cast<u32>(xfmem.alpha[j].diffusefunc.Value()) << (2 * (j + 2));
|
||||
uid_data.light_mask |= xfmem.alpha[j].GetFullLightMask() << (8 * (j + 2));
|
||||
uid_data.ambsource |= static_cast<u32>(xfmem.alpha[chan].ambsource.Value()) << chan_a;
|
||||
uid_data.attnfunc |= static_cast<u32>(xfmem.alpha[chan].attnfunc.Value()) << (2 * chan_a);
|
||||
uid_data.diffusefunc |= static_cast<u32>(xfmem.alpha[chan].diffusefunc.Value())
|
||||
<< (2 * chan_a);
|
||||
uid_data.light_mask |= xfmem.alpha[chan].GetFullLightMask() << (NUM_XF_LIGHTS * chan_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1124,10 +1124,6 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
|||
out.Write("\tfloat3 _normal = normalize(Normal.xyz);\n\n"
|
||||
"\tfloat3 pos = WorldPos;\n");
|
||||
|
||||
out.Write("\tint4 lacc;\n"
|
||||
"\tfloat3 ldir, h, cosAttn, distAttn;\n"
|
||||
"\tfloat dist, dist2, attn;\n");
|
||||
|
||||
// TODO: Our current constant usage code isn't able to handle more than one buffer.
|
||||
// So we can't mark the VS constant as used here. But keep them here as reference.
|
||||
// out.SetConstantsUsed(C_PLIGHT_COLORS, C_PLIGHT_COLORS+7); // TODO: Can be optimized further
|
||||
|
|
|
@ -26,18 +26,13 @@ void WriteLightingFunction(ShaderCode& out)
|
|||
out.Write(" case {:s}:\n", AttenuationFunc::Dir);
|
||||
out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
|
||||
" attn = 1.0;\n"
|
||||
" if (length(ldir) == 0.0)\n"
|
||||
" ldir = normal;\n"
|
||||
" break;\n\n");
|
||||
out.Write(" case {:s}:\n", AttenuationFunc::Spec);
|
||||
out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
|
||||
" attn = (dot(normal, ldir) >= 0.0) ? max(0.0, dot(normal, " I_LIGHTS
|
||||
"[index].dir.xyz)) : 0.0;\n"
|
||||
" cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n");
|
||||
out.Write(" if (diffusefunc == {:s})\n", DiffuseFunc::None);
|
||||
out.Write(" distAttn = " I_LIGHTS "[index].distatt.xyz;\n"
|
||||
" else\n"
|
||||
" distAttn = normalize(" I_LIGHTS "[index].distatt.xyz);\n"
|
||||
" cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n"
|
||||
" distAttn = " I_LIGHTS "[index].distatt.xyz;\n"
|
||||
" attn = max(0.0, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
|
||||
"float3(1.0, attn, attn*attn));\n"
|
||||
" break;\n\n");
|
||||
|
|
|
@ -430,10 +430,6 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
out.Write("o.pos = float4(dot(" I_PROJECTION "[0], pos), dot(" I_PROJECTION
|
||||
"[1], pos), dot(" I_PROJECTION "[2], pos), dot(" I_PROJECTION "[3], pos));\n");
|
||||
|
||||
out.Write("int4 lacc;\n"
|
||||
"float3 ldir, h, cosAttn, distAttn;\n"
|
||||
"float dist, dist2, attn;\n");
|
||||
|
||||
GenerateLightingShaderCode(out, uid_data->lighting, "vertex_color_", "o.colors_");
|
||||
|
||||
// transform texcoords
|
||||
|
@ -497,7 +493,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
|
|||
case TexGenType::EmbossMap: // calculate tex coords into bump map
|
||||
|
||||
// transform the light dir into tangent space
|
||||
out.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n",
|
||||
out.Write("float3 ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n",
|
||||
LIGHT_POS_PARAMS(texinfo.embosslightshift));
|
||||
out.Write(
|
||||
"o.tex{}.xyz = o.tex{}.xyz + float3(dot(ldir, _tangent), dot(ldir, _binormal), 0.0);\n",
|
||||
|
|
|
@ -256,22 +256,9 @@ void VertexShaderManager::SetConstants(const std::vector<std::string>& textures,
|
|||
dstlight.pos[1] = light.dpos[1];
|
||||
dstlight.pos[2] = light.dpos[2];
|
||||
|
||||
// TODO: Hardware testing is needed to confirm that this normalization is correct
|
||||
auto sanitize = [](float f) {
|
||||
if (std::isnan(f))
|
||||
return 0.0f;
|
||||
else if (std::isinf(f))
|
||||
return f > 0.0f ? 1.0f : -1.0f;
|
||||
else
|
||||
return f;
|
||||
};
|
||||
double norm = double(light.ddir[0]) * double(light.ddir[0]) +
|
||||
double(light.ddir[1]) * double(light.ddir[1]) +
|
||||
double(light.ddir[2]) * double(light.ddir[2]);
|
||||
norm = 1.0 / sqrt(norm);
|
||||
dstlight.dir[0] = sanitize(static_cast<float>(light.ddir[0] * norm));
|
||||
dstlight.dir[1] = sanitize(static_cast<float>(light.ddir[1] * norm));
|
||||
dstlight.dir[2] = sanitize(static_cast<float>(light.ddir[2] * norm));
|
||||
dstlight.dir[0] = light.ddir[0];
|
||||
dstlight.dir[1] = light.ddir[1];
|
||||
dstlight.dir[2] = light.ddir[2];
|
||||
}
|
||||
dirty = true;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "VideoCommon/CPMemory.h"
|
||||
|
||||
constexpr size_t NUM_XF_COLOR_CHANNELS = 2;
|
||||
constexpr size_t NUM_XF_LIGHTS = 8;
|
||||
|
||||
// Lighting
|
||||
|
||||
|
@ -430,7 +431,7 @@ struct alignas(16) XFMemory
|
|||
float normalMatrices[96]; // 0x0400 - 0x045f
|
||||
u32 unk1[160]; // 0x0460 - 0x04ff
|
||||
float postMatrices[256]; // 0x0500 - 0x05ff
|
||||
Light lights[8]; // 0x0600 - 0x067f
|
||||
Light lights[NUM_XF_LIGHTS]; // 0x0600 - 0x067f
|
||||
u32 unk2[2432]; // 0x0680 - 0x0fff
|
||||
u32 error; // 0x1000
|
||||
u32 diag; // 0x1001
|
||||
|
|
Loading…
Add table
Reference in a new issue