Skip to content

Commit

Permalink
ecere/gfx/3D: Proper implementation of Painter's algorithm for sortin…
Browse files Browse the repository at this point in the history
…g translucent primitives

- First, primitives are sorted by their mid point Z coordinates. If `maxFullSort` is set to 0, the sorting is done, otherwise the full sorting proceeds.
- The default value for `maxFullSort` is 3000, fully sorting the 3000 primitives closest to the camera.
- Further comparisons have no total order, therefore a topological sort must be used.
- An XY overlap test (in normalized screen coordinates) uses a MinMax tree to quickly locate overlapping polygon pairs on which further tests must be performed.
- The next check performed is whether all points of either primitive fall completely on the other side of the other primitive's plane compared to the camera, therefore one could never obscure the other.
- A Z overlap check is then performed to see if one primitive could possibly obscur the other.
- If `fullProjCheck` is set to true, a full check is done to see if either primitive obscurs the other once projected.
- The full projection check determines whether one primitive intersects the tetrahedron formed by the camera and the points of a triangle being obscured.
- Using new corrected Matrix::InverseTransposeTransform() method to compute full inverse transpose matrix and doing full plane transform with Plane::MultMatrix().
- This should correctly handle most cases except intersecting and cyclic overlaps.
  • Loading branch information
jerstlouis committed Jan 23, 2022
1 parent e851001 commit f298ea9
Show file tree
Hide file tree
Showing 10 changed files with 1,629 additions and 427 deletions.
2 changes: 1 addition & 1 deletion butterbur/src/presentation/GraphicalPresentation.ec
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ static inline double ::fromLine(const Pointf p, const Pointf a, const Pointf b)
}

// For detecting if a point is in a shape using the tesselated shape.
#define signedArea(p1, p2, p3) fromLine(p3, p1, p2)
#define signedArea(p1, p2, p3) fromLine(p3, p1, p2) // NOTE: this is actually TWICE the signed area, isn't it? Though here we only care about the sign.

