Merge branch 'master' into collada_zae

pull/2545/head
Kim Kulling 2019-08-14 20:02:53 +02:00 committed by GitHub
commit a2ee19e86d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 173 additions and 72 deletions

View File

@ -341,7 +341,7 @@ SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
IF (is_multi_config OR (CMAKE_BUILD_TYPE STREQUAL "Debug")) IF (INJECT_DEBUG_POSTFIX AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools") SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
ELSE() ELSE()
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")

View File

@ -90,7 +90,6 @@ namespace Assimp {
, anim_fps() , anim_fps()
, out(out) , out(out)
, doc(doc) , doc(doc)
, mRemoveEmptyBones( removeEmptyBones )
, mCurrentUnit(FbxUnit::cm) { , mCurrentUnit(FbxUnit::cm) {
// animations need to be converted first since this will // animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed // populate the node_anim_chain_bits map, which is needed
@ -1462,14 +1461,8 @@ namespace Assimp {
const WeightIndexArray& indices = cluster->GetIndices(); const WeightIndexArray& indices = cluster->GetIndices();
if (indices.empty() && mRemoveEmptyBones ) {
continue;
}
const MatIndexArray& mats = geo.GetMaterialIndices(); const MatIndexArray& mats = geo.GetMaterialIndices();
bool ok = false;
const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
count_out_indices.clear(); count_out_indices.clear();
@ -1510,7 +1503,6 @@ namespace Assimp {
} }
++count_out_indices.back(); ++count_out_indices.back();
ok = true;
} }
} }
} }
@ -1518,12 +1510,10 @@ namespace Assimp {
// if we found at least one, generate the output bones // if we found at least one, generate the output bones
// XXX this could be heavily simplified by collecting the bone // XXX this could be heavily simplified by collecting the bone
// data in a single step. // data in a single step.
if (ok && mRemoveEmptyBones) {
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices, ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
count_out_indices, node_global_transform); count_out_indices, node_global_transform);
} }
} }
}
catch (std::exception&) { catch (std::exception&) {
std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>()); std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
throw; throw;

View File

@ -470,9 +470,6 @@ private:
aiScene* const out; aiScene* const out;
const FBX::Document& doc; const FBX::Document& doc;
bool mRemoveEmptyBones;
FbxUnit mCurrentUnit; FbxUnit mCurrentUnit;
}; };

View File

@ -90,14 +90,6 @@ const Object* LazyObject::Get(bool dieOnError)
return object.get(); return object.get();
} }
// if this is the root object, we return a dummy since there
// is no root object int he fbx file - it is just referenced
// with id 0.
if(id == 0L) {
object.reset(new Object(id, element, "Model::RootNode"));
return object.get();
}
const Token& key = element.KeyToken(); const Token& key = element.KeyToken();
const TokenList& tokens = element.Tokens(); const TokenList& tokens = element.Tokens();

View File

