Browse Source

Fixed odd crash in editor script after scene load.
Fixed nearclip & farclip related rendering issues.

Lasse Öörni 14 years ago
parent
commit
b7797e95f2

+ 4 - 1
Bin/Data/Scripts/Editor/EditorUI.as

@@ -174,9 +174,12 @@ void CenterDialog(UIElement@ element)
 
 
 void UpdateWindowTitle()
 void UpdateWindowTitle()
 {
 {
-    String sceneName = sceneFileName.empty ? "Untitled" : GetFileNameAndExtension(sceneFileName);
+    String sceneName = GetFileNameAndExtension(sceneFileName);
+    if (sceneName.empty)
+        sceneName = "Untitled";
     if (sceneModified)
     if (sceneModified)
         sceneName += "*";
         sceneName += "*";
+    
     graphics.windowTitle = "Urho3D editor - " + sceneName;
     graphics.windowTitle = "Urho3D editor - " + sceneName;
 }
 }
 
 

+ 20 - 7
Engine/Graphics/Camera.cpp

@@ -76,12 +76,12 @@ void Camera::RegisterObject(Context* context)
 
 
 void Camera::SetNearClip(float nearClip)
 void Camera::SetNearClip(float nearClip)
 {
 {
-    nearClip_ = Max(nearClip, 0.0f);
+    nearClip_ = Max(nearClip, M_MIN_NEARCLIP);
 }
 }
 
 
 void Camera::SetFarClip(float farClip)
 void Camera::SetFarClip(float farClip)
 {
 {
-    farClip_ = Max(farClip, 0.0f);
+    farClip_ = Max(farClip, M_MIN_NEARCLIP);
 }
 }
 
 
 void Camera::SetFov(float fov)
 void Camera::SetFov(float fov)
@@ -182,6 +182,16 @@ Frustum Camera::GetSplitFrustum(float nearClip, float farClip)
 
 
 Ray Camera::GetScreenRay(float x, float y)
 Ray Camera::GetScreenRay(float x, float y)
 {
 {
+    Ray ret;
+    
+    // If projection is invalid, just return a ray pointing forward
+    if (!IsProjectionValid())
+    {
+        ret.origin_ = GetWorldPosition();
+        ret.direction_ = GetForwardVector();
+        return ret;
+    }
+    
     Matrix4 viewProjInverse = (GetProjection() * GetInverseWorldTransform()).Inverse();
     Matrix4 viewProjInverse = (GetProjection() * GetInverseWorldTransform()).Inverse();
     
     
     // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
     // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
@@ -196,11 +206,9 @@ Ray Camera::GetScreenRay(float x, float y)
     Vector3 far(x, y, 1.0f);
     Vector3 far(x, y, 1.0f);
     #endif
     #endif
     
     
-    Ray ray;
-    ray.origin_ = viewProjInverse * near;
-    ray.direction_ = ((viewProjInverse * far) - ray.origin_).Normalized();
-    
-    return ray;
+    ret.origin_ = viewProjInverse * near;
+    ret.direction_ = ((viewProjInverse * far) - ret.origin_).Normalized();
+    return ret;
 }
 }
 
 
 Frustum Camera::GetFrustum() const
 Frustum Camera::GetFrustum() const
@@ -344,3 +352,8 @@ float Camera::GetLodDistance(float distance, float scale, float bias) const
     else
     else
         return orthoSize_ / d;
         return orthoSize_ / d;
 }
 }
+
+bool Camera::IsProjectionValid() const
+{
+    return farClip_ > GetNearClip();
+}

+ 2 - 0
Engine/Graphics/Camera.h

@@ -123,6 +123,8 @@ public:
     float GetDistanceSquared(const Vector3& worldPos);
     float GetDistanceSquared(const Vector3& worldPos);
     /// Return a scene node's LOD scaled distance.
     /// Return a scene node's LOD scaled distance.
     float GetLodDistance(float distance, float scale, float bias) const;
     float GetLodDistance(float distance, float scale, float bias) const;
+    /// Return if projection parameters are valid for rendering and raycasting
+    bool IsProjectionValid() const;
     
     
     /// Return inverse world transform, also known as the view matrix.
     /// Return inverse world transform, also known as the view matrix.
     Matrix3x4 GetInverseWorldTransform() const { return GetWorldTransform().Inverse(); }
     Matrix3x4 GetInverseWorldTransform() const { return GetWorldTransform().Inverse(); }