static bool pointInsideTriangle(Pointf p, Pointf v1, Pointf v2, Pointf v3)
{
Expand Down
40 changes: 40 additions & 0 deletions ecere/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ _ECSOURCES1 = \
src/gfx/3D/meshes/SkyBox.ec \
src/gfx/3D/meshes/Sphere.ec \
src/gfx/3D/models/Object3DSFormat.ec \
src/gfx/3D/depthsort/Tetrahedron.ec \
src/gfx/3D/depthsort/TopoSort.ec \
src/gfx/3D/depthsort/DepthSort.ec \
src/gfx/3D/depthsort/Pool.ec \
src/gfx/3D/Camera.ec \
src/gfx/3D/Matrix.ec \
src/gfx/3D/Mesh.ec \
Expand Down Expand Up @@ -764,6 +768,18 @@ $(OBJ)Sphere.sym: src/gfx/3D/meshes/Sphere.ec
$(OBJ)Object3DSFormat.sym: src/gfx/3D/models/Object3DSFormat.ec
$(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/models/Object3DSFormat.ec -o $(OBJ)Object3DSFormat.sym

$(OBJ)Tetrahedron.sym: src/gfx/3D/depthsort/Tetrahedron.ec
$(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/Tetrahedron.ec -o $(OBJ)Tetrahedron.sym

$(OBJ)TopoSort.sym: src/gfx/3D/depthsort/TopoSort.ec
$(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/TopoSort.ec -o $(OBJ)TopoSort.sym

$(OBJ)DepthSort.sym: src/gfx/3D/depthsort/DepthSort.ec
$(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/DepthSort.ec -o $(OBJ)DepthSort.sym

$(OBJ)Pool.sym: src/gfx/3D/depthsort/Pool.ec
$(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/Pool.ec -o $(OBJ)Pool.sym

$(OBJ)Camera.sym: src/gfx/3D/Camera.ec
$(ECP) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/Camera.ec -o $(OBJ)Camera.sym

Expand Down Expand Up @@ -1227,6 +1243,18 @@ $(OBJ)Sphere.c: src/gfx/3D/meshes/Sphere.ec $(OBJ)Sphere.sym | $(SYMBOLS)
$(OBJ)Object3DSFormat.c: src/gfx/3D/models/Object3DSFormat.ec $(OBJ)Object3DSFormat.sym | $(SYMBOLS)
$(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/models/Object3DSFormat.ec -o $(OBJ)Object3DSFormat.c -symbols $(OBJ)

$(OBJ)Tetrahedron.c: src/gfx/3D/depthsort/Tetrahedron.ec
$(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/Tetrahedron.ec -o $(OBJ)Tetrahedron.c -symbols $(OBJ)

$(OBJ)TopoSort.c: src/gfx/3D/depthsort/TopoSort.ec
$(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/TopoSort.ec -o $(OBJ)TopoSort.c -symbols $(OBJ)

$(OBJ)DepthSort.c: src/gfx/3D/depthsort/DepthSort.ec
$(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/DepthSort.ec -o $(OBJ)DepthSort.c -symbols $(OBJ)

$(OBJ)Pool.c: src/gfx/3D/depthsort/Pool.ec
$(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/depthsort/Pool.ec -o $(OBJ)Pool.c -symbols $(OBJ)

$(OBJ)Camera.c: src/gfx/3D/Camera.ec $(OBJ)Camera.sym | $(SYMBOLS)
$(ECC) $(CFLAGS) $(CECFLAGS) $(ECFLAGS) $(PRJ_CFLAGS) -c src/gfx/3D/Camera.ec -o $(OBJ)Camera.c -symbols $(OBJ)

Expand Down Expand Up @@ -1699,6 +1727,18 @@ $(OBJ)Sphere.o: $(OBJ)Sphere.c
$(OBJ)Object3DSFormat.o: $(OBJ)Object3DSFormat.c
$(CC) $(CFLAGS) $(PRJ_CFLAGS) -c $(OBJ)Object3DSFormat.c -o $(OBJ)Object3DSFormat.o

$(OBJ)Tetrahedron$(O): $(OBJ)Tetrahedron.c
$(CC) $(CFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(OBJ)Tetrahedron.c -o $(OBJ)Tetrahedron.o

$(OBJ)TopoSort$(O): $(OBJ)TopoSort.c
$(CC) $(CFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(OBJ)TopoSort.c -o $(OBJ)TopoSort.o

$(OBJ)DepthSort$(O): $(OBJ)DepthSort.c
$(CC) $(CFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(OBJ)DepthSort.c -o $(OBJ)DepthSort.o

$(OBJ)Pool$(O): $(OBJ)Pool.c
$(CC) $(CFLAGS) $(PRJ_CFLAGS) $(FVISIBILITY) -c $(OBJ)Pool.c -o $(OBJ)Pool.o

$(OBJ)Camera.o: $(OBJ)Camera.c
$(CC) $(CFLAGS) $(PRJ_CFLAGS) -c $(OBJ)Camera.c -o $(OBJ)Camera.o

Expand Down
10 changes: 10 additions & 0 deletions ecere/ecere.epj
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,16 @@
"Object3DSFormat.ec"
]
},
{
"Folder" : "depthsort",
"Files" : [
"Tetrahedron.ec",
"TopoSort.ec",
"DepthSort.ec",
"MinMaxTree.eh",
"Pool.ec"
]
},
"Camera.ec",
"Matrix.ec",
"Mesh.ec",
Expand Down
101 changes: 97 additions & 4 deletions ecere/src/gfx/3D/Plane.ec
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,117 @@ public struct Plane

void IntersectLinef(const Line line, Vector3Df result)
{
double divisor = a * line.delta.x + b * line.delta.y + c * line.delta.z;
// 1.0 / Dot product of plane normal and line
double divisor = 1.0 / (a * line.delta.x + b * line.delta.y + c * line.delta.z);

result.x = (float)((b * line.delta.y * line.p0.x - b * line.delta.x * line.p0.y +
c * line.delta.z * line.p0.x - c * line.delta.x * line.p0.z -
d * line.delta.x ) / divisor);
d * line.delta.x ) * divisor);

result.y = (float)((a * line.delta.x * line.p0.y - a * line.delta.y * line.p0.x +
c * line.delta.z * line.p0.y - c * line.delta.y * line.p0.z -
d * line.delta.y ) / divisor);
d * line.delta.y ) * divisor);

result.z = (float)((a * line.delta.x * line.p0.z - a * line.delta.z * line.p0.x +
b * line.delta.y * line.p0.z - b * line.delta.z * line.p0.y -
d * line.delta.z ) / divisor);
d * line.delta.z ) * divisor);
}

int IntersectLinefT(const Line line, Vector3Df result, double * rt)
{
int r = 0;
double t;
double dot = normal.x * line.delta.x + normal.y * line.delta.y + normal.z * line.delta.z; // normal.DotProduct(line.delta);
double adot = fabs(dot);
if(adot > 1E-11)
{
if(adot < 0.001)
{
double divisor = 1.0 / dot;
result.x = (float)((b * line.delta.y * line.p0.x - b * line.delta.x * line.p0.y +
c * line.delta.z * line.p0.x - c * line.delta.x * line.p0.z -
d * line.delta.x ) * divisor);
result.y = (float)((a * line.delta.x * line.p0.y - a * line.delta.y * line.p0.x +
c * line.delta.z * line.p0.y - c * line.delta.y * line.p0.z -
d * line.delta.y ) * divisor);
result.z = (float)((a * line.delta.x * line.p0.z - a * line.delta.z * line.p0.x +
b * line.delta.y * line.p0.z - b * line.delta.z * line.p0.y -
d * line.delta.z ) * divisor);
if(fabs(line.delta.x) > fabs(line.delta.y) && fabs(line.delta.x) > fabs(line.delta.z))
t = (result.x - line.p0.x) / line.delta.x;
else if(fabs(line.delta.y) > fabs(line.delta.z))
t = (result.y - line.p0.y) / line.delta.y;
else
t = (result.z - line.p0.z) / line.delta.z;
}
else
{
double distance = d + line.p0.x * normal.x + line.p0.y * normal.y + line.p0.z * normal.z; // line.p0.DotProduct(normal);

t = -distance / dot;
result = { (float)(line.p0.x + line.delta.x * t), (float)(line.p0.y + line.delta.y * t), (float)(line.p0.z + line.delta.z * t) };
r = 1;
}
}
else
{
double distance = d + line.p0.x * normal.x + line.p0.y * normal.y + line.p0.z * normal.z; // line.p0.DotProduct(normal);

// Line is parallel to the plane
t = 0;
result = { (float)line.p0.x, (float)line.p0.y, (float)line.p0.z };
r = (distance == 0 ? 2 : 0); // The whole line intersects with the plane if p0 is at 0 distance
}

if(rt) *rt = t;
return r;
}

void FromPointNormal(const Vector3D normal, const Vector3D point)
{
this.normal = normal;
d = -(normal.x * point.x + normal.y * point.y + normal.z * point.z);
}

#define EPSILON 0.00001f

private uint IntersectSegment(const Vector3Df a, const Vector3Df b, Vector3Df i)
{
Line line { { a.x, a.y, a.z }, { (double)b.x - (double)a.x, (double)b.y - (double)a.y, (double)b.z - (double)a.z } };
double t;
Vector3Df v;
int r = IntersectLinefT(line, v, &t);
i = v;
return (r == 1 && t > EPSILON && t < 1 - EPSILON) | ((r && fabs(t) < EPSILON) << 1) | ((r && fabs(t - 1) < EPSILON) << 2);
}

// Returns the number of intersections
// NOTE: Currently this does not consider triangles co-planar with the plane
private int IntersectTriangle(const Vector3Df a, const Vector3Df b, const Vector3Df c, Vector3Df * i)
{
int n = 0;
Vector3Df v;
uint r = IntersectSegment(a, b, v);
if(r)
{
if(r == 1) i[n++] = v;
if(r & 2) i[n++] = a;
if(r & 4) i[n++] = b;
}

r = IntersectSegment(b, c, v);
if(r)
{
if(r == 1) i[n++] = v;
if(r & 4) i[n++] = b;
}

r = IntersectSegment(c, a, v);
if(r)
{
if(r == 1) i[n++] = v;
if(r & 2) i[n++] = c;
}
return n;
}
};
Loading

0 comments on commit f298ea9

Please sign in to comment.