2
0
Эх сурвалжийг харах

Increased occlusion buffer Z-accuracy.
Use similar calculations for occluders and occludees to minimize errors.
Decreased default minimum occluder screen size to allow better occluder fusion of small occluders.

Lasse Öörni 13 жил өмнө
parent
commit
6fbf8d0404

+ 29 - 34
Engine/Graphics/OcclusionBuffer.cpp

@@ -313,46 +313,41 @@ bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
     if (!buffer_)
     if (!buffer_)
         return true;
         return true;
     
     
-    Vector3 vertices[8];
-    
-    // Transform corners to view space. Note: do not directly transform the bounding box, as this would expand it unnecessarily
-    vertices[0] = view_ * worldSpaceBox.min_;
-    vertices[1] = view_ * Vector3(worldSpaceBox.max_.x_, worldSpaceBox.min_.y_, worldSpaceBox.min_.z_);
-    vertices[2] = view_ * Vector3(worldSpaceBox.min_.x_, worldSpaceBox.max_.y_, worldSpaceBox.min_.z_);
-    vertices[3] = view_ * Vector3(worldSpaceBox.max_.x_, worldSpaceBox.max_.y_, worldSpaceBox.min_.z_);
-    vertices[4] = view_ * Vector3(worldSpaceBox.min_.x_, worldSpaceBox.min_.y_, worldSpaceBox.max_.z_);
-    vertices[5] = view_ * Vector3(worldSpaceBox.max_.x_, worldSpaceBox.min_.y_, worldSpaceBox.max_.z_);
-    vertices[6] = view_ * Vector3(worldSpaceBox.min_.x_, worldSpaceBox.max_.y_, worldSpaceBox.max_.z_);
-    vertices[7] = view_ * worldSpaceBox.max_;
-    
-    // Project to screen. If any of the corners cross the near plane, assume visible
+    // Transform corners to projection space
+    Vector4 vertices[8];
+    vertices[0] = ModelTransform(viewProj_, worldSpaceBox.min_);
+    vertices[1] = ModelTransform(viewProj_, Vector3(worldSpaceBox.max_.x_, worldSpaceBox.min_.y_, worldSpaceBox.min_.z_));
+    vertices[2] = ModelTransform(viewProj_, Vector3(worldSpaceBox.min_.x_, worldSpaceBox.max_.y_, worldSpaceBox.min_.z_));
+    vertices[3] = ModelTransform(viewProj_, Vector3(worldSpaceBox.max_.x_, worldSpaceBox.max_.y_, worldSpaceBox.min_.z_));
+    vertices[4] = ModelTransform(viewProj_, Vector3(worldSpaceBox.min_.x_, worldSpaceBox.min_.y_, worldSpaceBox.max_.z_));
+    vertices[5] = ModelTransform(viewProj_, Vector3(worldSpaceBox.max_.x_, worldSpaceBox.min_.y_, worldSpaceBox.max_.z_));
+    vertices[6] = ModelTransform(viewProj_, Vector3(worldSpaceBox.min_.x_, worldSpaceBox.max_.y_, worldSpaceBox.max_.z_));
+    vertices[7] = ModelTransform(viewProj_, worldSpaceBox.max_);
+    
+    // Transform to screen space. If any of the corners cross the near plane, assume visible
     float minX, maxX, minY, maxY, minZ;
     float minX, maxX, minY, maxY, minZ;
     
     
-    if (vertices[0].z_ <= nearClip_)
+    if (vertices[0].w_ <= nearClip_)
         return true;
         return true;
     
     
-    // Project the first corner to initialize the rectangle
-    float invW = 1.0f / (vertices[0].z_ * projection_.m32_ + projection_.m33_);
-    minX = maxX = invW * (projOffsetScaleX_ * vertices[0].x_) + offsetX_;
-    minY = maxY = invW * (projOffsetScaleY_ * vertices[0].y_) + offsetY_;
-    minZ = invW * (projection_.m22_ * vertices[0].z_ + projection_.m23_);
+    Vector3 projected = ViewportTransform(vertices[0]);
+    minX = maxX = projected.x_;
+    minY = maxY = projected.y_;
+    minZ = projected.z_;
     
     
     // Project the rest
     // Project the rest
     for (unsigned i = 1; i < 8; ++i)
     for (unsigned i = 1; i < 8; ++i)
     {
     {
-        if (vertices[i].z_ <= nearClip_)
+        if (vertices[i].w_ <= nearClip_)
             return true;
             return true;
         
         
-        float invW = 1.0f / (vertices[i].z_ * projection_.m32_ + projection_.m33_);
-        float x = invW * (projOffsetScaleX_ * vertices[i].x_) + offsetX_;
-        float y = invW * (projOffsetScaleY_ * vertices[i].y_) + offsetY_;
-        float z = invW * (projection_.m22_ * vertices[i].z_ + projection_.m23_);
+        projected = ViewportTransform(vertices[i]);
         
         
-        if (x < minX) minX = x;
-        if (x > maxX) maxX = x;
-        if (y < minY) minY = y;
-        if (y > maxY) maxY = y;
-        if (z < minZ) minZ = z;
+        if (projected.x_ < minX) minX = projected.x_;
+        if (projected.x_ > maxX) maxX = projected.x_;
+        if (projected.y_ < minY) minY = projected.y_;
+        if (projected.y_ > maxY) maxY = projected.y_;
+        if (projected.z_ < minZ) minZ = projected.z_;
     }
     }
     
     
     // Expand the bounding box 1 pixel in each direction to be conservative and correct rasterization offset
     // Expand the bounding box 1 pixel in each direction to be conservative and correct rasterization offset
