forked from bartvdbraak/blender
Code refactor: reduce special node types, use generic constant folding.
This commit is contained in:
parent
2cfadecf97
commit
dd8bfa0929
@ -32,7 +32,7 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
typedef map<void*, ShaderInput*> PtrInputMap;
|
||||
typedef map<void*, ShaderOutput*> PtrOutputMap;
|
||||
typedef map<std::string, ProxyNode*> ProxyMap;
|
||||
typedef map<std::string, ConvertNode*> ProxyMap;
|
||||
|
||||
/* Find */
|
||||
|
||||
@ -321,10 +321,6 @@ static ShaderNode *add_node(Scene *scene,
|
||||
BL::ShaderNodeMixRGB b_mix_node(b_node);
|
||||
MixNode *mix = new MixNode();
|
||||
mix->type = MixNode::type_enum[b_mix_node.blend_type()];
|
||||
/* Tag if it's Mix */
|
||||
if(b_mix_node.blend_type() == 0)
|
||||
mix->special_type = SHADER_SPECIAL_TYPE_MIX_RGB;
|
||||
|
||||
mix->use_clamp = b_mix_node.use_clamp();
|
||||
node = mix;
|
||||
}
|
||||
@ -1029,7 +1025,8 @@ static void add_nodes(Scene *scene,
|
||||
BL::Node::internal_links_iterator b_link;
|
||||
for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
|
||||
BL::NodeSocket to_socket(b_link->to_socket());
|
||||
ProxyNode *proxy = new ProxyNode(convert_socket_type(to_socket));
|
||||
ShaderSocketType to_socket_type = convert_socket_type(to_socket);
|
||||
ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true);
|
||||
|
||||
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
|
||||
output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
|
||||
@ -1051,7 +1048,8 @@ static void add_nodes(Scene *scene,
|
||||
* so that links have something to connect to and assert won't fail.
|
||||
*/
|
||||
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
||||
ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_input));
|
||||
ShaderSocketType input_type = convert_socket_type(*b_input);
|
||||
ConvertNode *proxy = new ConvertNode(input_type, input_type, true);
|
||||
graph->add(proxy);
|
||||
|
||||
/* register the proxy node for internal binding */
|
||||
@ -1062,7 +1060,8 @@ static void add_nodes(Scene *scene,
|
||||
set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
|
||||
}
|
||||
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
||||
ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_output));
|
||||
ShaderSocketType output_type = convert_socket_type(*b_output);
|
||||
ConvertNode *proxy = new ConvertNode(output_type, output_type, true);
|
||||
graph->add(proxy);
|
||||
|
||||
/* register the proxy node for internal binding */
|
||||
@ -1088,7 +1087,7 @@ static void add_nodes(Scene *scene,
|
||||
for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
|
||||
ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier());
|
||||
if(proxy_it != proxy_input_map.end()) {
|
||||
ProxyNode *proxy = proxy_it->second;
|
||||
ConvertNode *proxy = proxy_it->second;
|
||||
|
||||
output_map[b_output->ptr.data] = proxy->outputs[0];
|
||||
}
|
||||
@ -1102,7 +1101,7 @@ static void add_nodes(Scene *scene,
|
||||
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
|
||||
ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier());
|
||||
if(proxy_it != proxy_output_map.end()) {
|
||||
ProxyNode *proxy = proxy_it->second;
|
||||
ConvertNode *proxy = proxy_it->second;
|
||||
|
||||
input_map[b_input->ptr.data] = proxy->inputs[0];
|
||||
|
||||
|
@ -290,18 +290,21 @@ void ShaderGraph::disconnect(ShaderInput *to)
|
||||
from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
|
||||
}
|
||||
|
||||
void ShaderGraph::relink(vector<ShaderInput*> inputs, vector<ShaderInput*> outputs, ShaderOutput *output)
|
||||
void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
|
||||
{
|
||||
/* Remove nodes and re-link if output isn't NULL. */
|
||||
foreach(ShaderInput *sock, inputs) {
|
||||
/* Copy because disconnect modifies this list */
|
||||
vector<ShaderInput*> outputs = from->links;
|
||||
|
||||
/* Bypass node by moving all links from "from" to "to" */
|
||||
foreach(ShaderInput *sock, node->inputs) {
|
||||
if(sock->link)
|
||||
disconnect(sock);
|
||||
}
|
||||
|
||||
foreach(ShaderInput *sock, outputs) {
|
||||
disconnect(sock);
|
||||
if(output)
|
||||
connect(output, sock);
|
||||
if(to)
|
||||
connect(to, sock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,39 +414,29 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
|
||||
/* Graph simplification */
|
||||
/* ******************** */
|
||||
|
||||
/* Step 1: Remove unused nodes.
|
||||
* Remove nodes which are not needed in the graph, such as proxies,
|
||||
* mix nodes with a factor of 0 or 1, emission shaders without contribution...
|
||||
/* Step 1: Remove proxy nodes.
|
||||
* These only exists temporarily when exporting groups, and we must remove them
|
||||
* early so that node->attributes() and default links do not see them.
|
||||
*/
|
||||
void ShaderGraph::remove_unneeded_nodes()
|
||||
void ShaderGraph::remove_proxy_nodes()
|
||||
{
|
||||
vector<bool> removed(num_node_ids, false);
|
||||
bool any_node_removed = false;
|
||||
|
||||
ShaderNode *geom = NULL;
|
||||
|
||||
/* find and unlink proxy nodes */
|
||||
foreach(ShaderNode *node, nodes) {
|
||||
if(node->special_type == SHADER_SPECIAL_TYPE_PROXY) {
|
||||
ProxyNode *proxy = static_cast<ProxyNode*>(node);
|
||||
ConvertNode *proxy = static_cast<ConvertNode*>(node);
|
||||
ShaderInput *input = proxy->inputs[0];
|
||||
ShaderOutput *output = proxy->outputs[0];
|
||||
|
||||
/* temp. copy of the output links list.
|
||||
* output->links is modified when we disconnect!
|
||||
*/
|
||||
vector<ShaderInput*> links(output->links);
|
||||
ShaderOutput *from = input->link;
|
||||
|
||||
/* bypass the proxy node */
|
||||
if(from) {
|
||||
disconnect(input);
|
||||
foreach(ShaderInput *to, links) {
|
||||
disconnect(to);
|
||||
connect(from, to);
|
||||
}
|
||||
if(input->link) {
|
||||
relink(proxy, output, input->link);
|
||||
}
|
||||
else {
|
||||
/* Copy because disconnect modifies this list */
|
||||
vector<ShaderInput*> links(output->links);
|
||||
|
||||
foreach(ShaderInput *to, links) {
|
||||
/* remove any autoconvert nodes too if they lead to
|
||||
* sockets with an automatically set default value */
|
||||
@ -465,132 +458,16 @@ void ShaderGraph::remove_unneeded_nodes()
|
||||
}
|
||||
|
||||
disconnect(to);
|
||||
|
||||
|
||||
/* transfer the default input value to the target socket */
|
||||
to->set(input->value);
|
||||
to->set(input->value_string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
removed[proxy->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_BACKGROUND) {
|
||||
BackgroundNode *bg = static_cast<BackgroundNode*>(node);
|
||||
|
||||
if(bg->outputs[0]->links.size()) {
|
||||
/* Black color or zero strength, remove node */
|
||||
if((!bg->inputs[0]->link && bg->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
|
||||
(!bg->inputs[1]->link && bg->inputs[1]->value.x == 0.0f))
|
||||
{
|
||||
vector<ShaderInput*> inputs = bg->outputs[0]->links;
|
||||
|
||||
relink(bg->inputs, inputs, NULL);
|
||||
removed[bg->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_EMISSION) {
|
||||
EmissionNode *em = static_cast<EmissionNode*>(node);
|
||||
|
||||
if(em->outputs[0]->links.size()) {
|
||||
/* Black color or zero strength, remove node */
|
||||
if((!em->inputs[0]->link && em->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
|
||||
(!em->inputs[1]->link && em->inputs[1]->value.x == 0.0f))
|
||||
{
|
||||
vector<ShaderInput*> inputs = em->outputs[0]->links;
|
||||
|
||||
relink(em->inputs, inputs, NULL);
|
||||
removed[em->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
|
||||
BumpNode *bump = static_cast<BumpNode*>(node);
|
||||
|
||||
if(bump->outputs[0]->links.size()) {
|
||||
/* Height inputs is not connected. */
|
||||
/* TODO(sergey): Ignore bump with zero strength. */
|
||||
if(bump->inputs[0]->link == NULL) {
|
||||
vector<ShaderInput*> inputs = bump->outputs[0]->links;
|
||||
if(bump->inputs[4]->link == NULL) {
|
||||
if(geom == NULL) {
|
||||
geom = new GeometryNode();
|
||||
}
|
||||
relink(bump->inputs, inputs, geom->output("Normal"));
|
||||
}
|
||||
else {
|
||||
relink(bump->inputs, inputs, bump->input("Normal")->link);
|
||||
}
|
||||
removed[bump->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_MIX_CLOSURE) {
|
||||
MixClosureNode *mix = static_cast<MixClosureNode*>(node);
|
||||
|
||||
/* remove useless mix closures nodes */
|
||||
if(mix->outputs[0]->links.size() && mix->inputs[1]->link == mix->inputs[2]->link) {
|
||||
ShaderOutput *output = mix->inputs[1]->link;
|
||||
vector<ShaderInput*> inputs = mix->outputs[0]->links;
|
||||
|
||||
relink(mix->inputs, inputs, output);
|
||||
removed[mix->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
|
||||
/* remove unused mix closure input when factor is 0.0 or 1.0 */
|
||||
/* check for closure links and make sure factor link is disconnected */
|
||||
if(mix->outputs[0]->links.size() && mix->inputs[1]->link && mix->inputs[2]->link && !mix->inputs[0]->link) {
|
||||
/* factor 0.0 */
|
||||
if(mix->inputs[0]->value.x == 0.0f) {
|
||||
ShaderOutput *output = mix->inputs[1]->link;
|
||||
vector<ShaderInput*> inputs = mix->outputs[0]->links;
|
||||
|
||||
relink(mix->inputs, inputs, output);
|
||||
removed[mix->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
/* factor 1.0 */
|
||||
else if(mix->inputs[0]->value.x == 1.0f) {
|
||||
ShaderOutput *output = mix->inputs[2]->link;
|
||||
vector<ShaderInput*> inputs = mix->outputs[0]->links;
|
||||
|
||||
relink(mix->inputs, inputs, output);
|
||||
removed[mix->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_MIX_RGB) {
|
||||
MixNode *mix = static_cast<MixNode*>(node);
|
||||
|
||||
/* remove unused Mix RGB inputs when factor is 0.0 or 1.0 */
|
||||
/* check for color links and make sure factor link is disconnected */
|
||||
if(mix->outputs[0]->links.size() && mix->inputs[1]->link && mix->inputs[2]->link && !mix->inputs[0]->link) {
|
||||
/* factor 0.0 */
|
||||
if(mix->inputs[0]->value.x == 0.0f) {
|
||||
ShaderOutput *output = mix->inputs[1]->link;
|
||||
vector<ShaderInput*> inputs = mix->outputs[0]->links;
|
||||
|
||||
relink(mix->inputs, inputs, output);
|
||||
removed[mix->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
/* factor 1.0 */
|
||||
else if(mix->inputs[0]->value.x == 1.0f) {
|
||||
ShaderOutput *output = mix->inputs[2]->link;
|
||||
vector<ShaderInput*> inputs = mix->outputs[0]->links;
|
||||
|
||||
relink(mix->inputs, inputs, output);
|
||||
removed[mix->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove nodes */
|
||||
@ -606,10 +483,6 @@ void ShaderGraph::remove_unneeded_nodes()
|
||||
|
||||
nodes = newnodes;
|
||||
}
|
||||
|
||||
if(geom != NULL) {
|
||||
add(geom);
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 2: Constant folding.
|
||||
@ -634,6 +507,9 @@ void ShaderGraph::constant_fold()
|
||||
traverse_queue.pop();
|
||||
done.insert(node);
|
||||
foreach(ShaderOutput *output, node->outputs) {
|
||||
if (output->links.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
/* Schedule node which was depending on the value,
|
||||
* when possible. Do it before disconnect.
|
||||
*/
|
||||
@ -652,7 +528,7 @@ void ShaderGraph::constant_fold()
|
||||
}
|
||||
/* Optimize current node. */
|
||||
float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(node->constant_fold(output, &optimized_value)) {
|
||||
if(node->constant_fold(this, output, &optimized_value)) {
|
||||
/* Apply optimized value to connected sockets. */
|
||||
vector<ShaderInput*> links(output->links);
|
||||
foreach(ShaderInput *input, links) {
|
||||
@ -737,8 +613,7 @@ void ShaderGraph::deduplicate_nodes()
|
||||
}
|
||||
/* TODO(sergey): Consider making it an utility function. */
|
||||
for(int i = 0; i < node->outputs.size(); ++i) {
|
||||
vector<ShaderInput*> inputs = node->outputs[i]->links;
|
||||
relink(node->inputs, inputs, other_node->outputs[i]);
|
||||
relink(node, node->outputs[i], other_node->outputs[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -771,15 +646,9 @@ void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<b
|
||||
|
||||
void ShaderGraph::clean(Scene *scene)
|
||||
{
|
||||
/* Graph simplification:
|
||||
* 1: Remove unnecessary nodes
|
||||
* 2: Constant folding
|
||||
* 3: Simplification
|
||||
* 4: De-duplication
|
||||
*/
|
||||
/* Graph simplification */
|
||||
|
||||
/* 1: Remove proxy and unnecessary nodes. */
|
||||
remove_unneeded_nodes();
|
||||
/* 1: Remove proxy nodes was already done. */
|
||||
|
||||
/* 2: Constant folding. */
|
||||
constant_fold();
|
||||
@ -892,7 +761,7 @@ void ShaderGraph::refine_bump_nodes()
|
||||
* to "center" input. */
|
||||
|
||||
foreach(ShaderNode *node, nodes) {
|
||||
if(node->name == ustring("bump") && node->input("Height")->link) {
|
||||
if(node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
|
||||
ShaderInput *bump_input = node->input("Height");
|
||||
ShaderNodeSet nodes_bump;
|
||||
|
||||
|
@ -76,15 +76,11 @@ enum ShaderBump {
|
||||
enum ShaderNodeSpecialType {
|
||||
SHADER_SPECIAL_TYPE_NONE,
|
||||
SHADER_SPECIAL_TYPE_PROXY,
|
||||
SHADER_SPECIAL_TYPE_MIX_CLOSURE,
|
||||
SHADER_SPECIAL_TYPE_MIX_RGB, /* Only Mix subtype */
|
||||
SHADER_SPECIAL_TYPE_AUTOCONVERT,
|
||||
SHADER_SPECIAL_TYPE_GEOMETRY,
|
||||
SHADER_SPECIAL_TYPE_SCRIPT,
|
||||
SHADER_SPECIAL_TYPE_BACKGROUND,
|
||||
SHADER_SPECIAL_TYPE_IMAGE_SLOT,
|
||||
SHADER_SPECIAL_TYPE_CLOSURE,
|
||||
SHADER_SPECIAL_TYPE_EMISSION,
|
||||
SHADER_SPECIAL_TYPE_BUMP,
|
||||
};
|
||||
|
||||
@ -197,7 +193,7 @@ public:
|
||||
|
||||
/* ** Node optimization ** */
|
||||
/* Check whether the node can be replaced with single constant. */
|
||||
virtual bool constant_fold(ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
|
||||
virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
|
||||
|
||||
/* Simplify settings used by artists to the ones which are simpler to
|
||||
* evaluate in the kernel but keep the final result unchanged.
|
||||
@ -307,9 +303,9 @@ public:
|
||||
|
||||
void connect(ShaderOutput *from, ShaderInput *to);
|
||||
void disconnect(ShaderInput *to);
|
||||
void relink(vector<ShaderInput*> inputs, vector<ShaderInput*> outputs, ShaderOutput *output);
|
||||
void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
|
||||
|
||||
void remove_unneeded_nodes();
|
||||
void remove_proxy_nodes();
|
||||
void finalize(Scene *scene,
|
||||
bool do_bump = false,
|
||||
bool do_osl = false,
|
||||
|
@ -1210,7 +1210,7 @@ void MeshManager::device_update_displacement_images(Device *device,
|
||||
progress);
|
||||
return;
|
||||
}
|
||||
ImageSlotNode *image_node = static_cast<ImageSlotNode*>(node);
|
||||
ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode*>(node);
|
||||
int slot = image_node->slot;
|
||||
if(slot != -1) {
|
||||
bump_images.insert(slot);
|
||||
|
@ -1595,10 +1595,12 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
|
||||
from = from_;
|
||||
to = to_;
|
||||
|
||||
if(autoconvert)
|
||||
special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
|
||||
|
||||
assert(from != to);
|
||||
if(autoconvert) {
|
||||
if(from == to)
|
||||
special_type = SHADER_SPECIAL_TYPE_PROXY;
|
||||
else
|
||||
special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
|
||||
}
|
||||
|
||||
if(from == SHADER_SOCKET_FLOAT)
|
||||
add_input("Val", SHADER_SOCKET_FLOAT);
|
||||
@ -1614,6 +1616,8 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
|
||||
add_input("Normal", SHADER_SOCKET_NORMAL);
|
||||
else if(from == SHADER_SOCKET_STRING)
|
||||
add_input("String", SHADER_SOCKET_STRING);
|
||||
else if(from == SHADER_SOCKET_CLOSURE)
|
||||
add_input("Closure", SHADER_SOCKET_CLOSURE);
|
||||
else
|
||||
assert(0);
|
||||
|
||||
@ -1631,48 +1635,50 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
|
||||
add_output("Normal", SHADER_SOCKET_NORMAL);
|
||||
else if(to == SHADER_SOCKET_STRING)
|
||||
add_output("String", SHADER_SOCKET_STRING);
|
||||
else if(to == SHADER_SOCKET_CLOSURE)
|
||||
add_output("Closure", SHADER_SOCKET_CLOSURE);
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bool ConvertNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
bool ConvertNode::constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value)
|
||||
{
|
||||
ShaderInput *in = inputs[0];
|
||||
float3 value = in->value;
|
||||
|
||||
/* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
|
||||
|
||||
if(socket == outputs[0] && in->link == NULL) {
|
||||
if(in->link == NULL) {
|
||||
if(from == SHADER_SOCKET_FLOAT) {
|
||||
if(to == SHADER_SOCKET_INT)
|
||||
/* float to int */
|
||||
/* float to int */
|
||||
return false;
|
||||
else
|
||||
/* float to float3 */
|
||||
/* float to float3 */
|
||||
*optimized_value = make_float3(value.x, value.x, value.x);
|
||||
}
|
||||
else if(from == SHADER_SOCKET_INT) {
|
||||
if(to == SHADER_SOCKET_FLOAT)
|
||||
/* int to float */
|
||||
/* int to float */
|
||||
return false;
|
||||
else
|
||||
/* int to vector/point/normal */
|
||||
/* int to vector/point/normal */
|
||||
return false;
|
||||
}
|
||||
else if(to == SHADER_SOCKET_FLOAT) {
|
||||
if(from == SHADER_SOCKET_COLOR)
|
||||
/* color to float */
|
||||
/* color to float */
|
||||
optimized_value->x = linear_rgb_to_gray(value);
|
||||
else
|
||||
/* vector/point/normal to float */
|
||||
/* vector/point/normal to float */
|
||||
optimized_value->x = average(value);
|
||||
}
|
||||
else if(to == SHADER_SOCKET_INT) {
|
||||
if(from == SHADER_SOCKET_COLOR)
|
||||
/* color to int */
|
||||
/* color to int */
|
||||
return false;
|
||||
else
|
||||
/* vector/point/normal to int */
|
||||
/* vector/point/normal to int */
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
@ -1687,6 +1693,9 @@ bool ConvertNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
|
||||
void ConvertNode::compile(SVMCompiler& compiler)
|
||||
{
|
||||
/* constant folding should eliminate proxy nodes */
|
||||
assert(from != to);
|
||||
|
||||
ShaderInput *in = inputs[0];
|
||||
ShaderOutput *out = outputs[0];
|
||||
|
||||
@ -1753,6 +1762,9 @@ void ConvertNode::compile(SVMCompiler& compiler)
|
||||
|
||||
void ConvertNode::compile(OSLCompiler& compiler)
|
||||
{
|
||||
/* constant folding should eliminate proxy nodes */
|
||||
assert(from != to);
|
||||
|
||||
if(from == SHADER_SOCKET_FLOAT)
|
||||
compiler.add(this, "node_convert_from_float");
|
||||
else if(from == SHADER_SOCKET_INT)
|
||||
@ -1769,26 +1781,6 @@ void ConvertNode::compile(OSLCompiler& compiler)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* Proxy */
|
||||
|
||||
ProxyNode::ProxyNode(ShaderSocketType type_)
|
||||
: ShaderNode("proxy")
|
||||
{
|
||||
type = type_;
|
||||
special_type = SHADER_SPECIAL_TYPE_PROXY;
|
||||
|
||||
add_input("Input", type);
|
||||
add_output("Output", type);
|
||||
}
|
||||
|
||||
void ProxyNode::compile(SVMCompiler& /*compiler*/)
|
||||
{
|
||||
}
|
||||
|
||||
void ProxyNode::compile(OSLCompiler& /*compiler*/)
|
||||
{
|
||||
}
|
||||
|
||||
/* BSDF Closure */
|
||||
|
||||
BsdfNode::BsdfNode(bool scattering_)
|
||||
@ -2285,8 +2277,6 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
|
||||
EmissionNode::EmissionNode()
|
||||
: ShaderNode("emission")
|
||||
{
|
||||
special_type = SHADER_SPECIAL_TYPE_EMISSION;
|
||||
|
||||
add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
|
||||
add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
|
||||
add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
|
||||
@ -2315,13 +2305,20 @@ void EmissionNode::compile(OSLCompiler& compiler)
|
||||
compiler.add(this, "node_emission");
|
||||
}
|
||||
|
||||
bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
|
||||
{
|
||||
ShaderInput *color_in = input("Color");
|
||||
ShaderInput *strength_in = input("Strength");
|
||||
|
||||
return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
|
||||
(!strength_in->link && strength_in->value.x == 0.0f));
|
||||
}
|
||||
|
||||
/* Background Closure */
|
||||
|
||||
BackgroundNode::BackgroundNode()
|
||||
: ShaderNode("background")
|
||||
{
|
||||
special_type = SHADER_SPECIAL_TYPE_BACKGROUND;
|
||||
|
||||
add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
|
||||
add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
|
||||
add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
|
||||
@ -2350,6 +2347,15 @@ void BackgroundNode::compile(OSLCompiler& compiler)
|
||||
compiler.add(this, "node_background");
|
||||
}
|
||||
|
||||
bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
|
||||
{
|
||||
ShaderInput *color_in = input("Color");
|
||||
ShaderInput *strength_in = input("Strength");
|
||||
|
||||
return ((!color_in->link && color_in->value == make_float3(0.0f, 0.0f, 0.0f)) ||
|
||||
(!strength_in->link && strength_in->value.x == 0.0f));
|
||||
}
|
||||
|
||||
/* Holdout Closure */
|
||||
|
||||
HoldoutNode::HoldoutNode()
|
||||
@ -3249,7 +3255,7 @@ ValueNode::ValueNode()
|
||||
add_output("Value", SHADER_SOCKET_FLOAT);
|
||||
}
|
||||
|
||||
bool ValueNode::constant_fold(ShaderOutput * /*socket*/,
|
||||
bool ValueNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
|
||||
float3 *optimized_value)
|
||||
{
|
||||
*optimized_value = make_float3(value, value, value);
|
||||
@ -3280,7 +3286,7 @@ ColorNode::ColorNode()
|
||||
add_output("Color", SHADER_SOCKET_COLOR);
|
||||
}
|
||||
|
||||
bool ColorNode::constant_fold(ShaderOutput * /*socket*/,
|
||||
bool ColorNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/,
|
||||
float3 *optimized_value)
|
||||
{
|
||||
*optimized_value = value;
|
||||
@ -3330,8 +3336,6 @@ void AddClosureNode::compile(OSLCompiler& compiler)
|
||||
MixClosureNode::MixClosureNode()
|
||||
: ShaderNode("mix_closure")
|
||||
{
|
||||
special_type = SHADER_SPECIAL_TYPE_MIX_CLOSURE;
|
||||
|
||||
add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
|
||||
add_input("Closure1", SHADER_SOCKET_CLOSURE);
|
||||
add_input("Closure2", SHADER_SOCKET_CLOSURE);
|
||||
@ -3348,6 +3352,37 @@ void MixClosureNode::compile(OSLCompiler& compiler)
|
||||
compiler.add(this, "node_mix_closure");
|
||||
}
|
||||
|
||||
bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
|
||||
{
|
||||
ShaderInput *fac_in = input("Fac");
|
||||
ShaderInput *closure1_in = input("Closure1");
|
||||
ShaderInput *closure2_in = input("Closure2");
|
||||
ShaderOutput *closure_out = output("Closure");
|
||||
|
||||
/* remove useless mix closures nodes */
|
||||
if(closure1_in->link == closure2_in->link) {
|
||||
graph->relink(this, closure_out, closure1_in->link);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* remove unused mix closure input when factor is 0.0 or 1.0 */
|
||||
/* check for closure links and make sure factor link is disconnected */
|
||||
if(closure1_in->link && closure2_in->link && !fac_in->link) {
|
||||
/* factor 0.0 */
|
||||
if(fac_in->value.x == 0.0f) {
|
||||
graph->relink(this, closure_out, closure1_in->link);
|
||||
return true;
|
||||
}
|
||||
/* factor 1.0 */
|
||||
else if(fac_in->value.x == 1.0f) {
|
||||
graph->relink(this, closure_out, closure2_in->link);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Mix Closure */
|
||||
|
||||
MixClosureWeightNode::MixClosureWeightNode()
|
||||
@ -3480,6 +3515,41 @@ void MixNode::compile(OSLCompiler& compiler)
|
||||
compiler.add(this, "node_mix");
|
||||
}
|
||||
|
||||
bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput * /*socket*/, float3 * /*optimized_value*/)
|
||||
{
|
||||
if(type != ustring("Mix")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderInput *fac_in = input("Fac");
|
||||
ShaderInput *color1_in = input("Color1");
|
||||
ShaderInput *color2_in = input("Color2");
|
||||
ShaderOutput *color_out = output("Color");
|
||||
|
||||
/* remove useless mix colors nodes */
|
||||
if(color1_in->link == color2_in->link) {
|
||||
graph->relink(this, color_out, color1_in->link);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* remove unused mix color input when factor is 0.0 or 1.0 */
|
||||
/* check for color links and make sure factor link is disconnected */
|
||||
if(color1_in->link && color2_in->link && !fac_in->link) {
|
||||
/* factor 0.0 */
|
||||
if(fac_in->value.x == 0.0f) {
|
||||
graph->relink(this, color_out, color1_in->link);
|
||||
return true;
|
||||
}
|
||||
/* factor 1.0 */
|
||||
else if(fac_in->value.x == 1.0f) {
|
||||
graph->relink(this, color_out, color2_in->link);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Combine RGB */
|
||||
CombineRGBNode::CombineRGBNode()
|
||||
: ShaderNode("combine_rgb")
|
||||
@ -3588,7 +3658,7 @@ GammaNode::GammaNode()
|
||||
add_output("Color", SHADER_SOCKET_COLOR);
|
||||
}
|
||||
|
||||
bool GammaNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
bool GammaNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
|
||||
{
|
||||
ShaderInput *color_in = input("Color");
|
||||
ShaderInput *gamma_in = input("Gamma");
|
||||
@ -3597,7 +3667,6 @@ bool GammaNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
if(color_in->link == NULL && gamma_in->link == NULL) {
|
||||
*optimized_value = svm_math_gamma_color(color_in->value,
|
||||
gamma_in->value.x);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -4058,14 +4127,13 @@ BlackbodyNode::BlackbodyNode()
|
||||
add_output("Color", SHADER_SOCKET_COLOR);
|
||||
}
|
||||
|
||||
bool BlackbodyNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
|
||||
{
|
||||
ShaderInput *temperature_in = input("Temperature");
|
||||
|
||||
if(socket == output("Color")) {
|
||||
if(temperature_in->link == NULL) {
|
||||
*optimized_value = svm_math_blackbody_color(temperature_in->value.x);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -4165,7 +4233,7 @@ static ShaderEnum math_type_init()
|
||||
|
||||
ShaderEnum MathNode::type_enum = math_type_init();
|
||||
|
||||
bool MathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
bool MathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
|
||||
{
|
||||
ShaderInput *value1_in = input("Value1");
|
||||
ShaderInput *value2_in = input("Value2");
|
||||
@ -4242,7 +4310,7 @@ static ShaderEnum vector_math_type_init()
|
||||
|
||||
ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
|
||||
|
||||
bool VectorMathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
|
||||
bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, ShaderOutput *socket, float3 *optimized_value)
|
||||
{
|
||||
ShaderInput *vector1_in = input("Vector1");
|
||||
ShaderInput *vector2_in = input("Vector2");
|
||||
@ -4409,6 +4477,28 @@ void BumpNode::compile(OSLCompiler& compiler)
|
||||
compiler.add(this, "node_bump");
|
||||
}
|
||||
|
||||
bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value)
|
||||
{
|
||||
ShaderInput *height_in = input("Height");
|
||||
ShaderInput *normal_in = input("Normal");
|
||||
|
||||
if(height_in->link == NULL) {
|
||||
if(normal_in->link == NULL) {
|
||||
GeometryNode *geom = new GeometryNode();
|
||||
graph->add(geom);
|
||||
graph->relink(this, outputs[0], geom->output("Normal"));
|
||||
}
|
||||
else {
|
||||
graph->relink(this, outputs[0], normal_in->link);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO(sergey): Ignore bump with zero strength. */
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* RGBCurvesNode */
|
||||
|
||||
RGBCurvesNode::RGBCurvesNode()
|
||||
|
@ -70,15 +70,6 @@ public:
|
||||
|
||||
/* Nodes */
|
||||
|
||||
/* Any node which uses image manager's slot should be a subclass of this one. */
|
||||
class ImageSlotNode : public ShaderNode {
|
||||
public:
|
||||
ImageSlotNode(const char *name_) : ShaderNode(name_) {
|
||||
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
|
||||
}
|
||||
int slot;
|
||||
};
|
||||
|
||||
class TextureNode : public ShaderNode {
|
||||
public:
|
||||
TextureNode(const char *name_) : ShaderNode(name_) {}
|
||||
@ -90,15 +81,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ImageSlotTextureNode : public ImageSlotNode {
|
||||
/* Any node which uses image manager's slot should be a subclass of this one. */
|
||||
class ImageSlotTextureNode : public TextureNode {
|
||||
public:
|
||||
ImageSlotTextureNode(const char *name_) : ImageSlotNode(name_) {}
|
||||
TextureMapping tex_mapping;
|
||||
|
||||
virtual bool equals(const ShaderNode *other) {
|
||||
return ShaderNode::equals(other) &&
|
||||
tex_mapping.equals(((const ImageSlotTextureNode*)other)->tex_mapping);
|
||||
ImageSlotTextureNode(const char *name_) : TextureNode(name_) {
|
||||
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
|
||||
}
|
||||
int slot;
|
||||
};
|
||||
|
||||
class ImageTextureNode : public ImageSlotTextureNode {
|
||||
@ -372,7 +361,7 @@ public:
|
||||
ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false);
|
||||
SHADER_NODE_BASE_CLASS(ConvertNode)
|
||||
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
ShaderSocketType from, to;
|
||||
|
||||
@ -385,23 +374,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ProxyNode : public ShaderNode {
|
||||
public:
|
||||
ProxyNode(ShaderSocketType type);
|
||||
SHADER_NODE_BASE_CLASS(ProxyNode)
|
||||
|
||||
ShaderSocketType type;
|
||||
|
||||
virtual bool equals(const ShaderNode * /*other*/)
|
||||
{
|
||||
/* Proxy nodes are created for node groups and can't be duplicated
|
||||
* actually. So in order to make code a bit more robust in obscure cases
|
||||
* lets explicitly forbid de-duplication of proxy nodes for now.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class BsdfNode : public ShaderNode {
|
||||
public:
|
||||
BsdfNode(bool scattering = false);
|
||||
@ -505,6 +477,7 @@ public:
|
||||
class EmissionNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(EmissionNode)
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
bool has_surface_emission() { return true; }
|
||||
};
|
||||
@ -512,6 +485,7 @@ public:
|
||||
class BackgroundNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(BackgroundNode)
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
};
|
||||
|
||||
class HoldoutNode : public ShaderNode {
|
||||
@ -650,7 +624,7 @@ class ValueNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(ValueNode)
|
||||
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
float value;
|
||||
|
||||
@ -665,7 +639,7 @@ class ColorNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(ColorNode)
|
||||
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
float3 value;
|
||||
|
||||
@ -684,6 +658,7 @@ public:
|
||||
class MixClosureNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(MixClosureNode)
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
};
|
||||
|
||||
class MixClosureWeightNode : public ShaderNode {
|
||||
@ -701,6 +676,7 @@ public:
|
||||
class MixNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(MixNode)
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
|
||||
|
||||
@ -743,7 +719,7 @@ class GammaNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(GammaNode)
|
||||
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
|
||||
};
|
||||
@ -834,7 +810,7 @@ public:
|
||||
class BlackbodyNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(BlackbodyNode)
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
|
||||
};
|
||||
@ -843,7 +819,7 @@ class MathNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(MathNode)
|
||||
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
bool use_clamp;
|
||||
|
||||
@ -878,7 +854,7 @@ class VectorMathNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(VectorMathNode)
|
||||
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
|
||||
bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
|
||||
ustring type;
|
||||
static ShaderEnum type_enum;
|
||||
@ -916,6 +892,7 @@ public:
|
||||
class BumpNode : public ShaderNode {
|
||||
public:
|
||||
SHADER_NODE_CLASS(BumpNode)
|
||||
bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, float3 *optimized_value);
|
||||
bool has_spatial_varying() { return true; }
|
||||
virtual int get_feature() {
|
||||
return NODE_FEATURE_BUMP;
|
||||
|
@ -483,11 +483,11 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
|
||||
if(strcmp(input->name, "Normal") == 0)
|
||||
return true;
|
||||
}
|
||||
else if(node->name == ustring("bump")) {
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
|
||||
if(strcmp(input->name, "Height") == 0)
|
||||
return true;
|
||||
}
|
||||
else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump"))
|
||||
else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -175,7 +175,7 @@ void Shader::set_graph(ShaderGraph *graph_)
|
||||
* are needed, since the node attribute callbacks check if their sockets
|
||||
* are connected but proxy nodes should not count */
|
||||
if(graph_)
|
||||
graph_->remove_unneeded_nodes();
|
||||
graph_->remove_proxy_nodes();
|
||||
|
||||
/* assign graph */
|
||||
delete graph;
|
||||
|
@ -365,7 +365,7 @@ uint SVMCompiler::attribute(AttributeStandard std)
|
||||
bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
|
||||
{
|
||||
/* nasty exception .. */
|
||||
if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump"))
|
||||
if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user