Browse Source

Optimized dense model rendering using back-face culling.

David Piuva 5 years ago
parent
commit
673f53836a
1 changed files with 22 additions and 2 deletions
  1. 22 2
      Source/SDK/sandbox/sprite/spriteAPI.cpp

+ 22 - 2
Source/SDK/sandbox/sprite/spriteAPI.cpp

@@ -823,6 +823,26 @@ static IRect boundingBoxToRectangle(const FVector3D& minBound, const FVector3D&
 	return result;
 }
 
+static IRect getBackCulledTriangleBound(LVector2D a, LVector2D b, LVector2D c) {
+	if (((c.x - a.x) * (b.y - a.y)) + ((c.y - a.y) * (a.x - b.x)) >= 0) {
+		// Back facing
+		return IRect();
+	} else {
+		// Front facing
+		int32_t rX1 = (a.x + constants::unitsPerHalfPixel) / constants::unitsPerPixel;
+		int32_t rY1 = (a.y + constants::unitsPerHalfPixel) / constants::unitsPerPixel;
+		int32_t rX2 = (b.x + constants::unitsPerHalfPixel) / constants::unitsPerPixel;
+		int32_t rY2 = (b.y + constants::unitsPerHalfPixel) / constants::unitsPerPixel;
+		int32_t rX3 = (c.x + constants::unitsPerHalfPixel) / constants::unitsPerPixel;
+		int32_t rY3 = (c.y + constants::unitsPerHalfPixel) / constants::unitsPerPixel;
+		int leftBound = std::min(std::min(rX1, rX2), rX3) - 1;
+		int topBound = std::min(std::min(rY1, rY2), rY3) - 1;
+		int rightBound = std::max(std::max(rX1, rX2), rX3) + 1;
+		int bottomBound = std::max(std::max(rY1, rY2), rY3) + 1;
+		return IRect(leftBound, topBound, rightBound - leftBound, bottomBound - topBound);
+	}
+}
+
 // Pre-conditions:
 //   * All images must exist and have the same dimensions
 //   * All triangles in model must be contained within the image bounds after being projected using view
@@ -891,7 +911,7 @@ static IRect renderModel(Model model, OrthoView view, ImageF32 depthBuffer, Imag
 				FVector3D pointC = projectedPoints[indexC];
 				LVector2D subPixelB = LVector2D(safeRoundInt64(pointB.x * constants::unitsPerPixel), safeRoundInt64(pointB.y * constants::unitsPerPixel));
 				LVector2D subPixelC = LVector2D(safeRoundInt64(pointC.x * constants::unitsPerPixel), safeRoundInt64(pointC.y * constants::unitsPerPixel));
-				IRect triangleBound = IRect::cut(clipBound, getTriangleBound(subPixelA, subPixelB, subPixelC));
+				IRect triangleBound = IRect::cut(clipBound, getBackCulledTriangleBound(subPixelA, subPixelB, subPixelC));
 				int rowCount = triangleBound.height();
 				if (rowCount > 0) {
 					RowInterval rows[rowCount];
@@ -910,10 +930,10 @@ static IRect renderModel(Model model, OrthoView view, ImageF32 depthBuffer, Imag
 						SafePointer<uint32_t> normalPixel = normalRow + left;
 						SafePointer<float> heightPixel = heightRow + left;
 						for (int x = left; x < right; x++) {
+							// TODO: This custom rendering pipeline was never designed to be clipped against edges, so the vertex weights are out of bound when vertices are on the left side of the target image.
 							FVector3D weight = getAffineWeight(FVector3Dto2D(pointA), FVector3Dto2D(pointB), FVector3Dto2D(pointC), FVector2D(x + 0.5f, y + 0.5f));
 							float height = interpolateUsingAffineWeight(pointA.z, pointB.z, pointC.z, weight);
 							if (height > *heightPixel) {
-								// TODO: Interpolate the values directly using integer addition and bit shifting
 								FVector4D vertexColor = interpolateUsingAffineWeight(vertexColorA, vertexColorB, vertexColorC, weight);
 								FVector3D normal = (normalize(interpolateUsingAffineWeight(normalA, normalB, normalC, weight)) + 1.0f) * 127.5f;
 								// Write data directly without saturation (Do not use colors outside of the visible range!)