@ -1706,8 +1706,7 @@ void FBXExporter::WriteObjects ()
} }
if (end) { break; } if (end) { break; }
} }
limbnodes.insert(parent);
skeleton.insert(parent);
// if it was the skeleton root we can finish here // if it was the skeleton root we can finish here
if (end) { break; } if (end) { break; }
} }
@ -1848,46 +1847,10 @@ void FBXExporter::WriteObjects ()
inverse_bone_xform.Inverse(); inverse_bone_xform.Inverse();
aiMatrix4x4 tr = inverse_bone_xform * mesh_xform; aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
// this should be the same as the bone's mOffsetMatrix.
// if it's not the same, the skeleton isn't in the bind pose.
float epsilon = 1e-4f; // some error is to be expected
float epsilon_custom = mProperties->GetPropertyFloat("BINDPOSE_EPSILON", -1);
if(epsilon_custom > 0) {
epsilon = epsilon_custom;
}
bool bone_xform_okay = true;
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
not_in_bind_pose.insert(b);
bone_xform_okay = false;
}
// if we have a bone we should use the mOffsetMatrix,
// otherwise try to just use the calculated transform.
if (b) {
sdnode.AddChild("Transform", b->mOffsetMatrix);
} else {
sdnode.AddChild("Transform", tr); sdnode.AddChild("Transform", tr);
}
// note: it doesn't matter if we mix these,
// because if they disagree we'll throw an exception later.
// it could be that the skeleton is not in the bone pose
// but all bones are still defined,
// in which case this would use the mOffsetMatrix for everything
// and a correct skeleton would still be output.
// transformlink should be the position of the bone in world space.
// if the bone is in the bind pose (or nonexistent),
// we can just use the matrix we already calculated
if (bone_xform_okay) {
sdnode.AddChild("TransformLink", bone_xform); sdnode.AddChild("TransformLink", bone_xform);
// otherwise we can only work it out using the mesh position.
} else {
aiMatrix4x4 trl = b->mOffsetMatrix;
trl.Inverse();
trl *= mesh_xform;
sdnode.AddChild("TransformLink", trl);
}
// note: this means we ALWAYS rely on the mesh node transform // note: this means we ALWAYS rely on the mesh node transform
// being unchanged from the time the skeleton was bound. // being unchanged from the time the skeleton was bound.
// there's not really any way around this at the moment. // there's not really any way around this at the moment.

View File

@ -115,7 +115,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(tempVerts.empty()) { if(tempVerts.empty()) {
FBXImporter::LogWarn("encountered mesh with no vertices"); FBXImporter::LogWarn("encountered mesh with no vertices");
return;
} }
std::vector<int> tempFaces; std::vector<int> tempFaces;
@ -123,7 +122,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(tempFaces.empty()) { if(tempFaces.empty()) {
FBXImporter::LogWarn("encountered mesh with no faces"); FBXImporter::LogWarn("encountered mesh with no faces");
return;
} }
m_vertices.reserve(tempFaces.size()); m_vertices.reserve(tempFaces.size());

View File

