Add LOD switching and blending out culling nodes

We're not blending between LODs yet as we're not sure of the best way to implement it
Also implementing control bits for disable culling and enable model scale (needed for ECA and Harley)
This commit is contained in:
gm-matthew 2023-11-02 00:25:52 +00:00
parent 3a85bd9e25
commit 483dbdda2e
4 changed files with 68 additions and 39 deletions

View file

@ -4,12 +4,13 @@ namespace New3D {
NodeAttributes::NodeAttributes() NodeAttributes::NodeAttributes()
{ {
currentTexOffsetX = 0; currentTexOffsetX = 0;
currentTexOffsetY = 0; currentTexOffsetY = 0;
currentPage = 0; currentPage = 0;
currentClipStatus = Clip::INTERCEPT; currentClipStatus = Clip::INTERCEPT;
currentModelScale = 1.0f; currentModelScale = 1.0f;
currentModelAlpha = 1.0; currentModelAlpha = 1.0;
currentDisableCulling = false;
} }
bool NodeAttributes::Push() bool NodeAttributes::Push()
@ -23,12 +24,13 @@ bool NodeAttributes::Push()
return false; return false;
} }
na.page = currentPage; na.page = currentPage;
na.texOffsetX = currentTexOffsetX; na.texOffsetX = currentTexOffsetX;
na.texOffsetY = currentTexOffsetY; na.texOffsetY = currentTexOffsetY;
na.clip = currentClipStatus; na.clip = currentClipStatus;
na.modelScale = currentModelScale; na.modelScale = currentModelScale;
na.modelAlpha = currentModelAlpha; na.modelAlpha = currentModelAlpha;
na.disableCulling = currentDisableCulling;
m_vecAttribs.emplace_back(na); m_vecAttribs.emplace_back(na);
@ -43,12 +45,13 @@ bool NodeAttributes::Pop()
auto &last = m_vecAttribs.back(); auto &last = m_vecAttribs.back();
currentPage = last.page; currentPage = last.page;
currentTexOffsetX = last.texOffsetX; currentTexOffsetX = last.texOffsetX;
currentTexOffsetY = last.texOffsetY; currentTexOffsetY = last.texOffsetY;
currentClipStatus = last.clip; currentClipStatus = last.clip;
currentModelScale = last.modelScale; currentModelScale = last.modelScale;
currentModelAlpha = last.modelAlpha; currentModelAlpha = last.modelAlpha;
currentDisableCulling = last.disableCulling;
m_vecAttribs.pop_back(); m_vecAttribs.pop_back();
@ -62,12 +65,13 @@ bool NodeAttributes::StackLimit()
void NodeAttributes::Reset() void NodeAttributes::Reset()
{ {
currentPage = 0; currentPage = 0;
currentTexOffsetX = 0; currentTexOffsetX = 0;
currentTexOffsetY = 0; currentTexOffsetY = 0;
currentClipStatus = Clip::INTERCEPT; currentClipStatus = Clip::INTERCEPT;
currentModelScale = 1.0f; currentModelScale = 1.0f;
currentModelAlpha = 1.0f; currentModelAlpha = 1.0f;
currentDisableCulling = false;
m_vecAttribs.clear(); m_vecAttribs.clear();
} }

View file

@ -242,6 +242,7 @@ public:
Clip currentClipStatus; Clip currentClipStatus;
float currentModelScale; float currentModelScale;
float currentModelAlpha; float currentModelAlpha;
bool currentDisableCulling;
private: private:
@ -253,6 +254,7 @@ private:
Clip clip; Clip clip;
float modelScale; float modelScale;
float modelAlpha; // from culling node float modelAlpha; // from culling node
bool disableCulling;
}; };
std::vector<NodeAttribs> m_vecAttribs; std::vector<NodeAttribs> m_vecAttribs;
}; };

View file

