Преглед изворни кода

Initial negative light support. Right now works only with per-vertex lights. Set negative light color to use. Per-pixel negative lights may be problematic, as they require different blend mode, will also darken any emissive materials, and will not work in light pre-pass mode (there is nothing to subtract from, as light buffer is initialized with black)

Lasse Öörni пре 11 година
родитељ
комит
6fbda65a4f
3 измењених фајлова са 19 додато и 18 уклоњено
  1. 6 12
      Source/Engine/Graphics/Light.cpp
  2. 9 0
      Source/Engine/Graphics/Light.h
  3. 4 6
      Source/Engine/Graphics/View.cpp

+ 6 - 12
Source/Engine/Graphics/Light.cpp

@@ -269,9 +269,7 @@ void Light::SetPerVertex(bool enable)
 
 void Light::SetColor(const Color& color)
 {
-    // Clamp RGB values to positive, as negative values behave erratically depending on whether the pass uses
-    // replace or additive blend mode
-    color_ = Color(Max(color.r_, 0.0f), Max(color.g_, 0.0f), Max(color.b_, 0.0f), 1.0f);
+    color_ = Color(color.r_, color.g_, color.b_, 1.0f);
     MarkNetworkUpdate();
 }
 
@@ -475,13 +473,9 @@ void Light::SetIntensitySortValue(float distance)
 {
     // When sorting lights globally, give priority to directional lights so that they will be combined into the ambient pass
     if (lightType_ != LIGHT_DIRECTIONAL)
-        sortValue_ = Max(distance, M_MIN_NEARCLIP) / (color_.SumRGB() + M_EPSILON);
+        sortValue_ = Max(distance, M_MIN_NEARCLIP) / (Max(color_.SumRGB(), 0.0f) + M_EPSILON);
     else
-        sortValue_ = M_EPSILON / (color_.SumRGB() + M_EPSILON);
-
-    // Additionally, give priority to vertex lights so that vertex light base passes can be determined before per pixel lights
-    if (perVertex_)
-        sortValue_ -= M_LARGE_VALUE;
+        sortValue_ = M_EPSILON / (Max(color_.SumRGB(), 0.0f) + M_EPSILON);
 }
 
 void Light::SetIntensitySortValue(const BoundingBox& box)
@@ -490,7 +484,7 @@ void Light::SetIntensitySortValue(const BoundingBox& box)
     switch (lightType_)
     {
     case LIGHT_DIRECTIONAL:
-        sortValue_ = 1.0f / (color_.SumRGB() + M_EPSILON);
+        sortValue_ = 1.0f / (Max(color_.SumRGB(), 0.0f) + M_EPSILON);
         break;
 
     case LIGHT_SPOT:
@@ -517,7 +511,7 @@ void Light::SetIntensitySortValue(const BoundingBox& box)
             float spotFactor = Min(spotAngle / maxAngle, 1.0f);
             // We do not know the actual range attenuation ramp, so take only spot attenuation into account
             float att = Max(1.0f - spotFactor * spotFactor, M_EPSILON);
-            sortValue_ = 1.0f / (color_.SumRGB() * att + M_EPSILON);
+            sortValue_ = 1.0f / (Max(color_.SumRGB(), 0.0f) * att + M_EPSILON);
         }
         break;
 
@@ -530,7 +524,7 @@ void Light::SetIntensitySortValue(const BoundingBox& box)
             float distance = lightRay.HitDistance(box);
             float normDistance = distance / range_;
             float att = Max(1.0f - normDistance * normDistance, M_EPSILON);
-            sortValue_ = 1.0f / (color_.SumRGB() * att + M_EPSILON);
+            sortValue_ = 1.0f / (Max(color_.SumRGB(), 0.0f) * att + M_EPSILON);
         }
         break;
     }

+ 9 - 0
Source/Engine/Graphics/Light.h

@@ -310,4 +310,13 @@ private:
     bool perVertex_;
 };
 
+inline bool CompareLights(Light* lhs, Light* rhs)
+{
+    // When sorting lights, give priority to per-vertex lights, so that vertex lit base pass can be evaluated first
+    if (lhs->GetPerVertex() != rhs->GetPerVertex())
+        return lhs->GetPerVertex();
+    else
+        return lhs->GetSortValue() < rhs->GetSortValue();
+}
+
 }

+ 4 - 6
Source/Engine/Graphics/View.cpp

@@ -61,8 +61,6 @@ static const Vector3* directions[] =
     &Vector3::BACK
 };
 
-static const float LIGHT_INTENSITY_THRESHOLD = 0.003f;
-
 /// %Frustum octree query for shadowcasters.
 class ShadowCasterOctreeQuery : public FrustumOctreeQuery
 {
@@ -229,8 +227,8 @@ void CheckVisibilityWork(const WorkItem* item, unsigned threadIndex)
             else if (drawable->GetDrawableFlags() & DRAWABLE_LIGHT)
             {
                 Light* light = static_cast<Light*>(drawable);
-                // Skip lights which are so dim that they can not contribute to a rendertarget
-                if (light->GetColor().SumRGB() > LIGHT_INTENSITY_THRESHOLD)
+                // Currently per pixel lights can not be reliably negative (darkening), so skip them
+                if (light->GetColor().SumRGB() > 0.0f || light->GetPerVertex())
                     result.lights_.Push(light);
             }
         }
@@ -740,7 +738,7 @@ void View::GetDrawables()
     if (minZ_ == M_INFINITY)
         minZ_ = 0.0f;
     
-    // Sort the lights to brightest/closest first
+    // Sort the lights to brightest/closest first, and per-vertex lights first so that per-vertex base pass can be evaluated first
     for (unsigned i = 0; i < lights_.Size(); ++i)
     {
         Light* light = lights_[i];
@@ -748,7 +746,7 @@ void View::GetDrawables()
         light->SetLightQueue(0);
     }
     
-    Sort(lights_.Begin(), lights_.End(), CompareDrawables);
+    Sort(lights_.Begin(), lights_.End(), CompareLights);
 }
 
 void View::GetBatches()