Merge pull request #702 from Areloch/ImposterFix

Fixes mapping of imposter images to be packed as part of the shape asset, and fixes paths to be formatted more sanely.
This commit is contained in:
Brian Roberts 2021-12-10 03:39:58 -06:00 committed by GitHub
commit b0218d129c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 186 additions and 7 deletions

View file

@ -129,6 +129,13 @@ ShapeAsset::ShapeAsset()
mConstructorFileName = StringTable->EmptyString();
mFilePath = StringTable->EmptyString();
mConstructorFilePath = StringTable->EmptyString();
mDiffuseImposterFileName = StringTable->EmptyString();
mDiffuseImposterPath = StringTable->EmptyString();
mNormalImposterFileName = StringTable->EmptyString();
mNormalImposterPath = StringTable->EmptyString();
mLoadedState = AssetErrCode::NotLoaded;
}
@ -162,6 +169,12 @@ void ShapeAsset::initPersistFields()
&setShapeFile, &getShapeFile, "Path to the shape file we want to render");
addProtectedField("constuctorFileName", TypeAssetLooseFilePath, Offset(mConstructorFileName, ShapeAsset),
&setShapeConstructorFile, &getShapeConstructorFile, "Path to the shape file we want to render");
addProtectedField("diffuseImposterFileName", TypeAssetLooseFilePath, Offset(mDiffuseImposterFileName, ShapeAsset),
&setDiffuseImposterFile, &getDiffuseImposterFile, "Path to the diffuse imposter file we want to render");
addProtectedField("normalImposterFileName", TypeAssetLooseFilePath, Offset(mNormalImposterFileName, ShapeAsset),
&setNormalImposterFile, &getNormalImposterFile, "Path to the normal imposter file we want to render");
}
void ShapeAsset::setDataField(StringTableEntry slotName, StringTableEntry array, StringTableEntry value)
@ -193,6 +206,20 @@ void ShapeAsset::initializeAsset()
mConstructorFilePath = getOwned() ? expandAssetFilePath(mConstructorFilePath) : mConstructorFilePath;
mDiffuseImposterPath = getOwned() ? expandAssetFilePath(mDiffuseImposterFileName) : mDiffuseImposterFileName;
if (mDiffuseImposterPath == StringTable->EmptyString())
{
String diffusePath = String(mFilePath) + "_imposter.dds";
mDiffuseImposterPath = StringTable->insert(diffusePath.c_str());
}
mNormalImposterPath = getOwned() ? expandAssetFilePath(mNormalImposterFileName) : mNormalImposterFileName;
if (mNormalImposterPath == StringTable->EmptyString())
{
String normalPath = String(mFilePath) + "_imposter_normals.dds";
mNormalImposterPath = StringTable->insert(normalPath.c_str());
}
loadShape();
}
@ -232,6 +259,42 @@ void ShapeAsset::setShapeConstructorFile(const char* pShapeConstructorFile)
refreshAsset();
}
void ShapeAsset::setDiffuseImposterFile(const char* pImageFile)
{
// Sanity!
AssertFatal(pImageFile != NULL, "Cannot use a NULL image file.");
// Fetch image file.
pImageFile = StringTable->insert(pImageFile, true);
// Ignore no change,
if (pImageFile == mDiffuseImposterFileName)
return;
mDiffuseImposterFileName = getOwned() ? expandAssetFilePath(pImageFile) : pImageFile;
// Refresh the asset.
refreshAsset();
}
void ShapeAsset::setNormalImposterFile(const char* pImageFile)
{
// Sanity!
AssertFatal(pImageFile != NULL, "Cannot use a NULL image file.");
// Fetch image file.
pImageFile = StringTable->insert(pImageFile, true);
// Ignore no change,
if (pImageFile == mNormalImposterFileName)
return;
mNormalImposterFileName = getOwned() ? expandAssetFilePath(pImageFile) : pImageFile;
// Refresh the asset.
refreshAsset();
}
void ShapeAsset::_onResourceChanged(const Torque::Path &path)
{
if (path != Torque::Path(mFilePath) )
@ -292,6 +355,10 @@ bool ShapeAsset::loadShape()
return false; //if it failed to load, bail out
}
mShape->setupBillboardDetails(mFilePath, mDiffuseImposterPath, mNormalImposterPath);
//If they exist, grab our imposters here and bind them to our shapeAsset
bool hasBlends = false;
//Now that we've successfully loaded our shape and have any materials and animations loaded