@ -80,7 +80,13 @@ const aiImporterDesc X3DImporter::Description = {
//const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)"); //const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)");
//const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase); //const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase);
struct WordIterator: public std::iterator<std::input_iterator_tag, const char*> { struct WordIterator {
using iterator_category = std::input_iterator_tag;
using value_type = const char*;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
static const char *whitespace; static const char *whitespace;
const char *start_, *end_; const char *start_, *end_;
WordIterator(const char *start, const char *end): start_(start), end_(end) { WordIterator(const char *start, const char *end): start_(start), end_(end) {

View File

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* glTF Extensions Support: * glTF Extensions Support:
* KHR_materials_pbrSpecularGlossiness full * KHR_materials_pbrSpecularGlossiness full
* KHR_materials_unlit full * KHR_materials_unlit full
* KHR_lights_punctual full
*/ */
#ifndef GLTF2ASSET_H_INC #ifndef GLTF2ASSET_H_INC
#define GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC
@ -668,6 +669,28 @@ namespace glTF2
void Read(Value& obj, Asset& r); void Read(Value& obj, Asset& r);
}; };
//! A light (from KHR_lights_punctual extension)
struct Light : public Object
{
enum Type
{
Directional,
Point,
Spot
};
Type type;
vec3 color;
float intensity;
Nullable<float> range;
float innerConeAngle;
float outerConeAngle;
Light() {}
void Read(Value& obj, Asset& r);
};
//! Image data used to create a texture. //! Image data used to create a texture.
struct Image : public Object struct Image : public Object
@ -819,6 +842,7 @@ namespace glTF2
Nullable<vec3> scale; Nullable<vec3> scale;
Ref<Camera> camera; Ref<Camera> camera;
Ref<Light> light;
std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy.
Ref<Skin> skin; //!< The ID of the skin referenced by this node. Ref<Skin> skin; //!< The ID of the skin referenced by this node.
@ -1050,6 +1074,7 @@ namespace glTF2
{ {
bool KHR_materials_pbrSpecularGlossiness; bool KHR_materials_pbrSpecularGlossiness;
bool KHR_materials_unlit; bool KHR_materials_unlit;
bool KHR_lights_punctual;
} extensionsUsed; } extensionsUsed;
@ -1063,6 +1088,7 @@ namespace glTF2
LazyDict<Buffer> buffers; LazyDict<Buffer> buffers;
LazyDict<BufferView> bufferViews; LazyDict<BufferView> bufferViews;
LazyDict<Camera> cameras; LazyDict<Camera> cameras;
LazyDict<Light> lights;
LazyDict<Image> images; LazyDict<Image> images;
LazyDict<Material> materials; LazyDict<Material> materials;
LazyDict<Mesh> meshes; LazyDict<Mesh> meshes;
@ -1083,6 +1109,7 @@ namespace glTF2
, buffers (*this, "buffers") , buffers (*this, "buffers")
, bufferViews (*this, "bufferViews") , bufferViews (*this, "bufferViews")
, cameras (*this, "cameras") , cameras (*this, "cameras")
, lights (*this, "lights", "KHR_lights_punctual")
, images (*this, "images") , images (*this, "images")
, materials (*this, "materials") , materials (*this, "materials")
, meshes (*this, "meshes") , meshes (*this, "meshes")

View File

@ -1067,6 +1067,39 @@ inline void Camera::Read(Value& obj, Asset& /*r*/)
} }
} }
inline void Light::Read(Value& obj, Asset& /*r*/)
{
#ifndef M_PI
const float M_PI = 3.14159265358979323846f;
#endif
std::string type_string;
ReadMember(obj, "type", type_string);
if (type_string == "directional")
type = Light::Directional;
else if (type_string == "point")
type = Light::Point;
else
type = Light::Spot;
name = MemberOrDefault(obj, "name", "");
SetVector(color, vec3{ 1.0f, 1.0f, 1.0f });
ReadMember(obj, "color", color);
intensity = MemberOrDefault(obj, "intensity", 1.0f);
ReadMember(obj, "range", range);
if (type == Light::Spot)
{
Value* spot = FindObject(obj, "spot");
if (!spot) throw DeadlyImportError("GLTF: Light missing its spot parameters");
innerConeAngle = MemberOrDefault(*spot, "innerConeAngle", 0.0f);
outerConeAngle = MemberOrDefault(*spot, "outerConeAngle", M_PI / 4.0f);
}
}
inline void Node::Read(Value& obj, Asset& r) inline void Node::Read(Value& obj, Asset& r)
{ {
@ -1110,6 +1143,19 @@ inline void Node::Read(Value& obj, Asset& r)
if (this->camera) if (this->camera)
this->camera->id = this->id; this->camera->id = this->id;
} }
if (Value* extensions = FindObject(obj, "extensions")) {
if (r.extensionsUsed.KHR_lights_punctual) {
if (Value* ext = FindObject(*extensions, "KHR_lights_punctual")) {
if (Value* light = FindUInt(*ext, "light")) {
this->light = r.lights.Retrieve(light->GetUint());
if (this->light)
this->light->id = this->id;
}
}
}
}
} }
inline void Scene::Read(Value& obj, Asset& r) inline void Scene::Read(Value& obj, Asset& r)
@ -1421,6 +1467,7 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
CHECK_EXT(KHR_materials_pbrSpecularGlossiness); CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
CHECK_EXT(KHR_materials_unlit); CHECK_EXT(KHR_materials_unlit);
CHECK_EXT(KHR_lights_punctual);
#undef CHECK_EXT #undef CHECK_EXT
} }

View File

