Amend ambient fog logic

Should stop the sky flashing in lemans24, and the background totally disappearing in sega rally after a game. The logic here is still not totally understood but works well enough for the games.
This commit is contained in:
Ian Curtis 2023-12-27 12:42:32 +00:00
parent c039d08c03
commit 0e07f29f80

View file

@ -227,27 +227,46 @@ void CNew3D::DrawAmbientFog()
// If fogAmbient = 1.0 it's a no-op. Lower values darken the image // If fogAmbient = 1.0 it's a no-op. Lower values darken the image
// Does this work with scroll fog? Well technically scroll fog already takes into account the fog ambient as it darkens the fog colour // Does this work with scroll fog? Well technically scroll fog already takes into account the fog ambient as it darkens the fog colour
// Let's pick the lowest fog ambient value // lemans24 every viewport will set ambient fog, scroll attentuation is sometimes set (for every viewport) for explosion effects from car exhaust. So has no effect on ambient fog
// otherwise we'll make the ambient fog flash
// sega rally will set ambient fog to zero for every viewport in priority layers 1-3 with a fog density set. Disabled viewports with priority zero have ambient fog disabled (1.0). Don't think srally uses ambient fog
// vf3 almost all viewports in all priority layers have ambient fog set (<1.0)
// lost world is setting an ambient fog value every every viewport but has no density or fog start value set. Don't think lost world is using ambient fog
// Let's pick the lowest fog ambient value from only the first priority layer
// Check for fog density or a fog start value, otherwise the effect seems to be disabled (lost world) // Check for fog density or a fog start value, otherwise the effect seems to be disabled (lost world)
float fogAmbient = 1.0f; float fogAmbient = 1.0f;
Node* nodePtr = nullptr; Node* nodePtr = nullptr;
for (int i = 0; i < 4; i++) {
bool hasPriority = false;
for (auto& n : m_nodes) { for (auto& n : m_nodes) {
auto& vp = n.viewport;
if (vp.priority == i) {
hasPriority = true;
// check to see if we have a fog density or fog start // check to see if we have a fog density or fog start
if (n.viewport.fogParams[3] <= 0.0f && n.viewport.fogParams[4] <= 0.0f) { if (vp.fogParams[3] <= 0.0f && vp.fogParams[4] <= 0.0f) {
continue; continue;
} }
if (n.viewport.scrollAtt > 0.0f) { if (vp.fogParams[6] < fogAmbient) {
continue; // scroll attenuation indicates scroll fog layer nodePtr = &n;
fogAmbient = vp.fogParams[6];
}
}
} }
if (n.viewport.fogParams[6] < fogAmbient) { if (nodePtr || hasPriority) {
nodePtr = &n; break;
fogAmbient = n.viewport.fogParams[6];
} }
} }
if (nodePtr) { if (nodePtr) {
@ -982,14 +1001,15 @@ void CNew3D::RenderViewport(UINT32 addr)
return; return;
} }
if (!(vpnode[0] & 0x20)) { // only if viewport enabled bool vpDisabled = vpnode[0] & 0x20; // only if viewport enabled
{
// create node object // create node object
m_nodes.emplace_back(Node()); m_nodes.emplace_back(Node());
m_nodes.back().models.reserve(2048); // create space for models m_nodes.back().models.reserve(2048); // create space for models
// get pointer to its viewport // get pointer to its viewport
Viewport *vp = &m_nodes.back().viewport; Viewport* vp = &m_nodes.back().viewport;
vp->priority = (vpnode[0] >> 3) & 0x3; vp->priority = (vpnode[0] >> 3) & 0x3;
vp->select = (vpnode[0] >> 8) & 0x3; vp->select = (vpnode[0] >> 8) & 0x3;
@ -1024,8 +1044,8 @@ void CNew3D::RenderViewport(UINT32 addr)
vp->angle_left = (0.0f - jo) / cv; vp->angle_left = (0.0f - jo) / cv;
vp->angle_right = (1.0f - jo) / cv; vp->angle_right = (1.0f - jo) / cv;
vp->angle_bottom = -(1.0f - io)/ cw; vp->angle_bottom = -(1.0f - io) / cw;
vp->angle_top = -(0.0f - io)/ cw; vp->angle_top = -(0.0f - io) / cw;
CalcViewport(vp); CalcViewport(vp);
@ -1085,7 +1105,7 @@ void CNew3D::RenderViewport(UINT32 addr)
vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (float)(1.0 / 255.0); // fog color G vp->fogParams[1] = (float)((vpnode[0x22] >> 8) & 0xFF) * (float)(1.0 / 255.0); // fog color G
vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (float)(1.0 / 255.0); // fog color B vp->fogParams[2] = (float)((vpnode[0x22] >> 0) & 0xFF) * (float)(1.0 / 255.0); // fog color B
vp->fogParams[3] = std::abs(Util::Uint32AsFloat(vpnode[0x23])); // fog density - ocean hunter uses negative values, but looks the same vp->fogParams[3] = std::abs(Util::Uint32AsFloat(vpnode[0x23])); // fog density - ocean hunter uses negative values, but looks the same
vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF)* (float)(1.0 / 255.0); // fog start vp->fogParams[4] = (float)(INT16)(vpnode[0x25] & 0xFFFF) * (float)(1.0 / 255.0); // fog start
// Avoid Infinite and NaN values for Star Wars Trilogy // Avoid Infinite and NaN values for Star Wars Trilogy
if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3])) { if (std::isinf(vp->fogParams[3]) || std::isnan(vp->fogParams[3])) {
@ -1105,11 +1125,13 @@ void CNew3D::RenderViewport(UINT32 addr)
InitMatrixStack(matrixBase, m_modelMat); InitMatrixStack(matrixBase, m_modelMat);
// Descend down the node link. Need to start with a culling node because that defines our culling radius. // Descend down the node link. Need to start with a culling node because that defines our culling radius.
if (!vpDisabled) {
auto childptr = vpnode[0x02]; auto childptr = vpnode[0x02];
if (((childptr >> 24) & 0x5) == 0) { if (((childptr >> 24) & 0x5) == 0) {
DescendNodePtr(vpnode[0x02]); DescendNodePtr(vpnode[0x02]);
} }
} }
}
// render next viewport // render next viewport
if (vpnode[0x01] != 0x01000000) { if (vpnode[0x01] != 0x01000000) {