@ -559,11 +559,12 @@ bool CNew3D::DrawModel(UINT32 modelAddr)
-------- -------- -------- -----x-- Valid color table -------- -------- -------- -----x-- Valid color table
-------- -------- -------- ------xx Node type(0 = viewport, 1 = root node, 2 = culling node) -------- -------- -------- ------xx Node type(0 = viewport, 1 = root node, 2 = culling node)
0x01, 0x02 only present on Step 2 + 0x01, 0x02 only present on Step 1.5+
0x01: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx-- Model scale (float32) last 2 bits are control words 0x01: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx-- Model scale (float32) last 2 bits are control words
-------- -------- -------- ------x- Disable culling -------- -------- -------- ------x- Disable culling
-------- -------- -------- -------x Valid model scale -------- -------- -------- -------x Valid model scale
0x02 : -------- -------- x------- -------- Texture replace 0x02 : -------- -------- x------- -------- Texture replace
-------- -------- -x------ -------- Switch bank -------- -------- -x------ -------- Switch bank
-------- -------- --xxxxxx x------- X offset -------- -------- --xxxxxx x------- X offset
@ -595,7 +596,7 @@ void CNew3D::DescendCullingNode(UINT32 addr)
{ {
enum class NodeType { undefined = -1, viewport = 0, rootNode = 1, cullingNode = 2 }; enum class NodeType { undefined = -1, viewport = 0, rootNode = 1, cullingNode = 2 };
const UINT32 *node, *lodTable; const UINT32 *node, *lodPtr;
UINT32 matrixOffset, child1Ptr, sibling2Ptr; UINT32 matrixOffset, child1Ptr, sibling2Ptr;
BBox bbox; BBox bbox;
UINT16 uCullRadius; UINT16 uCullRadius;
@ -645,10 +646,11 @@ void CNew3D::DescendCullingNode(UINT32 addr)
if (!m_offset) { // Step 1.5+ if (!m_offset) { // Step 1.5+
float modelScale = Util::Uint32AsFloat(node[1]); if (node[0x01] & 1)
if (modelScale > std::numeric_limits<float>::min()) { m_nodeAttribs.currentModelScale = Util::Uint32AsFloat(node[0x01] & ~3); // mask out control bits
m_nodeAttribs.currentModelScale = modelScale;
} if (node[0x01] & 2)
m_nodeAttribs.currentDisableCulling = true;
// apply texture offsets, else retain current ones // apply texture offsets, else retain current ones
if ((node[0x02] & 0x8000)) { if ((node[0x02] & 0x8000)) {
@ -660,8 +662,6 @@ void CNew3D::DescendCullingNode(UINT32 addr)
} }
} }
m_nodeAttribs.currentModelAlpha = 1; // TODO fade out if required
// Apply matrix and translation // Apply matrix and translation
m_modelMat.PushMatrix(); m_modelMat.PushMatrix();
@ -705,19 +705,42 @@ void CNew3D::DescendCullingNode(UINT32 addr)
} }
} }
if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && fCullRadius > R3DFloat::Pro16BitFltMin) { float LODscale = fBlendRadius * m_nodeAttribs.currentModelScale / std::abs(m_modelMat.currentMatrix[14]);
LODFeatureType lodTableEntry = m_LODBlendTable->table[lodTablePointer];
if (m_nodeAttribs.currentDisableCulling)
{
m_nodeAttribs.currentModelAlpha = 1.0f;
}
else
{
float nodeAlpha = lodTableEntry.lod[3].blendFactor * (LODscale - lodTableEntry.lod[3].deleteSize);
nodeAlpha = std::clamp(nodeAlpha, 0.0f, 1.0f);
m_nodeAttribs.currentModelAlpha *= nodeAlpha; // alpha of each node multiples by the alpha of its parent
}
if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && m_nodeAttribs.currentModelAlpha > 0.0f) {
// Descend down first link // Descend down first link
if ((node[0x00] & 0x08)) // 4-element LOD table if ((node[0x00] & 0x08)) // 4-element LOD table
{ {
lodTable = TranslateCullingAddress(child1Ptr); lodPtr = TranslateCullingAddress(child1Ptr);
if (NULL != lodTable) { // determine which LOD to use; we do not currently blend between LODs
int modelLOD;
for (modelLOD = 0; modelLOD < 3; modelLOD++)
{
if (LODscale >= lodTableEntry.lod[modelLOD].deleteSize)
break;
}
if (NULL != lodPtr) {
if ((node[0x03 - m_offset] & 0x20000000)) { if ((node[0x03 - m_offset] & 0x20000000)) {
DescendCullingNode(lodTable[0] & 0xFFFFFF); DescendCullingNode(lodPtr[modelLOD] & 0xFFFFFF);
} }
else { else {
DrawModel(lodTable[0] & 0xFFFFFF); //TODO DrawModel(lodPtr[modelLOD] & 0xFFFFFF);
} }
} }
} }

View file

@ -3,8 +3,8 @@
struct LOD struct LOD
{ {
float startRange; // possibly specified as angles also, yeah who knows >_< float deleteSize;
float deleteRange; float blendFactor;
}; };
struct LODFeatureType struct LODFeatureType