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

Implement KHR_lights_punctual.

Par Winzell 6 жил өмнө
parent
commit
5389d848e2

+ 3 - 0
src/FBX2glTF.cpp

@@ -94,6 +94,9 @@ int main(int argc, char *argv[])
                (
                    "khr-materials-unlit", "Use KHR_materials_unlit extension to specify Unlit shader.",
                    cxxopts::value<bool>(gltfOptions.useKHRMatUnlit))
+               (
+                   "no-khr-punctual-lights", "Don't use KHR_punctual_lights extension to export lights.",
+                   cxxopts::value<bool>(gltfOptions.useKHRPunctualLights))
                (
                    "user-properties", "Transcribe FBX User Properties into glTF node and material 'extras'.",
                    cxxopts::value<bool>(gltfOptions.enableUserProperties))

+ 4 - 0
src/FBX2glTF.h

@@ -91,6 +91,10 @@ struct GltfOptions
     bool useKHRMatUnlit { false };
     /** Whether to populate the pbrMetallicRoughness substruct in materials. */
     bool usePBRMetRough { false };
+
+    /** Whether to include lights through the KHR_punctual_lights extension. */
+    bool useKHRPunctualLights { true };
+
     /** Whether to include blend shape normals, if present according to the SDK. */
     bool useBlendShapeNormals { false };
     /** Whether to include blend shape tangents, if present according to the SDK. */

+ 37 - 1
src/fbx/Fbx2Raw.cpp

@@ -380,6 +380,40 @@ double VFOV2HFOV(double v, double ar)
     return 2.0 * std::atan((ar) * std::tan((v * FBXSDK_PI_DIV_180) * 0.5)) * FBXSDK_180_DIV_PI;
 }
 
+static void ReadLight(RawModel &raw, FbxScene *pScene, FbxNode *pNode) {
+  const FbxLight *pLight = pNode->GetLight();
+
+  int lightIx;
+  float intensity = (float)pLight->Intensity.Get();
+  Vec3f color = toVec3f(pLight->Color.Get());
+  switch (pLight->LightType.Get()) {
+    case FbxLight::eDirectional: {
+      lightIx = raw.AddLight(pLight->GetName(), RAW_LIGHT_TYPE_DIRECTIONAL,
+                             color, intensity, 0, 0);
+      break;
+    }
+    case FbxLight::ePoint: {
+      lightIx = raw.AddLight(pLight->GetName(), RAW_LIGHT_TYPE_POINT, color,
+                             intensity, 0, 0);
+      break;
+    }
+    case FbxLight::eSpot: {
+      lightIx = raw.AddLight(pLight->GetName(), RAW_LIGHT_TYPE_SPOT, color,
+                             intensity, (float)pLight->InnerAngle.Get(),
+                             (float)pLight->OuterAngle.Get());
+      break;
+    }
+    default: {
+      fmt::printf("Warning:: Ignoring unsupported light type.\n");
+      return;
+    }
+  }
+
+  int nodeId = raw.GetNodeById(pNode->GetUniqueID());
+  RawNode &node = raw.GetNode(nodeId);
+  node.lightIx = lightIx;
+}
+
 // Largely adopted from fbx example 
 static void ReadCamera(RawModel &raw, FbxScene *pScene, FbxNode *pNode)
 {
@@ -486,13 +520,15 @@ static void ReadNodeAttributes(
                 ReadCamera(raw, pScene, pNode);
                 break;
             }
+            case FbxNodeAttribute::eLight:
+                ReadLight(raw, pScene, pNode);
+                break;
             case FbxNodeAttribute::eUnknown:
             case FbxNodeAttribute::eNull:
             case FbxNodeAttribute::eMarker:
             case FbxNodeAttribute::eSkeleton:
             case FbxNodeAttribute::eCameraStereo:
             case FbxNodeAttribute::eCameraSwitcher:
-            case FbxNodeAttribute::eLight:
             case FbxNodeAttribute::eOpticalReference:
             case FbxNodeAttribute::eOpticalMarker:
             case FbxNodeAttribute::eNurbsCurve:

+ 5 - 0
src/gltf/GltfModel.cpp

@@ -77,4 +77,9 @@ void GltfModel::serializeHolders(json &glTFJson)
     serializeHolder(glTFJson, "animations", animations);
     serializeHolder(glTFJson, "cameras", cameras);
     serializeHolder(glTFJson, "nodes", nodes);
+    if (!lights.ptrs.empty()) {
+        json lightsJson = json::object();
+        serializeHolder(lightsJson, "lights", lights);
+        glTFJson["extensions"][KHR_LIGHTS_PUNCTUAL] = lightsJson;
+    }
 }

