Merge pull request #2578 from petrmohelnik/glTF-2.0-Lights-import
glTF 2.0 Lights importpull/2568/head^2
commit
563ec1662c
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue