overte-lubosz/libraries/hfm/src/hfm/HFM.h
2019-11-11 17:52:16 -08:00

411 lines
11 KiB
C++

//
// HFM.h
// libraries/hfm/src
//
// Created by Sabrina Shanman on 2018/11/02.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_HFM_h_
#define hifi_HFM_h_
#include <QMetaType>
#include <QSet>
#include <QVector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <Extents.h>
#include <Transform.h>
#include <graphics/Geometry.h>
#include <graphics/Material.h>
#include <image/ColorChannel.h>
#if defined(Q_OS_ANDROID)
#define HFM_PACK_NORMALS 0
#else
#define HFM_PACK_NORMALS 1
#endif
#if HFM_PACK_NORMALS
using NormalType = glm::uint32;
#define HFM_NORMAL_ELEMENT gpu::Element::VEC4F_NORMALIZED_XYZ10W2
#else
using NormalType = glm::vec3;
#define HFM_NORMAL_ELEMENT gpu::Element::VEC3F_XYZ
#endif
#define HFM_PACK_COLORS 1
#if HFM_PACK_COLORS
using ColorType = glm::uint32;
#define HFM_COLOR_ELEMENT gpu::Element::COLOR_RGBA_32
#else
using ColorType = glm::vec3;
#define HFM_COLOR_ELEMENT gpu::Element::VEC3F_XYZ
#endif
const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048;
using ShapeVertices = std::vector<glm::vec3>;
// The version of the Draco mesh binary data itself. See also: FBX_DRACO_MESH_VERSION in FBX.h
static const int DRACO_MESH_VERSION = 3;
static const int DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES = 1000;
static const int DRACO_ATTRIBUTE_MATERIAL_ID = DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES;
static const int DRACO_ATTRIBUTE_TEX_COORD_1 = DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES + 1;
static const int DRACO_ATTRIBUTE_ORIGINAL_INDEX = DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES + 2;
// High Fidelity Model namespace
namespace hfm {
static const uint32_t UNDEFINED_KEY = (uint32_t)-1;
/// A single blendshape.
class Blendshape {
public:
QVector<int> indices;
QVector<glm::vec3> vertices;
QVector<glm::vec3> normals;
QVector<glm::vec3> tangents;
};
struct JointShapeInfo {
// same units and frame as Joint.translation
glm::vec3 avgPoint;
std::vector<float> dots;
std::vector<glm::vec3> points;
std::vector<glm::vec3> debugLines;
};
/// A single joint (transformation node).
class Joint {
public:
JointShapeInfo shapeInfo;
int parentIndex;
float distanceToParent;
// http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/SDKRef/a00209.html
glm::vec3 translation; // T
glm::mat4 preTransform; // Roff * Rp
glm::quat preRotation; // Rpre
glm::quat rotation; // R
glm::quat postRotation; // Rpost
glm::mat4 postTransform; // Rp-1 * Soff * Sp * S * Sp-1
// World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1)
glm::mat4 transform;
glm::vec3 rotationMin; // radians
glm::vec3 rotationMax; // radians
glm::quat inverseDefaultRotation;
glm::quat inverseBindRotation;
glm::mat4 bindTransform;
QString name;
bool isSkeletonJoint;
bool bindTransformFoundInCluster;
// geometric offset is applied in local space but does NOT affect children.
// TODO: Apply hfm::Joint.geometricOffset to transforms in the model preparation step
glm::mat4 geometricOffset;
// globalTransform is the transform of the joint with all parent transforms applied, plus the geometric offset
glm::mat4 localTransform;
glm::mat4 globalTransform;
};
/// A single binding to a joint.
class Cluster {
public:
static const uint32_t INVALID_JOINT_INDEX { (uint32_t)-1 };
uint32_t jointIndex { INVALID_JOINT_INDEX };
glm::mat4 inverseBindMatrix;
Transform inverseBindTransform;
};
/// A texture map.
class Texture {
public:
QString id;
QString name;
QByteArray filename;
QByteArray content;
image::ColorChannel sourceChannel { image::ColorChannel::NONE };
Transform transform;
int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE };
int texcoordSet;
QString texcoordSetName;
bool isBumpmap{ false };
bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); }
};
/// A single part of a mesh (with the same material).
class MeshPart {
public:
QVector<int> quadIndices; // original indices from the FBX mesh
QVector<int> quadTrianglesIndices; // original indices from the FBX mesh of the quad converted as triangles
QVector<int> triangleIndices; // original indices from the FBX mesh
};
class Material {
public:
Material() {};
Material(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor,
float shininess, float opacity) :
diffuseColor(diffuseColor),
specularColor(specularColor),
emissiveColor(emissiveColor),
shininess(shininess),
opacity(opacity) {}
void getTextureNames(QSet<QString>& textureList) const;
void setMaxNumPixelsPerTexture(int maxNumPixels);
glm::vec3 diffuseColor{ 1.0f };
float diffuseFactor{ 1.0f };
glm::vec3 specularColor{ 0.02f };
float specularFactor{ 1.0f };
glm::vec3 emissiveColor{ 0.0f };
float emissiveFactor{ 0.0f };
float shininess{ 23.0f };
float opacity{ 1.0f };
float metallic{ 0.0f };
float roughness{ 1.0f };
float emissiveIntensity{ 1.0f };
float ambientFactor{ 1.0f };
float bumpMultiplier { 1.0f }; // TODO: to be implemented
QString materialID;
QString name;
QString shadingModel;
graphics::MaterialPointer _material;
Texture normalTexture;
Texture albedoTexture;
Texture opacityTexture;
Texture glossTexture;
Texture roughnessTexture;
Texture specularTexture;
Texture metallicTexture;
Texture emissiveTexture;
Texture occlusionTexture;
Texture scatteringTexture;
Texture lightmapTexture;
glm::vec2 lightmapParams{ 0.0f, 1.0f };
bool isPBSMaterial{ false };
// THe use XXXMap are not really used to drive which map are going or not, debug only
bool useNormalMap{ false };
bool useAlbedoMap{ false };
bool useOpacityMap{ false };
bool useRoughnessMap{ false };
bool useSpecularMap{ false };
bool useMetallicMap{ false };
bool useEmissiveMap{ false };
bool useOcclusionMap{ false };
bool needTangentSpace() const;
};
/// Simple Triangle List Mesh
struct TriangleListMesh {
std::vector<glm::vec3> vertices;
std::vector<uint32_t> indices;
std::vector<glm::ivec2> parts; // Offset in the indices, Number of indices
std::vector<Extents> partExtents; // Extents of each part with no transform applied. Same length as parts.
};
/// A single mesh (with optional blendshapes).
class Mesh {
public:
std::vector<MeshPart> parts;
QVector<glm::vec3> vertices;
QVector<glm::vec3> normals;
QVector<glm::vec3> tangents;
QVector<glm::vec3> colors;
QVector<glm::vec2> texCoords;
QVector<glm::vec2> texCoords1;
Extents meshExtents; // DEPRECATED (see hfm::Shape::transformedExtents)
glm::mat4 modelTransform; // DEPRECATED (see hfm::Joint::globalTransform, hfm::Shape::transform, hfm::Model::joints)
// Skinning cluster attributes
std::vector<uint16_t> clusterIndices;
std::vector<uint16_t> clusterWeights;
uint16_t clusterWeightsPerVertex { 0 };
// Blendshape attributes
QVector<Blendshape> blendshapes;
// Simple Triangle List Mesh generated during baking
hfm::TriangleListMesh triangleListMesh;
QVector<int32_t> originalIndices; // Original indices of the vertices
unsigned int meshIndex; // the order the meshes appeared in the object file
graphics::MeshPointer _mesh;
bool wasCompressed { false };
};
/// A single animation frame.
class AnimationFrame {
public:
QVector<glm::quat> rotations;
QVector<glm::vec3> translations;
};
/// A light.
class Light {
public:
QString name;
Transform transform;
float intensity;
float fogValue;
glm::vec3 color;
Light() :
name(),
transform(),
intensity(1.0f),
fogValue(0.0f),
color(1.0f)
{}
};
class FlowData {
public:
FlowData() {};
QVariantMap _physicsConfig;
QVariantMap _collisionsConfig;
bool shouldInitFlow() const { return _physicsConfig.size() > 0; }
bool shouldInitCollisions() const { return _collisionsConfig.size() > 0; }
};
// A different skinning representation, used by FBXSerializer. We convert this to our graphics-optimized runtime representation contained within the mesh.
class SkinCluster {
public:
std::vector<uint32_t> indices;
std::vector<float> weights;
};
class SkinDeformer {
public:
std::vector<Cluster> clusters;
};
// The lightweight model part description.
class Shape {
public:
uint32_t mesh { UNDEFINED_KEY };
uint32_t meshPart { UNDEFINED_KEY };
uint32_t material { UNDEFINED_KEY };
uint32_t joint { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information
// TODO: Have all serializers calculate hfm::Shape::transformedExtents in world space where they previously calculated hfm::Mesh::meshExtents. Change all code that uses hfm::Mesh::meshExtents to use this instead.
Extents transformedExtents; // The precise extents of the meshPart vertices in world space, after transform information is applied, while not taking into account rigging/skinning
uint32_t skinDeformer { UNDEFINED_KEY };
};
/// The runtime model format.
class Model {
public:
using Pointer = std::shared_ptr<Model>;
using ConstPointer = std::shared_ptr<const Model>;
QString originalURL;
QString author;
QString applicationName; ///< the name of the application that generated the model
std::vector<Shape> shapes;
std::vector<Mesh> meshes;
std::vector<Material> materials;
std::vector<SkinDeformer> skinDeformers;
std::vector<Joint> joints;
QHash<QString, int> jointIndices; ///< 1-based, so as to more easily detect missing indices
bool hasSkeletonJoints;
QVector<QString> scripts;
glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file
glm::vec3 neckPivot;
Extents bindExtents;
Extents meshExtents;
QVector<AnimationFrame> animationFrames;
int getJointIndex(const QString& name) const { return jointIndices.value(name) - 1; }
QStringList getJointNames() const;
bool hasBlendedMeshes() const;
/// Returns the unscaled extents of the model's mesh
Extents getUnscaledMeshExtents() const;
const Extents& getMeshExtents() const { return meshExtents; }
bool convexHullContains(const glm::vec3& point) const;
QHash<int, QString> meshIndicesToModelNames;
/// given a meshIndex this will return the name of the model that mesh belongs to if known
QString getModelNameOfMesh(int meshIndex) const;
void computeKdops();
QList<QString> blendshapeChannelNames;
QMap<int, glm::quat> jointRotationOffsets;
std::vector<ShapeVertices> shapeVertices;
FlowData flowData;
void debugDump() const;
};
};
typedef hfm::Blendshape HFMBlendshape;
typedef hfm::JointShapeInfo HFMJointShapeInfo;
typedef hfm::Joint HFMJoint;
typedef hfm::Cluster HFMCluster;
typedef hfm::Texture HFMTexture;
typedef hfm::MeshPart HFMMeshPart;
typedef hfm::Material HFMMaterial;
typedef hfm::Mesh HFMMesh;
typedef hfm::SkinDeformer HFMSkinDeformer;
typedef hfm::AnimationFrame HFMAnimationFrame;
typedef hfm::Light HFMLight;
typedef hfm::Shape HFMShape;
typedef hfm::Model HFMModel;
typedef hfm::FlowData FlowData;
Q_DECLARE_METATYPE(HFMAnimationFrame)
Q_DECLARE_METATYPE(QVector<HFMAnimationFrame>)
Q_DECLARE_METATYPE(HFMModel)
Q_DECLARE_METATYPE(HFMModel::Pointer)
#endif // hifi_HFM_h_