View file

@ -73,6 +73,12 @@ protected:
StringTableEntry mConstructorFilePath;
Resource<TSShape> mShape;
StringTableEntry mDiffuseImposterFileName;
StringTableEntry mDiffuseImposterPath;
StringTableEntry mNormalImposterFileName;
StringTableEntry mNormalImposterPath;
//Material assets we're dependent on and use
Vector<StringTableEntry> mMaterialAssetIds;
Vector<AssetPtr<MaterialAsset>> mMaterialAssets;
@ -170,6 +176,15 @@ public:
inline StringTableEntry getShapeFilePath(void) const { return mFilePath; };
inline StringTableEntry getShapeConstructorFilePath(void) const { return mConstructorFilePath; };
//Imposter images
void setDiffuseImposterFile(const char* pImageFile);
inline StringTableEntry getDiffuseImposterFile(void) const { return mDiffuseImposterFileName; };
inline StringTableEntry getDiffuseImposterFilePath(void) const { return mDiffuseImposterPath; };
void setNormalImposterFile(const char* pImageFile);
inline StringTableEntry getNormalImposterFile(void) const { return mNormalImposterFileName; };
inline StringTableEntry getNormalImposterFilePath(void) const { return mNormalImposterPath; };
static U32 getAssetByFilename(StringTableEntry fileName, AssetPtr<ShapeAsset>* shapeAsset);
static StringTableEntry getAssetIdByFilename(StringTableEntry fileName);
@ -188,6 +203,10 @@ protected:
static bool setShapeConstructorFile(void* obj, const char* index, const char* data) { static_cast<ShapeAsset*>(obj)->setShapeConstructorFile(data); return false; }
static const char* getShapeConstructorFile(void* obj, const char* data) { return static_cast<ShapeAsset*>(obj)->getShapeConstructorFile(); }
static bool setDiffuseImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast<ShapeAsset*>(obj)->setDiffuseImposterFile(data); return false; }
static const char* getDiffuseImposterFile(void* obj, const char* data) { return static_cast<ShapeAsset*>(obj)->getDiffuseImposterFile(); }
static bool setNormalImposterFile(void* obj, StringTableEntry index, StringTableEntry data) { static_cast<ShapeAsset*>(obj)->setNormalImposterFile(data); return false; }
static const char* getNormalImposterFile(void* obj, const char* data) { return static_cast<ShapeAsset*>(obj)->getNormalImposterFile(); }
};
#ifdef TORQUE_TOOLS

View file

@ -3062,6 +3062,15 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
}
}
if (Con::getBoolVariable("$TSLastDetail::dumpImposters", false))
{
String imposterPath = assetItem->assetName + "_imposter.png";
String normalsPath = assetItem->assetName + "_imposter_normals.png";
newAsset->setDiffuseImposterFile(imposterPath.c_str());
newAsset->setNormalImposterFile(normalsPath.c_str());
}
Taml tamlWriter;
bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());

View file

