Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 110 additions & 17 deletions Client/MeshPool/MeshDataPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,46 +368,139 @@ public void FrustumCull(FrustumCulling frustumCuller, EnumFrustumCullMode frustu
RenderedTriangles = 0;
AllocatedTris = 0;

for (int i = 0; i < poolLocations.Count; i++)
// Cache frequently used values ​​outside the loop
int visIdx = ModelDataPoolLocation.VisibleBufIndex;
int count = poolLocations.Count;
ModelDataPoolLocation location;
int size;

// switch is moved OUTSIDE the loop
switch (frustumCullMode)
{
ModelDataPoolLocation location = poolLocations[i];

int size = location.IndicesEnd - location.IndicesStart;
if (location.IsVisible(frustumCullMode, frustumCuller))
{
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4; // Offset in bytes, not ints
indicesSizes[indicesGroupsCount] = size;
case EnumFrustumCullMode.CullInstant:
for (int i = 0; i < count; i++)
{
location = poolLocations[i];
size = location.IndicesEnd - location.IndicesStart;
AllocatedTris += size;

if (!location.Hide && location.CullVisible[visIdx] && frustumCuller.InFrustum(location.FrustumCullSphere))
{
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4;
indicesSizes[indicesGroupsCount] = size;
RenderedTriangles += size;
indicesGroupsCount++;
}
}
break;

RenderedTriangles += size / 3;
case EnumFrustumCullMode.CullInstantShadowPassNear:
for (int i = 0; i < count; i++)
{
location = poolLocations[i];
size = location.IndicesEnd - location.IndicesStart;
AllocatedTris += size;

if (!location.Hide && location.CullVisible[visIdx] && frustumCuller.InFrustumShadowPass(location.FrustumCullSphere))
{
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4;
indicesSizes[indicesGroupsCount] = size;
RenderedTriangles += size;
indicesGroupsCount++;
}
}
break;

indicesGroupsCount++;
}
case EnumFrustumCullMode.CullInstantShadowPassFar:
for (int i = 0; i < count; i++)
{
location = poolLocations[i];
size = location.IndicesEnd - location.IndicesStart;
AllocatedTris += size;

if (!location.Hide && location.CullVisible[visIdx] && location.LodLevel >= 1 && frustumCuller.InFrustumShadowPass(location.FrustumCullSphere))
{
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4;
indicesSizes[indicesGroupsCount] = size;
RenderedTriangles += size;
indicesGroupsCount++;
}
}
break;

AllocatedTris += size / 3;
case EnumFrustumCullMode.CullNormal:
for (int i = 0; i < count; i++)
{
location = poolLocations[i];
size = location.IndicesEnd - location.IndicesStart;
AllocatedTris += size;

if (!location.Hide && location.CullVisible[visIdx])
{
bool inFrustum = frustumCuller.InFrustumAndRange(location.FrustumCullSphere, location.FrustumVisible, location.LodLevel);
// UpdateVisibleFlag is inlined directly - removing the extra method call
location.FrustumVisible = inFrustum;
if (inFrustum)
{
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4;
indicesSizes[indicesGroupsCount] = size;
RenderedTriangles += size;
indicesGroupsCount++;
}
}
}
break;

default: // NoCull
for (int i = 0; i < count; i++)
{
location = poolLocations[i];
size = location.IndicesEnd - location.IndicesStart;
AllocatedTris += size;

if (!location.Hide)
{
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4;
indicesSizes[indicesGroupsCount] = size;
RenderedTriangles += size;
indicesGroupsCount++;
}
}
break;
}


AllocatedTris = (int)(AllocatedTris / 3);
RenderedTriangles = (int)(RenderedTriangles / 3);
}

public void SetFullyVisible()
{
indicesGroupsCount = 0;

RenderedTriangles = 0;
AllocatedTris = 0;

ModelDataPoolLocation location;
int size;

for (int i = 0; i < poolLocations.Count; i++)
{
ModelDataPoolLocation location = poolLocations[i];
location = poolLocations[i];

int size = location.IndicesEnd - location.IndicesStart;
size = location.IndicesEnd - location.IndicesStart;
indicesStartsByte[indicesGroupsCount * 2] = location.IndicesStart * 4; // Offset in bytes, not ints
indicesSizes[indicesGroupsCount] = size;

RenderedTriangles += size / 3;
RenderedTriangles += size;

indicesGroupsCount++;

AllocatedTris += size / 3;
AllocatedTris += size;
}

AllocatedTris = (int)(AllocatedTris / 3);
RenderedTriangles = (int)(RenderedTriangles / 3);

}