@ -202,6 +202,11 @@ namespace glTF2 {
} }
inline void Write(Value& /*obj*/, Light& /*c*/, AssetWriter& /*w*/)
{
}
inline void Write(Value& obj, Image& img, AssetWriter& w) inline void Write(Value& obj, Image& img, AssetWriter& w)
{ {
if (img.bufferView) { if (img.bufferView) {

View File

@ -140,10 +140,10 @@ static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode)
} }
} }
//static void CopyValue(const glTF2::vec3& v, aiColor3D& out) static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
//{ {
// out.r = v[0]; out.g = v[1]; out.b = v[2]; out.r = v[0]; out.g = v[1]; out.b = v[2];
//} }
static void CopyValue(const glTF2::vec4& v, aiColor4D& out) static void CopyValue(const glTF2::vec4& v, aiColor4D& out)
{ {
@ -710,6 +710,69 @@ void glTF2Importer::ImportCameras(glTF2::Asset& r)
} }
} }
void glTF2Importer::ImportLights(glTF2::Asset& r)
{
if (!r.lights.Size())
return;
mScene->mNumLights = r.lights.Size();
mScene->mLights = new aiLight*[r.lights.Size()];
for (size_t i = 0; i < r.lights.Size(); ++i) {
Light& light = r.lights[i];
aiLight* ail = mScene->mLights[i] = new aiLight();
switch (light.type)
{
case Light::Directional:
ail->mType = aiLightSource_DIRECTIONAL; break;
case Light::Point:
ail->mType = aiLightSource_POINT; break;
case Light::Spot:
ail->mType = aiLightSource_SPOT; break;
}
if (ail->mType != aiLightSource_POINT)
{
ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f);
ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
}
vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity };
CopyValue(colorWithIntensity, ail->mColorAmbient);
CopyValue(colorWithIntensity, ail->mColorDiffuse);
CopyValue(colorWithIntensity, ail->mColorSpecular);
if (ail->mType == aiLightSource_DIRECTIONAL)
{
ail->mAttenuationConstant = 1.0;
ail->mAttenuationLinear = 0.0;
ail->mAttenuationQuadratic = 0.0;
}
else
{
//in PBR attenuation is calculated using inverse square law which can be expressed
//using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters
//this is correct equation for the case when range (see
//https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
//is not present. When range is not present it is assumed that it is infinite and so numerator is 1.
//When range is present then numerator might be any value in range [0,1] and then assimps equation
//will not suffice. In this case range is added into metadata in ImportNode function
//and its up to implementation to read it when it wants to
ail->mAttenuationConstant = 0.0;
ail->mAttenuationLinear = 0.0;
ail->mAttenuationQuadratic = 1.0;
}
if (ail->mType == aiLightSource_SPOT)
{
ail->mAngleInnerCone = light.innerConeAngle;
ail->mAngleOuterCone = light.outerConeAngle;
}
}
}
static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) { static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) {
if (node.matrix.isPresent) { if (node.matrix.isPresent) {
CopyValue(node.matrix.value, matrix); CopyValue(node.matrix.value, matrix);
@ -881,6 +944,18 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>&
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
} }
if (node.light) {
pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
//range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
//it is added to meta data of parent node, because there is no other place to put it
if (node.light->range.isPresent)
{
ainode->mMetaData = aiMetadata::Alloc(1);
ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
}
}
return ainode; return ainode;
} }
@ -1150,6 +1225,7 @@ void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IO
ImportMeshes(asset); ImportMeshes(asset);
ImportCameras(asset); ImportCameras(asset);
ImportLights(asset);
ImportNodes(asset); ImportNodes(asset);

View File

@ -142,7 +142,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @brief Specifies the maximum angle that may be between two vertex tangents /** @brief Specifies the maximum angle that may be between two vertex tangents
* that their tangents and bi-tangents are smoothed. * that their tangents and bi-tangents are smoothed.
* *
* This applies to the CalcTangentSpace-Step. TFvhe angle is specified * This applies to the CalcTangentSpace-Step. The angle is specified
* in degrees. The maximum value is 175. * in degrees. The maximum value is 175.
* Property type: float. Default value: 45 degrees * Property type: float. Default value: 45 degrees
*/ */