Browse Source

Using only 5 planes in view frustums when farClip is set to infinity.

David Piuva 2 years ago
parent
commit
4a35c49513
2 changed files with 27 additions and 15 deletions
  1. 1 0
      README.md
  2. 26 15
      Source/DFPSR/render/Camera.h

+ 1 - 0
README.md

@@ -29,6 +29,7 @@ Real-time dynamic light with depth-based casted shadows and normal mapping at 45
 * **2D drawing** Pixel exact standard draw calls for lines, rectangles, solid image copy, alpha filtered image drawing, depth buffered drawing, and stencil drawing.
 * **3D rendering** Roughly equivalent to Direct3D 7 with bi-linear texture sampling, mipmapping, lightmaps and alpha filtering when used out of the box, but can be modified to be more like Direct 3D 9 if you apply shading to textures (can use SIMD with multi-threading and be scheduled based on viewing distance).
 * **Occlusion system** The collection of rendering tasks for multi-threading also contains an occlusion grid where occlusion shapes can be drawn to skip drawing of triangles, object or whole groups if your engine implements a broad-phase for culling and occlusion tests. This fully dynamic occlusion can then be combined with static optimizations for specific games using information about which regions can be seen from each camera location.
+* **Optional far clipping** Because this graphics API only uses floating-point depth buffers for perspective, there is no need to normalize the depth values for any integer based representation. This allow selecting an infinite far clip distance when creating your camera, if you can afford rendering the entire scene at once.
 * **Media layer** Cross-platform media layer designed for robustness. Alsa and WinMM sound backends for full control over sound mixing, without having to call anything system specific yourself. On X11, the window management uses multi-threading for uploading the canvas, so that you get the same performance that you would get with a GPU graphics API but without needing any graphics drivers. Uses a borderless window for full-screen, so that you can easily access other programs if you get an important e-mail or instant message in the background. Upscaling is done on the CPU to work with any screen resolution without relying on graphics drivers that might give pixels the wrong interpolation or not even exist. Older media layers designed for CTR displays may cause frequency out of range errors when no graphics drivers are installed and the display does not accept the arbitrary selection of resolution. Uses an invisible cursor icon to hide the mouse, so that a crashing program will not take away the cursor when trying to kill the process.
 * **Graphical user interface framework** Load a visual interface to your window using a single line of code reading a layout file or string. Get generic handles to components using names or a combination of name and index. Add events by attaching lambda functions to component and window callbacks.
 * **Timers** Get the double precision seconds passed since the first call to the timer, so that you won't have to worry about midnight bugs when the time of day resets.

+ 26 - 15
Source/DFPSR/render/Camera.h

@@ -44,23 +44,25 @@ private:
 public:
 	ViewFrustum() : planeCount(0) {}
 	// Orthogonal view frustum in camera space
