Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCIO base support #840

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions CMakeLists.txt
Expand Up @@ -43,6 +43,7 @@ option(MATERIALX_BUILD_GEN_MDL "Build the MDL shader generator back-end." ON)
option(MATERIALX_BUILD_RENDER "Build the MaterialX Render modules." ON)
option(MATERIALX_BUILD_OIIO "Build OpenImageIO support for MaterialXRender." OFF)
option(MATERIALX_BUILD_TESTS "Build unit tests." ON)
option(MATERIALX_BUILD_OCIO "Build OpenColorIO support for shader generators." OFF)

option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF)
option(MATERIALX_PYTHON_LTO "Enable link-time optimizations for MaterialX Python." ON)
Expand Down Expand Up @@ -125,6 +126,7 @@ mark_as_advanced(MATERIALX_INSTALL_LIB_PATH)
mark_as_advanced(MATERIALX_INSTALL_STDLIB_PATH)
mark_as_advanced(MATERIALX_BUILD_JS)
mark_as_advanced(MATERIALX_EMSDK_PATH)
mark_as_advanced(MATERIALX_BUILD_OCIO)
if (MATERIALX_BUILD_GEN_MDL)
mark_as_advanced(MATERIALX_MDLC_EXECUTABLE)
mark_as_advanced(MATERIALX_MDL_RENDER_EXECUTABLE)
Expand All @@ -140,6 +142,9 @@ add_definitions(-DMATERIALX_OSL_INCLUDE_PATH=\"${MATERIALX_OSL_INCLUDE_PATH}\")
if(MATERIALX_BUILD_OIIO)
add_definitions(-DMATERIALX_BUILD_OIIO)
endif()
if(MATERIALX_BUILD_OCIO)
add_definitions(-DMATERIALX_BUILD_OCIO)
endif()
if(MATERIALX_TEST_RENDER)
add_definitions(-DMATERIALX_TEST_RENDER)
endif()
Expand Down Expand Up @@ -227,6 +232,9 @@ endif()

# Add rendering and viewer subdirectories
if(MATERIALX_BUILD_RENDER)
if(MATERIALX_BUILD_OIIO)
add_definitions(-DMATERIALX_BUILD_OIIO)
endif()
add_subdirectory(source/MaterialXRender)
add_subdirectory(source/MaterialXRenderOsl)
add_subdirectory(source/MaterialXRenderHw)
Expand Down
@@ -0,0 +1,58 @@
<?xml version="1.0"?>
<!-- OCIO example tests
- Test of color4
- Test of color3 where no conversion from color3->color4->color3 is required
- Test reuse single update node with a given color transform
- Test us of multiple upstrea nodes using the same color transform code but different inputs / outputs
-->
<materialx version="1.38" cms="ocio" cmsconfig="config.ocio" colorspace="lin_rec709">
<!-- non-LUT color4 input test -->
<nodegraph name="color4_acescg_nodegraph">
<!-- The transform will be generated once. The node will rout to multiple downstream inputs -->
<constant name="color4_acescg" type="color4">
<input name="value" type="color4" value="0.5, 0.0, 0.0, 1.0" colorspace="acescg" />
</constant>
<standard_surface name="color4_acescg_shader" type="surfaceshader">
<input name="base_color" type="color3" value="1, 1, 1" nodename="color4_acescg" channels="rgb" />
</standard_surface>
<output name="color4_acescg_output" type="surfaceshader" nodename="color4_acescg_shader" />
<standard_surface name="color4_acescg_shader2" type="surfaceshader">
<input name="base_color" type="color3" value="1, 1, 1" nodename="color4_acescg" channels="rgb" />
</standard_surface>
<output name="color4_acescg_output" type="surfaceshader" nodename="color4_acescg_shader" />
<output name="color4_acescg_output2" type="surfaceshader" nodename="color4_acescg_shader2" />
</nodegraph>

<!-- non-LUT color3 -->
<nodegraph name="color3_acescg_nodegraph">
<constant name="color3_acescg" type="color3">
<input name="value" type="color3" value="0.5, 0.0, 0.0" colorspace="acescg" />
</constant>
<standard_surface name="color3_acescg_shader" type="surfaceshader">
<input name="base_color" type="color3" value="1, 1, 1" nodename="color3_acescg" />
</standard_surface>
<output name="color3_acescg_output" type="surfaceshader" nodename="color3_acescg_shader" />

<!-- This node will reuse the same transform code as color3_acescg -->
<constant name="color3_acescg2" type="color3">
<input name="value" type="color3" value="0.0, 0.5, 0.0" colorspace="acescg" />
</constant>
<add name="add_acescg" type="color3">
<input name="in1" type="color3" nodename="color3_acescg"/>
<input name="in2" type="color3" nodename="color3_acescg2" />
</add>
<standard_surface name="color3_acescg_shader_add" type="surfaceshader">
<input name="base_color" type="color3" value="1, 1, 1" nodename="add_acescg" />
</standard_surface>
<output name="color3_acescg_output_add" type="surfaceshader" nodename="color3_acescg_shader_add" />
</nodegraph>

<!-- Basic image input to test appending transform after image read -->
<nodegraph name="image3_acescg_nodegraph">
<image name="image3_acescg" type="color3">
<input name="file" type="filename" value="resources/Images/grid.png" colorspace="acescg" />
</image>
<output name="out_image3_acescg" type="color3" nodename="image3_acescg" />
</nodegraph>

</materialx>
2 changes: 1 addition & 1 deletion source/MaterialXGenGlsl/Nodes/TexCoordNodeGlsl.cpp
Expand Up @@ -50,7 +50,7 @@ void TexCoordNodeGlsl::emitFunctionCall(const ShaderNode& node, GenContext& cont
VariableBlock& vertexData = stage.getInputBlock(HW::VERTEX_DATA);
const string prefix = shadergen.getVertexDataPrefix(vertexData);
ShaderPort* texcoord = vertexData[variable];
shadergen.emitLineBegin(stage);
shadergen.emitLineBegin(stage);
shadergen.emitOutput(node.getOutput(), true, false, context, stage);
shadergen.emitString(" = " + prefix + texcoord->getVariable(), stage);
shadergen.emitLineEnd(stage);
Expand Down
31 changes: 25 additions & 6 deletions source/MaterialXGenShader/CMakeLists.txt
@@ -1,13 +1,38 @@
file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*")

if(NOT MATERIALX_BUILD_OCIO)
list(REMOVE_ITEM materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/OCIOColorManagementSystem.cpp")
endif()

assign_source_group("Source Files" ${materialx_source})
assign_source_group("Header Files" ${materialx_headers})

add_library(MaterialXGenShader ${materialx_source} ${materialx_headers})

add_definitions(-DMATERIALX_GENSHADER_EXPORTS)

target_link_libraries(
MaterialXGenShader
MaterialXCore
MaterialXFormat
${CMAKE_DL_LIBS})

if(MATERIALX_BUILD_OCIO)
set(MATERIALX_OCIO_DIR ${MATERIALX_OCIO_DIR})
message(STATUS "OCIO root path: ${MATERIALX_OCIO_DIR}")

message(STATUS "OCIO include path: ${MATERIALX_OCIO_DIR}/include")
include_directories("${MATERIALX_OCIO_DIR}/include")

message(STATUS "OCIO library path: ${MATERIALX_OCIO_DIR}/lib")
file(GLOB OCIO_LIBRARIES "${MATERIALX_OCIO_DIR}/lib/*${CMAKE_STATIC_LIBRARY_SUFFIX}")
message(STATUS "OCIO library files: ${OCIO_LIBRARIES}")
target_link_libraries(MaterialXGenShader "${OCIO_LIBRARIES}")
# Expose to other libraries
set(MATERIALX_OCIO_LIBRARIES ${OCIO_LIBRARIES} PARENT_SCOPE)
endif()

set_target_properties(
MaterialXGenShader PROPERTIES
OUTPUT_NAME MaterialXGenShader${MATERIALX_LIBNAME_SUFFIX}
Expand All @@ -16,12 +41,6 @@ set_target_properties(
VERSION "${MATERIALX_LIBRARY_VERSION}"
SOVERSION "${MATERIALX_MAJOR_VERSION}")

target_link_libraries(
MaterialXGenShader
MaterialXCore
MaterialXFormat
${CMAKE_DL_LIBS})

target_include_directories(MaterialXGenShader
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../>
Expand Down
135 changes: 132 additions & 3 deletions source/MaterialXGenShader/ColorManagementSystem.cpp
Expand Up @@ -11,6 +11,34 @@

MATERIALX_NAMESPACE_BEGIN

// Color management uniform block name
std::string ColorManagementSystem::COLOR_MANAGEMENT_UNIFORMS = "ColorManagmentUniforms";

//
// Color management uniform methods
//
ColorSpaceConstant::ColorSpaceConstant(const string name, const ValuePtr value)
: ColorSpaceUniform(name),
_value(value)
{
}

ColorSpaceConstantPtr ColorSpaceConstant::create(const std::string& name, const ValuePtr value)
{
return std::make_shared<ColorSpaceConstant>(name, value);
}

ColorSpaceTexture::ColorSpaceTexture(const string name, const FloatVec& inputData)
: ColorSpaceUniform(name),
data(inputData.begin(), inputData.end())
{
}

ColorSpaceTexturePtr ColorSpaceTexture::create(const std::string& name, const FloatVec& data)
{
return std::make_shared<ColorSpaceTexture>(name, data);
}

//
// ColorSpaceTransform methods
//
Expand Down Expand Up @@ -70,11 +98,11 @@ ShaderNodePtr ColorManagementSystem::createNode(const ShaderGraph* parent, const

// Create ports on the node.
ShaderInput* input = shaderNode->addInput("in", transform.type);
if (transform.type == Type::COLOR3)
if (transform.type->getName() == Type::COLOR3->getName())
{
input->setValue(Value::createValue(Color3(0.0f, 0.0f, 0.0f)));
}
else if (transform.type == Type::COLOR4)
else if (transform.type->getName() == Type::COLOR4->getName())
{
input->setValue(Value::createValue(Color4(0.0f, 0.0f, 0.0f, 1.0)));
}
Expand All @@ -87,4 +115,105 @@ ShaderNodePtr ColorManagementSystem::createNode(const ShaderGraph* parent, const
return shaderNode;
}

} // namespace MaterialX

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pulled out from ShaderGraph code into CM system where these utilities should belong.
They allow for insert on CM transforms on inputs and outputs. If need be a conversion from color3 to color4
can be performed as well as OCIO requires color4.

void ColorManagementSystem::getPortConnections(ShaderGraph* graph, ShaderNode* colorTransformNode,
const TypeDesc* targetType, GenContext& context,
ShaderInput*& inputToConnect, ShaderOutput*& outputToConnect)
{
const std::string colorTransformNodeName = colorTransformNode->getName();
ShaderOutput* colorTransformNodeOutput = colorTransformNode->getOutput(0);
ShaderInput* colorTransformNodeInput = colorTransformNode->getInput(0);

outputToConnect = colorTransformNodeOutput;
inputToConnect = colorTransformNodeInput;
if ((colorTransformNodeInput->getType() == Type::COLOR4 && targetType == Type::COLOR3) ||
(colorTransformNodeInput->getType() == Type::COLOR3 && targetType == Type::COLOR4))
{
const string convertToColor4String = "c3_to_" + colorTransformNodeName;
ShaderNode* convertToColor4Ptr = graph->getNode(convertToColor4String);
if (!convertToColor4Ptr)
{
NodeDefPtr toColor4NodeDef = _document->getNodeDef("ND_convert_color3_color4");
ShaderNodePtr convertToColor4 = ShaderNode::create(graph, convertToColor4String, *toColor4NodeDef, context);
graph->addNode(convertToColor4);
convertToColor4Ptr = convertToColor4.get();
}
const string convertToColor3String = colorTransformNodeName + "_to_c3";
ShaderNode* convertToColor3Ptr = graph->getNode(convertToColor3String);
if (!convertToColor3Ptr)
{
NodeDefPtr toColor3NodeDef = _document->getNodeDef("ND_convert_color4_color3");
ShaderNodePtr convertToColor3 = ShaderNode::create(graph, convertToColor3String, *toColor3NodeDef, context);
graph->addNode(convertToColor3);
convertToColor3Ptr = convertToColor3.get();
}

if (targetType == Type::COLOR3)
{
colorTransformNodeInput->makeConnection(convertToColor4Ptr->getOutput(0));
convertToColor3Ptr->getInput(0)->makeConnection(colorTransformNodeOutput);
inputToConnect = convertToColor4Ptr->getInput(0);
outputToConnect = convertToColor3Ptr->getOutput(0);
}
else
{
colorTransformNodeInput->makeConnection(convertToColor3Ptr->getOutput(0));
convertToColor4Ptr->getInput(0)->makeConnection(colorTransformNodeOutput);
inputToConnect = convertToColor3Ptr->getInput(0);
outputToConnect = convertToColor4Ptr->getOutput(0);
}
}
}

void ColorManagementSystem::connectNodeToShaderInput(ShaderGraph* graph, ShaderNode* colorTransformNode, ShaderInput* shaderInput, GenContext& context)
{
if (!graph || !colorTransformNode|| !shaderInput)
{
throw ExceptionShaderGenError("Cannot connect color management node to shader input");
}

ShaderInput* inputToConnect = nullptr;
ShaderOutput* outputToConnect = nullptr;

getPortConnections(graph, colorTransformNode, shaderInput->getType(), context, inputToConnect, outputToConnect);
if (inputToConnect && outputToConnect)
{
inputToConnect->setValue(shaderInput->getValue());

if (shaderInput->isBindInput())
{
ShaderOutput* oldConnection = shaderInput->getConnection();
inputToConnect->makeConnection(oldConnection);
}

shaderInput->makeConnection(outputToConnect);
}
}


void ColorManagementSystem::connectNodeToShaderOutput(ShaderGraph* graph, ShaderNode* colorTransformNode, ShaderOutput* shaderOutput, GenContext& context)
{
if (!graph || !colorTransformNode || !shaderOutput)
{
throw ExceptionShaderGenError("Cannot connect color management node to shader output");
}

ShaderInput* inputToConnect = nullptr;
ShaderOutput* outputToConnect = nullptr;

getPortConnections(graph, colorTransformNode, shaderOutput->getType(), context, inputToConnect, outputToConnect);
if (inputToConnect && outputToConnect)
{
ShaderInputVec downStreamInputs = shaderOutput->getConnections();
for (ShaderInput* downStreamInput : downStreamInputs)
{
downStreamInput->breakConnection();
downStreamInput->makeConnection(outputToConnect);
}

// Connect the node to the upstream output.
inputToConnect->makeConnection(shaderOutput);
}
}

MATERIALX_NAMESPACE_END