Skip to content

Commit

Permalink
Merge pull request #3968 from Autodesk/feldstj/EMSUSD-1746/nodegraph_…
Browse files Browse the repository at this point in the history
…input_defaultgeomprop_values

Adds support for defaultgeomprop values on nodegraph inputs.
  • Loading branch information
seando-adsk authored Oct 23, 2024
2 parents 885ad8b + a974805 commit a44df39
Show file tree
Hide file tree
Showing 3 changed files with 540 additions and 0 deletions.
211 changes: 211 additions & 0 deletions lib/mayaUsd/render/MaterialXGenOgsXml/GlslFragmentGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "GlslFragmentGenerator.h"

#include "Nodes/MayaShaderGraph.h"
#include "Nodes/SurfaceNodeMaya.h"
#include "Nodes/TexcoordNodeMaya.h"
#if MX_COMBINED_VERSION < 13809
Expand Down Expand Up @@ -253,12 +254,222 @@ ShaderPtr GlslFragmentGenerator::createShader(
ElementPtr element,
GenContext& context) const
{
#if MX_COMBINED_VERSION >= 13810
// Create the root shader graph
ShaderGraphPtr graph = MayaShaderGraph::create(nullptr, name, element, context);
ShaderPtr shader = std::make_shared<Shader>(name, graph);

// Check if there are inputs with default geomprops assigned. In order to bind the
// corresponding data to these inputs we insert geomprop nodes in the graph.
bool geomNodeAdded = false;
for (ShaderGraphInputSocket* socket : graph->getInputSockets()) {
if (!socket->getGeomProp().empty()) {
ConstDocumentPtr doc = element->getDocument();
GeomPropDefPtr geomprop = doc->getGeomPropDef(socket->getGeomProp());
if (geomprop) {
// A default geomprop was assigned to this graph input.
// For all internal connections to this input, break the connection
// and assign a geomprop node that generates this data.
// Note: If a geomprop node exists already it is reused,
// so only a single node per geometry type is created.
ShaderInputVec connections = socket->getConnections();
for (auto connection : connections) {
connection->breakConnection();
graph->addDefaultGeomNode(connection, *geomprop, context);
geomNodeAdded = true;
}
}
}
}
// If nodes were added we need to re-sort the nodes in topological order.
if (geomNodeAdded) {
graph->topologicalSort();
}

// Create vertex stage.
ShaderStagePtr vs = createStage(Stage::VERTEX, *shader);
vs->createInputBlock(HW::VERTEX_INPUTS, "i_vs");

// Each Stage must have three types of uniform blocks:
// Private, Public and Sampler blocks
// Public uniforms are inputs that should be published in a user interface for user interaction,
// while private uniforms are internal variables needed by the system which should not be
// exposed in UI. So when creating these uniforms for a shader node, if the variable is
// user-facing it should go into the public block, and otherwise the private block. All texture
// based objects should be added to Sampler block

vs->createUniformBlock(HW::PRIVATE_UNIFORMS, "u_prv");
vs->createUniformBlock(HW::PUBLIC_UNIFORMS, "u_pub");

// Create required variables for vertex stage
VariableBlock& vsInputs = vs->getInputBlock(HW::VERTEX_INPUTS);
vsInputs.add(Type::VECTOR3, HW::T_IN_POSITION);
VariableBlock& vsPrivateUniforms = vs->getUniformBlock(HW::PRIVATE_UNIFORMS);
vsPrivateUniforms.add(Type::MATRIX44, HW::T_WORLD_MATRIX);
vsPrivateUniforms.add(Type::MATRIX44, HW::T_VIEW_PROJECTION_MATRIX);

// Create pixel stage.
ShaderStagePtr ps = createStage(Stage::PIXEL, *shader);
VariableBlockPtr psOutputs = ps->createOutputBlock(HW::PIXEL_OUTPUTS, "o_ps");

// Create required Uniform blocks and any additonal blocks if needed.
VariableBlockPtr psPrivateUniforms = ps->createUniformBlock(HW::PRIVATE_UNIFORMS, "u_prv");
VariableBlockPtr psPublicUniforms = ps->createUniformBlock(HW::PUBLIC_UNIFORMS, "u_pub");
VariableBlockPtr lightData = ps->createUniformBlock(HW::LIGHT_DATA, HW::T_LIGHT_DATA_INSTANCE);
lightData->add(Type::INTEGER, "type");

// Add a block for data from vertex to pixel shader.
addStageConnectorBlock(HW::VERTEX_DATA, HW::T_VERTEX_DATA_INSTANCE, *vs, *ps);

// Add uniforms for transparent rendering.
if (context.getOptions().hwTransparency) {
psPrivateUniforms->add(Type::FLOAT, HW::T_ALPHA_THRESHOLD, Value::createValue(0.001f));
}

// Add uniforms for shadow map rendering.
if (context.getOptions().hwShadowMap) {
psPrivateUniforms->add(Type::FILENAME, HW::T_SHADOW_MAP);
psPrivateUniforms->add(
Type::MATRIX44, HW::T_SHADOW_MATRIX, Value::createValue(Matrix44::IDENTITY));
}

// Add inputs and uniforms for ambient occlusion.
if (context.getOptions().hwAmbientOcclusion) {
addStageInput(HW::VERTEX_INPUTS, Type::VECTOR2, HW::T_IN_TEXCOORD + "_0", *vs);
addStageConnector(HW::VERTEX_DATA, Type::VECTOR2, HW::T_TEXCOORD + "_0", *vs, *ps);
psPrivateUniforms->add(Type::FILENAME, HW::T_AMB_OCC_MAP);
psPrivateUniforms->add(Type::FLOAT, HW::T_AMB_OCC_GAIN, Value::createValue(1.0f));
}

// Add uniforms for environment lighting.
bool lighting = graph->hasClassification(
ShaderNode::Classification::SHADER | ShaderNode::Classification::SURFACE)
|| graph->hasClassification(ShaderNode::Classification::BSDF);
if (lighting && context.getOptions().hwSpecularEnvironmentMethod != SPECULAR_ENVIRONMENT_NONE) {
const Matrix44 yRotationPI = Matrix44::createScale(Vector3(-1, 1, -1));
psPrivateUniforms->add(Type::MATRIX44, HW::T_ENV_MATRIX, Value::createValue(yRotationPI));
psPrivateUniforms->add(Type::FILENAME, HW::T_ENV_RADIANCE);
psPrivateUniforms->add(Type::FLOAT, HW::T_ENV_LIGHT_INTENSITY, Value::createValue(1.0f));
psPrivateUniforms->add(Type::INTEGER, HW::T_ENV_RADIANCE_MIPS, Value::createValue<int>(1));
psPrivateUniforms->add(
Type::INTEGER, HW::T_ENV_RADIANCE_SAMPLES, Value::createValue<int>(16));
psPrivateUniforms->add(Type::FILENAME, HW::T_ENV_IRRADIANCE);
psPrivateUniforms->add(Type::BOOLEAN, HW::T_REFRACTION_TWO_SIDED);
}

// Add uniforms for the directional albedo table.
if (context.getOptions().hwDirectionalAlbedoMethod == DIRECTIONAL_ALBEDO_TABLE
|| context.getOptions().hwWriteAlbedoTable) {
psPrivateUniforms->add(Type::FILENAME, HW::T_ALBEDO_TABLE);
psPrivateUniforms->add(Type::INTEGER, HW::T_ALBEDO_TABLE_SIZE, Value::createValue<int>(64));
}

// Add uniforms for environment prefiltering.
if (context.getOptions().hwWriteEnvPrefilter) {
psPrivateUniforms->add(Type::FILENAME, HW::T_ENV_RADIANCE);
psPrivateUniforms->add(Type::FLOAT, HW::T_ENV_LIGHT_INTENSITY, Value::createValue(1.0f));
psPrivateUniforms->add(Type::INTEGER, HW::T_ENV_PREFILTER_MIP, Value::createValue<int>(1));
const Matrix44 yRotationPI = Matrix44::createScale(Vector3(-1, 1, -1));
psPrivateUniforms->add(Type::MATRIX44, HW::T_ENV_MATRIX, Value::createValue(yRotationPI));
psPrivateUniforms->add(Type::INTEGER, HW::T_ENV_RADIANCE_MIPS, Value::createValue<int>(1));
}

// Create uniforms for the published graph interface
for (ShaderGraphInputSocket* inputSocket : graph->getInputSockets()) {
// Only for inputs that are connected/used internally,
// and are editable by users.
if (!inputSocket->getConnections().empty() && graph->isEditable(*inputSocket)) {
psPublicUniforms->add(inputSocket->getSelf());
}
}

// Add the pixel stage output. This needs to be a color4 for rendering,
// so copy name and variable from the graph output but set type to color4.
// TODO: Improve this to support multiple outputs and other data types.
ShaderGraphOutputSocket* outputSocket = graph->getOutputSocket();
ShaderPort* output = psOutputs->add(Type::COLOR4, outputSocket->getName());
output->setVariable(outputSocket->getVariable());
output->setPath(outputSocket->getPath());

// Create shader variables for all nodes that need this.
createVariables(graph, context, *shader);

HwLightShadersPtr lightShaders
= context.getUserData<HwLightShaders>(HW::USER_DATA_LIGHT_SHADERS);

// For surface shaders we need light shaders
if (lightShaders
&& graph->hasClassification(
ShaderNode::Classification::SHADER | ShaderNode::Classification::SURFACE)) {
// Create shader variables for all bound light shaders
for (const auto& it : lightShaders->get()) {
ShaderNode* node = it.second.get();
node->getImplementation().createVariables(*node, context, *shader);
}
}

//
// For image textures we need to convert filenames into uniforms (texture samplers).
// Any unconnected filename input on file texture nodes needs to have a corresponding
// uniform.
//

// Start with top level graphs.
vector<ShaderGraph*> graphStack = { graph.get() };
if (lightShaders) {
for (const auto& it : lightShaders->get()) {
ShaderNode* node = it.second.get();
ShaderGraph* lightGraph = node->getImplementation().getGraph();
if (lightGraph) {
graphStack.push_back(lightGraph);
}
}
}

while (!graphStack.empty()) {
ShaderGraph* g = graphStack.back();
graphStack.pop_back();

for (ShaderNode* node : g->getNodes()) {
if (node->hasClassification(ShaderNode::Classification::FILETEXTURE)) {
for (ShaderInput* input : node->getInputs()) {
if (!input->getConnection() && *input->getType() == *Type::FILENAME) {
// Create the uniform using the filename type to make this uniform into a
// texture sampler.
ShaderPort* filename = psPublicUniforms->add(
Type::FILENAME, input->getVariable(), input->getValue());
filename->setPath(input->getPath());

// Assing the uniform name to the input value
// so we can reference it during code generation.
input->setValue(Value::createValue(input->getVariable()));
}
}
}
// Push subgraphs on the stack to process these as well.
ShaderGraph* subgraph = node->getImplementation().getGraph();
if (subgraph) {
graphStack.push_back(subgraph);
}
}
}

if (context.getOptions().hwTransparency) {
// Flag the shader as being transparent.
shader->setAttribute(HW::ATTR_TRANSPARENT);
}
#else
ShaderPtr shader = GlslShaderGenerator::createShader(name, element, context);
ShaderGraph& graph = shader->getGraph();
#endif
ShaderStage& pixelStage = shader->getStage(Stage::PIXEL);

// Add uniforms for environment lighting.
#if MX_COMBINED_VERSION >= 13810
if (requiresLighting(*graph) && OgsXmlGenerator::useLightAPI() < 2) {
#else
if (requiresLighting(graph) && OgsXmlGenerator::useLightAPI() < 2) {
#endif
VariableBlock& psPrivateUniforms = pixelStage.getUniformBlock(HW::PUBLIC_UNIFORMS);
psPrivateUniforms.add(
Type::COLOR3, LIGHT_LOOP_RESULT, Value::createValue(Color3(0.0f, 0.0f, 0.0f)));
Expand Down
Loading

0 comments on commit a44df39

Please sign in to comment.