Skip to content

Commit

Permalink
PR notes addressed:
Browse files Browse the repository at this point in the history
- HD_CYCLES_UP_AXIS is an environment variable, renderParam now has a GetUpAxis() function call so code can check against (only dome light orientation is using this for now)
- Addressed PR notes eg. check string length instead
- The code will only rebuild the graph if any combination of IES/texture/temperature is set or changed

Misc features/fixes/changes made:
- Added IES light support, probably needs a little testing but it looked "correct", normalize/scale isn't supported yet
- Dome light with temperature now working also
- Background/dome transform node will now be located from the graph and tweaked and not cached from a pointer
  • Loading branch information
boberfly committed Jan 26, 2021
1 parent ecc9f33 commit 2e6db72
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 57 deletions.
4 changes: 4 additions & 0 deletions plugin/hdCycles/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ TF_DEFINE_ENV_SETTING(HD_CYCLES_ENABLE_PROGRESS, false,
TF_DEFINE_ENV_SETTING(HD_CYCLES_USE_TILED_RENDERING, false,
"Use Tiled Rendering (Experimental)");

TF_DEFINE_ENV_SETTING(HD_CYCLES_UP_AXIS, "Z",
"Set custom up axis (Z or Y currently supported)");

// HdCycles Constructor
HdCyclesConfig::HdCyclesConfig()
Expand All @@ -101,6 +103,8 @@ HdCyclesConfig::HdCyclesConfig()
enable_logging = TfGetEnvSetting(HD_CYCLES_ENABLE_LOGGING);
enable_progress = TfGetEnvSetting(HD_CYCLES_ENABLE_PROGRESS);

up_axis = TfGetEnvSetting(HD_CYCLES_UP_AXIS);

enable_motion_blur = HdCyclesEnvValue<bool>("HD_CYCLES_ENABLE_MOTION_BLUR",
false);
motion_steps = HdCyclesEnvValue<int>("HD_CYCLES_MOTION_STEPS", 3);
Expand Down
6 changes: 6 additions & 0 deletions plugin/hdCycles/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ class HdCyclesConfig {
*/
bool enable_progress;

/**
* @brief Set custom up axis (Z or Y currently supported)
*
*/
std::string up_axis;

/**
* @brief If enabled, HdCycles will populate object's motion and enable motion blur
*
Expand Down
215 changes: 162 additions & 53 deletions plugin/hdCycles/light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ HdCyclesLight::HdCyclesLight(SdfPath const& id, TfToken const& lightType,
: HdLight(id)
, m_cyclesLight(nullptr)
, m_hdLightType(lightType)
, m_backgroundTransform(nullptr)
, m_shaderGraphBits(ShaderGraphBits::Default)
, m_renderDelegate(a_renderDelegate)
{
// Added to prevent fallback lights
Expand Down Expand Up @@ -144,8 +144,11 @@ HdCyclesLight::_SetTransform(const ccl::Transform& a_transform)
m_cyclesLight->tfm = a_transform;

if (m_cyclesLight->type == ccl::LIGHT_BACKGROUND) {
if (m_backgroundTransform)
m_backgroundTransform->ob_tfm = a_transform;
ccl::TextureCoordinateNode *backgroundTransform =
(ccl::TextureCoordinateNode*)_FindShaderNode(
m_cyclesLight->shader->graph, ccl::TextureCoordinateNode::node_type);
if (backgroundTransform)
backgroundTransform->ob_tfm = a_transform;
} else {
// Set the area light transforms
m_cyclesLight->axisu = ccl::transform_get_column(&a_transform, 0);
Expand Down Expand Up @@ -182,6 +185,17 @@ HdCyclesLight::_GetDefaultShaderGraph(bool isBackground)
return graph;
}

ccl::ShaderNode*
HdCyclesLight::_FindShaderNode(const ccl::ShaderGraph *graph, const ccl::NodeType *type)
{
for( ccl::ShaderNode *node : graph->nodes ) {
if (node->type == type) {
return node;
}
}
return nullptr;
}

void
HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,
HdDirtyBits* dirtyBits)
Expand All @@ -196,8 +210,51 @@ HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,

if (*dirtyBits & HdLight::DirtyParams) {
light_updated = true;
ccl::ShaderGraph *graph = _GetDefaultShaderGraph(m_cyclesLight->type == ccl::LIGHT_BACKGROUND ? true : false);
ccl::ShaderNode *outNode = (ccl::ShaderNode*)graph->output()->input("Surface")->link->parent;
ccl::ShaderGraph *oldGraph = m_cyclesLight->shader->graph;

// Check if we need to rebuild the graph
ShaderGraphBits shaderGraphBits = ShaderGraphBits::Default;

VtValue enableTemperature = sceneDelegate->GetLightParamValue(
id, HdLightTokens->enableColorTemperature);
if (enableTemperature.IsHolding<bool>()) {
shaderGraphBits = enableTemperature.UncheckedGet<bool>() ?
(ShaderGraphBits)(shaderGraphBits|ShaderGraphBits::Temperature) : (ShaderGraphBits)(shaderGraphBits);
}

VtValue iesFile
= sceneDelegate->GetLightParamValue(id,
HdLightTokens->shapingIesFile);
if (iesFile.IsHolding<SdfAssetPath>()) {
shaderGraphBits = (ShaderGraphBits)(shaderGraphBits|ShaderGraphBits::IES);
}

VtValue textureFile
= sceneDelegate->GetLightParamValue(id,
HdLightTokens->textureFile);
if (textureFile.IsHolding<SdfAssetPath>()) {
SdfAssetPath ap = textureFile.UncheckedGet<SdfAssetPath>();
std::string filepath = ap.GetResolvedPath();

if (filepath.length() > 0) {
shaderGraphBits = (ShaderGraphBits)(shaderGraphBits|ShaderGraphBits::Texture);
}
}

ccl::ShaderGraph *graph = nullptr;
ccl::ShaderNode *outNode = nullptr;

// Ideally we would just check if it is different, however some nodes
// simplify & fold internally so we have to re-create the graph, so if
// there is any nodes used, re-create...
if (shaderGraphBits ||
shaderGraphBits != m_shaderGraphBits) {
graph = _GetDefaultShaderGraph(m_cyclesLight->type == ccl::LIGHT_BACKGROUND ? true : false);
outNode = (ccl::ShaderNode*)graph->output()->input("Surface")->link->parent;
m_shaderGraphBits = shaderGraphBits;
} else {
outNode = (ccl::ShaderNode*)oldGraph->output()->input("Surface")->link->parent;
}

// -- Common params

Expand Down Expand Up @@ -254,30 +311,61 @@ HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,
// }

// Enable Temperature
VtValue enableTemperature = sceneDelegate->GetLightParamValue(
id, HdLightTokens->enableColorTemperature);
bool useTemperature = false;
if (enableTemperature.IsHolding<bool>()) {
useTemperature = enableTemperature.UncheckedGet<bool>();
}

ccl::BlackbodyNode *blackbodyNode = nullptr;
if (useTemperature) {
if (shaderGraphBits & ShaderGraphBits::Temperature) {
// Get Temperature
VtValue temperature = sceneDelegate->GetLightParamValue(
id, HdLightTokens->colorTemperature);
if (temperature.IsHolding<float>()) {
// Add temperature node
blackbodyNode = new ccl::BlackbodyNode();
if (graph) {
blackbodyNode = new ccl::BlackbodyNode();
graph->add(blackbodyNode);

graph->connect(
blackbodyNode->output("Color"),
outNode->input("Color"));
}
else {
blackbodyNode = (ccl::BlackbodyNode*)_FindShaderNode(
oldGraph, ccl::BlackbodyNode::node_type);
}
assert(blackbodyNode != nullptr);
blackbodyNode->temperature = temperature.UncheckedGet<float>();
}
}

graph->add(blackbodyNode);
// Enable IES profile. Angle scale and normalize are not supported currently.
// TODO: Perhaps usdCycles could store embedded IES into a string? ->ies can
// be used instead of ->filename, Blender uses it to store IES profiles in
// .blend files...
if (shaderGraphBits & ShaderGraphBits::IES) {
SdfAssetPath ap = iesFile.UncheckedGet<SdfAssetPath>();
std::string iesfilepath = ap.GetResolvedPath();

ccl::IESLightNode *iesNode = nullptr;
if (graph) {
ccl::TextureCoordinateNode *iesTransform =
new ccl::TextureCoordinateNode();
iesTransform->use_transform = true;
iesTransform->ob_tfm = m_cyclesLight->tfm;
graph->add(iesTransform);

iesNode = new ccl::IESLightNode();
graph->add(iesNode);

graph->connect(
blackbodyNode->output("Color"),
outNode->input("Color"));
iesTransform->output("Normal"),
iesNode->input("Vector"));

blackbodyNode->temperature = temperature.UncheckedGet<float>();
graph->connect(
iesNode->output("Fac"),
outNode->input("Strength"));
} else {
iesNode = (ccl::IESLightNode*)_FindShaderNode(
oldGraph, ccl::IESLightNode::node_type);
}
assert(iesNode != nullptr);
iesNode->filename = iesfilepath;
}

if (m_hdLightType == HdPrimTypeTokens->rectLight) {
Expand All @@ -296,17 +384,13 @@ HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,
if (height.IsHolding<float>())
m_cyclesLight->sizev = height.UncheckedGet<float>();

VtValue textureFile
= sceneDelegate->GetLightParamValue(id,
HdLightTokens->textureFile);

if (textureFile.IsHolding<SdfAssetPath>()) {
if (shaderGraphBits & ShaderGraphBits::Texture) {
SdfAssetPath ap = textureFile.UncheckedGet<SdfAssetPath>();
std::string filepath = ap.GetResolvedPath();

// TODO: Prevent this string comparison
if (filepath != "") {
ccl::ImageTextureNode *textureNode = new ccl::ImageTextureNode();
ccl::ImageTextureNode *textureNode = nullptr;
if (graph) {
textureNode = new ccl::ImageTextureNode();
graph->add(textureNode);
ccl::GeometryNode *geometryNode = new ccl::GeometryNode();
graph->add(geometryNode);
Expand All @@ -315,7 +399,7 @@ HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,
geometryNode->output("Parametric"),
textureNode->input("Vector"));

if (useTemperature && blackbodyNode) {
if ((shaderGraphBits & ShaderGraphBits::Temperature) && blackbodyNode) {
ccl::VectorMathNode *vecMathNode = new ccl::VectorMathNode();
vecMathNode->type = ccl::NODE_VECTOR_MATH_MULTIPLY;
graph->add(vecMathNode);
Expand All @@ -337,8 +421,12 @@ HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,
textureNode->output("Color"),
outNode->input("Color"));
}
textureNode->filename = filepath;
} else {
textureNode = (ccl::ImageTextureNode*)_FindShaderNode(
oldGraph, ccl::ImageTextureNode::node_type);
}
assert(textureNode != nullptr);
textureNode->filename = filepath;
}
}

Expand Down Expand Up @@ -412,53 +500,74 @@ HdCyclesLight::Sync(HdSceneDelegate* sceneDelegate, HdRenderParam* renderParam,
backroundNode->color = m_cyclesLight->strength;

backroundNode->strength = m_finalIntensity;
VtValue textureFile
= sceneDelegate->GetLightParamValue(id,
HdLightTokens->textureFile);

if (textureFile.IsHolding<SdfAssetPath>()) {
if (shaderGraphBits & ShaderGraphBits::Texture) {
SdfAssetPath ap = textureFile.UncheckedGet<SdfAssetPath>();
std::string filepath = ap.GetResolvedPath();

// TODO: Prevent this string comparison
if (filepath != "") {
ccl::EnvironmentTextureNode *backgroundTexture = nullptr;
if (graph) {
// Add environment texture nodes
ccl::TextureCoordinateNode *backgroundTransform =
new ccl::TextureCoordinateNode();
backgroundTransform->use_transform = true;
backgroundTransform->ob_tfm = m_cyclesLight->tfm;

m_backgroundTransform = backgroundTransform;

graph->add(backgroundTransform);

ccl::EnvironmentTextureNode *backgroundTexture =
backgroundTexture =
new ccl::EnvironmentTextureNode();
// Change co-ordinate mapping on environment texture to match other Hydra delegates
backgroundTexture->tex_mapping.y_mapping =
ccl::TextureMapping::Z;
backgroundTexture->tex_mapping.z_mapping =
ccl::TextureMapping::Y;
backgroundTexture->tex_mapping.scale =
ccl::make_float3(-1.0f, 1.0f, 1.0f);
backgroundTexture->tex_mapping.rotation =
ccl::make_float3(0.0f, 0.0f, M_PI * -0.5f);
if (param->GetUpAxis() == HdCyclesRenderParam::UpAxis::Y) {
// Change co-ordinate mapping on environment texture to match other Hydra delegates
backgroundTexture->tex_mapping.y_mapping =
ccl::TextureMapping::Z;
backgroundTexture->tex_mapping.z_mapping =
ccl::TextureMapping::Y;
backgroundTexture->tex_mapping.scale =
ccl::make_float3(-1.0f, 1.0f, 1.0f);
backgroundTexture->tex_mapping.rotation =
ccl::make_float3(0.0f, 0.0f, M_PI * -0.5f);
}

graph->add(backgroundTexture);

graph->connect(
backgroundTransform->output("Object"),
backgroundTexture->input("Vector"));
graph->connect(
backgroundTexture->output("Color"),
backroundNode->input("Color"));

backgroundTexture->filename = filepath;
if ((shaderGraphBits & ShaderGraphBits::Temperature) && blackbodyNode) {
ccl::VectorMathNode *vecMathNode = new ccl::VectorMathNode();
vecMathNode->type = ccl::NODE_VECTOR_MATH_MULTIPLY;
graph->add(vecMathNode);

graph->connect(
backgroundTexture->output("Color"),
vecMathNode->input("Vector1"));

graph->connect(
blackbodyNode->output("Color"),
vecMathNode->input("Vector2"));

graph->disconnect(outNode->input("Color"));
graph->connect(
vecMathNode->output("Vector"),
outNode->input("Color"));
} else {
graph->connect(
backgroundTexture->output("Color"),
outNode->input("Color"));
}
} else {
backgroundTexture = (ccl::EnvironmentTextureNode*)_FindShaderNode(
oldGraph, ccl::EnvironmentTextureNode::node_type);
}
assert(backgroundTexture != nullptr);
backgroundTexture->filename = filepath;
}
}

m_cyclesLight->shader->set_graph(graph);
if (graph) {
m_cyclesLight->shader->set_graph(graph);
}
}

#ifdef USE_USD_CYCLES_SCHEMA
Expand Down
28 changes: 24 additions & 4 deletions plugin/hdCycles/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ class HdCyclesLight final : public HdLight {
void Finalize(HdRenderParam* renderParam) override;

private:
// Tracking for Cycles light shader graphs, saves on potentially
// expensive new/delete re-creation of graphs for interactive sessions.
enum ShaderGraphBits : uint8_t {
Default = 0,
Temperature = 1 << 0,
IES = 1 << 1,
Texture = 1 << 2,
All = (Temperature
|IES
|Texture)
};

/**
* @brief Create the cycles light representation
*
Expand All @@ -126,14 +138,22 @@ class HdCyclesLight final : public HdLight {
* @brief Get default shader graph for lights
*
* @param isBackground Is the shader graph for the background shader
* @return Newly allocated default shader graph
*/
ccl::ShaderGraph *_GetDefaultShaderGraph(const bool isBackground = false);

/**
* @brief Find first shader node based on type.
*
* @param graph ShaderGraph to search in
* @param type The type of ShaderNode to search for
* @return The first ShaderNode found based on type in graph
*/
ccl::ShaderGraph *_GetDefaultShaderGraph(bool isBackground = false);
ccl::ShaderNode *_FindShaderNode(const ccl::ShaderGraph *graph, const ccl::NodeType *type);

const TfToken m_hdLightType;
ccl::Light* m_cyclesLight;

// Background light-specific
ccl::TextureCoordinateNode* m_backgroundTransform;
ShaderGraphBits m_shaderGraphBits;

bool m_normalize;

Expand Down
Loading

0 comments on commit 2e6db72

Please sign in to comment.