// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #ifndef MATERIALXVIEW_VIEWER_H #define MATERIALXVIEW_VIEWER_H #include #include #include #include #include #include #include #include #include namespace mx = MaterialX; namespace ng = nanogui; class DocumentModifiers { public: mx::StringMap remapElements; mx::StringSet skipElements; std::string filePrefixTerminator; }; class Viewer : public ng::Screen { friend class RenderPipeline; friend class GLRenderPipeline; friend class MetalRenderPipeline; public: Viewer(const std::string& materialFilename, const std::string& meshFilename, const std::string& envRadianceFilename, const mx::FileSearchPath& searchPath, const mx::FilePathVec& libraryFolders, int screenWidth, int screenHeight, const mx::Color3& screenColor); ~Viewer() { } // Initialize the viewer for rendering. void initialize(); // Set the rotation of the current mesh as Euler angles. void setMeshRotation(const mx::Vector3& rotation) { _meshRotation = rotation; } // Set the scale of the current mesh. void setMeshScale(float scale) { _meshScale = scale; } // Set whether turntable rendering is enabled. void setTurntableEnabled(bool val) { _turntableEnabled = val; } // Set the total number of steps for one 360 degree rotation. void setTurntableSteps(int steps) { _turntableSteps = steps; } // Set the world-space position of the camera. void setCameraPosition(const mx::Vector3& position) { _cameraPosition = position; } // Set the world-space target of the camera. void setCameraTarget(const mx::Vector3& target) { _cameraTarget = target; } // Set the view angle of the camera. void setCameraViewAngle(float angle) { _cameraViewAngle = angle; } // Set the zoom scale of the camera. void setCameraZoom(float zoom) { _cameraZoom = zoom; } // Set the method for specular environment rendering. void setSpecularEnvironmentMethod(mx::HwSpecularEnvironmentMethod method) { _genContext.getOptions().hwSpecularEnvironmentMethod = method; } // Set the number of environment samples. void setEnvSampleCount(int count) { _lightHandler->setEnvSampleCount(count); } // Set the environment light intensity. void setEnvLightIntensity(float intensity) { _lightHandler->setEnvLightIntensity(intensity); } // Set the rotation of the lighting environment about the Y axis. void setLightRotation(float rotation) { _lightRotation = rotation; } // Enable or disable shadow maps. void setShadowMapEnable(bool enable) { _genContext.getOptions().hwShadowMap = enable; } // Enable or disable drawing environment as the background. void setDrawEnvironment(bool enable) { _drawEnvironment = enable; } // Set the modifiers to be applied to loaded documents. void setDocumentModifiers(const DocumentModifiers& modifiers) { _modifiers = modifiers; } // Set the target width for texture baking. void setBakeWidth(unsigned int bakeWidth) { _bakeWidth = bakeWidth; } // Set the target height for texture baking. void setBakeHeight(unsigned int bakeHeight) { _bakeHeight = bakeHeight; } // Set the output document filename for texture baking. void setBakeFilename(const mx::FilePath& bakeFilename) { _bakeFilename = bakeFilename; } // Return true if all inputs should be shown in the property editor. bool getShowAllInputs() const { return _showAllInputs; } // Return the underlying NanoGUI window. ng::Window* getWindow() const { return _window; } // Return the active image handler. mx::ImageHandlerPtr getImageHandler() const { return _imageHandler; } // Return the selected material. mx::MaterialPtr getSelectedMaterial() const { if (_selectedMaterial < _materials.size()) { return _materials[_selectedMaterial]; } return nullptr; } // Return the selected mesh partition. mx::MeshPartitionPtr getSelectedGeometry() const { if (_selectedGeom < _geometryList.size()) { return _geometryList[_selectedGeom]; } return nullptr; } // Request a capture of the current frame, writing it to the given filename. void requestFrameCapture(const mx::FilePath& filename) { _captureRequested = true; _captureFilename = filename; } // Request that the viewer be closed after the next frame is rendered. void requestExit() { _exitRequested = true; } // Bake textures to disk using the current render pipeline. void bakeTextures() { _renderPipeline->bakeTextures(); } private: void draw_contents() override; bool keyboard_event(int key, int scancode, int action, int modifiers) override; bool scroll_event(const ng::Vector2i& p, const ng::Vector2f& rel) override; bool mouse_motion_event(const ng::Vector2i& p, const ng::Vector2i& rel, int button, int modifiers) override; bool mouse_button_event(const ng::Vector2i& p, int button, bool down, int modifiers) override; void initContext(mx::GenContext& context); void loadMesh(const mx::FilePath& filename); void loadEnvironmentLight(); void applyDirectLights(mx::DocumentPtr doc); void loadDocument(const mx::FilePath& filename, mx::DocumentPtr libraries); void reloadShaders(); void loadStandardLibraries(); void saveShaderSource(mx::GenContext& context); void loadShaderSource(); void saveDotFiles(); // Compute the resolution for texture baking. mx::UnsignedIntPair computeBakingResolution(mx::ConstDocumentPtr doc); // Translate the current material to the target shading model. mx::DocumentPtr translateMaterial(); // Assign the given material to the given geometry, or remove any // existing assignment if the given material is nullptr. void assignMaterial(mx::MeshPartitionPtr geometry, mx::MaterialPtr material); // Mark the given material as currently selected in the viewer. void setSelectedMaterial(mx::MaterialPtr material) { for (size_t i = 0; i < _materials.size(); i++) { if (material == _materials[i]) { _selectedMaterial = i; break; } } } // Generate a base output filepath for data derived from the current material. mx::FilePath getBaseOutputPath(); // Return an element predicate for documents written from the viewer. mx::ElementPredicate getElementPredicate(); void initCamera(); void updateCameras(); void updateGeometrySelections(); void updateMaterialSelections(); void updateMaterialSelectionUI(); void updateDisplayedProperties(); void createLoadMeshInterface(Widget* parent, const std::string& label); void createLoadMaterialsInterface(Widget* parent, const std::string& label); void createLoadEnvironmentInterface(Widget* parent, const std::string& label); void createSaveMaterialsInterface(Widget* parent, const std::string& label); void createPropertyEditorInterface(Widget* parent, const std::string& label); void createAdvancedSettings(Widget* parent); // Return the ambient occlusion image, if any, associated with the given material. mx::ImagePtr getAmbientOcclusionImage(mx::MaterialPtr material); // Split the given radiance map into indirect and direct components, // returning a new indirect map and directional light document. void splitDirectLight(mx::ImagePtr envRadianceMap, mx::ImagePtr& indirectMap, mx::DocumentPtr& dirLightDoc); mx::MaterialPtr getEnvironmentMaterial(); mx::MaterialPtr getWireframeMaterial(); mx::ImagePtr getShadowMap(); void invalidateShadowMap(); mx::ImagePtr renderWedge(); void renderTurnable(); void renderScreenSpaceQuad(mx::MaterialPtr material); // Update the directional albedo table. void updateAlbedoTable(); // Toggle turntable void toggleTurntable(bool enable); // Set shader interface type void setShaderInterfaceType(mx::ShaderInterfaceType interfaceType); private: ng::Window* _window; RenderPipelinePtr _renderPipeline; mx::FilePath _materialFilename; mx::FileSearchPath _materialSearchPath; mx::FilePath _meshFilename; mx::FilePath _envRadianceFilename; mx::FileSearchPath _searchPath; mx::FilePathVec _libraryFolders; mx::Vector3 _meshTranslation; mx::Vector3 _meshRotation; float _meshScale; bool _turntableEnabled; int _turntableSteps; int _turntableStep; mx::ScopedTimer _turntableTimer; mx::Vector3 _cameraPosition; mx::Vector3 _cameraTarget; mx::Vector3 _cameraUp; float _cameraViewAngle; float _cameraNearDist; float _cameraFarDist; float _cameraZoom; bool _userCameraEnabled; mx::Vector3 _userTranslation; mx::Vector3 _userTranslationStart; bool _userTranslationActive; mx::Vector2 _userTranslationPixel; // Document management mx::DocumentPtr _stdLib; DocumentModifiers _modifiers; mx::StringSet _xincludeFiles; // Lighting information mx::FilePath _lightRigFilename; mx::DocumentPtr _lightRigDoc; float _lightRotation; // Light processing options bool _normalizeEnvironment; bool _splitDirectLight; bool _generateReferenceIrradiance; bool _saveGeneratedLights; // Shadow mapping mx::MaterialPtr _shadowMaterial; mx::MaterialPtr _shadowBlurMaterial; mx::ImagePtr _shadowMap; unsigned int _shadowSoftness; // Ambient occlusion float _ambientOcclusionGain; // Geometry selections std::vector _geometryList; size_t _selectedGeom; ng::Label* _geomLabel; ng::ComboBox* _geometrySelectionBox; // Material selections std::vector _materials; mx::MaterialPtr _wireMaterial; size_t _selectedMaterial; ng::Label* _materialLabel; ng::ComboBox* _materialSelectionBox; PropertyEditor _propertyEditor; // Material assignments std::map _materialAssignments; // Cameras mx::CameraPtr _identityCamera; mx::CameraPtr _viewCamera; mx::CameraPtr _envCamera; mx::CameraPtr _shadowCamera; // Resource handlers mx::GeometryHandlerPtr _geometryHandler; mx::ImageHandlerPtr _imageHandler; mx::LightHandlerPtr _lightHandler; // Supporting materials and geometry. mx::GeometryHandlerPtr _envGeometryHandler; mx::MaterialPtr _envMaterial; mx::MeshPtr _quadMesh; // Shader generator contexts mx::GenContext _genContext; #ifndef MATERIALXVIEW_METAL_BACKEND mx::GenContext _genContextEssl; #endif #if MATERIALX_BUILD_GEN_OSL mx::GenContext _genContextOsl; #endif #if MATERIALX_BUILD_GEN_MDL mx::GenContext _genContextMdl; #endif // Unit registry mx::UnitConverterRegistryPtr _unitRegistry; // Viewing options bool _drawEnvironment; bool _outlineSelection; // Render options bool _renderTransparency; bool _renderDoubleSided; // Framebuffer Color Texture void* _colorTexture; // Scene options mx::StringVec _distanceUnitOptions; mx::LinearUnitConverterPtr _distanceUnitConverter; // Mesh loading options bool _splitByUdims; // Material loading options bool _mergeMaterials; bool _showAllInputs; bool _flattenSubgraphs; // Shader translation std::string _targetShader; // Frame capture bool _captureRequested; mx::FilePath _captureFilename; bool _exitRequested; // Wedge rendering bool _wedgeRequested; mx::FilePath _wedgeFilename; std::string _wedgePropertyName; float _wedgePropertyMin; float _wedgePropertyMax; unsigned int _wedgeImageCount; // Texture baking bool _bakeHdr; bool _bakeAverage; bool _bakeOptimize; bool _bakeRequested; unsigned int _bakeWidth; unsigned int _bakeHeight; bool _bakeDocumentPerMaterial; mx::FilePath _bakeFilename; }; extern const mx::Vector3 DEFAULT_CAMERA_POSITION; extern const float DEFAULT_CAMERA_VIEW_ANGLE; extern const float DEFAULT_CAMERA_ZOOM; #endif // MATERIALXVIEW_VIEWER_H