@@ -377,7 +372,7 @@ bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
     if (rect.bottom_ >= height_)
     if (rect.bottom_ >= height_)
         rect.bottom_ = height_ - 1;
         rect.bottom_ = height_ - 1;
     
     
-    int z = (int)(minZ * OCCLUSION_Z_SCALE + 0.5f) - OCCLUSION_DEPTH_BIAS;
+    int z = (int)(minZ + 0.5f) - OCCLUSION_DEPTH_BIAS;
     
     
     if (!depthHierarchyDirty_)
     if (!depthHierarchyDirty_)
     {
     {
@@ -760,10 +755,10 @@ void OcclusionBuffer::DrawTriangle2D(const Vector3* vertices)
     
     
     int topY = (int)vertices[top].y_;
     int topY = (int)vertices[top].y_;
     int middleY = (int)vertices[middle].y_;
     int middleY = (int)vertices[middle].y_;
-    int bottoy_ = (int)vertices[bottom].y_;
+    int bottomY = (int)vertices[bottom].y_;
     
     
     // Check for degenerate triangle
     // Check for degenerate triangle
-    if (topY == bottoy_)
+    if (topY == bottomY)
         return;
         return;
     
     
     Gradients gradients(vertices);
     Gradients gradients(vertices);
@@ -798,7 +793,7 @@ void OcclusionBuffer::DrawTriangle2D(const Vector3* vertices)
         
         
         // Bottom half
         // Bottom half
         row = buffer_ + middleY * width_;
         row = buffer_ + middleY * width_;
-        endRow = buffer_ + bottoy_ * width_;
+        endRow = buffer_ + bottomY * width_;
         while (row < endRow)
         while (row < endRow)
         {
         {
             int invZ = topToBottom.invZ_;
             int invZ = topToBottom.invZ_;
@@ -844,7 +839,7 @@ void OcclusionBuffer::DrawTriangle2D(const Vector3* vertices)
         
         
         // Bottom half
         // Bottom half
         row = buffer_ + middleY * width_;
         row = buffer_ + middleY * width_;
-        endRow = buffer_ + bottoy_ * width_;
+        endRow = buffer_ + bottomY * width_;
         while (row < endRow)
         while (row < endRow)
         {
         {
             int invZ = middleToBottom.invZ_;
             int invZ = middleToBottom.invZ_;

+ 2 - 2
Engine/Graphics/OcclusionBuffer.h

@@ -48,9 +48,9 @@ struct DepthValue
 
 
 static const int OCCLUSION_MIN_SIZE = 8;
 static const int OCCLUSION_MIN_SIZE = 8;
 static const int OCCLUSION_DEFAULT_MAX_TRIANGLES = 5000;
 static const int OCCLUSION_DEFAULT_MAX_TRIANGLES = 5000;
-static const int OCCLUSION_DEPTH_BIAS = 4;
+static const int OCCLUSION_DEPTH_BIAS = 256;
 static const float OCCLUSION_X_SCALE = 65536.0f;
 static const float OCCLUSION_X_SCALE = 65536.0f;
-static const float OCCLUSION_Z_SCALE = 65536.0f;
+static const float OCCLUSION_Z_SCALE = 16777216.0f;
 
 
 /// Software renderer for occlusion.
 /// Software renderer for occlusion.
 class OcclusionBuffer : public Object
 class OcclusionBuffer : public Object

+ 1 - 1
Engine/Graphics/Renderer.cpp

@@ -276,7 +276,7 @@ Renderer::Renderer(Context* context) :
     maxInstanceTriangles_(500),
     maxInstanceTriangles_(500),
     maxOccluderTriangles_(5000),
     maxOccluderTriangles_(5000),
     occlusionBufferSize_(256),
     occlusionBufferSize_(256),
-    occluderSizeThreshold_(0.1f),
+    occluderSizeThreshold_(0.025f),
     shadersChangedFrameNumber_(M_MAX_UNSIGNED),
     shadersChangedFrameNumber_(M_MAX_UNSIGNED),
     renderMode_(RENDER_FORWARD),
     renderMode_(RENDER_FORWARD),
     specularLighting_(true),
     specularLighting_(true),