+ 4 - 0
Engine/Graphics/Light.cpp

@@ -331,11 +331,15 @@ Matrix3x4 Light::GetDirLightTransform(Camera& camera, bool getNearQuad)
         distance = Max(nearSplit_ - nearFadeRange_, nearClip);
         distance = Max(nearSplit_ - nearFadeRange_, nearClip);
     else
     else
         distance = Min(farSplit_, farClip);
         distance = Min(farSplit_, farClip);
+    
     if (!camera.IsOrthographic())
     if (!camera.IsOrthographic())
         farVector *= (distance / farClip);
         farVector *= (distance / farClip);
     else
     else
         farVector.z_ *= (distance / farClip);
         farVector.z_ *= (distance / farClip);
     
     
+    // Set an epsilon from clip planes due to possible inaccuracy
+    farVector.z_ = Clamp(farVector.z_, (1.0f + M_LARGE_EPSILON) * nearClip, (1.0f - M_LARGE_EPSILON) * farClip);
+    
     return  Matrix3x4(Vector3(0.0f, 0.0f, farVector.z_), Quaternion::IDENTITY, Vector3(farVector.x_, farVector.y_, 1.0f));
     return  Matrix3x4(Vector3(0.0f, 0.0f, farVector.z_), Quaternion::IDENTITY, Vector3(farVector.x_, farVector.y_, 1.0f));
 }
 }
 
 

+ 1 - 6
Engine/Graphics/OcclusionBuffer.cpp

@@ -322,9 +322,6 @@ bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
     // Project to screen. If any of the corners cross the near plane, assume visible
     // Project to screen. If any of the corners cross the near plane, assume visible
     float minX, maxX, minY, maxY, minZ;
     float minX, maxX, minY, maxY, minZ;
     
     
-    // Subtract a small bias to prevent self-occlusion artifacts
-    // (need for bias results from different floating point transformations producing different errors)
-    vertices[0].z_ -= depthBias_;
     if (vertices[0].z_ <= nearClip_)
     if (vertices[0].z_ <= nearClip_)
         return true;
         return true;
     
     