-	ViewFrustum(float halfWidth, float halfHeight) : planeCount(4) {
+	ViewFrustum(float halfWidth, float halfHeight)
+	: planeCount(4) {
 		// Sides
-		planes[0] = FPlane3D(FVector3D(1.0f, 0.0f, 0.0f), halfWidth * 1.01);
-		planes[1] = FPlane3D(FVector3D(-1.0f, 0.0f, 0.0f), halfWidth * 1.01);
-		planes[2] = FPlane3D(FVector3D(0.0f, 1.0f, 0.0f), halfHeight * 1.01);
-		planes[3] = FPlane3D(FVector3D(0.0f, -1.0f, 0.0f), halfHeight * 1.01);
+		planes[0] = FPlane3D(FVector3D(1.0f, 0.0f, 0.0f), halfWidth);
+		planes[1] = FPlane3D(FVector3D(-1.0f, 0.0f, 0.0f), halfWidth);
+		planes[2] = FPlane3D(FVector3D(0.0f, 1.0f, 0.0f), halfHeight);
+		planes[3] = FPlane3D(FVector3D(0.0f, -1.0f, 0.0f), halfHeight);
 	}
 	// Perspective view frustum in camera space
-	ViewFrustum(float nearClip, float farClip, float widthSlope, float heightSlope) : planeCount(6) {
+	ViewFrustum(float nearClip, float farClip, float widthSlope, float heightSlope)
+	: planeCount(farClip == std::numeric_limits<float>::infinity() ? 5 : 6) { // Skip the far clip plane if its distance is infinite.
 		// Sides
-		planes[0] = FPlane3D(FVector3D(1.0f, 0.0f, -widthSlope - 0.01f), 0.0f);
-		planes[1] = FPlane3D(FVector3D(-1.0f, 0.0f, -widthSlope - 0.01f), 0.0f);
-		planes[2] = FPlane3D(FVector3D(0.0f, 1.0f, -heightSlope - 0.01f), 0.0f);
-		planes[3] = FPlane3D(FVector3D(0.0f, -1.0f, -heightSlope - 0.01f), 0.0f);
+		planes[0] = FPlane3D(FVector3D(1.0f, 0.0f, -widthSlope), 0.0f);
+		planes[1] = FPlane3D(FVector3D(-1.0f, 0.0f, -widthSlope), 0.0f);
+		planes[2] = FPlane3D(FVector3D(0.0f, 1.0f, -heightSlope), 0.0f);
+		planes[3] = FPlane3D(FVector3D(0.0f, -1.0f, -heightSlope), 0.0f);
 		// Near and far clip planes
-		planes[4] = FPlane3D(FVector3D(0.0f, 0.0f, 1.0f), farClip);
-		planes[5] = FPlane3D(FVector3D(0.0f, 0.0f, -1.0f), -nearClip);
+		planes[4] = FPlane3D(FVector3D(0.0f, 0.0f, -1.0f), -nearClip);
+		planes[5] = FPlane3D(FVector3D(0.0f, 0.0f, 1.0f), farClip);
 	}
 	int getPlaneCount() const {
 		return this->planeCount;
@@ -71,9 +73,18 @@ public:
 	}
 };
 
+// How much is the image region magnified for skipping entire triangles.
+//   A small margin is needed to prevent missing pixels from rounding errors along the borders in high image resolutions.
+static const float cullRatio = 1.0001f;
+// How much is the image region magnified for clipping triangles.
+//   The larger you make the clip region, the less triangles you have to apply clipping to.
+//   The triangle rasterization can handle clipping triangles in integer coordinates,
+//     but there are limits to how large those integers can become before overflowing.
+static const float clipRatio = 2.0f;
+// To prevent division by zero, a near clipping distance is slightly above zero to
+//   clip triangles in 3D camera space before projecting the coordinates to the target image.
 static const float defaultNearClip = 0.01f;
 static const float defaultFarClip = 1000.0f;
-static const float clipRatio = 2.0f;
 
 // Just create a new camera on stack memory every time you need to render something
 class Camera {
@@ -94,14 +105,14 @@ public:
 	static Camera createPerspective(const Transform3D &location, float imageWidth, float imageHeight, float widthSlope = 1.0f, float nearClip = defaultNearClip, float farClip = defaultFarClip) {
 		float heightSlope = widthSlope * imageHeight / imageWidth;
 		return Camera(true, location, imageWidth, imageHeight, widthSlope, heightSlope, nearClip, farClip,
-		  ViewFrustum(nearClip, farClip, widthSlope, heightSlope),
+		  ViewFrustum(nearClip, farClip, widthSlope * cullRatio, heightSlope * cullRatio),
 		  ViewFrustum(nearClip, farClip, widthSlope * clipRatio, heightSlope * clipRatio));
 	}
 	// Orthogonal cameras doesn't have any near or far clip planes
 	static Camera createOrthogonal(const Transform3D &location, float imageWidth, float imageHeight, float halfWidth) {
 		float halfHeight = halfWidth * imageHeight / imageWidth;
 		return Camera(false, location, imageWidth, imageHeight, halfWidth, halfHeight, -std::numeric_limits<float>::max(), std::numeric_limits<float>::max(),
-		  ViewFrustum(halfWidth, halfHeight),
+		  ViewFrustum(halfWidth * cullRatio, halfHeight * cullRatio),
 		  ViewFrustum(halfWidth * clipRatio, halfHeight * clipRatio));
 	}
 	FVector3D worldToCamera(const FVector3D &worldSpace) const {