Implement KHR_lights_punctual.
This commit is contained in:
parent
09089a7d79
commit
5389d848e2
|
@ -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))
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue