Rendering/DayNight: Difference between revisions
No edit summary |
|||
(15 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
= Overview = | |||
In World of Warcraft, the <tt>DayNight</tt> system governs most of the general appearance of the world. | In World of Warcraft, the <tt>DayNight</tt> system governs most of the general appearance of the world. | ||
Things like area lighting, zone lighting, clouds, the sky sphere (ie the color gradient of the sky), stars (ie sky boxes) are all managed by <tt>DayNight</tt>. | Things like area lighting, zone lighting, clouds, the sky sphere (ie the color gradient of the sky), stars (ie sky boxes) are all managed by <tt>DayNight</tt>. | ||
= Utility Functions = | |||
== InterpTable == | |||
Interpolate between table values of the tables used below. | |||
count - the number of rows in the table (Vec2's), usually 4 | |||
dayProgression - internal time normalized (time / 2880f) | |||
<syntaxhighlight lang="cpp"> | |||
double InterpTable(C2Vector[] table, uint count, float dayProgression) | |||
{ | |||
unsigned int idxA = 0; | |||
int idxB; | |||
if (count != 0) | |||
{ | |||
do | |||
{ | |||
if (dayProgression <= (double)(table[idxA].x)) | |||
break; | |||
++idxA; | |||
} | |||
while (idxA < count); | |||
} | |||
if (idxA == count) | |||
{ | |||
idxA = 0; | |||
idxB = (int)(count - 1); | |||
} | |||
else if (idxA != 0) | |||
{ | |||
idxB = (int)(idxA - 1); | |||
} | |||
else | |||
{ | |||
idxB = (int)(count - 1); | |||
} | |||
double v6 = table[idxA].x - table[idxB].x; | |||
if (v6 < 0.0) | |||
v6 = v6 + 1.0; | |||
double v7 = dayProgression - table[idxB].x; | |||
if (v7 < 0.0) | |||
v7 = v7 + 1.0; | |||
double v8 = v7 / v6; | |||
if (table[idxA].y < table[idxB].y) | |||
return table[idxB].y - v8 * (table[idxB].y - table[idxA].y); | |||
else | |||
return table[idxB].y + v8 * (table[idxA].y - table[idxB].y); | |||
} | |||
</syntaxhighlight> | |||
== DayNight::DarkenColor == | |||
<syntaxhighlight lang="cpp"> | |||
CImVector DayNight::DarkenColor(CImVector const &clr, float amount) { | |||
C3Vector rgb; | |||
C3Vector hsv; | |||
rgb.x = clr->r / 255.0; | |||
rgb.y = clr->g / 255.0; | |||
rgb.z = clr->b / 255.0; | |||
hsv.x = 0.0; | |||
hsv.y = 0.0; | |||
hsv.z = 0.0; | |||
RGBtoHSV(&rgb, &hsv); | |||
hsv.z = hsv.z * amount; | |||
HSVtoRGB(&hsv, &rgb); | |||
CImVector result; | |||
CImVector::operator=(&result, &rgb); | |||
return result; | |||
} | |||
</syntaxhighlight> | |||
= Lighting Functions = | |||
== DayNight::SetDirection == | == DayNight::SetDirection == | ||
Line 17: | Line 105: | ||
dword_D39104 |= 1u; | dword_D39104 |= 1u; | ||
DayNight::phiTable | DayNight::phiTable = { | ||
{ 0.0, 2.2165682 }, | |||
{ 0.25, 1.9198623 }, | |||
{ 0.5, 2.2165682 }, | |||
{ 0.75, 1.9198623 } | |||
}; | |||
} | } | ||
Line 29: | Line 121: | ||
dword_D39104 |= 2; | dword_D39104 |= 2; | ||
DayNight::thetaTable | DayNight::thetaTable = { | ||
{ 0.0, 3.926991 }, | |||
{ 0.25, 3.926991 }, | |||
{ 0.5, 3.926991 }, | |||
{ 0.75, 3.926991 } | |||
}; | |||
} | } | ||
float phi = DayNight::InterpTable(&DayNight::phiTable, 4u, DayNight::g_dnInfo.dayProgression); | |||
float phi = DayNight::InterpTable(&DayNight::phiTable, 4u, | float theta = DayNight::InterpTable(&DayNight::thetaTable, 4u, DayNight::g_dnInfo.dayProgression); | ||
float theta = DayNight::InterpTable(&DayNight::thetaTable, 4u, | |||
// Convert from spherical coordinates to XYZ | // Convert from spherical coordinates to XYZ | ||
Line 51: | Line 146: | ||
float cosTheta = CMath::cosoid(theta); | float cosTheta = CMath::cosoid(theta); | ||
// | DayNight::g_dnInfo.lightInfo.dir.x = sinPhi * cosTheta; | ||
DayNight::g_dnInfo.lightInfo.dir.y = sinPhi * sinTheta; | |||
DayNight::g_dnInfo.lightInfo.dir.z = cosPhi; | |||
} | |||
</syntaxhighlight> | |||
== DayNight::SetLightColors == | |||
Sets up lighting colors in <tt>DNInfo->lightInfo</tt>. The colors in <tt>DNInfo->lightInfo</tt> directly feed the lighting for ADTs, M2s, WMOs, etc. | |||
For WMO materials with the <tt>F_WINDOW</tt> flag set, the <tt>windowAmbColor</tt> and <<tt>windowDirColor</tt> are used. | |||
<syntaxhighlight lang="cpp"> | |||
void DayNight::SetLightColors() { | |||
// Light colors | |||
DayNight::g_dnInfo.lightInfo.dirColor = DayNight::g_dnInfo.light.dirColor; | |||
DayNight::g_dnInfo.lightInfo.ambColor = DayNight::g_dnInfo.light.ambColor; | |||
// Window light colors | |||
// MOMT.flags & F_WINDOW | |||
CImVector windowDirColor = DayNight::g_dnInfo.light.dirColor; | |||
CImVector::Blend255_(&windowDirColor, 128u, &DayNight::g_dnInfo.light.ambColor); | |||
CImVector windowAmbColor = DayNight::g_dnInfo.light.ambColor; | |||
CImVector::Blend255_(&windowAmbColor, 128u, &DayNight::g_dnInfo.light.dirColor); | |||
windowAmbColor.r = std::min(windowAmbColor.r + 16u, 255u); | |||
windowAmbColor.g = std::min(windowAmbColor.g + 16u, 255u); | |||
windowAmbColor.b = std::min(windowAmbColor.b + 16u, 255u); | |||
windowAmbColor.a = windowAmbColor.a - 1; // 0 wraps to 255 | |||
DayNight::g_dnInfo.lightInfo.windowDirColor = windowDirColor; | |||
DayNight::g_dnInfo.lightInfo.windowAmbColor = windowAmbColor; | |||
// Shadow color | |||
// TODO: Clean up | |||
int v1; | |||
BYTE1(v1) = (unsigned __int16)(85 * (DayNight::g_dnInfo.light.ambColor.r + 3)) >> 8; | |||
LOBYTE(v1) = (unsigned __int16)(85 * (DayNight::g_dnInfo.light.ambColor.g + 3)) >> 8; | |||
DayNight::g_dnInfo.shadowColor = (CImVector)(*(_DWORD *)&DayNight::g_dnInfo.light.ambColor & 0xFF000000 | ((unsigned __int16)(85 * (DayNight::g_dnInfo.light.ambColor.b + 3)) >> 8) | ((unsigned __int16)v1 << 8)); | |||
DayNight::g_dnInfo.shadowColor.a = DayNight::g_dnInfo.light.shadowOpacity.r; | |||
// TODO: What is unkLightInfo? | |||
DayNight::g_dnInfo.unkLightInfo.dir.x = DayNight::g_dnInfo.lightInfo.dir.x; | |||
DayNight::g_dnInfo.unkLightInfo.dir.y = DayNight::g_dnInfo.lightInfo.dir.y; | |||
DayNight::g_dnInfo.unkLightInfo.dir.z = DayNight::g_dnInfo.lightInfo.dir.z; | |||
DayNight::g_dnInfo.unkLightInfo.dirColor = DayNight::g_dnInfo.light.dirColor; | |||
DayNight::g_dnInfo.unkLightInfo.ambColor = DayNight::g_dnInfo.light.ambColor; | |||
DayNight::g_dnInfo.unkLightInfo.windowDirColor = DayNight::g_dnInfo.lightInfo.windowDirColor; | |||
DayNight::g_dnInfo.unkLightInfo.windowAmbColor = DayNight::g_dnInfo.lightInfo.windowAmbColor; | |||
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.x = DayNight::g_dnInfo.lightInfo.shaderShadowColor.x; | |||
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.y = DayNight::g_dnInfo.lightInfo.shaderShadowColor.y; | |||
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.z = DayNight::g_dnInfo.lightInfo.shaderShadowColor.z; | |||
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.w = DayNight::g_dnInfo.lightInfo.shaderShadowColor.w; | |||
// Shader shadow color | |||
C3Vector rgb; | |||
rgb.x = DayNight::g_dnInfo.light.ambColor.r / 255.0f; | |||
rgb.y = DayNight::g_dnInfo.light.ambColor.g / 255.0f; | |||
rgb.z = DayNight::g_dnInfo.light.ambColor.b / 255.0f; | |||
C3Vector hsv; | |||
hsv.x = 0.0; | |||
hsv.y = 0.0; | |||
hsv.z = 0.0; | |||
RGBtoHSV(&rgb, &hsv); | |||
hsv.y = hsv.y * 0.33000001; | |||
hsv.z = hsv.z * 1.25; | |||
HSVtoRGB(&hsv, &rgb); | |||
DayNight::g_dnInfo.lightInfo.shaderShadowColor.x = rgb.x; | |||
DayNight::g_dnInfo.lightInfo.shaderShadowColor.y = rgb.y; | |||
DayNight::g_dnInfo.lightInfo.shaderShadowColor.z = rgb.z; | |||
DayNight::g_dnInfo.lightInfo.shaderShadowColor.w = 1.0; | |||
} | |||
</syntaxhighlight> | |||
= Stars = | |||
<tt>DNStars</tt> controls the skybox (the model that overlays the sky sphere). | |||
== DayNight::DNStars::Update == | |||
<syntaxhighlight lang="cpp"> | |||
void DayNight::DNStars::Update(DNStars *this) { | |||
DayNight::DNStars::s_fadeTable = { | |||
{ 0.1250f, 1f }, | |||
{ 0.1875f, 0f }, | |||
{ 0.9374f, 0f }, | |||
{ 0.9999f, 1f } | |||
}; | |||
this->pos.x = DayNight::g_dnInfo.cameraPos.x; | |||
this->pos.y = DayNight::g_dnInfo.cameraPos.y; | |||
this->pos.z = DayNight::g_dnInfo.cameraPos.z; | |||
float fade = DayNight::InterpTable(&DayNight::DNStars::s_fadeTable, 4u, DayNight::g_dnInfo.dayProgression); | |||
this->color.a = (signed int)(fade * 254.0 + 1.0); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Latest revision as of 15:31, 21 August 2021
Overview
In World of Warcraft, the DayNight system governs most of the general appearance of the world.
Things like area lighting, zone lighting, clouds, the sky sphere (ie the color gradient of the sky), stars (ie sky boxes) are all managed by DayNight.
Utility Functions
InterpTable
Interpolate between table values of the tables used below.
count - the number of rows in the table (Vec2's), usually 4
dayProgression - internal time normalized (time / 2880f)
double InterpTable(C2Vector[] table, uint count, float dayProgression)
{
unsigned int idxA = 0;
int idxB;
if (count != 0)
{
do
{
if (dayProgression <= (double)(table[idxA].x))
break;
++idxA;
}
while (idxA < count);
}
if (idxA == count)
{
idxA = 0;
idxB = (int)(count - 1);
}
else if (idxA != 0)
{
idxB = (int)(idxA - 1);
}
else
{
idxB = (int)(count - 1);
}
double v6 = table[idxA].x - table[idxB].x;
if (v6 < 0.0)
v6 = v6 + 1.0;
double v7 = dayProgression - table[idxB].x;
if (v7 < 0.0)
v7 = v7 + 1.0;
double v8 = v7 / v6;
if (table[idxA].y < table[idxB].y)
return table[idxB].y - v8 * (table[idxB].y - table[idxA].y);
else
return table[idxB].y + v8 * (table[idxA].y - table[idxB].y);
}
DayNight::DarkenColor
CImVector DayNight::DarkenColor(CImVector const &clr, float amount) {
C3Vector rgb;
C3Vector hsv;
rgb.x = clr->r / 255.0;
rgb.y = clr->g / 255.0;
rgb.z = clr->b / 255.0;
hsv.x = 0.0;
hsv.y = 0.0;
hsv.z = 0.0;
RGBtoHSV(&rgb, &hsv);
hsv.z = hsv.z * amount;
HSVtoRGB(&hsv, &rgb);
CImVector result;
CImVector::operator=(&result, &rgb);
return result;
}
Lighting Functions
DayNight::SetDirection
DayNight::SetDirection calculates a C3Vector containing the direction vector for the global light, aka sunDir.
This direction vector is transformed by the view matrix prior to being uploaded to the shader.
void DayNight::SetDirection() {
// Phi Table
if ( !(dword_D39104 & 1) ) {
dword_D39104 |= 1u;
DayNight::phiTable = {
{ 0.0, 2.2165682 },
{ 0.25, 1.9198623 },
{ 0.5, 2.2165682 },
{ 0.75, 1.9198623 }
};
}
// Theta Table
if ( !(dword_D39104 & 2) ) {
dword_D39104 |= 2;
DayNight::thetaTable = {
{ 0.0, 3.926991 },
{ 0.25, 3.926991 },
{ 0.5, 3.926991 },
{ 0.75, 3.926991 }
};
}
float phi = DayNight::InterpTable(&DayNight::phiTable, 4u, DayNight::g_dnInfo.dayProgression);
float theta = DayNight::InterpTable(&DayNight::thetaTable, 4u, DayNight::g_dnInfo.dayProgression);
// Convert from spherical coordinates to XYZ
// x = rho * sin(phi) * cos(theta)
// y = rho * sin(phi) * sin(theta)
// z = rho * cos(phi)
float sinPhi = CMath::sinoid(phi);
float cosPhi = CMath::cosoid(phi);
float sinTheta = CMath::sinoid(theta);
float cosTheta = CMath::cosoid(theta);
DayNight::g_dnInfo.lightInfo.dir.x = sinPhi * cosTheta;
DayNight::g_dnInfo.lightInfo.dir.y = sinPhi * sinTheta;
DayNight::g_dnInfo.lightInfo.dir.z = cosPhi;
}
DayNight::SetLightColors
Sets up lighting colors in DNInfo->lightInfo. The colors in DNInfo->lightInfo directly feed the lighting for ADTs, M2s, WMOs, etc.
For WMO materials with the F_WINDOW flag set, the windowAmbColor and <windowDirColor are used.
void DayNight::SetLightColors() {
// Light colors
DayNight::g_dnInfo.lightInfo.dirColor = DayNight::g_dnInfo.light.dirColor;
DayNight::g_dnInfo.lightInfo.ambColor = DayNight::g_dnInfo.light.ambColor;
// Window light colors
// MOMT.flags & F_WINDOW
CImVector windowDirColor = DayNight::g_dnInfo.light.dirColor;
CImVector::Blend255_(&windowDirColor, 128u, &DayNight::g_dnInfo.light.ambColor);
CImVector windowAmbColor = DayNight::g_dnInfo.light.ambColor;
CImVector::Blend255_(&windowAmbColor, 128u, &DayNight::g_dnInfo.light.dirColor);
windowAmbColor.r = std::min(windowAmbColor.r + 16u, 255u);
windowAmbColor.g = std::min(windowAmbColor.g + 16u, 255u);
windowAmbColor.b = std::min(windowAmbColor.b + 16u, 255u);
windowAmbColor.a = windowAmbColor.a - 1; // 0 wraps to 255
DayNight::g_dnInfo.lightInfo.windowDirColor = windowDirColor;
DayNight::g_dnInfo.lightInfo.windowAmbColor = windowAmbColor;
// Shadow color
// TODO: Clean up
int v1;
BYTE1(v1) = (unsigned __int16)(85 * (DayNight::g_dnInfo.light.ambColor.r + 3)) >> 8;
LOBYTE(v1) = (unsigned __int16)(85 * (DayNight::g_dnInfo.light.ambColor.g + 3)) >> 8;
DayNight::g_dnInfo.shadowColor = (CImVector)(*(_DWORD *)&DayNight::g_dnInfo.light.ambColor & 0xFF000000 | ((unsigned __int16)(85 * (DayNight::g_dnInfo.light.ambColor.b + 3)) >> 8) | ((unsigned __int16)v1 << 8));
DayNight::g_dnInfo.shadowColor.a = DayNight::g_dnInfo.light.shadowOpacity.r;
// TODO: What is unkLightInfo?
DayNight::g_dnInfo.unkLightInfo.dir.x = DayNight::g_dnInfo.lightInfo.dir.x;
DayNight::g_dnInfo.unkLightInfo.dir.y = DayNight::g_dnInfo.lightInfo.dir.y;
DayNight::g_dnInfo.unkLightInfo.dir.z = DayNight::g_dnInfo.lightInfo.dir.z;
DayNight::g_dnInfo.unkLightInfo.dirColor = DayNight::g_dnInfo.light.dirColor;
DayNight::g_dnInfo.unkLightInfo.ambColor = DayNight::g_dnInfo.light.ambColor;
DayNight::g_dnInfo.unkLightInfo.windowDirColor = DayNight::g_dnInfo.lightInfo.windowDirColor;
DayNight::g_dnInfo.unkLightInfo.windowAmbColor = DayNight::g_dnInfo.lightInfo.windowAmbColor;
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.x = DayNight::g_dnInfo.lightInfo.shaderShadowColor.x;
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.y = DayNight::g_dnInfo.lightInfo.shaderShadowColor.y;
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.z = DayNight::g_dnInfo.lightInfo.shaderShadowColor.z;
DayNight::g_dnInfo.unkLightInfo.shaderShadowColor.w = DayNight::g_dnInfo.lightInfo.shaderShadowColor.w;
// Shader shadow color
C3Vector rgb;
rgb.x = DayNight::g_dnInfo.light.ambColor.r / 255.0f;
rgb.y = DayNight::g_dnInfo.light.ambColor.g / 255.0f;
rgb.z = DayNight::g_dnInfo.light.ambColor.b / 255.0f;
C3Vector hsv;
hsv.x = 0.0;
hsv.y = 0.0;
hsv.z = 0.0;
RGBtoHSV(&rgb, &hsv);
hsv.y = hsv.y * 0.33000001;
hsv.z = hsv.z * 1.25;
HSVtoRGB(&hsv, &rgb);
DayNight::g_dnInfo.lightInfo.shaderShadowColor.x = rgb.x;
DayNight::g_dnInfo.lightInfo.shaderShadowColor.y = rgb.y;
DayNight::g_dnInfo.lightInfo.shaderShadowColor.z = rgb.z;
DayNight::g_dnInfo.lightInfo.shaderShadowColor.w = 1.0;
}
Stars
DNStars controls the skybox (the model that overlays the sky sphere).
DayNight::DNStars::Update
void DayNight::DNStars::Update(DNStars *this) {
DayNight::DNStars::s_fadeTable = {
{ 0.1250f, 1f },
{ 0.1875f, 0f },
{ 0.9374f, 0f },
{ 0.9999f, 1f }
};
this->pos.x = DayNight::g_dnInfo.cameraPos.x;
this->pos.y = DayNight::g_dnInfo.cameraPos.y;
this->pos.z = DayNight::g_dnInfo.cameraPos.z;
float fade = DayNight::InterpTable(&DayNight::DNStars::s_fadeTable, 4u, DayNight::g_dnInfo.dayProgression);
this->color.a = (signed int)(fade * 254.0 + 1.0);
}