Updates the handling of the baking of shape asset previews to generate them with support for view angle control to improve visibility, as well as supporting overriding of a material in the preview bake

Also utilizes the updated bake handling to have material asset previews render as a sphere shape asset, overriding with the material asset's material, improving distinction of what is a material asset vs image asset
Also updates the sphere preview mesh to be more generic and not only for reflection probes
This commit is contained in:
JeffR 2021-12-24 17:26:45 -06:00
parent d9bedbe31c
commit b70faae38f
10 changed files with 206 additions and 172 deletions

View file

@ -51,6 +51,9 @@
#endif #endif
#include "util/imposterCapture.h" #include "util/imposterCapture.h"
#include "ts/tsShapeInstance.h"
#include "gfx/bitmap/imageUtils.h"
StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL; StringTableEntry ShapeAsset::smNoShapeAssetFallback = NULL;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -560,25 +563,94 @@ ShapeAnimationAsset* ShapeAsset::getAnimation(S32 index)
} }
#ifdef TORQUE_TOOLS #ifdef TORQUE_TOOLS
const char* ShapeAsset::generateCachedPreviewImage(S32 resolution) const char* ShapeAsset::generateCachedPreviewImage(S32 resolution, String overrideMaterial)
{ {
if (!mShape) if (!mShape)
return ""; return "";
TSLastDetail* dt = new TSLastDetail(mShape, // We're gonna render... make sure we can.
mFilePath, bool sceneBegun = GFX->canCurrentlyRender();
1, if (!sceneBegun)
0, GFX->beginScene();
0,
false,
0,
resolution);
dt->update(); // We need to create our own instance to render with.
TSShapeInstance* shape = new TSShapeInstance(mShape, true);
delete dt; if(overrideMaterial.isNotEmpty())
shape->reSkin(overrideMaterial, mShape->materialList->getMaterialName(0));
return mFilePath; // Animate the shape once.
shape->animate(0);
// So we don't have to change it everywhere.
const GFXFormat format = GFXFormatR8G8B8A8;
GBitmap* imposter = NULL;
GBitmap* imposterNrml = NULL;
ImposterCapture* imposterCap = new ImposterCapture();
static const MatrixF topXfm(EulerF(-M_PI_F / 2.0f, 0, 0));
static const MatrixF bottomXfm(EulerF(M_PI_F / 2.0f, 0, 0));
MatrixF angMat;
S32 mip = 0;
PROFILE_START(ShapeAsset_generateCachedPreviewImage);
//dMemset(destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize(format));
F32 rotX = -(mDegToRad(60.0) - 0.5f * M_PI_F);
F32 rotZ = -(mDegToRad(45.0) - 0.5f * M_PI_F);
// We capture the images in a particular order which must
// match the order expected by the imposter renderer.
imposterCap->begin(shape, 0, resolution, mShape->mRadius, mShape->center);
angMat.mul(MatrixF(EulerF(rotX, 0, 0)),
MatrixF(EulerF(0, 0, rotZ)));
imposterCap->capture(angMat, &imposter, &imposterNrml);
imposterCap->end();
PROFILE_END(); // ShapeAsset_generateCachedPreviewImage
delete imposterCap;
delete shape;
String dumpPath = String(mFilePath) + "_Preview.dds";
char* returnBuffer = Con::getReturnBuffer(dumpPath.length());
dSprintf(returnBuffer, dumpPath.length(), "%s", dumpPath.c_str());
/*FileStream stream;
if (stream.open(dumpPath, Torque::FS::File::Write))
destBmp.writeBitmap("png", stream);
stream.close();*/
DDSFile* ddsDest = DDSFile::createDDSFileFromGBitmap(imposter);
ImageUtil::ddsCompress(ddsDest, GFXFormatBC2);
// Finally save the imposters to disk.
FileStream fs;
if (fs.open(returnBuffer, Torque::FS::File::Write))
{
ddsDest->write(fs);
fs.close();
}
delete ddsDest;
delete imposter;
delete imposterNrml;
// If we did a begin then end it now.
if (!sceneBegun)
GFX->endScene();
return returnBuffer;
} }
#endif #endif
@ -625,9 +697,12 @@ DefineEngineMethod(ShapeAsset, getStatusString, String, (), , "get status string
#ifdef TORQUE_TOOLS #ifdef TORQUE_TOOLS
DefineEngineMethod(ShapeAsset, generateCachedPreviewImage, const char*, (S32 resolution), (256), "") DefineEngineMethod(ShapeAsset, generateCachedPreviewImage, const char*, (S32 resolution, const char* overrideMaterialName), (256, ""),
"Generates a baked preview image of the given shapeAsset. Only really used for generating Asset Browser icons.\n"
"@param resolution Optional field for what resolution to bake the preview image at. Must be pow2\n"
"@param overrideMaterialName Optional field for overriding the material used when rendering the shape for the bake.")
{ {
return object->generateCachedPreviewImage(resolution); return object->generateCachedPreviewImage(resolution, overrideMaterialName);
} }
DefineEngineStaticMethod(ShapeAsset, getAssetIdByFilename, const char*, (const char* filePath), (""), DefineEngineStaticMethod(ShapeAsset, getAssetIdByFilename, const char*, (const char* filePath), (""),

View file

@ -191,7 +191,7 @@ public:
static U32 getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* shapeAsset); static U32 getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* shapeAsset);
#ifdef TORQUE_TOOLS #ifdef TORQUE_TOOLS
const char* generateCachedPreviewImage(S32 resolution); const char* generateCachedPreviewImage(S32 resolution, String overrideMaterial = "");
#endif #endif
protected: protected:

View file

@ -798,7 +798,7 @@ void ReflectionProbe::createEditorResources()
mEditorShape = NULL; mEditorShape = NULL;
String shapeFile = "tools/resources/ReflectProbeSphere.dae"; String shapeFile = "tools/resources/previewSphereShape.dae";
// Attempt to get the resource from the ResourceManager // Attempt to get the resource from the ResourceManager
mEditorShape = ResourceManager::get().load(shapeFile); mEditorShape = ResourceManager::get().load(shapeFile);

View file

@ -433,7 +433,7 @@ function AssetBrowser::buildMaterialAssetPreview(%this, %assetDef, %previewData)
%generatePreview = false; %generatePreview = false;
%previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.png"; %previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.dds";
if(!isFile(%previewFilePath)) if(!isFile(%previewFilePath))
{ {
%generatePreview = true; %generatePreview = true;
@ -457,17 +457,11 @@ function AssetBrowser::buildMaterialAssetPreview(%this, %assetDef, %previewData)
if(isObject(%assetDef.materialDefinitionName)) if(isObject(%assetDef.materialDefinitionName))
{ {
if(isFile(%assetDef.materialDefinitionName.getDiffuseMap(0))) %previewShapeDef = AssetDatabase.acquireAsset("ToolsModule:previewSphereShape");
{ %generatedFilePath = %previewShapeDef.generateCachedPreviewImage(256, %assetDef.materialDefinitionName);
%difMap = %assetDef.materialDefinitionName.getDiffuseMap(0);
}
else if(%assetDef.materialDefinitionName.getDiffuseMapAsset(0) !$= "")
{
%imgAsset = AssetDatabase.acquireAsset(%assetDef.materialDefinitionName.getDiffuseMapAsset(0));
%difMap = %imgAsset.getImagePath();
}
%success = saveScaledImage(%difMap, %previewFilePath); pathCopy(%generatedFilePath, %previewFilePath);
fileDelete(%generatedFilePath);
%previewAsset = new ImageAsset() %previewAsset = new ImageAsset()
{ {

View file

@ -258,7 +258,7 @@ function AssetBrowser::buildShapeAssetPreview(%this, %assetDef, %previewData)
%generatePreview = false; %generatePreview = false;
%previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.png"; %previewFilePath = %previewPath @ %assetDef.assetName @ "_Preview.dds";
if(!isFile(%previewFilePath) || (compareFileTimes(%assetDef.getShapeFile(), %previewFilePath) == 1)) if(!isFile(%previewFilePath) || (compareFileTimes(%assetDef.getShapeFile(), %previewFilePath) == 1))
{ {
%generatePreview = true; %generatePreview = true;
@ -272,21 +272,11 @@ function AssetBrowser::buildShapeAssetPreview(%this, %assetDef, %previewData)
//This is slightly hacky, but we're going to utilize the imposter/last detail system //This is slightly hacky, but we're going to utilize the imposter/last detail system
//to generate our previews for us and then clean up the unneeded bits //to generate our previews for us and then clean up the unneeded bits
%oldImposterSetting = $TSLastDetail::dumpImposters;
$TSLastDetail::dumpImposters = true;
%filePath = %assetDef.generateCachedPreviewImage(); %filePath = %assetDef.generateCachedPreviewImage();
%imposterPath = %filePath @ ".imposter.png"; pathCopy(%filePath, %previewFilePath);
pathCopy(%imposterPath, %previewFilePath); fileDelete(%filePath); //cleanup
//cleanup
fileDelete(%imposterPath);
fileDelete(%filePath @ ".imposter.dds");
fileDelete(%filePath @ ".imposter_normals.png");
fileDelete(%filePath @ ".imposter_normals.dds");
$TSLastDetail::dumpImposters = %oldImposterSetting;
%previewAsset = new ImageAsset() %previewAsset = new ImageAsset()
{ {

View file

@ -1,6 +0,0 @@
<ShapeAsset
canSave="true"
canSaveDynamicFields="true"
AssetName="ReflectProbeSphere"
fileName="@assetFile=ReflectProbeSphere.dae"
constuctorFileName="@assetFile=ReflectProbeSphere.tscript" />

File diff suppressed because one or more lines are too long

View file

@ -1,11 +0,0 @@
singleton TSShapeConstructor(ReflectProbeSpheredae)
{
baseShapeAsset = "ToolsModule:ReflectProbeSphere";
singleDetailSize = "0";
flipUVCoords = "0";
JoinIdenticalVerts = "0";
reverseWindingOrder = "0";
removeRedundantMats = "0";
animFPS = "2";
};

View file

@ -0,0 +1,6 @@
<ShapeAsset
canSave="true"
canSaveDynamicFields="true"
AssetName="previewSphereShape"
fileName="@assetFile=previewSphereShape.dae"
constuctorFileName="@assetFile=previewSphereShape.tscript" />

File diff suppressed because one or more lines are too long