@ -86,6 +86,8 @@ TSLastDetail::TSLastDetail( TSShape *shape,
mCenter = mShape->center;
mCachePath = cachePath;
mDiffusePath = mCachePath + "_imposter.dds";
mNormalPath = mCachePath + "_imposter_normals.dds";
mMaterial = NULL;
mMatInstance = NULL;
@ -94,6 +96,38 @@ TSLastDetail::TSLastDetail( TSShape *shape,
smLastDetails.push_back( this );
}
TSLastDetail::TSLastDetail(TSShape* shape,
const String& cachePath,
const String& diffusePath,
const String& normalPath,
U32 numEquatorSteps,
U32 numPolarSteps,
F32 polarAngle,
bool includePoles,
S32 dl, S32 dim)
{
mNumEquatorSteps = getMax(numEquatorSteps, (U32)1);
mNumPolarSteps = numPolarSteps;
mPolarAngle = polarAngle;
mIncludePoles = includePoles;
mShape = shape;
mDl = dl;
mDim = getMax(dim, (S32)32);
mRadius = mShape->mRadius;
mCenter = mShape->center;
mCachePath = cachePath;
mDiffusePath = diffusePath;
mNormalPath = normalPath;
mMaterial = NULL;
mMatInstance = NULL;
// Store this in the static list.
smLastDetails.push_back(this);
}
TSLastDetail::~TSLastDetail()
{
SAFE_DELETE( mMatInstance );
@ -189,7 +223,8 @@ void TSLastDetail::update( bool forceUpdate )
// Do we need to update the imposter?
const String diffuseMapPath = _getDiffuseMapPath();
if ( forceUpdate ||
bool isFile = Platform::isFile(diffuseMapPath.c_str());
if ( forceUpdate || !Platform::isFile(diffuseMapPath.c_str()) ||
Platform::compareModifiedTimes( diffuseMapPath, shapeFile ) <= 0 )
_update();
@ -218,8 +253,9 @@ void TSLastDetail::update( bool forceUpdate )
// Setup the material for this imposter.
mMaterial = MATMGR->allocateAndRegister( String::EmptyString );
mMaterial->mAutoGenerated = true;
mMaterial->_setDiffuseMap(diffuseMapPath,0);
mMaterial->_setNormalMap(_getNormalMapPath(), 0);
mMaterial->setDiffuseMapFile(diffuseMapPath, 0);
mMaterial->setNormalMapFile(_getNormalMapPath(), 0);
mMaterial->mImposterLimits.set( (mNumPolarSteps * 2) + 1, mNumEquatorSteps, mPolarAngle, mIncludePoles );
mMaterial->mTranslucent = true;
mMaterial->mTranslucentBlendOp = Material::None;
@ -466,8 +502,8 @@ void TSLastDetail::_update()
// Should we dump the images?
if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) )
{
String imposterPath = mCachePath + ".imposter.png";
String normalsPath = mCachePath + ".imposter_normals.png";
String imposterPath = _getDiffuseMapPath();
String normalsPath = _getNormalMapPath();
FileStream stream;
if ( stream.open( imposterPath, Torque::FS::File::Write ) )

View file

@ -92,6 +92,9 @@ protected:
/// where we'll be storing our cache for rendered imposters.
String mCachePath;
String mDiffusePath;
String mNormalPath;
/// The shape detail level to capture into
/// the imposters.
S32 mDl;
@ -148,10 +151,10 @@ protected:
void _validateDim();
/// Helper which returns the imposter diffuse map path.
String _getDiffuseMapPath() const { return mCachePath + ".imposter.dds"; }
String _getDiffuseMapPath() const { return mDiffusePath; }
/// Helper which returns the imposter normal map path.
String _getNormalMapPath() const { return mCachePath + ".imposter_normals.dds"; }
String _getNormalMapPath() const { return mNormalPath; }
public:
@ -164,6 +167,16 @@ public:
S32 dl,
S32 dim );
TSLastDetail(TSShape* shape,
const String& cachePath,
const String& diffusePath,
const String& normalPath,
U32 numEquatorSteps,
U32 numPolarSteps,
F32 polarAngle,
bool includePoles,
S32 dl, S32 dim);
~TSLastDetail();
/// Global preference for rendering imposters to shadows.

View file

@ -969,6 +969,39 @@ void TSShape::setupBillboardDetails( const String &cachePath )
}
}
void TSShape::setupBillboardDetails(const String& cachePath, const String& diffsePath, const String& normalPath)
{
// set up billboard details -- only do this once, meaning that
// if we add a sequence to the shape we don't redo the billboard
// details...
if (!billboardDetails.empty())
return;
for (U32 i = 0; i < details.size(); i++)
{
const Detail& det = details[i];
if (det.subShapeNum >= 0)
continue; // not a billboard detail
while (billboardDetails.size() <= i)
billboardDetails.push_back(NULL);
billboardDetails[i] = new TSLastDetail(this,
cachePath,
diffsePath,
normalPath,
det.bbEquatorSteps,
det.bbPolarSteps,
det.bbPolarAngle,
det.bbIncludePoles,
det.bbDetailLevel,
det.bbDimension);
billboardDetails[i]->update();
}
}
void TSShape::initMaterialList()
{
S32 numSubShapes = subShapeFirstObject.size();

View file

@ -429,6 +429,8 @@ class TSShape
void setupBillboardDetails( const String &cachePath );
void setupBillboardDetails(const String& cachePath, const String& diffsePath, const String& normalPath);
/// Inits object list (no geometry buffers)
void initObjects();