Files
UnrealEngine/Engine/Source/ThirdParty/MaterialX/MaterialX-1.38.10/source/MaterialXView/Main.cpp
2025-05-18 13:04:45 +08:00

318 lines
13 KiB
C++

//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//
#include <MaterialXView/Viewer.h>
#include <MaterialXRender/Util.h>
#include <MaterialXFormat/Util.h>
#include <MaterialXCore/Util.h>
#include <iostream>
NANOGUI_FORCE_DISCRETE_GPU();
const std::string options =
" Options: \n"
" --material [FILENAME] Specify the filename of the MTLX document to be displayed in the viewer\n"
" --mesh [FILENAME] Specify the filename of the OBJ mesh to be displayed in the viewer\n"
" --meshRotation [VECTOR3] Specify the rotation of the displayed mesh as three comma-separated floats, representing rotations in degrees about the X, Y, and Z axes (defaults to 0,0,0)\n"
" --meshScale [FLOAT] Specify the uniform scale of the displayed mesh\n"
" --enableTurntable[BOOLEAN] Specify whether to enable turntable rendering of the scene\n"
" --turntableSteps [INTEGER] Specify the number of steps for a complete turntable rotation. Defaults to 360\n"
" --cameraPosition [VECTOR3] Specify the position of the camera as three comma-separated floats (defaults to 0,0,5)\n"
" --cameraTarget [VECTOR3] Specify the position of the camera target as three comma-separated floats (defaults to 0,0,0)\n"
" --cameraViewAngle [FLOAT] Specify the view angle of the camera, or zero for an orthographic projection (defaults to 45)\n"
" --cameraZoom [FLOAT] Specify the zoom factor for the camera, implemented as a mesh scale multiplier (defaults to 1)\n"
" --envRad [FILENAME] Specify the filename of the environment light to display, stored as HDR environment radiance in the latitude-longitude format\n"
" --envMethod [INTEGER] Specify the environment lighting method (0 = filtered importance sampling, 1 = prefiltered environment maps, defaults to 0)\n"
" --envSampleCount [INTEGER] Specify the environment sample count (defaults to 16)\n"
" --envLightIntensity [FLOAT] Specify the environment light intensity (defaults to 1)\n"
" --lightRotation [FLOAT] Specify the rotation in degrees of the lighting environment about the Y axis (defaults to 0)\n"
" --shadowMap [BOOLEAN] Specify whether shadow mapping is enabled (defaults to true)\n"
" --path [FILEPATH] Specify an additional data search path location (e.g. '/projects/MaterialX'). This absolute path will be queried when locating data libraries, XInclude references, and referenced images.\n"
" --library [FILEPATH] Specify an additional data library folder (e.g. 'vendorlib', 'studiolib'). This relative path will be appended to each location in the data search path when loading data libraries.\n"
" --screenWidth [INTEGER] Specify the width of the screen image in pixels (defaults to 1280)\n"
" --screenHeight [INTEGER] Specify the height of the screen image in pixels (defaults to 960)\n"
" --screenColor [VECTOR3] Specify the background color of the viewer as three comma-separated floats (defaults to 0.3,0.3,0.32)\n"
" --drawEnvironment [BOOLEAN] Specify whether to render the environment as the background (defaults to false)\n"
" --captureFilename [FILENAME] Specify the filename to which the first rendered frame should be written\n"
" --bakeWidth [INTEGER] Specify the target width for texture baking (defaults to maximum image width of the source document)\n"
" --bakeHeight [INTEGER] Specify the target height for texture baking (defaults to maximum image height of the source document)\n"
" --bakeFilename [STRING] Specify the output document filename for texture baking\n"
" --refresh [FLOAT] Specify the refresh period for the viewer in milliseconds (defaults to 50, set to -1 to disable)\n"
" --remap [TOKEN1:TOKEN2] Specify the remapping from one token to another when MaterialX document is loaded\n"
" --skip [NAME] Specify to skip elements matching the given name attribute\n"
" --terminator [STRING] Specify to enforce the given terminator string for file prefixes\n"
" --help Display the complete list of command-line options\n";
template <class T> void parseToken(std::string token, std::string type, T& res)
{
if (token.empty())
{
return;
}
mx::ValuePtr value = mx::Value::createValueFromStrings(token, type);
if (!value)
{
std::cout << "Unable to parse token " << token << " as type " << type << std::endl;
return;
}
res = value->asA<T>();
}
int main(int argc, char* const argv[])
{
std::vector<std::string> tokens;
for (int i = 1; i < argc; i++)
{
tokens.emplace_back(argv[i]);
}
std::string materialFilename = "resources/Materials/Examples/StandardSurface/standard_surface_default.mtlx";
std::string meshFilename = "resources/Geometry/shaderball.glb";
std::string envRadianceFilename = "resources/Lights/san_giuseppe_bridge_split.hdr";
mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath();
mx::FilePathVec libraryFolders;
mx::Vector3 meshRotation;
float meshScale = 1.0f;
bool turntableEnabled = false;
int turntableSteps = 360;
mx::Vector3 cameraPosition(DEFAULT_CAMERA_POSITION);
mx::Vector3 cameraTarget;
float cameraViewAngle(DEFAULT_CAMERA_VIEW_ANGLE);
float cameraZoom(DEFAULT_CAMERA_ZOOM);
mx::HwSpecularEnvironmentMethod specularEnvironmentMethod = mx::SPECULAR_ENVIRONMENT_FIS;
int envSampleCount = mx::DEFAULT_ENV_SAMPLE_COUNT;
float envLightIntensity = 1.0f;
float lightRotation = 0.0f;
bool shadowMap = true;
DocumentModifiers modifiers;
int screenWidth = 1280;
int screenHeight = 960;
mx::Color3 screenColor(mx::DEFAULT_SCREEN_COLOR_SRGB);
bool drawEnvironment = false;
std::string captureFilename;
int bakeWidth = 0;
int bakeHeight = 0;
std::string bakeFilename;
float refresh = 50.0f;
for (size_t i = 0; i < tokens.size(); i++)
{
const std::string& token = tokens[i];
const std::string& nextToken = i + 1 < tokens.size() ? tokens[i + 1] : mx::EMPTY_STRING;
if (token == "--material")
{
materialFilename = nextToken;
}
else if (token == "--mesh")
{
meshFilename = nextToken;
}
else if (token == "--envRad")
{
envRadianceFilename = nextToken;
}
else if (token == "--meshRotation")
{
parseToken(nextToken, "vector3", meshRotation);
}
else if (token == "--meshScale")
{
parseToken(nextToken, "float", meshScale);
}
else if (token == "--enableTurntable")
{
parseToken(nextToken, "boolean", turntableEnabled);
}
else if (token == "--turntableSteps")
{
parseToken(nextToken, "integer", turntableSteps);
turntableSteps = std::clamp(turntableSteps, 2, 360);
}
else if (token == "--cameraPosition")
{
parseToken(nextToken, "vector3", cameraPosition);
}
else if (token == "--cameraTarget")
{
parseToken(nextToken, "vector3", cameraTarget);
}
else if (token == "--cameraViewAngle")
{
parseToken(nextToken, "float", cameraViewAngle);
}
else if (token == "--cameraZoom")
{
parseToken(nextToken, "float", cameraZoom);
}
else if (token == "--envMethod")
{
if (std::stoi(nextToken) == 1)
{
specularEnvironmentMethod = mx::SPECULAR_ENVIRONMENT_PREFILTER;
}
}
else if (token == "--envSampleCount")
{
parseToken(nextToken, "integer", envSampleCount);
}
else if (token == "--envLightIntensity")
{
parseToken(nextToken, "float", envLightIntensity);
}
else if (token == "--lightRotation")
{
parseToken(nextToken, "float", lightRotation);
}
else if (token == "--shadowMap")
{
parseToken(nextToken, "boolean", shadowMap);
}
else if (token == "--path")
{
searchPath.append(mx::FileSearchPath(nextToken));
}
else if (token == "--library")
{
libraryFolders.push_back(nextToken);
}
else if (token == "--screenWidth")
{
parseToken(nextToken, "integer", screenWidth);
}
else if (token == "--screenHeight")
{
parseToken(nextToken, "integer", screenHeight);
}
else if (token == "--screenColor")
{
parseToken(nextToken, "color3", screenColor);
}
else if (token == "--drawEnvironment")
{
parseToken(nextToken, "boolean", drawEnvironment);
}
else if (token == "--captureFilename")
{
parseToken(nextToken, "string", captureFilename);
}
else if (token == "--bakeWidth")
{
parseToken(nextToken, "integer", bakeWidth);
}
else if (token == "--bakeHeight")
{
parseToken(nextToken, "integer", bakeHeight);
}
else if (token == "--bakeFilename")
{
parseToken(nextToken, "string", bakeFilename);
}
else if (token == "--refresh")
{
parseToken(nextToken, "float", refresh);
}
else if (token == "--remap")
{
mx::StringVec vec = mx::splitString(nextToken, ":");
if (vec.size() == 2)
{
modifiers.remapElements[vec[0]] = vec[1];
}
else if (!nextToken.empty())
{
std::cout << "Unable to parse token following command-line option: " << token << std::endl;
}
}
else if (token == "--skip")
{
modifiers.skipElements.insert(nextToken);
}
else if (token == "--terminator")
{
modifiers.filePrefixTerminator = nextToken;
}
else if (token == "--help")
{
std::cout << " MaterialXView version " << mx::getVersionString() << std::endl;
std::cout << options << std::endl;
return 0;
}
else
{
std::cout << "Unrecognized command-line option: " << token << std::endl;
std::cout << "Launch the viewer with '--help' for a complete list of supported options." << std::endl;
continue;
}
if (nextToken.empty())
{
std::cout << "Expected another token following command-line option: " << token << std::endl;
}
else
{
i++;
}
}
// Append the standard library folder, giving it a lower precedence than user-supplied libraries.
libraryFolders.push_back("libraries");
ng::init();
{
ng::ref<Viewer> viewer = new Viewer(materialFilename,
meshFilename,
envRadianceFilename,
searchPath,
libraryFolders,
screenWidth,
screenHeight,
screenColor);
viewer->setMeshRotation(meshRotation);
viewer->setMeshScale(meshScale);
viewer->setTurntableEnabled(turntableEnabled);
viewer->setTurntableSteps(turntableSteps);
viewer->setCameraPosition(cameraPosition);
viewer->setCameraTarget(cameraTarget);
viewer->setCameraViewAngle(cameraViewAngle);
viewer->setCameraZoom(cameraZoom);
viewer->setSpecularEnvironmentMethod(specularEnvironmentMethod);
viewer->setEnvSampleCount(envSampleCount);
viewer->setEnvLightIntensity(envLightIntensity);
viewer->setLightRotation(lightRotation);
viewer->setShadowMapEnable(shadowMap);
viewer->setDrawEnvironment(drawEnvironment);
viewer->setDocumentModifiers(modifiers);
viewer->setBakeWidth(bakeWidth);
viewer->setBakeHeight(bakeHeight);
viewer->setBakeFilename(bakeFilename);
viewer->initialize();
if (!captureFilename.empty())
{
viewer->requestFrameCapture(captureFilename);
viewer->draw_all();
viewer->requestExit();
}
else if (!bakeFilename.empty())
{
viewer->bakeTextures();
viewer->requestExit();
}
else
{
viewer->set_visible(true);
}
ng::mainloop(refresh);
}
ng::shutdown();
return 0;
}