mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 13:55:38 +00:00
Implement LOD blending
If two translucent polygons with opposing patterns overlap the result is always opaque Also the LOD scale calculation depends on Euclidean distance of x, y and z, not just z
This commit is contained in:
parent
a065df24b8
commit
ac53101214
|
@ -714,46 +714,69 @@ void CNew3D::DescendCullingNode(UINT32 addr)
|
|||
}
|
||||
}
|
||||
|
||||
float LODscale = fBlendRadius * m_nodeAttribs.currentModelScale / std::abs(m_modelMat.currentMatrix[14]);
|
||||
float LODscale;
|
||||
if (m_nodeAttribs.currentDisableCulling)
|
||||
LODscale = FLT_MAX;
|
||||
else
|
||||
{
|
||||
float distance = std::hypot(m_modelMat.currentMatrix[12], m_modelMat.currentMatrix[13], m_modelMat.currentMatrix[14]);
|
||||
LODscale = fBlendRadius * m_nodeAttribs.currentModelScale / distance;
|
||||
}
|
||||
|
||||
const 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) {
|
||||
if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && LODscale >= lodTableEntry.lod[3].deleteSize) {
|
||||
|
||||
// Descend down first link
|
||||
if ((node[0x00] & 0x08)) // 4-element LOD table
|
||||
{
|
||||
lodPtr = TranslateCullingAddress(child1Ptr);
|
||||
|
||||
// determine which LOD to use; we do not currently blend between LODs
|
||||
if (NULL != lodPtr)
|
||||
{
|
||||
int modelLOD;
|
||||
for (modelLOD = 0; modelLOD < 3; modelLOD++)
|
||||
{
|
||||
if (LODscale >= lodTableEntry.lod[modelLOD].deleteSize)
|
||||
if (LODscale >= lodTableEntry.lod[modelLOD].deleteSize && lodPtr[modelLOD] & 0x1000000)
|
||||
break;
|
||||
}
|
||||
|
||||
if (NULL != lodPtr) {
|
||||
float tempAlpha = m_nodeAttribs.currentModelAlpha;
|
||||
|
||||
float nodeAlpha = lodTableEntry.lod[modelLOD].blendFactor * (LODscale - lodTableEntry.lod[modelLOD].deleteSize);
|
||||
nodeAlpha = std::clamp(nodeAlpha, 0.0f, 1.0f);
|
||||
if (nodeAlpha > 15.0f / 16.0f) // shader discards pixels below 1/16 alpha
|
||||
nodeAlpha = 1.0f;
|
||||
else if (nodeAlpha < 1.0f / 16.0f)
|
||||
nodeAlpha = 0.0f;
|
||||
m_nodeAttribs.currentModelAlpha *= nodeAlpha; // alpha of each node multiples by the alpha of its parent
|
||||
|
||||
if ((node[0x03 - m_offset] & 0x20000000)) {
|
||||
DescendCullingNode(lodPtr[modelLOD] & 0xFFFFFF);
|
||||
|
||||
if (nodeAlpha < 1.0f && modelLOD != 3)
|
||||
{
|
||||
m_nodeAttribs.currentModelAlpha = (1.0f - nodeAlpha) * tempAlpha;
|
||||
DescendCullingNode(lodPtr[modelLOD+1] & 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DrawModel(lodPtr[modelLOD] & 0xFFFFFF);
|
||||
|
||||
if (nodeAlpha < 1.0f && modelLOD != 3)
|
||||
{
|
||||
m_nodeAttribs.currentModelAlpha = (1.0f - nodeAlpha) * tempAlpha;
|
||||
DrawModel(lodPtr[modelLOD + 1] & 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
DescendNodePtr(child1Ptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -275,16 +275,18 @@ void R3DFrameBuffers::AllocShaderTrans()
|
|||
vec4 colTrans1 = texture(tex1, fsTexCoord);
|
||||
vec4 colTrans2 = texture(tex2, fsTexCoord);
|
||||
|
||||
if(colTrans1.a+colTrans2.a > 0.0) {
|
||||
vec3 col1 = colTrans1.rgb * colTrans1.a;
|
||||
vec3 col2 = colTrans2.rgb * colTrans2.a;
|
||||
|
||||
colTrans1 = vec4((col1+col2) / (colTrans1.a + colTrans2.a), // this is my best guess at the blending between the layers
|
||||
colTrans1.a+colTrans2.a);
|
||||
// if both transparency layers overlap, the result is opaque
|
||||
if (colTrans1.a * colTrans2.a > 0.0) {
|
||||
vec3 mixCol = mix(colTrans1.rgb, colTrans2.rgb, (colTrans2.a + (1.0 - colTrans1.a)) / 2.0);
|
||||
fragColor = vec4(mixCol, 1.0);
|
||||
}
|
||||
|
||||
else if (colTrans1.a > 0.0) {
|
||||
fragColor = colTrans1;
|
||||
}
|
||||
else {
|
||||
fragColor = colTrans2; // if alpha is zero it will have no effect anyway
|
||||
}
|
||||
}
|
||||
|
||||
)glsl";
|
||||
|
||||
|
|
Loading…
Reference in a new issue