@@ -337,8 +334,6 @@ bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
     // Project the rest
     // Project the rest
     for (unsigned i = 1; i < 8; ++i)
     for (unsigned i = 1; i < 8; ++i)
     {
     {
-        // Subtract a small bias to prevent self-occlusion artifacts
-        vertices[i].z_ -= depthBias_;
         if (vertices[i].z_ <= nearClip_)
         if (vertices[i].z_ <= nearClip_)
             return true;
             return true;
         
         
@@ -376,7 +371,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));
+    int z = ((int)(minZ * OCCLUSION_Z_SCALE)) - OCCLUSION_DEPTH_BIAS;
     
     
     if (!depthHierarchyDirty_)
     if (!depthHierarchyDirty_)
     {
     {

+ 1 - 0
Engine/Graphics/OcclusionBuffer.h

@@ -47,6 +47,7 @@ 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 = 16;
 static const float OCCLUSION_X_SCALE = 65536.0f;
 static const float OCCLUSION_X_SCALE = 65536.0f;
 static const float OCCLUSION_Z_SCALE = 16777216.0f;
 static const float OCCLUSION_Z_SCALE = 16777216.0f;
 
 

+ 13 - 7
Engine/Graphics/View.cpp

@@ -182,6 +182,11 @@ void View::Update(const FrameInfo& frame)
     noShadowLightQueue_.Clear();
     noShadowLightQueue_.Clear();
     lightQueues_.Clear();
     lightQueues_.Clear();
     
     
+    // Do not update if camera projection is illegal
+    // (there is a possibility of crash if occlusion is used and it can not clip properly)
+    if (!camera_->IsProjectionValid())
+        return;
+    
     // Set automatic aspect ratio if required
     // Set automatic aspect ratio if required
     if (camera_->GetAutoAspectRatio())
     if (camera_->GetAutoAspectRatio())
         camera_->SetAspectRatio((float)frame_.viewSize_.x_ / (float)frame_.viewSize_.y_);
         camera_->SetAspectRatio((float)frame_.viewSize_.x_ / (float)frame_.viewSize_.y_);
@@ -1713,7 +1718,7 @@ unsigned View::SplitLight(Light* light)
         
         
         unsigned splits = cascade.splits_;
         unsigned splits = cascade.splits_;
         if (splits > MAX_LIGHT_SPLITS - 1)
         if (splits > MAX_LIGHT_SPLITS - 1)
-            splits = MAX_LIGHT_SPLITS;
+            splits = MAX_LIGHT_SPLITS - 1;
         
         
         // Orthographic view actually has near clip 0, but clamp it to a theoretical minimum
         // Orthographic view actually has near clip 0, but clamp it to a theoretical minimum
         float farClip = Min(cascade.shadowRange_, camera_->GetFarClip()); // Shadow range end
         float farClip = Min(cascade.shadowRange_, camera_->GetFarClip()); // Shadow range end
@@ -1756,9 +1761,8 @@ unsigned View::SplitLight(Light* light)
             splitLight->SetNearFadeRange(nearFadeRange);
             splitLight->SetNearFadeRange(nearFadeRange);
             splitLight->SetFarSplit(farSplit);
             splitLight->SetFarSplit(farSplit);
             
             
-            // The final split will not fade
-            if (createExtraSplit || i < splits - 1)
-                splitLight->SetFarFadeRange(farFadeRange);
+            // If not creating an extra split, the final split should not fade
+            splitLight->SetFarFadeRange((createExtraSplit || i < splits - 1) ? farFadeRange : 0.0f);
             
             
             // Create an extra unshadowed split if necessary
             // Create an extra unshadowed split if necessary
             if (createExtraSplit && i == splits - 1)
             if (createExtraSplit && i == splits - 1)
@@ -1941,11 +1945,13 @@ void View::CalculateShaderParameters()
 {
 {
     Time* time = GetSubsystem<Time>();
     Time* time = GetSubsystem<Time>();
     
     
-    float fogStart = zone_->GetFogStart();
-    float fogEnd = zone_->GetFogEnd();
-    float fogRange = Max(fogEnd - fogStart, M_EPSILON);
     float farClip = camera_->GetFarClip();
     float farClip = camera_->GetFarClip();
     float nearClip = camera_->GetNearClip();
     float nearClip = camera_->GetNearClip();
+    float fogStart = Min(zone_->GetFogStart(), farClip);
+    float fogEnd = Min(zone_->GetFogEnd(), farClip);
+    if (fogStart >= fogEnd * (1.0f - M_LARGE_EPSILON))
+        fogStart = fogEnd * (1.0f - M_LARGE_EPSILON);
+    float fogRange = Max(fogEnd - fogStart, M_EPSILON);
     Vector4 fogParams(fogStart / farClip, fogEnd / farClip, 1.0f / (fogRange / farClip), 0.0f);
     Vector4 fogParams(fogStart / farClip, fogEnd / farClip, 1.0f / (fogRange / farClip), 0.0f);
     Vector4 elapsedTime((time->GetTotalMSec() & 0x3fffff) / 1000.0f, 0.0f, 0.0f, 0.0f);
     Vector4 elapsedTime((time->GetTotalMSec() & 0x3fffff) / 1000.0f, 0.0f, 0.0f, 0.0f);
     
     

+ 1 - 0
Engine/Math/MathDefs.h

@@ -36,6 +36,7 @@ static const unsigned M_MIN_UNSIGNED = 0x00000000;
 static const unsigned M_MAX_UNSIGNED = 0xffffffff;
 static const unsigned M_MAX_UNSIGNED = 0xffffffff;
 
 
 static const float M_EPSILON = 0.000001f;
 static const float M_EPSILON = 0.000001f;
+static const float M_LARGE_EPSILON = 0.00005f;
 static const float M_MIN_NEARCLIP = 0.01f;
 static const float M_MIN_NEARCLIP = 0.01f;
 static const float M_MAX_FOV = 160.0f;
 static const float M_MAX_FOV = 160.0f;
 static const float M_LARGE_VALUE = 100000000.0f;
 static const float M_LARGE_VALUE = 100000000.0f;