Parcourir la source

Revamp light falloff calculation in Encoder

* Remove Linear, Quadratic and Constant calculation from Light class
* Perform exact calculation of range rather than using approximation algorithm
* Remove falloffExponent as it was unused
* Default range parameter to 1.0f directly, rather than deferring until actually writing to .gpb
Elliot Saba il y a 12 ans
Parent
commit
0ef10006ed
3 fichiers modifiés avec 55 ajouts et 130 suppressions
  1. 50 59
      tools/encoder/src/FBXSceneEncoder.cpp
  2. 4 62
      tools/encoder/src/Light.cpp
  3. 1 9
      tools/encoder/src/Light.h

+ 50 - 59
tools/encoder/src/FBXSceneEncoder.cpp

@@ -770,75 +770,66 @@ void FBXSceneEncoder::loadLight(FbxNode* fbxNode, Node* node)
     FbxDouble3 color = fbxLight->Color.Get();
     light->setColor((float)color[0], (float)color[1], (float)color[2]);
     
+    float range;
+    if( fbxLight->EnableFarAttenuation.Get() ) {
+        // If FarAttenuation is enabled, that gives us range directly
+        range = (float)fbxLight->FarAttenuationEnd.Get();
+    } else {
+        // Otherwise, we need to fit a decay type to calculate range
+        // For each attenuation type, the range at which the intensity falls to 1/100 can be computed as:
+        //
+        // Linear:      1/100 = I/(a*r)     =>    r = 100*I/a
+        // Quadratic:   1/100 = I/(a*r^2)   =>    r = sqrt(100*I/a)
+        // Cubic:       1/100 = I/(a*r^3)   =>    r = pow(100*I/a,1/3.0)
+        float attenuation = fbxLight->DecayStart.Get();
+        float intensity = fbxLight->Intensity.Get()/100.0f;
+        switch( fbxLight->DecayType.Get() ) {
+            case FbxLight::eLinear:
+                range = 100.0f*intensity/attenuation;
+                break;
+            case FbxLight::eQuadratic:
+                range = 10.0f*sqrtf(intensity/attenuation);
+                break;
+            case FbxLight::eCubic:
+                range = pow(100.0f*intensity/attenuation,1/3.0);
+                break;
+            case FbxLight::eNone:
+                // We don't support no attenuation; set range to 1.0f by default
+                range = 1.0f;
+                break;
+        }
+    }
+    
     switch (fbxLight->LightType.Get())
     {
-    case FbxLight::ePoint:
-    {
-        FbxLight::EDecayType decayType = fbxLight->DecayType.Get();
-        switch (decayType)
+        case FbxLight::ePoint:
         {
-        case FbxLight::eNone:
-            // FBX does not support ambients lights so ambient lights are converted 
-            // to point lights with no decay and visibility set to false.
-            if (fbxNode->GetVisibility())
-            {
-                light->setPointLight();
-            }
-            else
-            {
+            FbxLight::EDecayType decayType = fbxLight->DecayType.Get();
+            if( decayType == FbxLight::eNone && !fbxNode->GetVisibility() )
                 light->setAmbientLight();
+            else {
+                light->setPointLight();
+                light->setRange(range);
             }
-            break;
-        case FbxLight::eLinear:
-            light->setPointLight();
-            light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
-            break;
-        case FbxLight::eQuadratic:
-            light->setPointLight();
-            light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
-            break;
-        case FbxLight::eCubic:
-        default:
-            // Not supported..
-            break;
         }
-        break;
-    }
-    case FbxLight::eDirectional:
-    {
-        light->setDirectionalLight();
-        break;
-    }
-    case FbxLight::eSpot:
-    {
-        light->setSpotLight();
-
-        FbxLight::EDecayType decayType = fbxLight->DecayType.Get();
-        switch (decayType)
+        case FbxLight::eDirectional:
         {
-        case FbxLight::eNone:
-            // No decay.
+            light->setDirectionalLight();
             break;
-        case FbxLight::eLinear:
-            light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
-            break;
-        case FbxLight::eQuadratic:
-            light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
-            break;
-        case FbxLight::eCubic:
-            // Not supported..
+        }
+        case FbxLight::eSpot:
+        {
+            light->setSpotLight();
+            light->setInnerAngle(MATH_DEG_TO_RAD((float)fbxLight->InnerAngle.Get()));
+            light->setOuterAngle(MATH_DEG_TO_RAD((float)fbxLight->OuterAngle.Get()));
+            light->setRange(range);
             break;
         }
-
-        light->setInnerAngle(MATH_DEG_TO_RAD((float)fbxLight->InnerAngle.Get()));
-        light->setOuterAngle(MATH_DEG_TO_RAD((float)fbxLight->OuterAngle.Get()));
-        break;
-    }
-    default:
-    {
-        LOG(2, "Warning: Unknown light type in node.\n");
-        return;
-    }
+        default:
+        {
+            LOG(2, "Warning: Unknown light type in node.\n");
+            return;
+        }
     }
 
     _gamePlayFile.addLight(light);

+ 4 - 62
tools/encoder/src/Light.cpp

@@ -6,11 +6,7 @@ namespace gameplay
 
 Light::Light(void) :
     _lightType(0),
-    _constantAttenuation(0.0f),
-    _linearAttenuation(0.0f),
-    _quadraticAttenuation(0.0f),
-    _falloffExponent(0.0f),
-    _range(-1.0f),
+    _range(1.0f),
     _innerAngle(-1.0f),
     _outerAngle(0.0f)
 {
@@ -30,43 +26,12 @@ const char* Light::getElementName(void) const
     return "Light";
 }
 
-float Light::computeRange(float constantAttenuation, float linearAttenuation, float quadraticAttenuation)
-{
-    if (constantAttenuation == 0.0f && linearAttenuation == 0.0f && quadraticAttenuation == 0.0f)
-    {
-        return 0.0f;
-    }
-
-    // Constant Attenuation is currently not supported.
-    if (constantAttenuation == 1.0f)
-    {
-        return 1.0f;
-    }
-
-    const float step = 0.01f;
-    float range = 0.01f;
-    float att = 1.0f;
-    while (att > 0.01f)
-    {
-        att = 1 / (constantAttenuation + (range * linearAttenuation) + (range * range * quadraticAttenuation));
-        range += step;
-    }
-    return range;
-}
-
 void Light::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
     write(_lightType, file);
     write(_color, COLOR_SIZE, file);
 
-    // Compute an approximate light range with Collada's attenuation parameters.
-    // This facilitates bringing in the light nodes directly from maya to gameplay.
-    if (_range == -1.0f)
-    {
-        _range = computeRange(_constantAttenuation, _linearAttenuation, _quadraticAttenuation);
-    }
-
     if (_lightType == SpotLight)
     {
         write(_range, file);
@@ -85,13 +50,6 @@ void Light::writeText(FILE* file)
     fprintfElement(file, "lightType", _lightType);
     fprintfElement(file, "color", _color, COLOR_SIZE);
 
-    // Compute an approximate light range with Collada's attenuation parameters.
-    // This facilitates bringing in the light nodes directly from maya to gameplay.
-    if (_range == -1.0f)
-    {
-        _range = computeRange(_constantAttenuation, _linearAttenuation, _quadraticAttenuation);
-    }
-
     if (_lightType == SpotLight)
     {
         fprintfElement(file, "range", _range);
@@ -147,18 +105,10 @@ void Light::setColor(float r, float g, float b)
     _color[1] = g;
     _color[2] = b;
 }
-
-void Light::setConstantAttenuation(float value)
-{
-    _constantAttenuation = value;
-}
-void Light::setLinearAttenuation(float value)
+    
+void Light::setRange(float value)
 {
-    _linearAttenuation = value;
-}
-void Light::setQuadraticAttenuation(float value)
-{
-    _quadraticAttenuation = value;
+    _range = value;
 }
 void Light::setInnerAngle(float value)
 {
@@ -168,13 +118,5 @@ void Light::setOuterAngle(float value)
 {
     _outerAngle = value;
 }
-void Light::setFalloffExponent(float value)
-{
-    _falloffExponent = value;
-    if ( value != 1.0)
-    {
-        LOG(1, "Warning: spot light falloff_exponent must be 1.0. \n");
-    }
-}
 
 }

+ 1 - 9
tools/encoder/src/Light.h

@@ -44,12 +44,9 @@ public:
     void setColor(float r, float g, float b);
     void setColor(float r, float g, float b, float a);
 
-    void setConstantAttenuation(float value);
-    void setLinearAttenuation(float value);
-    void setQuadraticAttenuation(float value);
+    void setRange(float value);
     void setInnerAngle(float value);
     void setOuterAngle(float value);
-    void setFalloffExponent(float value);
 
     enum LightType
     {
@@ -67,11 +64,6 @@ private:
     unsigned char _lightType;
     float _color[COLOR_SIZE];
 
-    float _constantAttenuation;
-    float _linearAttenuation;
-    float _quadraticAttenuation;
-    float _falloffExponent;
-
     float _range;
     float _innerAngle;
     float _outerAngle;