/// <summary>
Expand Down
14 changes: 9 additions & 5 deletions Client/MeshPool/MeshDataPoolManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,12 @@ public ModelDataPoolLocation AddModel(MeshData modeldata, Vec3i modelOrigin, int
public void Render(Vec3d playerpos, string originUniformName, EnumFrustumCullMode frustumCullMode = EnumFrustumCullMode.CullNormal)
{
int count = pools.Count;
MeshDataPool pool;
IShaderProgram currShader;

for (int i = 0; i < count; i++)
{
MeshDataPool pool = pools[i];
pool = pools[i];
if (pool.dimensionId == Dimensions.MiniDimensions)
{
bool revertModelviewMatrix = false;
Expand All @@ -132,7 +135,7 @@ public void Render(Vec3d playerpos, string originUniformName, EnumFrustumCullMod

FastVec3d renderOffset = dimension.GetRenderOffset(masterPool.currentDt);

var currShader = capi.Render.CurrentActiveShader;
currShader = capi.Render.CurrentActiveShader;
if (currShader.HasUniform("modelViewMatrix"))
{
currShader.UniformMatrix("modelViewMatrix", dimension.GetRenderTransformMatrix(masterPool.currentModelViewMatrix, playerpos));
Expand Down Expand Up @@ -162,11 +165,11 @@ public void Render(Vec3d playerpos, string originUniformName, EnumFrustumCullMod
finally
{
if (revertModelviewMatrix)
capi.Render.CurrentActiveShader.UniformMatrix("modelViewMatrix", masterPool.currentModelViewMatrix);
currShader.UniformMatrix("modelViewMatrix", masterPool.currentModelViewMatrix);
if (revertMVPMatrix)
capi.Render.CurrentActiveShader.UniformMatrix("mvpMatrix", masterPool.shadowMVPMatrix);
currShader.UniformMatrix("mvpMatrix", masterPool.shadowMVPMatrix);
if (revertTransparency)
capi.Render.CurrentActiveShader.Uniform("forcedTransparency", 0f);
currShader.Uniform("forcedTransparency", 0f);
}
}
else
Expand Down Expand Up @@ -243,3 +246,4 @@ public void GetStats(ref long usedVideoMemory, ref long renderedTris, ref long a


}

28 changes: 20 additions & 8 deletions Client/Render/FrustumCulling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ public enum EnumFrustumCullMode
CullInstantShadowPassFar = 4
}


public struct Plane
{
public double normalX;
public double normalY;
public double normalZ;
public double D;
private const float SQRT3 = 1.7320508f;
private const float INV_SQRT3 = 0.577350269f; // 1 / √3

/// <summary>
/// Creates a Plane with normalised (length 1.0) normal vector
Expand All @@ -60,17 +60,28 @@ public bool AABBisOutside(Sphere sphere)

// Optimised algorithm: First, figure out which of the 8 corners of the AABB we are going to test against this plane - if even the "lowest" corner (the corner in the direction most opposed to the plane normal direction) is outside (above) the plane then the whole AABB must be outside the plane
// X axis
int sign = normalX > 0 ? 1 : -1;
double testX = (double)sphere.x + sign * sphere.radius / SQRT3; // sphere.radius is 16 if the sphere represents a chunk and chunksize is 32
//int sign = normalX > 0 ? 1 : -1;
//double testX = (double)sphere.x + sign * sphere.radius / SQRT3; // sphere.radius is 16 if the sphere represents a chunk and chunksize is 32

sign = normalY > 0 ? 1 : -1;
double testY = (double)sphere.y + sign * sphere.radiusY / SQRT3;
//sign = normalY > 0 ? 1 : -1;
//double testY = (double)sphere.y + sign * sphere.radiusY / SQRT3;

sign = normalZ > 0 ? 1 : -1;
double testZ = (double)sphere.z + sign * sphere.radiusZ / SQRT3;
//sign = normalZ > 0 ? 1 : -1;
//double testZ = (double)sphere.z + sign * sphere.radiusZ / SQRT3;

// Now see if that test corner is "outside" the plane
return testX * normalX + testY * normalY + testZ * normalZ + D < 0;
//return testX * normalX + testY * normalY + testZ * normalZ + D < 0;


// Sign for each axis (direction of the "worst" vertex)
float signX = normalX > 0 ? INV_SQRT3 : -INV_SQRT3;
float signY = normalY > 0 ? INV_SQRT3 : -INV_SQRT3;
float signZ = normalZ > 0 ? INV_SQRT3 : -INV_SQRT3;

// Calculate the scalar product directly, without intermediate variables
return (sphere.x + signX * sphere.radius) * normalX +
(sphere.y + signY * sphere.radiusY) * normalY +
(sphere.z + signZ * sphere.radiusZ) * normalZ + D < 0;
}
}

Expand Down Expand Up @@ -249,3 +260,4 @@ public class EnumLodPool
public const int FarDistanceOnly = 3;
}
}