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

View file

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

View file

@ -559,11 +559,12 @@ bool CNew3D::DrawModel(UINT32 modelAddr)
-------- -------- -------- -----x-- Valid color table
-------- -------- -------- ------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
-------- -------- -------- ------x- Disable culling
-------- -------- -------- -------x Valid model scale
0x02 : -------- -------- x------- -------- Texture replace
-------- -------- -x------ -------- Switch bank
-------- -------- --xxxxxx x------- X offset
@ -595,7 +596,7 @@ void CNew3D::DescendCullingNode(UINT32 addr)
{
enum class NodeType { undefined = -1, viewport = 0, rootNode = 1, cullingNode = 2 };
const UINT32 *node, *lodTable;
const UINT32 *node, *lodPtr;
UINT32 matrixOffset, child1Ptr, sibling2Ptr;
BBox bbox;
UINT16 uCullRadius;
@ -645,10 +646,11 @@ void CNew3D::DescendCullingNode(UINT32 addr)
if (!m_offset) { // Step 1.5+
float modelScale = Util::Uint32AsFloat(node[1]);
if (modelScale > std::numeric_limits<float>::min()) {
m_nodeAttribs.currentModelScale = modelScale;
}
if (node[0x01] & 1)
m_nodeAttribs.currentModelScale = Util::Uint32AsFloat(node[0x01] & ~3); // mask out control bits
if (node[0x01] & 2)
m_nodeAttribs.currentDisableCulling = true;
// apply texture offsets, else retain current ones
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
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
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)) {
DescendCullingNode(lodTable[0] & 0xFFFFFF);
DescendCullingNode(lodPtr[modelLOD] & 0xFFFFFF);
}
else {
DrawModel(lodTable[0] & 0xFFFFFF); //TODO
DrawModel(lodPtr[modelLOD] & 0xFFFFFF);
}
}
}

View file

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