forcing users to use osgDB::readRef*File() methods. The later is preferable as it closes a potential threading bug when using paging databases in conjunction
with the osgDB::Registry Object Cache. This threading bug occurs when one thread gets an object from the Cache via an osgDB::read*File() call where only
a pointer to the object is passed back, so taking a reference to the object is delayed till it gets reassigned to a ref_ptr<>, but at the same time another
thread calls a flush of the Object Cache deleting this object as it's referenceCount is now zero. Using osgDB::readREf*File() makes sure the a ref_ptr<> is
passed back and the referenceCount never goes to zero.
To ensure the OSG builds when OSG_PROVIDE_READFILE is to OFF the many cases of osgDB::read*File() usage had to be replaced with a ref_ptr<> osgDB::readRef*File()
usage. The avoid this change causing lots of other client code to be rewritten to handle the use of ref_ptr<> in place of C pointer I introduced a serious of
templte methods in various class to adapt ref_ptr<> to the underly C pointer to be passed to old OSG API's, example of this is found in include/osg/Group:
bool addChild(Node* child); // old method which can only be used with a Node*
tempalte<class T> bool addChild(const osg::ref_ptr<T>& child) { return addChild(child.get()); } // adapter template method
These changes together cover 149 modified files, so it's a large submission. This extent of changes are warrent to make use of the Object Cache
and multi-threaded loaded more robust.
git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@15164 16af8721-9629-0410-8352-f15c8da7e697
276 lines
11 KiB
C++
276 lines
11 KiB
C++
#include "fbxMaterialToOsgStateSet.h"
|
|
#include <sstream>
|
|
#include <osgDB/ReadFile>
|
|
#include <osgDB/FileUtils>
|
|
#include <osgDB/FileNameUtils>
|
|
|
|
|
|
static osg::Texture::WrapMode convertWrap(FbxFileTexture::EWrapMode wrap)
|
|
{
|
|
return wrap == FbxFileTexture::eRepeat ?
|
|
osg::Texture2D::REPEAT : osg::Texture2D::CLAMP_TO_EDGE;
|
|
}
|
|
|
|
StateSetContent
|
|
FbxMaterialToOsgStateSet::convert(const FbxSurfaceMaterial* pFbxMat)
|
|
{
|
|
FbxMaterialMap::const_iterator it = _fbxMaterialMap.find(pFbxMat);
|
|
if (it != _fbxMaterialMap.end())
|
|
return it->second;
|
|
|
|
osg::ref_ptr<osg::Material> pOsgMat = new osg::Material;
|
|
pOsgMat->setName(pFbxMat->GetName());
|
|
|
|
StateSetContent result;
|
|
|
|
result.material = pOsgMat;
|
|
|
|
FbxString shadingModel = pFbxMat->ShadingModel.Get();
|
|
|
|
const FbxSurfaceLambert* pFbxLambert = FbxCast<FbxSurfaceLambert>(pFbxMat);
|
|
|
|
// diffuse map...
|
|
const FbxProperty lProperty = pFbxMat->FindProperty(FbxSurfaceMaterial::sDiffuse);
|
|
if (lProperty.IsValid())
|
|
{
|
|
int lNbTex = lProperty.GetSrcObjectCount<FbxFileTexture>();
|
|
for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++)
|
|
{
|
|
FbxFileTexture* lTexture = FbxCast<FbxFileTexture>(lProperty.GetSrcObject<FbxFileTexture>(lTextureIndex));
|
|
if (lTexture)
|
|
{
|
|
result.diffuseTexture = fbxTextureToOsgTexture(lTexture);
|
|
result.diffuseChannel = lTexture->UVSet.Get();
|
|
result.diffuseScaleU = lTexture->GetScaleU();
|
|
result.diffuseScaleV = lTexture->GetScaleV();
|
|
}
|
|
|
|
//For now only allow 1 texture
|
|
break;
|
|
}
|
|
}
|
|
|
|
double transparencyColorFactor = 1.0;
|
|
bool useTransparencyColorFactor = false;
|
|
|
|
// opacity map...
|
|
const FbxProperty lOpacityProperty = pFbxMat->FindProperty(FbxSurfaceMaterial::sTransparentColor);
|
|
if (lOpacityProperty.IsValid())
|
|
{
|
|
FbxDouble3 transparentColor = lOpacityProperty.Get<FbxDouble3>();
|
|
// If transparent color is defined set the transparentFactor to gray scale value of transparentColor
|
|
if (transparentColor[0] < 1.0 || transparentColor[1] < 1.0 || transparentColor[2] < 1.0) {
|
|
transparencyColorFactor = transparentColor[0]*0.30 + transparentColor[1]*0.59 + transparentColor[2]*0.11;
|
|
useTransparencyColorFactor = true;
|
|
}
|
|
|
|
int lNbTex = lOpacityProperty.GetSrcObjectCount<FbxFileTexture>();
|
|
for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++)
|
|
{
|
|
FbxFileTexture* lTexture = FbxCast<FbxFileTexture>(lOpacityProperty.GetSrcObject<FbxFileTexture>(lTextureIndex));
|
|
if (lTexture)
|
|
{
|
|
// TODO: if texture image does NOT have an alpha channel, should it be added?
|
|
|
|
result.opacityTexture = fbxTextureToOsgTexture(lTexture);
|
|
result.opacityChannel = lTexture->UVSet.Get();
|
|
result.opacityScaleU = lTexture->GetScaleU();
|
|
result.opacityScaleV = lTexture->GetScaleV();
|
|
}
|
|
|
|
//For now only allow 1 texture
|
|
break;
|
|
}
|
|
}
|
|
|
|
// reflection map...
|
|
const FbxProperty lReflectionProperty = pFbxMat->FindProperty(FbxSurfaceMaterial::sReflection);
|
|
if (lReflectionProperty.IsValid())
|
|
{
|
|
int lNbTex = lReflectionProperty.GetSrcObjectCount<FbxFileTexture>();
|
|
for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++)
|
|
{
|
|
FbxFileTexture* lTexture = FbxCast<FbxFileTexture>(lReflectionProperty.GetSrcObject<FbxFileTexture>(lTextureIndex));
|
|
if (lTexture)
|
|
{
|
|
// support only spherical reflection maps...
|
|
if (FbxFileTexture::eUMT_ENVIRONMENT == lTexture->CurrentMappingType.Get())
|
|
{
|
|
result.reflectionTexture = fbxTextureToOsgTexture(lTexture);
|
|
result.reflectionChannel = lTexture->UVSet.Get();
|
|
}
|
|
}
|
|
|
|
//For now only allow 1 texture
|
|
break;
|
|
}
|
|
}
|
|
|
|
// emissive map...
|
|
const FbxProperty lEmissiveProperty = pFbxMat->FindProperty(FbxSurfaceMaterial::sEmissive);
|
|
if (lEmissiveProperty.IsValid())
|
|
{
|
|
int lNbTex = lEmissiveProperty.GetSrcObjectCount<FbxFileTexture>();
|
|
for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++)
|
|
{
|
|
FbxFileTexture* lTexture = FbxCast<FbxFileTexture>(lEmissiveProperty.GetSrcObject<FbxFileTexture>(lTextureIndex));
|
|
if (lTexture)
|
|
{
|
|
result.emissiveTexture = fbxTextureToOsgTexture(lTexture);
|
|
result.emissiveChannel = lTexture->UVSet.Get();
|
|
result.emissiveScaleU = lTexture->GetScaleU();
|
|
result.emissiveScaleV = lTexture->GetScaleV();
|
|
}
|
|
|
|
//For now only allow 1 texture
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ambient map...
|
|
const FbxProperty lAmbientProperty = pFbxMat->FindProperty(FbxSurfaceMaterial::sAmbient);
|
|
if (lAmbientProperty.IsValid())
|
|
{
|
|
int lNbTex = lAmbientProperty.GetSrcObjectCount<FbxFileTexture>();
|
|
for (int lTextureIndex = 0; lTextureIndex < lNbTex; lTextureIndex++)
|
|
{
|
|
FbxFileTexture* lTexture = FbxCast<FbxFileTexture>(lAmbientProperty.GetSrcObject<FbxFileTexture>(lTextureIndex));
|
|
if (lTexture)
|
|
{
|
|
result.ambientTexture = fbxTextureToOsgTexture(lTexture);
|
|
result.ambientChannel = lTexture->UVSet.Get();
|
|
result.ambientScaleU = lTexture->GetScaleU();
|
|
result.ambientScaleV = lTexture->GetScaleV();
|
|
}
|
|
|
|
//For now only allow 1 texture
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pFbxLambert)
|
|
{
|
|
FbxDouble3 color = pFbxLambert->Diffuse.Get();
|
|
double factor = pFbxLambert->DiffuseFactor.Get();
|
|
double transparencyFactor = useTransparencyColorFactor ? transparencyColorFactor : pFbxLambert->TransparencyFactor.Get();
|
|
pOsgMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(
|
|
static_cast<float>(color[0] * factor),
|
|
static_cast<float>(color[1] * factor),
|
|
static_cast<float>(color[2] * factor),
|
|
static_cast<float>(1.0 - transparencyFactor)));
|
|
|
|
color = pFbxLambert->Ambient.Get();
|
|
factor = pFbxLambert->AmbientFactor.Get();
|
|
pOsgMat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(
|
|
static_cast<float>(color[0] * factor),
|
|
static_cast<float>(color[1] * factor),
|
|
static_cast<float>(color[2] * factor),
|
|
1.0f));
|
|
|
|
color = pFbxLambert->Emissive.Get();
|
|
factor = pFbxLambert->EmissiveFactor.Get();
|
|
pOsgMat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(
|
|
static_cast<float>(color[0] * factor),
|
|
static_cast<float>(color[1] * factor),
|
|
static_cast<float>(color[2] * factor),
|
|
1.0f));
|
|
|
|
// get maps factors...
|
|
result.diffuseFactor = pFbxLambert->DiffuseFactor.Get();
|
|
|
|
if (const FbxSurfacePhong* pFbxPhong = FbxCast<FbxSurfacePhong>(pFbxLambert))
|
|
{
|
|
color = pFbxPhong->Specular.Get();
|
|
factor = pFbxPhong->SpecularFactor.Get();
|
|
pOsgMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(
|
|
static_cast<float>(color[0] * factor),
|
|
static_cast<float>(color[1] * factor),
|
|
static_cast<float>(color[2] * factor),
|
|
1.0f));
|
|
// Since Maya and 3D studio Max stores their glossiness values in exponential format (2^(log2(x))
|
|
// We need to linearize to values between 0-100 and then scale to values between 0-128.
|
|
// Glossiness values above 100 will result in shininess larger than 128.0 and will be clamped
|
|
double shininess = (64.0 * log (pFbxPhong->Shininess.Get())) / (5.0 * log(2.0));
|
|
pOsgMat->setShininess(osg::Material::FRONT_AND_BACK,
|
|
static_cast<float>(shininess));
|
|
|
|
// get maps factors...
|
|
result.reflectionFactor = pFbxPhong->ReflectionFactor.Get();
|
|
// get more factors here...
|
|
}
|
|
}
|
|
|
|
if (_lightmapTextures)
|
|
{
|
|
// if using an emission map then adjust material properties accordingly...
|
|
if (result.emissiveTexture)
|
|
{
|
|
osg::Vec4 diffuse = pOsgMat->getDiffuse(osg::Material::FRONT_AND_BACK);
|
|
pOsgMat->setEmission(osg::Material::FRONT_AND_BACK, diffuse);
|
|
pOsgMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,diffuse.a()));
|
|
pOsgMat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,diffuse.a()));
|
|
}
|
|
}
|
|
|
|
_fbxMaterialMap.insert(FbxMaterialMap::value_type(pFbxMat, result));
|
|
return result;
|
|
}
|
|
|
|
osg::ref_ptr<osg::Texture2D>
|
|
FbxMaterialToOsgStateSet::fbxTextureToOsgTexture(const FbxFileTexture* fbx)
|
|
{
|
|
ImageMap::iterator it = _imageMap.find(fbx->GetFileName());
|
|
if (it != _imageMap.end())
|
|
return it->second;
|
|
osg::ref_ptr<osg::Image> pImage = NULL;
|
|
|
|
// Warning: fbx->GetRelativeFileName() is relative TO EXECUTION DIR
|
|
// fbx->GetFileName() is as stored initially in the FBX
|
|
if ((pImage = osgDB::readRefImageFile(osgDB::concatPaths(_dir, fbx->GetFileName()), _options)) || // First try "export dir/name"
|
|
(pImage = osgDB::readRefImageFile(fbx->GetFileName(), _options)) || // Then try "name" (if absolute)
|
|
(pImage = osgDB::readRefImageFile(osgDB::concatPaths(_dir, fbx->GetRelativeFileName()), _options))) // Else try "current dir/name"
|
|
{
|
|
osg::ref_ptr<osg::Texture2D> pOsgTex = new osg::Texture2D;
|
|
pOsgTex->setImage(pImage.get());
|
|
pOsgTex->setWrap(osg::Texture2D::WRAP_S, convertWrap(fbx->GetWrapModeU()));
|
|
pOsgTex->setWrap(osg::Texture2D::WRAP_T, convertWrap(fbx->GetWrapModeV()));
|
|
_imageMap.insert(std::make_pair(fbx->GetFileName(), pOsgTex.get()));
|
|
return pOsgTex;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void FbxMaterialToOsgStateSet::checkInvertTransparency()
|
|
{
|
|
int zeroAlpha = 0, oneAlpha = 0;
|
|
for (FbxMaterialMap::const_iterator it = _fbxMaterialMap.begin(); it != _fbxMaterialMap.end(); ++it)
|
|
{
|
|
const osg::Material* pMaterial = it->second.material.get();
|
|
float alpha = pMaterial->getDiffuse(osg::Material::FRONT).a();
|
|
if (alpha > 0.999f)
|
|
{
|
|
++oneAlpha;
|
|
}
|
|
else if (alpha < 0.001f)
|
|
{
|
|
++zeroAlpha;
|
|
}
|
|
}
|
|
|
|
if (zeroAlpha > oneAlpha)
|
|
{
|
|
//Transparency values seem to be back to front so invert them.
|
|
|
|
for (FbxMaterialMap::const_iterator it = _fbxMaterialMap.begin(); it != _fbxMaterialMap.end(); ++it)
|
|
{
|
|
osg::Material* pMaterial = it->second.material.get();
|
|
osg::Vec4 diffuse = pMaterial->getDiffuse(osg::Material::FRONT);
|
|
diffuse.a() = 1.0f - diffuse.a();
|
|
pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
|
|
}
|
|
}
|
|
}
|