+ 2 - 0
src/gltf/GltfModel.hpp

@@ -19,6 +19,7 @@
 #include "gltf/properties/BufferViewData.hpp"
 #include "gltf/properties/CameraData.hpp"
 #include "gltf/properties/ImageData.hpp"
+#include "gltf/properties/LightData.hpp"
 #include "gltf/properties/MaterialData.hpp"
 #include "gltf/properties/MeshData.hpp"
 #include "gltf/properties/NodeData.hpp"
@@ -150,6 +151,7 @@ public:
     Holder<CameraData>     cameras;
     Holder<NodeData>       nodes;
     Holder<SceneData>      scenes;
+    Holder<LightData>      lights;
 
     std::shared_ptr<SamplerData> defaultSampler;
     std::shared_ptr<BufferData> defaultBuffer;

+ 47 - 0
src/gltf/Raw2Gltf.cpp

@@ -119,6 +119,8 @@ ModelData *Raw2Gltf(
         fmt::printf("%7d nodes\n", raw.GetNodeCount());
         fmt::printf("%7d surfaces\n", (int) materialModels.size());
         fmt::printf("%7d animations\n", raw.GetAnimationCount());
+        fmt::printf("%7d cameras\n", raw.GetCameraCount());
+        fmt::printf("%7d lights\n", raw.GetLightCount());
     }
 
     std::unique_ptr<GltfModel> gltf(new GltfModel(options));
@@ -624,6 +626,47 @@ ModelData *Raw2Gltf(
             }
             iter->second->SetCamera(camera.ix);
         }
+
+        //
+        // lights
+        //
+        std::vector<json> khrPunctualLights;
+        if (options.useKHRPunctualLights) {
+            for (int i = 0; i < raw.GetLightCount(); i ++) {
+                const RawLight &light = raw.GetLight(i);
+                LightData::Type type;
+                switch(light.type) {
+                    case RAW_LIGHT_TYPE_DIRECTIONAL:
+                        type = LightData::Type::Directional;
+                        break;
+                    case RAW_LIGHT_TYPE_POINT:
+                        type = LightData::Type::Point;
+                        break;
+                    case RAW_LIGHT_TYPE_SPOT:
+                        type = LightData::Type::Spot;
+                        break;
+                }
+                gltf->lights.hold(new LightData(
+                    light.name,
+                    type,
+                    light.color,
+                    // FBX intensity defaults to 100, so let's call that 1.0;
+                    // but caveat: I find nothing in the documentation to suggest
+                    // what unit the FBX value is meant to be measured in...
+                    light.intensity / 100,
+                    light.innerConeAngle,
+                    light.outerConeAngle));
+            }
+        }
+        for (int i = 0; i < raw.GetNodeCount(); i++) {
+            const RawNode &node = raw.GetNode(i);
+            const auto nodeData = gltf->nodes.ptrs[i];
+
+            if (node.lightIx >= 0) {
+                // we lean on the fact that in this simple case, raw and gltf indexing are aligned
+                nodeData->SetLight(node.lightIx);
+            }
+        }
     }
 
     NodeData        &rootNode  = require(nodesById, raw.GetRootNode());
@@ -651,6 +694,9 @@ ModelData *Raw2Gltf(
         if (options.useKHRMatUnlit) {
             extensionsUsed.push_back(KHR_MATERIALS_CMN_UNLIT);
         }
+        if (!gltf->lights.ptrs.empty()) {
+            extensionsUsed.push_back(KHR_LIGHTS_PUNCTUAL);
+        }
         if (options.draco.enabled) {
             extensionsUsed.push_back(KHR_DRACO_MESH_COMPRESSION);
             extensionsRequired.push_back(KHR_DRACO_MESH_COMPRESSION);
@@ -670,6 +716,7 @@ ModelData *Raw2Gltf(
         }
 
         gltf->serializeHolders(glTFJson);
+
         gltfOutStream << glTFJson.dump(options.outputBinary ? 0 : 4);
     }
     if (options.outputBinary) {

+ 1 - 0
src/gltf/Raw2Gltf.hpp

@@ -21,6 +21,7 @@
 
 const std::string KHR_DRACO_MESH_COMPRESSION            = "KHR_draco_mesh_compression";
 const std::string KHR_MATERIALS_CMN_UNLIT               = "KHR_materials_unlit";
+const std::string KHR_LIGHTS_PUNCTUAL                   = "KHR_lights_punctual";
 
 const std::string extBufferFilename = "buffer.bin";
 

+ 43 - 0
src/gltf/properties/LightData.cpp

@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#include "LightData.hpp"
+
+LightData::LightData(
+    std::string name, Type type, Vec3f color, float intensity,
+    float innerConeAngle, float outerConeAngle)
+    : Holdable(),
+      type(type),
+      color(color),
+      intensity(intensity),
+      innerConeAngle(innerConeAngle),
+      outerConeAngle(outerConeAngle)
+{
+}
+
+json LightData::serialize() const
+{
+    json result {
+        { "name", name },
+        { "color", toStdVec(color) },
+        { "intensity", intensity }
+    };
+    switch(type) {
+        case Directional:
+            result["type"] = "directional";
+            break;
+        case Point:
+            result["type"] = "point";
+            break;
+        case Spot:
+            result["type"] = "spot";
+            break;
+    }
+    return result;
+}

+ 33 - 0
src/gltf/properties/LightData.hpp

@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#pragma once
+
+#include "gltf/Raw2Gltf.hpp"
+
+struct LightData : Holdable
+{
+    enum Type {
+        Directional,
+        Point,
+        Spot,
+    };
+
+    LightData(std::string name, Type type, Vec3f color, float intensity,
+              float innerConeAngle, float outerConeAngle);
+
+    json serialize() const override;
+
+    const std::string name;
+    const Type type;
+    const Vec3f color;
+    const float intensity;
+    const float innerConeAngle;
+    const float outerConeAngle;
+};

+ 10 - 0
src/gltf/properties/NodeData.cpp

@@ -21,6 +21,7 @@ NodeData::NodeData(
       children(),
       mesh(-1),
       camera(-1),
+      light(-1),
       skin(-1)
 {
 }
@@ -50,6 +51,12 @@ void NodeData::SetCamera(uint32_t cameraIndex)
     camera = cameraIndex;
 }
 
+void NodeData::SetLight(uint32_t lightIndex)
+{
+    assert(!isJoint);
+    light = lightIndex;
+}
+
 json NodeData::serialize() const
 {
     json result = { { "name", name } };
@@ -84,6 +91,9 @@ json NodeData::serialize() const
         if (camera >= 0) {
             result["camera"] = camera;
         }
+        if (light >= 0) {
+            result["extensions"][KHR_LIGHTS_PUNCTUAL]["light"] = light;
+        }
     }
 
     for (const auto& i : userProperties)

+ 2 - 0
src/gltf/properties/NodeData.hpp

@@ -19,6 +19,7 @@ struct NodeData : Holdable
     void SetMesh(uint32_t meshIx);
     void SetSkin(uint32_t skinIx);
     void SetCamera(uint32_t camera);
+    void SetLight(uint32_t light);
 
     json serialize() const override;
 
@@ -30,6 +31,7 @@ struct NodeData : Holdable
     std::vector<uint32_t>    children;
     int32_t                  mesh;
     int32_t                  camera;
+    int32_t                  light;
     int32_t                  skin;
     std::vector<std::string> skeletons;
     std::vector<std::string> userProperties;

+ 4 - 0
src/mathfu.hpp

@@ -76,6 +76,10 @@ template<class T> std::vector<T> toStdVec(const mathfu::Quaternion<T> &quat) {
     return std::vector<T> { quat.vector()[0], quat.vector()[1], quat.vector()[2], quat.scalar() };
 }
 
+inline Vec3f toVec3f(const FbxDouble3 &v) {
+    return Vec3f((float) v[0], (float) v[1], (float) v[2]);
+}
+
 inline Vec3f toVec3f(const FbxVector4 &v) {
     return Vec3f((float) v[0], (float) v[1], (float) v[2]);
 }

+ 35 - 0
src/raw/RawModel.cpp

@@ -165,6 +165,40 @@ int RawModel::AddMaterial(
     return (int) materials.size() - 1;
 }
 
+int RawModel::AddLight(
+    const char *name,
+    const RawLightType lightType,
+    const Vec3f color,
+    const float intensity,
+    const float innerConeAngle,
+    const float outerConeAngle)
+{
+    for (size_t i = 0; i < lights.size(); i ++) {
+        if (lights[i].name != name || lights[i].type != lightType) {
+            continue;
+        }
+        // only care about cone angles for spot
+        if (lights[i].type == RAW_LIGHT_TYPE_SPOT) {
+            if (lights[i].innerConeAngle != innerConeAngle ||
+                lights[i].outerConeAngle != outerConeAngle) {
+                continue;
+            }
+        }
+        return (int) i;
+    }
+    RawLight light {
+        name,
+        lightType,
+        color,
+        intensity,
+        innerConeAngle,
+        outerConeAngle,
+    };
+    lights.push_back(light);
+    return (int) lights.size() - 1;
+}
+
+
 int RawModel::AddSurface(const RawSurface &surface)
 {
     for (size_t i = 0; i < surfaces.size(); i++) {
@@ -262,6 +296,7 @@ int RawModel::AddNode(const long id, const char *name, const long parentId)
     joint.name        = name;
     joint.parentId    = parentId;
     joint.surfaceId   = 0;
+    joint.lightIx     = -1;
     joint.translation = Vec3f(0, 0, 0);
     joint.rotation    = Quatf(0, 0, 0, 1);
     joint.scale       = Vec3f(1, 1, 1);

+ 26 - 0
src/raw/RawModel.hpp

@@ -261,6 +261,7 @@ struct RawMetRoughMatProps : RawMatProps {
     }
 };
 
+
 struct RawMaterial
 {
     std::string                  name;
@@ -270,6 +271,23 @@ struct RawMaterial
     std::vector<std::string>     userProperties;
 };
 
+enum RawLightType
+{
+    RAW_LIGHT_TYPE_DIRECTIONAL,
+    RAW_LIGHT_TYPE_POINT,
+    RAW_LIGHT_TYPE_SPOT,
+};
+
+struct RawLight
+{
+    std::string     name;
+    RawLightType    type;
+    Vec3f color;
+    float intensity;
+    float           innerConeAngle;     // only meaningful for spot
+    float           outerConeAngle;     // only meaningful for spot
+};
+
 struct RawBlendChannel
 {
     float defaultDeform;
@@ -348,6 +366,7 @@ struct RawNode
     Quatf                    rotation;
     Vec3f                    scale;
     long                     surfaceId;
+    long                     lightIx;
     std::vector<std::string> userProperties;
 };
 
@@ -365,6 +384,8 @@ public:
     int AddMaterial(
         const char *name, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX],
         std::shared_ptr<RawMatProps> materialInfo, const std::vector<std::string>& userProperties);
+    int AddLight(const char *name, RawLightType lightType, Vec3f color, float intensity,
+                 float innerConeAngle, float outerConeAngle);
     int AddSurface(const RawSurface &suface);
     int AddSurface(const char *name, long surfaceId);
     int AddAnimation(const RawAnimation &animation);
@@ -420,6 +441,10 @@ public:
     int GetCameraCount() const { return (int) cameras.size(); }
     const RawCamera &GetCamera(const int index) const { return cameras[index]; }
 
+    // Iterate over the lights.
+    int GetLightCount() const { return (int) lights.size(); }
+    const RawLight &GetLight(const int index) const { return lights[index]; }
+
     // Iterate over the nodes.
     int GetNodeCount() const { return (int) nodes.size(); }
     const RawNode &GetNode(const int index) const { return nodes[index]; }
@@ -447,6 +472,7 @@ private:
     std::vector<RawTriangle>                         triangles;
     std::vector<RawTexture>                          textures;
     std::vector<RawMaterial>                         materials;
+    std::vector<RawLight>                            lights;
     std::vector<RawSurface>                          surfaces;
     std::vector<RawAnimation>                        animations;
     std::vector<RawCamera>                           cameras;