2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/shader_nodes.h"
|
|
|
|
|
#include "scene/colorspace.h"
|
|
|
|
|
#include "scene/constant_fold.h"
|
|
|
|
|
#include "scene/film.h"
|
|
|
|
|
#include "scene/image.h"
|
|
|
|
|
#include "scene/image_sky.h"
|
|
|
|
|
#include "scene/integrator.h"
|
|
|
|
|
#include "scene/light.h"
|
|
|
|
|
#include "scene/mesh.h"
|
|
|
|
|
#include "scene/osl.h"
|
|
|
|
|
#include "scene/scene.h"
|
|
|
|
|
#include "scene/svm.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-07-09 17:19:52 +02:00
|
|
|
#include "sky_model.h"
|
|
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "util/color.h"
|
|
|
|
|
#include "util/foreach.h"
|
|
|
|
|
#include "util/log.h"
|
|
|
|
|
#include "util/transform.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-11-18 14:25:30 +01:00
|
|
|
#include "kernel/tables.h"
|
|
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "kernel/svm/color_util.h"
|
|
|
|
|
#include "kernel/svm/mapping_util.h"
|
|
|
|
|
#include "kernel/svm/math_util.h"
|
|
|
|
|
#include "kernel/svm/ramp_util.h"
|
2020-03-06 14:15:21 +01:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
2011-10-12 22:42:13 +00:00
|
|
|
/* Texture Mapping */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
#define TEXTURE_MAPPING_DEFINE(TextureNode) \
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_POINT(tex_mapping.translation, "Translation", zero_float3()); \
|
|
|
|
|
SOCKET_VECTOR(tex_mapping.rotation, "Rotation", zero_float3()); \
|
|
|
|
|
SOCKET_VECTOR(tex_mapping.scale, "Scale", one_float3()); \
|
2016-05-07 19:48:28 +02:00
|
|
|
\
|
|
|
|
|
SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
|
|
|
|
|
SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \
|
|
|
|
|
SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \
|
|
|
|
|
\
|
|
|
|
|
static NodeEnum mapping_axis_enum; \
|
|
|
|
|
mapping_axis_enum.insert("none", TextureMapping::NONE); \
|
2016-06-11 21:56:47 +02:00
|
|
|
mapping_axis_enum.insert("x", TextureMapping::X); \
|
|
|
|
|
mapping_axis_enum.insert("y", TextureMapping::Y); \
|
|
|
|
|
mapping_axis_enum.insert("z", TextureMapping::Z); \
|
|
|
|
|
SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
|
|
|
|
|
SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
|
|
|
|
|
SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
|
2016-05-07 19:48:28 +02:00
|
|
|
\
|
|
|
|
|
static NodeEnum mapping_type_enum; \
|
|
|
|
|
mapping_type_enum.insert("point", TextureMapping::POINT); \
|
|
|
|
|
mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
|
|
|
|
|
mapping_type_enum.insert("vector", TextureMapping::VECTOR); \
|
|
|
|
|
mapping_type_enum.insert("normal", TextureMapping::NORMAL); \
|
|
|
|
|
SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
|
|
|
|
|
\
|
|
|
|
|
static NodeEnum mapping_projection_enum; \
|
|
|
|
|
mapping_projection_enum.insert("flat", TextureMapping::FLAT); \
|
|
|
|
|
mapping_projection_enum.insert("cube", TextureMapping::CUBE); \
|
|
|
|
|
mapping_projection_enum.insert("tube", TextureMapping::TUBE); \
|
|
|
|
|
mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \
|
|
|
|
|
SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
|
2016-05-19 11:35:50 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
TextureMapping::TextureMapping() {}
|
2011-10-12 22:42:13 +00:00
|
|
|
|
|
|
|
|
Transform TextureMapping::compute_transform()
|
|
|
|
|
{
|
2021-02-17 01:47:18 +01:00
|
|
|
Transform mmat = transform_scale(zero_float3());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (x_mapping != NONE) {
|
2011-11-04 20:58:00 +00:00
|
|
|
mmat[0][x_mapping - 1] = 1.0f;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (y_mapping != NONE) {
|
2011-11-04 20:58:00 +00:00
|
|
|
mmat[1][y_mapping - 1] = 1.0f;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (z_mapping != NONE) {
|
2011-11-04 20:58:00 +00:00
|
|
|
mmat[2][z_mapping - 1] = 1.0f;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
float3 scale_clamped = scale;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
if (type == TEXTURE || type == NORMAL) {
|
|
|
|
|
/* keep matrix invertible */
|
2023-09-17 09:01:48 +10:00
|
|
|
if (fabsf(scale.x) < 1e-5f) {
|
2013-09-25 20:28:49 +00:00
|
|
|
scale_clamped.x = signf(scale.x) * 1e-5f;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (fabsf(scale.y) < 1e-5f) {
|
2013-09-25 20:28:49 +00:00
|
|
|
scale_clamped.y = signf(scale.y) * 1e-5f;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (fabsf(scale.z) < 1e-5f) {
|
2013-09-25 20:28:49 +00:00
|
|
|
scale_clamped.z = signf(scale.z) * 1e-5f;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-09-25 20:28:49 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
Transform smat = transform_scale(scale_clamped);
|
2011-10-12 22:42:13 +00:00
|
|
|
Transform rmat = transform_euler(rotation);
|
|
|
|
|
Transform tmat = transform_translate(translation);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
Transform mat;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
switch (type) {
|
|
|
|
|
case TEXTURE:
|
|
|
|
|
/* inverse transform on texture coordinate gives
|
|
|
|
|
* forward transform on texture */
|
|
|
|
|
mat = tmat * rmat * smat;
|
|
|
|
|
mat = transform_inverse(mat);
|
|
|
|
|
break;
|
|
|
|
|
case POINT:
|
|
|
|
|
/* full transform */
|
|
|
|
|
mat = tmat * rmat * smat;
|
|
|
|
|
break;
|
|
|
|
|
case VECTOR:
|
|
|
|
|
/* no translation for vectors */
|
|
|
|
|
mat = rmat * smat;
|
|
|
|
|
break;
|
|
|
|
|
case NORMAL:
|
|
|
|
|
/* no translation for normals, and inverse transpose */
|
|
|
|
|
mat = rmat * smat;
|
2018-03-08 06:48:14 +01:00
|
|
|
mat = transform_transposed_inverse(mat);
|
2013-09-25 20:28:49 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
/* projection last */
|
|
|
|
|
mat = mat * mmat;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-25 20:28:49 +00:00
|
|
|
return mat;
|
2011-10-12 22:42:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TextureMapping::skip()
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (translation != zero_float3()) {
|
2011-10-12 22:42:13 +00:00
|
|
|
return false;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (rotation != zero_float3()) {
|
2011-10-12 22:42:13 +00:00
|
|
|
return false;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (scale != one_float3()) {
|
2011-10-12 22:42:13 +00:00
|
|
|
return false;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (x_mapping != X || y_mapping != Y || z_mapping != Z) {
|
2011-10-12 22:42:13 +00:00
|
|
|
return false;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (use_minmax) {
|
2012-05-07 20:24:38 +00:00
|
|
|
return false;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2011-10-12 22:42:13 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
|
|
|
|
|
{
|
2019-09-04 23:17:13 +02:00
|
|
|
compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
|
2011-10-12 22:42:13 +00:00
|
|
|
|
|
|
|
|
Transform tfm = compute_transform();
|
|
|
|
|
compiler.add_node(tfm.x);
|
|
|
|
|
compiler.add_node(tfm.y);
|
|
|
|
|
compiler.add_node(tfm.z);
|
2012-05-07 20:24:38 +00:00
|
|
|
|
|
|
|
|
if (use_minmax) {
|
|
|
|
|
compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
|
|
|
|
|
compiler.add_node(float3_to_float4(min));
|
|
|
|
|
compiler.add_node(float3_to_float4(max));
|
|
|
|
|
}
|
2013-09-25 20:28:49 +00:00
|
|
|
|
|
|
|
|
if (type == NORMAL) {
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
compiler.add_node(NODE_VECTOR_MATH,
|
|
|
|
|
NODE_VECTOR_MATH_NORMALIZE,
|
|
|
|
|
compiler.encode_uchar4(offset_out, offset_out, offset_out),
|
|
|
|
|
compiler.encode_uchar4(SVM_STACK_INVALID, offset_out));
|
2013-09-25 20:28:49 +00:00
|
|
|
}
|
2011-10-12 22:42:13 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
/* Convenience function for texture nodes, allocating stack space to output
|
|
|
|
|
* a modified vector and returning its offset */
|
|
|
|
|
int TextureMapping::compile_begin(SVMCompiler &compiler, ShaderInput *vector_in)
|
|
|
|
|
{
|
|
|
|
|
if (!skip()) {
|
|
|
|
|
int offset_in = compiler.stack_assign(vector_in);
|
2016-05-08 01:32:09 +02:00
|
|
|
int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
|
2016-05-02 20:12:42 +02:00
|
|
|
|
|
|
|
|
compile(compiler, offset_in, offset_out);
|
|
|
|
|
|
|
|
|
|
return offset_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return compiler.stack_assign(vector_in);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextureMapping::compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset)
|
|
|
|
|
{
|
|
|
|
|
if (!skip()) {
|
2016-05-08 01:32:09 +02:00
|
|
|
compiler.stack_clear_offset(vector_in->type(), vector_offset);
|
2016-05-02 20:12:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-20 17:40:10 +00:00
|
|
|
void TextureMapping::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
if (!skip()) {
|
2018-03-08 06:48:14 +01:00
|
|
|
compiler.parameter("mapping", compute_transform());
|
2012-11-20 17:40:10 +00:00
|
|
|
compiler.parameter("use_mapping", 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Image Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ImageTextureNode)
|
2011-05-13 14:32:08 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER);
|
2011-05-13 14:32:08 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(ImageTextureNode);
|
2011-05-13 14:32:08 +00:00
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(filename, "Filename", ustring());
|
2019-05-02 15:45:31 +02:00
|
|
|
SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2019-05-18 20:52:20 +02:00
|
|
|
static NodeEnum alpha_type_enum;
|
|
|
|
|
alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
|
|
|
|
|
alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
|
|
|
|
|
alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
|
|
|
|
|
alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
|
|
|
|
|
alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
|
|
|
|
|
SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum interpolation_enum;
|
|
|
|
|
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
|
|
|
|
|
interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
|
|
|
|
|
interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
|
|
|
|
|
interpolation_enum.insert("smart", INTERPOLATION_SMART);
|
|
|
|
|
SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum extension_enum;
|
|
|
|
|
extension_enum.insert("periodic", EXTENSION_REPEAT);
|
|
|
|
|
extension_enum.insert("clamp", EXTENSION_EXTEND);
|
|
|
|
|
extension_enum.insert("black", EXTENSION_CLIP);
|
2022-12-14 19:19:52 +01:00
|
|
|
extension_enum.insert("mirror", EXTENSION_MIRROR);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
|
|
|
|
|
|
|
|
|
|
static NodeEnum projection_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
|
|
|
|
|
projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
|
|
|
|
|
projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
|
|
|
|
|
projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
|
|
|
|
|
|
|
|
|
|
SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
|
2015-10-08 03:31:15 +02:00
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_INT_ARRAY(tiles, "Tiles", array<int>());
|
|
|
|
|
SOCKET_BOOLEAN(animated, "Animated", false);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_UV);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2011-05-13 14:32:08 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-05-02 15:45:31 +02:00
|
|
|
colorspace = u_colorspace_raw;
|
2012-11-21 13:00:51 +00:00
|
|
|
animated = false;
|
2020-11-04 11:17:38 +01:00
|
|
|
tiles.push_back_slow(1001);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ShaderNode *ImageTextureNode::clone(ShaderGraph *graph) const
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ImageTextureNode *node = graph->create_node<ImageTextureNode>(*this);
|
2020-03-08 10:42:11 +01:00
|
|
|
node->handle = handle;
|
|
|
|
|
return node;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2020-03-08 14:21:29 +01:00
|
|
|
ImageParams ImageTextureNode::image_params() const
|
2020-02-20 00:52:50 +01:00
|
|
|
{
|
2020-03-08 14:21:29 +01:00
|
|
|
ImageParams params;
|
|
|
|
|
params.animated = animated;
|
|
|
|
|
params.interpolation = interpolation;
|
|
|
|
|
params.extension = extension;
|
|
|
|
|
params.alpha_type = alpha_type;
|
|
|
|
|
params.colorspace = colorspace;
|
|
|
|
|
return params;
|
2020-02-20 00:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-12-16 12:53:03 +01:00
|
|
|
/* Box projection computes its own UVs that always lie in the
|
|
|
|
|
* 1001 tile, so there's no point in loading any others. */
|
|
|
|
|
if (projection == NODE_IMAGE_PROJ_BOX) {
|
|
|
|
|
tiles.clear();
|
2020-11-04 11:17:38 +01:00
|
|
|
tiles.push_back_slow(1001);
|
2019-12-16 12:53:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
if (!scene->params.background) {
|
|
|
|
|
/* During interactive renders, all tiles are loaded.
|
|
|
|
|
* While we could support updating this when UVs change, that could lead
|
|
|
|
|
* to annoying interruptions when loading images while editing UVs. */
|
|
|
|
|
return;
|
2019-05-15 00:42:51 +02:00
|
|
|
}
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
|
|
|
|
|
/* Only check UVs for tile culling if there are multiple tiles. */
|
|
|
|
|
if (tiles.size() < 2) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ustring attribute;
|
|
|
|
|
if (vector_in->link) {
|
|
|
|
|
ShaderNode *node = vector_in->link->parent;
|
2021-03-15 16:11:12 +01:00
|
|
|
if (node->type == UVMapNode::get_node_type()) {
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
UVMapNode *uvmap = (UVMapNode *)node;
|
2020-11-04 11:17:38 +01:00
|
|
|
attribute = uvmap->get_attribute();
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
}
|
2021-03-15 16:11:12 +01:00
|
|
|
else if (node->type == TextureCoordinateNode::get_node_type()) {
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
if (vector_in->link != node->output("UV")) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unordered_set<int> used_tiles;
|
|
|
|
|
/* TODO(lukas): This is quite inefficient. A fairly simple improvement would
|
|
|
|
|
* be to have a cache in each mesh that is indexed by attribute.
|
|
|
|
|
* Additionally, building a graph-to-meshes list once could help. */
|
2020-02-02 12:04:19 +01:00
|
|
|
foreach (Geometry *geom, scene->geometry) {
|
2020-11-04 11:17:38 +01:00
|
|
|
foreach (Node *node, geom->get_used_shaders()) {
|
|
|
|
|
Shader *shader = static_cast<Shader *>(node);
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
if (shader->graph == graph) {
|
2020-02-02 12:04:19 +01:00
|
|
|
geom->get_uv_tiles(attribute, used_tiles);
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
array<int> new_tiles;
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
foreach (int tile, tiles) {
|
|
|
|
|
if (used_tiles.count(tile)) {
|
2020-11-04 11:17:38 +01:00
|
|
|
new_tiles.push_back_slow(tile);
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
tiles.steal_data(new_tiles);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2013-11-28 01:38:23 +01:00
|
|
|
{
|
|
|
|
|
#ifdef WITH_PTEX
|
|
|
|
|
/* todo: avoid loading other texture coordinates when using ptex,
|
|
|
|
|
* and hide texture coordinate socket in the UI */
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
|
2013-11-28 01:38:23 +01:00
|
|
|
/* ptex */
|
|
|
|
|
attributes->add(ATTR_STD_PTEX_FACE_ID);
|
|
|
|
|
attributes->add(ATTR_STD_PTEX_UV);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2013-11-28 01:38:23 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ImageTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
2011-09-16 13:14:02 +00:00
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (handle.empty()) {
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
cull_tiles(compiler.scene, compiler.current_graph);
|
2020-03-08 10:42:11 +01:00
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
2020-03-08 14:21:29 +01:00
|
|
|
handle = image_manager->add_image(filename.string(), image_params(), tiles);
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
/* All tiles have the same metadata. */
|
|
|
|
|
const ImageMetaData metadata = handle.metadata();
|
|
|
|
|
const bool compress_as_srgb = metadata.compress_as_srgb;
|
|
|
|
|
const ustring known_colorspace = metadata.colorspace;
|
|
|
|
|
|
|
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
|
|
|
|
uint flags = 0;
|
2019-05-19 02:46:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (compress_as_srgb) {
|
|
|
|
|
flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
|
|
|
|
|
}
|
|
|
|
|
if (!alpha_out->links.empty()) {
|
|
|
|
|
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
|
|
|
|
|
alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
|
|
|
|
|
alpha_type == IMAGE_ALPHA_IGNORE);
|
|
|
|
|
|
|
|
|
|
if (unassociate_alpha) {
|
|
|
|
|
flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
|
2019-05-19 02:46:24 +02:00
|
|
|
}
|
2020-03-08 10:42:11 +01:00
|
|
|
}
|
2019-05-19 02:56:12 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (projection != NODE_IMAGE_PROJ_BOX) {
|
|
|
|
|
/* If there only is one image (a very common case), we encode it as a negative value. */
|
|
|
|
|
int num_nodes;
|
|
|
|
|
if (handle.num_tiles() == 1) {
|
|
|
|
|
num_nodes = -handle.svm_slot();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
num_nodes = divide_up(handle.num_tiles(), 2);
|
2019-05-19 02:46:24 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
compiler.add_node(NODE_TEX_IMAGE,
|
|
|
|
|
num_nodes,
|
|
|
|
|
compiler.encode_uchar4(vector_offset,
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
|
|
|
|
compiler.stack_assign_if_linked(alpha_out),
|
|
|
|
|
flags),
|
|
|
|
|
projection);
|
2019-12-16 12:53:03 +01:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (num_nodes > 0) {
|
|
|
|
|
for (int i = 0; i < num_nodes; i++) {
|
|
|
|
|
int4 node;
|
|
|
|
|
node.x = tiles[2 * i];
|
|
|
|
|
node.y = handle.svm_slot(2 * i);
|
|
|
|
|
if (2 * i + 1 < tiles.size()) {
|
|
|
|
|
node.z = tiles[2 * i + 1];
|
|
|
|
|
node.w = handle.svm_slot(2 * i + 1);
|
2019-12-16 12:53:03 +01:00
|
|
|
}
|
2020-03-08 10:42:11 +01:00
|
|
|
else {
|
|
|
|
|
node.z = -1;
|
|
|
|
|
node.w = -1;
|
|
|
|
|
}
|
|
|
|
|
compiler.add_node(node.x, node.y, node.z, node.w);
|
2019-12-16 12:53:03 +01:00
|
|
|
}
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2020-03-08 10:42:11 +01:00
|
|
|
assert(handle.num_tiles() == 1);
|
|
|
|
|
compiler.add_node(NODE_TEX_IMAGE_BOX,
|
|
|
|
|
handle.svm_slot(),
|
|
|
|
|
compiler.encode_uchar4(vector_offset,
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
|
|
|
|
compiler.stack_assign_if_linked(alpha_out),
|
|
|
|
|
flags),
|
|
|
|
|
__float_as_int(projection_blend));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2020-03-08 10:42:11 +01:00
|
|
|
|
|
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ImageTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2013-06-21 13:05:10 +00:00
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (handle.empty()) {
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
2020-03-08 14:21:29 +01:00
|
|
|
handle = image_manager->add_image(filename.string(), image_params());
|
2014-06-12 13:26:48 +06:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
const ImageMetaData metadata = handle.metadata();
|
2020-03-08 14:21:29 +01:00
|
|
|
const bool is_float = metadata.is_float();
|
2020-03-08 10:42:11 +01:00
|
|
|
const bool compress_as_srgb = metadata.compress_as_srgb;
|
|
|
|
|
const ustring known_colorspace = metadata.colorspace;
|
|
|
|
|
|
|
|
|
|
if (handle.svm_slot() == -1) {
|
2019-06-28 17:41:59 +02:00
|
|
|
compiler.parameter_texture(
|
2022-05-06 21:41:31 -07:00
|
|
|
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
|
2019-05-02 15:45:31 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2022-05-11 20:11:44 -07:00
|
|
|
compiler.parameter_texture("filename", handle);
|
2019-05-02 15:45:31 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-19 02:56:12 +02:00
|
|
|
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
|
2019-05-18 20:52:20 +02:00
|
|
|
alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
|
|
|
|
|
alpha_type == IMAGE_ALPHA_IGNORE);
|
2022-01-25 22:00:23 -08:00
|
|
|
const bool is_tiled = (filename.find("<UDIM>") != string::npos ||
|
2022-05-11 20:11:44 -07:00
|
|
|
filename.find("<UVTILE>") != string::npos) ||
|
|
|
|
|
handle.num_tiles() > 1;
|
2019-05-19 02:56:12 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "projection");
|
|
|
|
|
compiler.parameter(this, "projection_blend");
|
2019-05-18 20:52:20 +02:00
|
|
|
compiler.parameter("compress_as_srgb", compress_as_srgb);
|
|
|
|
|
compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
|
2019-05-19 02:56:12 +02:00
|
|
|
compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
|
2016-06-19 17:54:01 +02:00
|
|
|
compiler.parameter("is_float", is_float);
|
2019-12-25 21:12:56 +01:00
|
|
|
compiler.parameter("is_tiled", is_tiled);
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "interpolation");
|
|
|
|
|
compiler.parameter(this, "extension");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_image_texture");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Environment Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(EnvironmentTextureNode)
|
2012-03-08 19:52:58 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("environment_texture", create, NodeType::SHADER);
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(filename, "Filename", ustring());
|
2019-05-02 15:45:31 +02:00
|
|
|
SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2019-05-18 20:52:20 +02:00
|
|
|
static NodeEnum alpha_type_enum;
|
|
|
|
|
alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
|
|
|
|
|
alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
|
|
|
|
|
alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
|
|
|
|
|
alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
|
|
|
|
|
alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
|
|
|
|
|
SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum interpolation_enum;
|
|
|
|
|
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
|
|
|
|
|
interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
|
|
|
|
|
interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
|
|
|
|
|
interpolation_enum.insert("smart", INTERPOLATION_SMART);
|
|
|
|
|
SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
|
|
|
|
|
|
|
|
|
|
static NodeEnum projection_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
|
|
|
|
|
projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
|
|
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_BOOLEAN(animated, "Animated", false);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2011-05-13 14:32:08 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-05-02 15:45:31 +02:00
|
|
|
colorspace = u_colorspace_raw;
|
2012-11-21 13:00:51 +00:00
|
|
|
animated = false;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ShaderNode *EnvironmentTextureNode::clone(ShaderGraph *graph) const
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
EnvironmentTextureNode *node = graph->create_node<EnvironmentTextureNode>(*this);
|
2020-03-08 10:42:11 +01:00
|
|
|
node->handle = handle;
|
|
|
|
|
return node;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2020-03-08 14:21:29 +01:00
|
|
|
ImageParams EnvironmentTextureNode::image_params() const
|
2020-02-20 00:52:50 +01:00
|
|
|
{
|
2020-03-08 14:21:29 +01:00
|
|
|
ImageParams params;
|
|
|
|
|
params.animated = animated;
|
|
|
|
|
params.interpolation = interpolation;
|
|
|
|
|
params.extension = EXTENSION_REPEAT;
|
|
|
|
|
params.alpha_type = alpha_type;
|
|
|
|
|
params.colorspace = colorspace;
|
|
|
|
|
return params;
|
2020-02-20 00:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2013-11-28 01:38:23 +01:00
|
|
|
{
|
|
|
|
|
#ifdef WITH_PTEX
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
|
2013-11-28 01:38:23 +01:00
|
|
|
/* ptex */
|
|
|
|
|
attributes->add(ATTR_STD_PTEX_FACE_ID);
|
|
|
|
|
attributes->add(ATTR_STD_PTEX_UV);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2013-11-28 01:38:23 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void EnvironmentTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
2011-09-16 13:14:02 +00:00
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (handle.empty()) {
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
2020-03-08 14:21:29 +01:00
|
|
|
handle = image_manager->add_image(filename.string(), image_params());
|
2012-11-20 17:40:10 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
const ImageMetaData metadata = handle.metadata();
|
|
|
|
|
const bool compress_as_srgb = metadata.compress_as_srgb;
|
|
|
|
|
const ustring known_colorspace = metadata.colorspace;
|
2019-05-19 02:46:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
|
|
|
|
uint flags = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
if (compress_as_srgb) {
|
|
|
|
|
flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2020-03-08 10:42:11 +01:00
|
|
|
|
|
|
|
|
compiler.add_node(NODE_TEX_ENVIRONMENT,
|
|
|
|
|
handle.svm_slot(),
|
|
|
|
|
compiler.encode_uchar4(vector_offset,
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
|
|
|
|
compiler.stack_assign_if_linked(alpha_out),
|
|
|
|
|
flags),
|
|
|
|
|
projection);
|
|
|
|
|
|
|
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void EnvironmentTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-03-08 10:42:11 +01:00
|
|
|
if (handle.empty()) {
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
2020-03-08 14:21:29 +01:00
|
|
|
handle = image_manager->add_image(filename.string(), image_params());
|
2014-06-12 13:26:48 +06:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 14:21:29 +01:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
const ImageMetaData metadata = handle.metadata();
|
2020-03-08 14:21:29 +01:00
|
|
|
const bool is_float = metadata.is_float();
|
2020-03-08 10:42:11 +01:00
|
|
|
const bool compress_as_srgb = metadata.compress_as_srgb;
|
|
|
|
|
const ustring known_colorspace = metadata.colorspace;
|
|
|
|
|
|
|
|
|
|
if (handle.svm_slot() == -1) {
|
2019-06-28 17:41:59 +02:00
|
|
|
compiler.parameter_texture(
|
2019-06-28 17:06:32 +02:00
|
|
|
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
|
2019-05-02 15:45:31 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2022-05-11 20:11:44 -07:00
|
|
|
compiler.parameter_texture("filename", handle);
|
2019-05-02 15:45:31 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-05-02 15:45:31 +02:00
|
|
|
compiler.parameter(this, "projection");
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "interpolation");
|
2019-05-18 20:52:20 +02:00
|
|
|
compiler.parameter("compress_as_srgb", compress_as_srgb);
|
|
|
|
|
compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
|
2016-06-22 16:10:10 +02:00
|
|
|
compiler.parameter("is_float", is_float);
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_environment_texture");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sky Texture */
|
|
|
|
|
|
|
|
|
|
static float2 sky_spherical_coordinates(float3 dir)
|
|
|
|
|
{
|
|
|
|
|
return make_float2(acosf(dir.z), atan2f(dir.x, dir.y));
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-28 14:11:28 +00:00
|
|
|
typedef struct SunSky {
|
|
|
|
|
/* sun direction in spherical and cartesian */
|
|
|
|
|
float theta, phi;
|
|
|
|
|
|
|
|
|
|
/* Parameter */
|
|
|
|
|
float radiance_x, radiance_y, radiance_z;
|
2020-07-13 01:49:25 +02:00
|
|
|
float config_x[9], config_y[9], config_z[9], nishita_data[10];
|
2013-08-28 14:11:28 +00:00
|
|
|
} SunSky;
|
|
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
/* Preetham model */
|
|
|
|
|
static float sky_perez_function(float lam[6], float theta, float gamma)
|
|
|
|
|
{
|
|
|
|
|
return (1.0f + lam[0] * expf(lam[1] / cosf(theta))) *
|
|
|
|
|
(1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma));
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
static void sky_texture_precompute_preetham(SunSky *sunsky, float3 dir, float turbidity)
|
2016-04-05 12:25:54 +02:00
|
|
|
{
|
|
|
|
|
/*
|
2016-07-02 10:02:04 +10:00
|
|
|
* We re-use the SunSky struct of the new model, to avoid extra variables
|
|
|
|
|
* zenith_Y/x/y is now radiance_x/y/z
|
|
|
|
|
* perez_Y/x/y is now config_x/y/z
|
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
float2 spherical = sky_spherical_coordinates(dir);
|
|
|
|
|
float theta = spherical.x;
|
|
|
|
|
float phi = spherical.y;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->theta = theta;
|
|
|
|
|
sunsky->phi = phi;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
float theta2 = theta * theta;
|
|
|
|
|
float theta3 = theta2 * theta;
|
|
|
|
|
float T = turbidity;
|
|
|
|
|
float T2 = T * T;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta);
|
|
|
|
|
sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
|
|
|
|
|
sunsky->radiance_x *= 0.06f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->radiance_y = (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 +
|
|
|
|
|
(-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T +
|
|
|
|
|
(0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->radiance_z = (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 +
|
|
|
|
|
(-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T +
|
|
|
|
|
(0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->config_x[0] = (0.1787f * T - 1.4630f);
|
|
|
|
|
sunsky->config_x[1] = (-0.3554f * T + 0.4275f);
|
|
|
|
|
sunsky->config_x[2] = (-0.0227f * T + 5.3251f);
|
|
|
|
|
sunsky->config_x[3] = (0.1206f * T - 2.5771f);
|
|
|
|
|
sunsky->config_x[4] = (-0.0670f * T + 0.3703f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->config_y[0] = (-0.0193f * T - 0.2592f);
|
|
|
|
|
sunsky->config_y[1] = (-0.0665f * T + 0.0008f);
|
|
|
|
|
sunsky->config_y[2] = (-0.0004f * T + 0.2125f);
|
|
|
|
|
sunsky->config_y[3] = (-0.0641f * T - 0.8989f);
|
|
|
|
|
sunsky->config_y[4] = (-0.0033f * T + 0.0452f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->config_z[0] = (-0.0167f * T - 0.2608f);
|
|
|
|
|
sunsky->config_z[1] = (-0.0950f * T + 0.0092f);
|
|
|
|
|
sunsky->config_z[2] = (-0.0079f * T + 0.2102f);
|
|
|
|
|
sunsky->config_z[3] = (-0.0441f * T - 1.6537f);
|
|
|
|
|
sunsky->config_z[4] = (-0.0109f * T + 0.0529f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
/* unused for old sky model */
|
|
|
|
|
for (int i = 5; i < 9; i++) {
|
|
|
|
|
sunsky->config_x[i] = 0.0f;
|
|
|
|
|
sunsky->config_y[i] = 0.0f;
|
|
|
|
|
sunsky->config_z[i] = 0.0f;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 12:25:54 +02:00
|
|
|
sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta);
|
|
|
|
|
sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta);
|
|
|
|
|
sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-28 14:11:28 +00:00
|
|
|
/* Hosek / Wilkie */
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
static void sky_texture_precompute_hosek(SunSky *sunsky,
|
|
|
|
|
float3 dir,
|
|
|
|
|
float turbidity,
|
|
|
|
|
float ground_albedo)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-08-17 16:08:03 +00:00
|
|
|
/* Calculate Sun Direction and save coordinates */
|
2011-04-27 11:58:34 +00:00
|
|
|
float2 spherical = sky_spherical_coordinates(dir);
|
|
|
|
|
float theta = spherical.x;
|
|
|
|
|
float phi = spherical.y;
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2013-09-27 10:26:00 +00:00
|
|
|
/* Clamp Turbidity */
|
2018-07-06 10:17:58 +02:00
|
|
|
turbidity = clamp(turbidity, 0.0f, 10.0f);
|
|
|
|
|
|
2013-08-30 18:04:23 +00:00
|
|
|
/* Clamp to Horizon */
|
2018-07-06 10:17:58 +02:00
|
|
|
theta = clamp(theta, 0.0f, M_PI_2_F);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2013-08-28 14:11:28 +00:00
|
|
|
sunsky->theta = theta;
|
|
|
|
|
sunsky->phi = phi;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-22 19:11:26 +02:00
|
|
|
float solarElevation = M_PI_2_F - theta;
|
2013-08-17 16:08:03 +00:00
|
|
|
|
|
|
|
|
/* Initialize Sky Model */
|
2020-07-09 17:19:52 +02:00
|
|
|
SKY_ArHosekSkyModelState *sky_state;
|
|
|
|
|
sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init(
|
2016-05-22 19:11:26 +02:00
|
|
|
(double)turbidity, (double)ground_albedo, (double)solarElevation);
|
2013-08-28 14:11:28 +00:00
|
|
|
|
|
|
|
|
/* Copy values from sky_state to SunSky */
|
2015-03-28 00:15:15 +05:00
|
|
|
for (int i = 0; i < 9; ++i) {
|
2014-05-03 07:22:14 +10:00
|
|
|
sunsky->config_x[i] = (float)sky_state->configs[0][i];
|
|
|
|
|
sunsky->config_y[i] = (float)sky_state->configs[1][i];
|
|
|
|
|
sunsky->config_z[i] = (float)sky_state->configs[2][i];
|
2013-08-28 14:11:28 +00:00
|
|
|
}
|
2014-05-03 07:22:14 +10:00
|
|
|
sunsky->radiance_x = (float)sky_state->radiances[0];
|
|
|
|
|
sunsky->radiance_y = (float)sky_state->radiances[1];
|
|
|
|
|
sunsky->radiance_z = (float)sky_state->radiances[2];
|
2013-08-17 16:08:03 +00:00
|
|
|
|
|
|
|
|
/* Free sky_state */
|
2020-07-09 17:19:52 +02:00
|
|
|
SKY_arhosekskymodelstate_free(sky_state);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
/* Nishita improved */
|
|
|
|
|
static void sky_texture_precompute_nishita(SunSky *sunsky,
|
|
|
|
|
bool sun_disc,
|
|
|
|
|
float sun_size,
|
2020-07-13 01:49:25 +02:00
|
|
|
float sun_intensity,
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
float sun_elevation,
|
|
|
|
|
float sun_rotation,
|
2020-07-13 01:49:25 +02:00
|
|
|
float altitude,
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
float air_density,
|
|
|
|
|
float dust_density)
|
|
|
|
|
{
|
|
|
|
|
/* sample 2 sun pixels */
|
|
|
|
|
float pixel_bottom[3];
|
|
|
|
|
float pixel_top[3];
|
2020-07-09 17:19:52 +02:00
|
|
|
SKY_nishita_skymodel_precompute_sun(
|
2020-07-13 01:49:25 +02:00
|
|
|
sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top);
|
2023-04-17 17:29:27 +02:00
|
|
|
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
/* send data to svm_sky */
|
|
|
|
|
sunsky->nishita_data[0] = pixel_bottom[0];
|
|
|
|
|
sunsky->nishita_data[1] = pixel_bottom[1];
|
|
|
|
|
sunsky->nishita_data[2] = pixel_bottom[2];
|
|
|
|
|
sunsky->nishita_data[3] = pixel_top[0];
|
|
|
|
|
sunsky->nishita_data[4] = pixel_top[1];
|
|
|
|
|
sunsky->nishita_data[5] = pixel_top[2];
|
|
|
|
|
sunsky->nishita_data[6] = sun_elevation;
|
2020-07-13 01:39:11 +02:00
|
|
|
sunsky->nishita_data[7] = sun_rotation;
|
2020-08-17 17:48:53 +02:00
|
|
|
sunsky->nishita_data[8] = sun_disc ? sun_size : -1.0f;
|
2020-07-13 01:49:25 +02:00
|
|
|
sunsky->nishita_data[9] = sun_intensity;
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 18:22:47 -06:00
|
|
|
float SkyTextureNode::get_sun_average_radiance()
|
|
|
|
|
{
|
|
|
|
|
float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
|
|
|
|
|
float angular_diameter = get_sun_size();
|
|
|
|
|
|
|
|
|
|
float pix_bottom[3];
|
|
|
|
|
float pix_top[3];
|
|
|
|
|
SKY_nishita_skymodel_precompute_sun(sun_elevation,
|
|
|
|
|
angular_diameter,
|
|
|
|
|
clamped_altitude,
|
|
|
|
|
air_density,
|
|
|
|
|
dust_density,
|
|
|
|
|
pix_bottom,
|
|
|
|
|
pix_top);
|
|
|
|
|
|
|
|
|
|
/* Approximate the direction's elevation as the sun's elevation. */
|
|
|
|
|
float dir_elevation = sun_elevation;
|
|
|
|
|
float half_angular = angular_diameter / 2.0f;
|
|
|
|
|
float3 pixel_bottom = make_float3(pix_bottom[0], pix_bottom[1], pix_bottom[2]);
|
|
|
|
|
float3 pixel_top = make_float3(pix_top[0], pix_top[1], pix_top[2]);
|
|
|
|
|
|
|
|
|
|
/* Same code as in the sun evaluation shader. */
|
|
|
|
|
float3 xyz = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
|
float y = 0.0f;
|
|
|
|
|
if (sun_elevation - half_angular > 0.0f) {
|
|
|
|
|
if (sun_elevation + half_angular > 0.0f) {
|
|
|
|
|
y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
|
|
|
|
|
xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (sun_elevation + half_angular > 0.0f) {
|
|
|
|
|
y = dir_elevation / (sun_elevation + half_angular);
|
|
|
|
|
xyz = interp(pixel_bottom, pixel_top, y) * sun_intensity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We first approximate the sun's contribution by
|
|
|
|
|
* multiplying the evaluated point by the square of the angular diameter.
|
|
|
|
|
* Then we scale the approximation using a piecewise function (determined empirically). */
|
|
|
|
|
float sun_contribution = average(xyz) * sqr(angular_diameter);
|
|
|
|
|
|
|
|
|
|
float first_point = 0.8f / 180.0f * M_PI_F;
|
|
|
|
|
float second_point = 1.0f / 180.0f * M_PI_F;
|
|
|
|
|
float third_point = M_PI_2_F;
|
|
|
|
|
if (angular_diameter < first_point) {
|
|
|
|
|
sun_contribution *= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (angular_diameter < second_point) {
|
|
|
|
|
float diff = angular_diameter - first_point;
|
|
|
|
|
float slope = (0.8f - 1.0f) / (second_point - first_point);
|
|
|
|
|
sun_contribution *= 1.0f + slope * diff;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
float diff = angular_diameter - 1.0f / 180.0f * M_PI_F;
|
|
|
|
|
float slope = (0.45f - 0.8f) / (third_point - second_point);
|
|
|
|
|
sun_contribution *= 0.8f + slope * diff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sun_contribution;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(SkyTextureNode)
|
2016-04-05 12:25:54 +02:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("sky_texture", create, NodeType::SHADER);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(SkyTextureNode);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
type_enum.insert("preetham", NODE_SKY_PREETHAM);
|
|
|
|
|
type_enum.insert("hosek_wilkie", NODE_SKY_HOSEK);
|
|
|
|
|
type_enum.insert("nishita_improved", NODE_SKY_NISHITA);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(sky_type, "Type", type_enum, NODE_SKY_NISHITA);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
|
|
|
|
|
SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
|
|
|
|
|
SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
SOCKET_BOOLEAN(sun_disc, "Sun Disc", true);
|
|
|
|
|
SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f);
|
2020-07-13 01:49:25 +02:00
|
|
|
SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f);
|
2020-07-20 18:43:21 +02:00
|
|
|
SOCKET_FLOAT(sun_elevation, "Sun Elevation", 15.0f * M_PI_F / 180.0f);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f);
|
2020-07-13 01:49:25 +02:00
|
|
|
SOCKET_FLOAT(altitude, "Altitude", 1.0f);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
SOCKET_FLOAT(air_density, "Air", 1.0f);
|
|
|
|
|
SOCKET_FLOAT(dust_density, "Dust", 1.0f);
|
|
|
|
|
SOCKET_FLOAT(ozone_density, "Ozone", 1.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
SkyTextureNode::SkyTextureNode() : TextureNode(get_node_type()) {}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-04-17 17:29:27 +02:00
|
|
|
void SkyTextureNode::simplify_settings(Scene * /* scene */)
|
|
|
|
|
{
|
|
|
|
|
/* Patch sun position so users are able to animate the daylight cycle while keeping the shading
|
|
|
|
|
* code simple. */
|
|
|
|
|
float new_sun_elevation = sun_elevation;
|
|
|
|
|
float new_sun_rotation = sun_rotation;
|
|
|
|
|
|
|
|
|
|
/* Wrap `new_sun_elevation` into [-2PI..2PI] range. */
|
|
|
|
|
new_sun_elevation = fmodf(new_sun_elevation, M_2PI_F);
|
|
|
|
|
/* Wrap `new_sun_elevation` into [-PI..PI] range. */
|
|
|
|
|
if (fabsf(new_sun_elevation) >= M_PI_F) {
|
|
|
|
|
new_sun_elevation -= copysignf(2.0f, new_sun_elevation) * M_PI_F;
|
|
|
|
|
}
|
|
|
|
|
/* Wrap `new_sun_elevation` into [-PI/2..PI/2] range while keeping the same absolute position. */
|
|
|
|
|
if (new_sun_elevation >= M_PI_2_F || new_sun_elevation <= -M_PI_2_F) {
|
|
|
|
|
new_sun_elevation = copysignf(M_PI_F, new_sun_elevation) - new_sun_elevation;
|
|
|
|
|
new_sun_rotation += M_PI_F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wrap `new_sun_rotation` into [-2PI..2PI] range. */
|
|
|
|
|
new_sun_rotation = fmodf(new_sun_rotation, M_2PI_F);
|
|
|
|
|
/* Wrap `new_sun_rotation` into [0..2PI] range. */
|
|
|
|
|
if (new_sun_rotation < 0.0f) {
|
|
|
|
|
new_sun_rotation += M_2PI_F;
|
|
|
|
|
}
|
|
|
|
|
new_sun_rotation = M_2PI_F - new_sun_rotation;
|
|
|
|
|
|
|
|
|
|
sun_elevation = new_sun_elevation;
|
|
|
|
|
sun_rotation = new_sun_rotation;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void SkyTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-28 14:11:28 +00:00
|
|
|
SunSky sunsky;
|
2023-09-17 09:01:48 +10:00
|
|
|
if (sky_type == NODE_SKY_PREETHAM) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (sky_type == NODE_SKY_HOSEK) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (sky_type == NODE_SKY_NISHITA) {
|
2020-07-13 01:53:02 +02:00
|
|
|
/* Clamp altitude to reasonable values.
|
|
|
|
|
* Below 1m causes numerical issues and above 60km is space. */
|
|
|
|
|
float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
|
|
|
|
|
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky_texture_precompute_nishita(&sunsky,
|
|
|
|
|
sun_disc,
|
2020-08-17 17:48:53 +02:00
|
|
|
get_sun_size(),
|
2020-07-13 01:49:25 +02:00
|
|
|
sun_intensity,
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sun_elevation,
|
|
|
|
|
sun_rotation,
|
2020-07-13 01:53:02 +02:00
|
|
|
clamped_altitude,
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
air_density,
|
|
|
|
|
dust_density);
|
|
|
|
|
/* precomputed texture image parameters */
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
|
|
|
|
ImageParams impar;
|
|
|
|
|
impar.interpolation = INTERPOLATION_LINEAR;
|
|
|
|
|
impar.extension = EXTENSION_EXTEND;
|
|
|
|
|
|
|
|
|
|
/* precompute sky texture */
|
|
|
|
|
if (handle.empty()) {
|
|
|
|
|
SkyLoader *loader = new SkyLoader(
|
2020-07-13 01:53:02 +02:00
|
|
|
sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
handle = image_manager->add_image(loader, impar);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-04-05 12:25:54 +02:00
|
|
|
assert(false);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.stack_assign(color_out);
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), sky_type);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
/* nishita doesn't need this data */
|
2020-11-04 11:17:38 +01:00
|
|
|
if (sky_type != NODE_SKY_NISHITA) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
compiler.add_node(__float_as_uint(sunsky.phi),
|
|
|
|
|
__float_as_uint(sunsky.theta),
|
|
|
|
|
__float_as_uint(sunsky.radiance_x),
|
|
|
|
|
__float_as_uint(sunsky.radiance_y));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.radiance_z),
|
|
|
|
|
__float_as_uint(sunsky.config_x[0]),
|
|
|
|
|
__float_as_uint(sunsky.config_x[1]),
|
|
|
|
|
__float_as_uint(sunsky.config_x[2]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.config_x[3]),
|
|
|
|
|
__float_as_uint(sunsky.config_x[4]),
|
|
|
|
|
__float_as_uint(sunsky.config_x[5]),
|
|
|
|
|
__float_as_uint(sunsky.config_x[6]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.config_x[7]),
|
|
|
|
|
__float_as_uint(sunsky.config_x[8]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[0]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[1]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.config_y[2]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[3]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[4]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[5]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.config_y[6]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[7]),
|
|
|
|
|
__float_as_uint(sunsky.config_y[8]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[0]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.config_z[1]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[2]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[3]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[4]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.config_z[5]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[6]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[7]),
|
|
|
|
|
__float_as_uint(sunsky.config_z[8]));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.nishita_data[0]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[1]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[2]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[3]));
|
|
|
|
|
compiler.add_node(__float_as_uint(sunsky.nishita_data[4]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[5]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[6]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[7]));
|
2020-07-13 01:49:25 +02:00
|
|
|
compiler.add_node(__float_as_uint(sunsky.nishita_data[8]),
|
|
|
|
|
__float_as_uint(sunsky.nishita_data[9]),
|
|
|
|
|
handle.svm_slot(),
|
|
|
|
|
0);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void SkyTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-08-28 14:11:28 +00:00
|
|
|
SunSky sunsky;
|
2023-09-17 09:01:48 +10:00
|
|
|
if (sky_type == NODE_SKY_PREETHAM) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (sky_type == NODE_SKY_HOSEK) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2020-11-04 11:17:38 +01:00
|
|
|
else if (sky_type == NODE_SKY_NISHITA) {
|
2020-07-13 01:53:02 +02:00
|
|
|
/* Clamp altitude to reasonable values.
|
|
|
|
|
* Below 1m causes numerical issues and above 60km is space. */
|
|
|
|
|
float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
|
|
|
|
|
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sky_texture_precompute_nishita(&sunsky,
|
|
|
|
|
sun_disc,
|
2020-08-17 17:48:53 +02:00
|
|
|
get_sun_size(),
|
2020-07-13 01:49:25 +02:00
|
|
|
sun_intensity,
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
sun_elevation,
|
|
|
|
|
sun_rotation,
|
2020-07-13 01:53:02 +02:00
|
|
|
clamped_altitude,
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
air_density,
|
|
|
|
|
dust_density);
|
|
|
|
|
/* precomputed texture image parameters */
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
|
|
|
|
ImageParams impar;
|
|
|
|
|
impar.interpolation = INTERPOLATION_LINEAR;
|
|
|
|
|
impar.extension = EXTENSION_EXTEND;
|
|
|
|
|
|
|
|
|
|
/* precompute sky texture */
|
|
|
|
|
if (handle.empty()) {
|
|
|
|
|
SkyLoader *loader = new SkyLoader(
|
2020-07-13 01:53:02 +02:00
|
|
|
sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
handle = image_manager->add_image(loader, impar);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-04-05 12:25:54 +02:00
|
|
|
assert(false);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "sky_type");
|
2013-08-28 14:11:28 +00:00
|
|
|
compiler.parameter("theta", sunsky.theta);
|
|
|
|
|
compiler.parameter("phi", sunsky.phi);
|
|
|
|
|
compiler.parameter_color("radiance",
|
|
|
|
|
make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
|
|
|
|
|
compiler.parameter_array("config_x", sunsky.config_x, 9);
|
|
|
|
|
compiler.parameter_array("config_y", sunsky.config_y, 9);
|
|
|
|
|
compiler.parameter_array("config_z", sunsky.config_z, 9);
|
2020-07-13 01:49:25 +02:00
|
|
|
compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
/* nishita texture */
|
2020-11-04 11:17:38 +01:00
|
|
|
if (sky_type == NODE_SKY_NISHITA) {
|
2022-05-11 20:11:44 -07:00
|
|
|
compiler.parameter_texture("filename", handle);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 20:27:10 +02:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_sky_texture");
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
/* Gradient Texture */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(GradientTextureNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("gradient_texture", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(GradientTextureNode);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("linear", NODE_BLEND_LINEAR);
|
|
|
|
|
type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
|
|
|
|
|
type_enum.insert("easing", NODE_BLEND_EASING);
|
|
|
|
|
type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
|
|
|
|
|
type_enum.insert("radial", NODE_BLEND_RADIAL);
|
|
|
|
|
type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
|
|
|
|
|
type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(gradient_type, "Type", type_enum, NODE_BLEND_LINEAR);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
GradientTextureNode::GradientTextureNode() : TextureNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void GradientTextureNode::compile(SVMCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
2011-11-06 21:05:58 +00:00
|
|
|
ShaderOutput *color_out = output("Color");
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderOutput *fac_out = output("Fac");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
compiler.add_node(NODE_TEX_GRADIENT,
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.encode_uchar4(gradient_type,
|
2016-05-02 20:12:42 +02:00
|
|
|
vector_offset,
|
|
|
|
|
compiler.stack_assign_if_linked(fac_out),
|
|
|
|
|
compiler.stack_assign_if_linked(color_out)));
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void GradientTextureNode::compile(OSLCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "gradient_type");
|
2011-11-06 21:05:58 +00:00
|
|
|
compiler.add(this, "node_gradient_texture");
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
/* Noise Texture */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(NoiseTextureNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("noise_texture", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
|
|
|
|
|
|
2019-09-04 17:54:32 +02:00
|
|
|
static NodeEnum dimensions_enum;
|
|
|
|
|
dimensions_enum.insert("1D", 1);
|
|
|
|
|
dimensions_enum.insert("2D", 2);
|
|
|
|
|
dimensions_enum.insert("3D", 3);
|
|
|
|
|
dimensions_enum.insert("4D", 4);
|
|
|
|
|
SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
|
|
|
|
|
|
2023-11-18 09:40:44 +01:00
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("multifractal", NODE_NOISE_MULTIFRACTAL);
|
|
|
|
|
type_enum.insert("fBM", NODE_NOISE_FBM);
|
|
|
|
|
type_enum.insert("hybrid_multifractal", NODE_NOISE_HYBRID_MULTIFRACTAL);
|
|
|
|
|
type_enum.insert("ridged_multifractal", NODE_NOISE_RIDGED_MULTIFRACTAL);
|
|
|
|
|
type_enum.insert("hetero_terrain", NODE_NOISE_HETERO_TERRAIN);
|
|
|
|
|
SOCKET_ENUM(type, "Type", type_enum, NODE_NOISE_FBM);
|
|
|
|
|
|
2023-08-15 17:38:45 +02:00
|
|
|
SOCKET_BOOLEAN(use_normalize, "Normalize", true);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2019-09-04 17:54:32 +02:00
|
|
|
SOCKET_IN_FLOAT(w, "W", 0.0f);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
|
2020-03-26 14:43:53 +01:00
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
|
2023-08-15 17:38:45 +02:00
|
|
|
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
|
2023-11-18 09:40:44 +01:00
|
|
|
SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
2019-09-04 17:54:32 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
NoiseTextureNode::NoiseTextureNode() : TextureNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void NoiseTextureNode::compile(SVMCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
2019-09-04 17:54:32 +02:00
|
|
|
ShaderInput *w_in = input("W");
|
|
|
|
|
ShaderInput *scale_in = input("Scale");
|
|
|
|
|
ShaderInput *detail_in = input("Detail");
|
2020-03-26 14:43:53 +01:00
|
|
|
ShaderInput *roughness_in = input("Roughness");
|
2023-08-15 17:38:45 +02:00
|
|
|
ShaderInput *lacunarity_in = input("Lacunarity");
|
2023-11-18 09:40:44 +01:00
|
|
|
ShaderInput *offset_in = input("Offset");
|
|
|
|
|
ShaderInput *gain_in = input("Gain");
|
2019-09-04 17:54:32 +02:00
|
|
|
ShaderInput *distortion_in = input("Distortion");
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderOutput *fac_out = output("Fac");
|
2019-09-04 17:54:32 +02:00
|
|
|
ShaderOutput *color_out = output("Color");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-04 17:54:32 +02:00
|
|
|
int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
|
|
|
|
|
int w_stack_offset = compiler.stack_assign_if_linked(w_in);
|
|
|
|
|
int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
|
|
|
|
|
int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
|
2020-03-26 14:43:53 +01:00
|
|
|
int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
|
2023-08-15 17:38:45 +02:00
|
|
|
int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
|
2023-11-18 09:40:44 +01:00
|
|
|
int offset_stack_offset = compiler.stack_assign_if_linked(offset_in);
|
|
|
|
|
int gain_stack_offset = compiler.stack_assign_if_linked(gain_in);
|
2019-09-04 17:54:32 +02:00
|
|
|
int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in);
|
|
|
|
|
int fac_stack_offset = compiler.stack_assign_if_linked(fac_out);
|
|
|
|
|
int color_stack_offset = compiler.stack_assign_if_linked(color_out);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-04 17:54:32 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_TEX_NOISE,
|
|
|
|
|
compiler.encode_uchar4(
|
|
|
|
|
vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset),
|
2023-11-18 09:40:44 +01:00
|
|
|
compiler.encode_uchar4(
|
|
|
|
|
roughness_stack_offset, lacunarity_stack_offset, offset_stack_offset, gain_stack_offset),
|
|
|
|
|
compiler.encode_uchar4(distortion_stack_offset, fac_stack_offset, color_stack_offset));
|
2023-08-15 17:38:45 +02:00
|
|
|
|
2020-03-26 14:43:53 +01:00
|
|
|
compiler.add_node(
|
|
|
|
|
__float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
|
|
|
|
|
|
2023-08-15 17:38:45 +02:00
|
|
|
compiler.add_node(__float_as_int(lacunarity),
|
2023-11-18 09:40:44 +01:00
|
|
|
__float_as_int(offset),
|
|
|
|
|
__float_as_int(gain),
|
|
|
|
|
__float_as_int(distortion));
|
|
|
|
|
compiler.add_node(dimensions, type, use_normalize, SVM_STACK_INVALID);
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2019-09-04 17:54:32 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void NoiseTextureNode::compile(OSLCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
2019-09-04 17:54:32 +02:00
|
|
|
compiler.parameter(this, "dimensions");
|
2023-11-18 09:40:44 +01:00
|
|
|
compiler.parameter(this, "type");
|
2023-08-15 17:38:45 +02:00
|
|
|
compiler.parameter(this, "use_normalize");
|
2011-11-06 21:05:58 +00:00
|
|
|
compiler.add(this, "node_noise_texture");
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Voronoi Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(VoronoiTextureNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-12 13:09:31 +02:00
|
|
|
static NodeEnum dimensions_enum;
|
|
|
|
|
dimensions_enum.insert("1D", 1);
|
|
|
|
|
dimensions_enum.insert("2D", 2);
|
|
|
|
|
dimensions_enum.insert("3D", 3);
|
|
|
|
|
dimensions_enum.insert("4D", 4);
|
|
|
|
|
SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
|
|
|
|
|
|
|
|
|
|
static NodeEnum metric_enum;
|
|
|
|
|
metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
|
|
|
|
|
metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
|
|
|
|
|
metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
|
|
|
|
|
metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
|
|
|
|
|
SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
|
2018-07-14 13:11:28 +02:00
|
|
|
|
|
|
|
|
static NodeEnum feature_enum;
|
2019-09-12 13:09:31 +02:00
|
|
|
feature_enum.insert("f1", NODE_VORONOI_F1);
|
|
|
|
|
feature_enum.insert("f2", NODE_VORONOI_F2);
|
|
|
|
|
feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
|
|
|
|
|
feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
|
|
|
|
|
feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
|
|
|
|
|
SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
|
2018-07-14 13:11:28 +02:00
|
|
|
|
2023-06-13 19:51:49 +02:00
|
|
|
SOCKET_BOOLEAN(use_normalize, "Normalize", false);
|
2023-06-13 09:18:12 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2019-09-12 13:09:31 +02:00
|
|
|
SOCKET_IN_FLOAT(w, "W", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
|
2023-06-13 09:18:12 +02:00
|
|
|
SOCKET_IN_FLOAT(detail, "Detail", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
|
2019-09-12 13:09:31 +02:00
|
|
|
SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-12 13:09:31 +02:00
|
|
|
SOCKET_OUT_FLOAT(distance, "Distance");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2019-09-12 13:09:31 +02:00
|
|
|
SOCKET_OUT_POINT(position, "Position");
|
|
|
|
|
SOCKET_OUT_FLOAT(w, "W");
|
|
|
|
|
SOCKET_OUT_FLOAT(radius, "Radius");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VoronoiTextureNode::VoronoiTextureNode() : TextureNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
2019-09-12 13:09:31 +02:00
|
|
|
ShaderInput *w_in = input("W");
|
|
|
|
|
ShaderInput *scale_in = input("Scale");
|
2023-06-13 09:18:12 +02:00
|
|
|
ShaderInput *detail_in = input("Detail");
|
|
|
|
|
ShaderInput *roughness_in = input("Roughness");
|
|
|
|
|
ShaderInput *lacunarity_in = input("Lacunarity");
|
2019-09-12 13:09:31 +02:00
|
|
|
ShaderInput *smoothness_in = input("Smoothness");
|
2018-07-14 13:11:28 +02:00
|
|
|
ShaderInput *exponent_in = input("Exponent");
|
2019-09-12 13:09:31 +02:00
|
|
|
ShaderInput *randomness_in = input("Randomness");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-12 13:09:31 +02:00
|
|
|
ShaderOutput *distance_out = output("Distance");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *position_out = output("Position");
|
|
|
|
|
ShaderOutput *w_out = output("W");
|
|
|
|
|
ShaderOutput *radius_out = output("Radius");
|
2018-07-14 13:11:28 +02:00
|
|
|
|
2019-09-12 13:09:31 +02:00
|
|
|
int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
|
|
|
|
|
int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
|
|
|
|
|
int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
|
2023-06-13 09:18:12 +02:00
|
|
|
int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
|
|
|
|
|
int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
|
|
|
|
|
int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
|
2019-09-12 13:09:31 +02:00
|
|
|
int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
|
|
|
|
|
int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
|
|
|
|
|
int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
|
|
|
|
|
int distance_stack_offset = compiler.stack_assign_if_linked(distance_out);
|
|
|
|
|
int color_stack_offset = compiler.stack_assign_if_linked(color_out);
|
|
|
|
|
int position_stack_offset = compiler.stack_assign_if_linked(position_out);
|
|
|
|
|
int w_out_stack_offset = compiler.stack_assign_if_linked(w_out);
|
|
|
|
|
int radius_stack_offset = compiler.stack_assign_if_linked(radius_out);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-12 13:09:31 +02:00
|
|
|
compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
compiler.encode_uchar4(
|
2023-06-13 09:18:12 +02:00
|
|
|
vector_stack_offset, w_in_stack_offset, scale_stack_offset, detail_stack_offset),
|
|
|
|
|
compiler.encode_uchar4(roughness_stack_offset,
|
|
|
|
|
lacunarity_stack_offset,
|
|
|
|
|
smoothness_stack_offset,
|
|
|
|
|
exponent_stack_offset),
|
|
|
|
|
compiler.encode_uchar4(
|
2023-06-13 19:51:49 +02:00
|
|
|
randomness_stack_offset, use_normalize, distance_stack_offset, color_stack_offset),
|
2023-06-13 09:18:12 +02:00
|
|
|
compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset));
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
__float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
|
|
|
|
|
compiler.add_node(__float_as_int(lacunarity),
|
2019-09-12 13:09:31 +02:00
|
|
|
__float_as_int(smoothness),
|
|
|
|
|
__float_as_int(exponent),
|
|
|
|
|
__float_as_int(randomness));
|
|
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoronoiTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2019-09-12 13:09:31 +02:00
|
|
|
compiler.parameter(this, "dimensions");
|
2018-07-14 13:11:28 +02:00
|
|
|
compiler.parameter(this, "feature");
|
2019-09-12 13:09:31 +02:00
|
|
|
compiler.parameter(this, "metric");
|
2023-06-13 19:51:49 +02:00
|
|
|
compiler.parameter(this, "use_normalize");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_voronoi_texture");
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
/* IES Light */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(IESLightNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("ies_light", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
TEXTURE_MAPPING_DEFINE(IESLightNode);
|
|
|
|
|
|
|
|
|
|
SOCKET_STRING(ies, "IES", ustring());
|
|
|
|
|
SOCKET_STRING(filename, "File Name", ustring());
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
|
2023-10-18 20:09:37 +02:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_INCOMING);
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
IESLightNode::IESLightNode() : TextureNode(get_node_type())
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
{
|
|
|
|
|
light_manager = NULL;
|
|
|
|
|
slot = -1;
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ShaderNode *IESLightNode::clone(ShaderGraph *graph) const
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
{
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
IESLightNode *node = graph->create_node<IESLightNode>(*this);
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
|
|
|
|
|
node->light_manager = NULL;
|
|
|
|
|
node->slot = -1;
|
|
|
|
|
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IESLightNode::~IESLightNode()
|
|
|
|
|
{
|
|
|
|
|
if (light_manager) {
|
|
|
|
|
light_manager->remove_ies(slot);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IESLightNode::get_slot()
|
|
|
|
|
{
|
|
|
|
|
assert(light_manager);
|
|
|
|
|
|
|
|
|
|
if (slot == -1) {
|
|
|
|
|
if (ies.empty()) {
|
2019-08-14 14:04:23 +02:00
|
|
|
slot = light_manager->add_ies_from_file(filename.string());
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2019-08-14 14:04:23 +02:00
|
|
|
slot = light_manager->add_ies(ies.string());
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IESLightNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
light_manager = compiler.scene->light_manager;
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
get_slot();
|
|
|
|
|
|
|
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
|
|
|
|
|
|
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_IES,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(strength_in),
|
|
|
|
|
vector_offset,
|
|
|
|
|
compiler.stack_assign(fac_out),
|
|
|
|
|
0),
|
|
|
|
|
slot,
|
|
|
|
|
__float_as_int(strength));
|
|
|
|
|
|
|
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IESLightNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
Add support for tiled images and the UDIM naming scheme
This patch contains the work that I did during my week at the Code Quest - adding support for tiled images to Blender.
With this patch, images now contain a list of tiles. By default, this just contains one tile, but if the source type is set to Tiled, the user can add additional tiles. When acquiring an ImBuf, the tile to be loaded is specified in the ImageUser.
Therefore, code that is not yet aware of tiles will just access the default tile as usual.
The filenames of the additional tiles are derived from the original filename according to the UDIM naming scheme - the filename contains an index that is calculated as (1001 + 10*<y coordinate of the tile> + <x coordinate of the tile>), where the x coordinate never goes above 9.
Internally, the various tiles are stored in a cache just like sequences. When acquired for the first time, the code will try to load the corresponding file from disk. Alternatively, a new operator can be used to initialize the tile similar to the New Image operator.
The following features are supported so far:
- Automatic detection and loading of all tiles when opening the first tile (1001)
- Saving all tiles
- Adding and removing tiles
- Filling tiles with generated images
- Drawing all tiles in the Image Editor
- Viewing a tiled grid even if no image is selected
- Rendering tiled images in Eevee
- Rendering tiled images in Cycles (in SVM mode)
- Automatically skipping loading of unused tiles in Cycles
- 2D texture painting (also across tiles)
- 3D texture painting (also across tiles, only limitation: individual faces can not cross tile borders)
- Assigning custom labels to individual tiles (drawn in the Image Editor instead of the ID)
- Different resolutions between tiles
There still are some missing features that will be added later (see T72390):
- Workbench engine support
- Packing/Unpacking support
- Baking support
- Cycles OSL support
- many other Blender features that rely on images
Thanks to Brecht for the review and to all who tested the intermediate versions!
Differential Revision: https://developer.blender.org/D3509
2019-12-12 16:06:08 +01:00
|
|
|
light_manager = compiler.scene->light_manager;
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
get_slot();
|
|
|
|
|
|
|
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2019-05-02 12:40:24 +02:00
|
|
|
compiler.parameter_texture_ies("filename", slot);
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-27 00:46:37 +02:00
|
|
|
compiler.add(this, "node_ies_light");
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 20:04:09 +02:00
|
|
|
/* White Noise Texture */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(WhiteNoiseTextureNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("white_noise_texture", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum dimensions_enum;
|
|
|
|
|
dimensions_enum.insert("1D", 1);
|
|
|
|
|
dimensions_enum.insert("2D", 2);
|
|
|
|
|
dimensions_enum.insert("3D", 3);
|
|
|
|
|
dimensions_enum.insert("4D", 4);
|
|
|
|
|
SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3());
|
2019-08-21 20:04:09 +02:00
|
|
|
SOCKET_IN_FLOAT(w, "W", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(value, "Value");
|
2020-01-27 15:04:49 +00:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2019-08-21 20:04:09 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(get_node_type()) {}
|
2019-08-21 20:04:09 +02:00
|
|
|
|
|
|
|
|
void WhiteNoiseTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderInput *w_in = input("W");
|
|
|
|
|
ShaderOutput *value_out = output("Value");
|
2020-01-27 15:04:49 +00:00
|
|
|
ShaderOutput *color_out = output("Color");
|
2019-08-21 20:04:09 +02:00
|
|
|
|
|
|
|
|
int vector_stack_offset = compiler.stack_assign(vector_in);
|
|
|
|
|
int w_stack_offset = compiler.stack_assign(w_in);
|
|
|
|
|
int value_stack_offset = compiler.stack_assign(value_out);
|
2020-01-27 15:04:49 +00:00
|
|
|
int color_stack_offset = compiler.stack_assign(color_out);
|
2019-08-21 20:04:09 +02:00
|
|
|
|
|
|
|
|
compiler.add_node(NODE_TEX_WHITE_NOISE,
|
|
|
|
|
dimensions,
|
|
|
|
|
compiler.encode_uchar4(vector_stack_offset, w_stack_offset),
|
2020-01-27 15:04:49 +00:00
|
|
|
compiler.encode_uchar4(value_stack_offset, color_stack_offset));
|
2019-08-21 20:04:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WhiteNoiseTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "dimensions");
|
|
|
|
|
compiler.add(this, "node_white_noise_texture");
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
/* Wave Texture */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(WaveTextureNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("wave_texture", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(WaveTextureNode);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("bands", NODE_WAVE_BANDS);
|
|
|
|
|
type_enum.insert("rings", NODE_WAVE_RINGS);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(wave_type, "Type", type_enum, NODE_WAVE_BANDS);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-02-17 12:31:38 +01:00
|
|
|
static NodeEnum bands_direction_enum;
|
|
|
|
|
bands_direction_enum.insert("x", NODE_WAVE_BANDS_DIRECTION_X);
|
|
|
|
|
bands_direction_enum.insert("y", NODE_WAVE_BANDS_DIRECTION_Y);
|
|
|
|
|
bands_direction_enum.insert("z", NODE_WAVE_BANDS_DIRECTION_Z);
|
|
|
|
|
bands_direction_enum.insert("diagonal", NODE_WAVE_BANDS_DIRECTION_DIAGONAL);
|
|
|
|
|
SOCKET_ENUM(
|
|
|
|
|
bands_direction, "Bands Direction", bands_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
|
|
|
|
|
|
|
|
|
|
static NodeEnum rings_direction_enum;
|
|
|
|
|
rings_direction_enum.insert("x", NODE_WAVE_RINGS_DIRECTION_X);
|
|
|
|
|
rings_direction_enum.insert("y", NODE_WAVE_RINGS_DIRECTION_Y);
|
|
|
|
|
rings_direction_enum.insert("z", NODE_WAVE_RINGS_DIRECTION_Z);
|
|
|
|
|
rings_direction_enum.insert("spherical", NODE_WAVE_RINGS_DIRECTION_SPHERICAL);
|
|
|
|
|
SOCKET_ENUM(
|
|
|
|
|
rings_direction, "Rings Direction", rings_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum profile_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
|
|
|
|
|
profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
|
2020-02-17 12:31:38 +01:00
|
|
|
profile_enum.insert("tri", NODE_WAVE_PROFILE_TRI);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
|
2015-12-29 14:42:49 +01:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
|
2020-03-26 14:43:53 +01:00
|
|
|
SOCKET_IN_FLOAT(detail_roughness, "Detail Roughness", 0.5f);
|
2020-02-17 12:31:38 +01:00
|
|
|
SOCKET_IN_FLOAT(phase, "Phase Offset", 0.0f);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
2015-12-29 14:42:49 +01:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
WaveTextureNode::WaveTextureNode() : TextureNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void WaveTextureNode::compile(SVMCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2020-02-17 12:31:38 +01:00
|
|
|
ShaderInput *vector_in = input("Vector");
|
2011-11-06 21:05:58 +00:00
|
|
|
ShaderInput *scale_in = input("Scale");
|
|
|
|
|
ShaderInput *distortion_in = input("Distortion");
|
|
|
|
|
ShaderInput *detail_in = input("Detail");
|
2020-02-17 12:31:38 +01:00
|
|
|
ShaderInput *dscale_in = input("Detail Scale");
|
2020-03-26 14:43:53 +01:00
|
|
|
ShaderInput *droughness_in = input("Detail Roughness");
|
2020-02-17 12:31:38 +01:00
|
|
|
ShaderInput *phase_in = input("Phase Offset");
|
2011-11-06 21:05:58 +00:00
|
|
|
ShaderOutput *color_out = output("Color");
|
2020-02-17 12:31:38 +01:00
|
|
|
ShaderOutput *fac_out = output("Fac");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
2011-11-06 21:05:58 +00:00
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
int scale_ofs = compiler.stack_assign_if_linked(scale_in);
|
|
|
|
|
int distortion_ofs = compiler.stack_assign_if_linked(distortion_in);
|
|
|
|
|
int detail_ofs = compiler.stack_assign_if_linked(detail_in);
|
|
|
|
|
int dscale_ofs = compiler.stack_assign_if_linked(dscale_in);
|
|
|
|
|
int droughness_ofs = compiler.stack_assign_if_linked(droughness_in);
|
|
|
|
|
int phase_ofs = compiler.stack_assign_if_linked(phase_in);
|
|
|
|
|
int color_ofs = compiler.stack_assign_if_linked(color_out);
|
|
|
|
|
int fac_ofs = compiler.stack_assign_if_linked(fac_out);
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
compiler.add_node(NODE_TEX_WAVE,
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.encode_uchar4(wave_type, bands_direction, rings_direction, profile),
|
2021-11-18 09:21:47 +01:00
|
|
|
compiler.encode_uchar4(vector_offset, scale_ofs, distortion_ofs),
|
|
|
|
|
compiler.encode_uchar4(detail_ofs, dscale_ofs, droughness_ofs, phase_ofs));
|
2020-03-26 14:43:53 +01:00
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
compiler.add_node(compiler.encode_uchar4(color_ofs, fac_ofs),
|
2020-03-26 14:43:53 +01:00
|
|
|
__float_as_int(scale),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int(distortion),
|
2020-03-26 14:43:53 +01:00
|
|
|
__float_as_int(detail));
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2020-03-26 14:43:53 +01:00
|
|
|
compiler.add_node(__float_as_int(detail_scale),
|
|
|
|
|
__float_as_int(detail_roughness),
|
|
|
|
|
__float_as_int(phase),
|
|
|
|
|
SVM_STACK_INVALID);
|
2020-02-17 12:31:38 +01:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void WaveTextureNode::compile(OSLCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "wave_type");
|
2020-02-17 12:31:38 +01:00
|
|
|
compiler.parameter(this, "bands_direction");
|
|
|
|
|
compiler.parameter(this, "rings_direction");
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "profile");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-06-02 21:34:25 +00:00
|
|
|
compiler.add(this, "node_wave_texture");
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Magic Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(MagicTextureNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("magic_texture", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
TEXTURE_MAPPING_DEFINE(MagicTextureNode);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_INT(depth, "Depth", 2);
|
2011-11-06 21:05:58 +00:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MagicTextureNode::MagicTextureNode() : TextureNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void MagicTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
2011-11-06 21:05:58 +00:00
|
|
|
ShaderInput *scale_in = input("Scale");
|
|
|
|
|
ShaderInput *distortion_in = input("Distortion");
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
compiler.add_node(NODE_TEX_MAGIC,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(depth,
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
|
|
|
|
compiler.stack_assign_if_linked(fac_out)),
|
|
|
|
|
compiler.encode_uchar4(vector_offset,
|
|
|
|
|
compiler.stack_assign_if_linked(scale_in),
|
|
|
|
|
compiler.stack_assign_if_linked(distortion_in)));
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(__float_as_int(scale), __float_as_int(distortion));
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void MagicTextureNode::compile(OSLCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "depth");
|
2011-11-06 21:05:58 +00:00
|
|
|
compiler.add(this, "node_magic_texture");
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-01-08 14:55:43 +00:00
|
|
|
/* Checker Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(CheckerTextureNode)
|
2012-01-08 14:55:43 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("checker_texture", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
|
2012-01-08 14:55:43 +00:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
|
|
|
|
SOCKET_IN_COLOR(color1, "Color1", zero_float3());
|
|
|
|
|
SOCKET_IN_COLOR(color2, "Color2", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CheckerTextureNode::CheckerTextureNode() : TextureNode(get_node_type()) {}
|
2012-01-08 14:55:43 +00:00
|
|
|
|
|
|
|
|
void CheckerTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderInput *color1_in = input("Color1");
|
|
|
|
|
ShaderInput *color2_in = input("Color2");
|
|
|
|
|
ShaderInput *scale_in = input("Scale");
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-01-08 14:55:43 +00:00
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
2012-01-08 14:55:43 +00:00
|
|
|
|
|
|
|
|
compiler.add_node(NODE_TEX_CHECKER,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(vector_offset,
|
|
|
|
|
compiler.stack_assign(color1_in),
|
|
|
|
|
compiler.stack_assign(color2_in),
|
|
|
|
|
compiler.stack_assign_if_linked(scale_in)),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
|
|
|
|
|
compiler.stack_assign_if_linked(fac_out)),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int(scale));
|
2012-03-08 19:52:58 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2012-01-08 14:55:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CheckerTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2012-01-08 14:55:43 +00:00
|
|
|
compiler.add(this, "node_checker_texture");
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
/* Brick Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(BrickTextureNode)
|
2012-09-04 13:29:07 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("brick_texture", create, NodeType::SHADER);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
TEXTURE_MAPPING_DEFINE(BrickTextureNode);
|
|
|
|
|
|
|
|
|
|
SOCKET_FLOAT(offset, "Offset", 0.5f);
|
|
|
|
|
SOCKET_INT(offset_frequency, "Offset Frequency", 2);
|
|
|
|
|
SOCKET_FLOAT(squash, "Squash", 1.0f);
|
|
|
|
|
SOCKET_INT(squash_frequency, "Squash Frequency", 2);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color1, "Color1", zero_float3());
|
|
|
|
|
SOCKET_IN_COLOR(color2, "Color2", zero_float3());
|
|
|
|
|
SOCKET_IN_COLOR(mortar, "Mortar", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
|
2016-10-30 01:33:10 +02:00
|
|
|
SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
BrickTextureNode::BrickTextureNode() : TextureNode(get_node_type()) {}
|
2012-09-04 13:29:07 +00:00
|
|
|
|
|
|
|
|
void BrickTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderInput *color1_in = input("Color1");
|
|
|
|
|
ShaderInput *color2_in = input("Color2");
|
|
|
|
|
ShaderInput *mortar_in = input("Mortar");
|
|
|
|
|
ShaderInput *scale_in = input("Scale");
|
|
|
|
|
ShaderInput *mortar_size_in = input("Mortar Size");
|
2016-10-30 01:33:10 +02:00
|
|
|
ShaderInput *mortar_smooth_in = input("Mortar Smooth");
|
2012-09-04 13:29:07 +00:00
|
|
|
ShaderInput *bias_in = input("Bias");
|
|
|
|
|
ShaderInput *brick_width_in = input("Brick Width");
|
|
|
|
|
ShaderInput *row_height_in = input("Row Height");
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
|
|
|
|
compiler.add_node(NODE_TEX_BRICK,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(vector_offset,
|
|
|
|
|
compiler.stack_assign(color1_in),
|
|
|
|
|
compiler.stack_assign(color2_in),
|
|
|
|
|
compiler.stack_assign(mortar_in)),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
|
|
|
|
|
compiler.stack_assign_if_linked(mortar_size_in),
|
|
|
|
|
compiler.stack_assign_if_linked(bias_in),
|
|
|
|
|
compiler.stack_assign_if_linked(brick_width_in)),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(row_height_in),
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
2016-10-30 01:33:10 +02:00
|
|
|
compiler.stack_assign_if_linked(fac_out),
|
|
|
|
|
compiler.stack_assign_if_linked(mortar_smooth_in)));
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int(scale),
|
|
|
|
|
__float_as_int(mortar_size),
|
|
|
|
|
__float_as_int(bias));
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(__float_as_int(brick_width),
|
|
|
|
|
__float_as_int(row_height),
|
2012-09-04 13:29:07 +00:00
|
|
|
__float_as_int(offset),
|
|
|
|
|
__float_as_int(squash));
|
|
|
|
|
|
2016-10-30 01:33:10 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
__float_as_int(mortar_smooth), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BrickTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2012-11-20 17:40:10 +00:00
|
|
|
tex_mapping.compile(compiler);
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "offset");
|
|
|
|
|
compiler.parameter(this, "offset_frequency");
|
|
|
|
|
compiler.parameter(this, "squash");
|
|
|
|
|
compiler.parameter(this, "squash_frequency");
|
2012-09-04 13:29:07 +00:00
|
|
|
compiler.add(this, "node_brick_texture");
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-18 22:09:20 +02:00
|
|
|
/* Point Density Texture */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(PointDensityTextureNode)
|
2015-07-18 22:09:20 +02:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("point_density_texture", create, NodeType::SHADER);
|
2015-07-18 22:09:20 +02:00
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(filename, "Filename", ustring());
|
2015-07-18 22:09:20 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum space_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
|
|
|
|
|
space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
|
|
|
|
|
|
|
|
|
|
static NodeEnum interpolation_enum;
|
|
|
|
|
interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
|
|
|
|
|
interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
|
|
|
|
|
interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
|
|
|
|
|
interpolation_enum.insert("smart", INTERPOLATION_SMART);
|
|
|
|
|
SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
|
|
|
|
|
|
|
|
|
|
SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
|
2015-07-18 22:09:20 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(density, "Density");
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2015-07-18 22:09:20 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(get_node_type()) {}
|
2015-07-18 22:09:20 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
PointDensityTextureNode::~PointDensityTextureNode() {}
|
2015-07-18 22:09:20 +02:00
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ShaderNode *PointDensityTextureNode::clone(ShaderGraph *graph) const
|
2015-07-18 22:09:20 +02:00
|
|
|
{
|
2019-05-15 00:42:51 +02:00
|
|
|
/* Increase image user count for new node. We need to ensure to not call
|
|
|
|
|
* add_image again, to work around access of freed data on the Blender
|
|
|
|
|
* side. A better solution should be found to avoid this. */
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
PointDensityTextureNode *node = graph->create_node<PointDensityTextureNode>(*this);
|
2020-03-08 14:21:29 +01:00
|
|
|
node->handle = handle; /* TODO: not needed? */
|
2020-03-08 10:42:11 +01:00
|
|
|
return node;
|
2015-07-18 22:09:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (shader->has_volume) {
|
2015-07-18 22:09:20 +02:00
|
|
|
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2015-07-18 22:09:20 +02:00
|
|
|
|
|
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-08 14:21:29 +01:00
|
|
|
ImageParams PointDensityTextureNode::image_params() const
|
2018-06-11 16:29:49 +02:00
|
|
|
{
|
2020-03-08 14:21:29 +01:00
|
|
|
ImageParams params;
|
|
|
|
|
params.interpolation = interpolation;
|
|
|
|
|
return params;
|
2020-02-20 00:52:50 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-18 22:09:20 +02:00
|
|
|
void PointDensityTextureNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *density_out = output("Density");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-18 22:09:20 +02:00
|
|
|
const bool use_density = !density_out->links.empty();
|
|
|
|
|
const bool use_color = !color_out->links.empty();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-10-08 19:08:28 +05:00
|
|
|
if (use_density || use_color) {
|
2020-03-08 14:21:29 +01:00
|
|
|
if (handle.empty()) {
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
|
|
|
|
handle = image_manager->add_image(filename.string(), image_params());
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-08 10:42:11 +01:00
|
|
|
const int slot = handle.svm_slot();
|
2015-07-18 22:09:20 +02:00
|
|
|
if (slot != -1) {
|
|
|
|
|
compiler.stack_assign(vector_in);
|
|
|
|
|
compiler.add_node(NODE_TEX_VOXEL,
|
|
|
|
|
slot,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(vector_in),
|
|
|
|
|
compiler.stack_assign_if_linked(density_out),
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
2016-05-29 16:13:14 +02:00
|
|
|
space));
|
|
|
|
|
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
|
2015-07-18 22:09:20 +02:00
|
|
|
compiler.add_node(tfm.x);
|
|
|
|
|
compiler.add_node(tfm.y);
|
|
|
|
|
compiler.add_node(tfm.z);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-07-18 22:09:20 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-02 20:12:42 +02:00
|
|
|
if (use_density) {
|
2016-12-06 15:36:35 +01:00
|
|
|
compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(density_out));
|
2016-05-02 20:12:42 +02:00
|
|
|
}
|
2016-05-17 22:08:34 +02:00
|
|
|
if (use_color) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_VALUE_V,
|
|
|
|
|
make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-02 20:12:42 +02:00
|
|
|
}
|
2015-07-18 22:09:20 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-18 22:09:20 +02:00
|
|
|
void PointDensityTextureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *density_out = output("Density");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-07-18 22:09:20 +02:00
|
|
|
const bool use_density = !density_out->links.empty();
|
|
|
|
|
const bool use_color = !color_out->links.empty();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-10-08 19:08:28 +05:00
|
|
|
if (use_density || use_color) {
|
2020-03-08 14:21:29 +01:00
|
|
|
if (handle.empty()) {
|
|
|
|
|
ImageManager *image_manager = compiler.scene->image_manager;
|
|
|
|
|
handle = image_manager->add_image(filename.string(), image_params());
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-11 20:11:44 -07:00
|
|
|
compiler.parameter_texture("filename", handle);
|
2016-05-29 16:13:14 +02:00
|
|
|
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
|
2018-03-08 06:48:14 +01:00
|
|
|
compiler.parameter("mapping", tfm);
|
2015-07-18 22:09:20 +02:00
|
|
|
compiler.parameter("use_mapping", 1);
|
|
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "interpolation");
|
2015-07-18 22:09:20 +02:00
|
|
|
compiler.add(this, "node_voxel_texture");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-16 18:15:07 +00:00
|
|
|
/* Normal */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(NormalNode)
|
2011-12-16 18:15:07 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("normal", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_VECTOR(direction, "direction", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_NORMAL(normal, "Normal");
|
|
|
|
|
SOCKET_OUT_FLOAT(dot, "Dot");
|
2011-12-16 18:15:07 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
NormalNode::NormalNode() : ShaderNode(get_node_type()) {}
|
2011-12-16 18:15:07 +00:00
|
|
|
|
|
|
|
|
void NormalNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
ShaderOutput *normal_out = output("Normal");
|
|
|
|
|
ShaderOutput *dot_out = output("Dot");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_NORMAL,
|
|
|
|
|
compiler.stack_assign(normal_in),
|
|
|
|
|
compiler.stack_assign(normal_out),
|
|
|
|
|
compiler.stack_assign(dot_out));
|
2011-12-16 18:15:07 +00:00
|
|
|
compiler.add_node(
|
|
|
|
|
__float_as_int(direction.x), __float_as_int(direction.y), __float_as_int(direction.z));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NormalNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "direction");
|
2011-12-16 18:15:07 +00:00
|
|
|
compiler.add(this, "node_normal");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Mapping */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(MappingNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
|
|
|
|
|
|
2019-09-04 23:17:13 +02:00
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
|
|
|
|
|
type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
|
|
|
|
|
type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
|
|
|
|
|
type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(mapping_type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_POINT(vector, "Vector", zero_float3());
|
|
|
|
|
SOCKET_IN_POINT(location, "Location", zero_float3());
|
|
|
|
|
SOCKET_IN_POINT(rotation, "Rotation", zero_float3());
|
|
|
|
|
SOCKET_IN_POINT(scale, "Scale", one_float3());
|
2019-09-04 23:17:13 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_POINT(vector, "Vector");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MappingNode::MappingNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-09-04 23:17:13 +02:00
|
|
|
void MappingNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
2020-11-04 11:17:38 +01:00
|
|
|
float3 result = svm_mapping((NodeMappingType)mapping_type, vector, location, rotation, scale);
|
2019-09-04 23:17:13 +02:00
|
|
|
folder.make_constant(result);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
folder.fold_mapping((NodeMappingType)mapping_type);
|
2019-09-04 23:17:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void MappingNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
2019-09-04 23:17:13 +02:00
|
|
|
ShaderInput *location_in = input("Location");
|
|
|
|
|
ShaderInput *rotation_in = input("Rotation");
|
|
|
|
|
ShaderInput *scale_in = input("Scale");
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
|
2019-09-04 23:17:13 +02:00
|
|
|
int vector_stack_offset = compiler.stack_assign(vector_in);
|
|
|
|
|
int location_stack_offset = compiler.stack_assign(location_in);
|
|
|
|
|
int rotation_stack_offset = compiler.stack_assign(rotation_in);
|
|
|
|
|
int scale_stack_offset = compiler.stack_assign(scale_in);
|
|
|
|
|
int result_stack_offset = compiler.stack_assign(vector_out);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MAPPING,
|
2020-11-04 11:17:38 +01:00
|
|
|
mapping_type,
|
2019-09-04 23:17:13 +02:00
|
|
|
compiler.encode_uchar4(
|
|
|
|
|
vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
|
|
|
|
|
result_stack_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MappingNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "mapping_type");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_mapping");
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-29 12:24:47 +02:00
|
|
|
/* RGBToBW */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(RGBToBWNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2016-06-17 05:20:47 +02:00
|
|
|
SOCKET_OUT_FLOAT(val, "Val");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
RGBToBWNode::RGBToBWNode() : ShaderNode(get_node_type()) {}
|
2016-05-29 12:24:47 +02:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void RGBToBWNode::constant_fold(const ConstantFolder &folder)
|
2016-05-29 12:24:47 +02:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2018-06-14 17:48:19 +02:00
|
|
|
float val = folder.scene->shader_manager->linear_rgb_to_gray(color);
|
|
|
|
|
folder.make_constant(val);
|
2016-05-29 12:24:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RGBToBWNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add_node(NODE_CONVERT,
|
2018-12-11 12:57:57 +01:00
|
|
|
NODE_CONVERT_CF,
|
|
|
|
|
compiler.stack_assign(inputs[0]),
|
|
|
|
|
compiler.stack_assign(outputs[0]));
|
2016-05-29 12:24:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RGBToBWNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-07-03 13:08:21 +02:00
|
|
|
compiler.add(this, "node_rgb_to_bw");
|
2016-05-29 12:24:47 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Convert */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
const NodeType *ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
|
|
|
|
|
bool ConvertNode::initialized = ConvertNode::register_types();
|
|
|
|
|
|
|
|
|
|
Node *ConvertNode::create(const NodeType *type)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
bool ConvertNode::register_types()
|
|
|
|
|
{
|
|
|
|
|
const int num_types = 8;
|
|
|
|
|
SocketType::Type types[num_types] = {SocketType::FLOAT,
|
|
|
|
|
SocketType::INT,
|
|
|
|
|
SocketType::COLOR,
|
|
|
|
|
SocketType::VECTOR,
|
|
|
|
|
SocketType::POINT,
|
|
|
|
|
SocketType::NORMAL,
|
|
|
|
|
SocketType::STRING,
|
|
|
|
|
SocketType::CLOSURE};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
for (size_t i = 0; i < num_types; i++) {
|
|
|
|
|
SocketType::Type from = types[i];
|
|
|
|
|
ustring from_name(SocketType::type_name(from));
|
|
|
|
|
ustring from_value_name("value_" + from_name.string());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
for (size_t j = 0; j < num_types; j++) {
|
|
|
|
|
SocketType::Type to = types[j];
|
|
|
|
|
ustring to_name(SocketType::type_name(to));
|
|
|
|
|
ustring to_value_name("value_" + to_name.string());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
|
|
|
|
|
NodeType *type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
type->register_input(from_value_name,
|
|
|
|
|
from_value_name,
|
|
|
|
|
from,
|
|
|
|
|
SOCKET_OFFSETOF(ConvertNode, value_float),
|
|
|
|
|
SocketType::zero_default_value(),
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
SocketType::LINKABLE);
|
|
|
|
|
type->register_output(to_value_name, to_value_name, to);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
assert(from < MAX_TYPE);
|
|
|
|
|
assert(to < MAX_TYPE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
node_types[from][to] = type;
|
|
|
|
|
}
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
|
|
|
|
|
: ShaderNode(node_types[from_][to_])
|
|
|
|
|
{
|
|
|
|
|
from = from_;
|
|
|
|
|
to = to_;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (from == to) {
|
2016-05-07 19:48:28 +02:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_PROXY;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (autoconvert) {
|
2016-05-07 19:48:28 +02:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-14 15:01:26 +01:00
|
|
|
/* Union usage requires a manual copy constructor. */
|
|
|
|
|
ConvertNode::ConvertNode(const ConvertNode &other)
|
|
|
|
|
: ShaderNode(other),
|
|
|
|
|
from(other.from),
|
|
|
|
|
to(other.to),
|
|
|
|
|
value_color(other.value_color),
|
|
|
|
|
value_string(other.value_string)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void ConvertNode::constant_fold(const ConstantFolder &folder)
|
2015-12-23 21:41:59 +01:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
/* proxy nodes should have been removed at this point */
|
|
|
|
|
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-23 21:41:59 +01:00
|
|
|
/* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2016-05-08 01:32:09 +02:00
|
|
|
if (from == SocketType::FLOAT) {
|
2016-05-29 13:26:41 +02:00
|
|
|
if (SocketType::is_float3(to)) {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.make_constant(make_float3(value_float, value_float, value_float));
|
2016-05-29 13:26:41 +02:00
|
|
|
}
|
2015-12-23 21:41:59 +01:00
|
|
|
}
|
2016-05-29 13:26:41 +02:00
|
|
|
else if (SocketType::is_float3(from)) {
|
|
|
|
|
if (to == SocketType::FLOAT) {
|
2016-07-16 13:16:54 +02:00
|
|
|
if (from == SocketType::COLOR) {
|
2016-05-07 19:48:28 +02:00
|
|
|
/* color to float */
|
2018-06-14 17:48:19 +02:00
|
|
|
float val = folder.scene->shader_manager->linear_rgb_to_gray(value_color);
|
|
|
|
|
folder.make_constant(val);
|
2016-07-16 13:16:54 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
/* vector/point/normal to float */
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.make_constant(average(value_vector));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-07-16 13:16:54 +02:00
|
|
|
}
|
2016-05-29 13:26:41 +02:00
|
|
|
else if (SocketType::is_float3(to)) {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.make_constant(value_color);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-29 13:26:41 +02:00
|
|
|
}
|
2016-08-02 12:22:43 +03:00
|
|
|
else {
|
|
|
|
|
ShaderInput *in = inputs[0];
|
|
|
|
|
ShaderNode *prev = in->link->parent;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-02 12:22:43 +03:00
|
|
|
/* no-op conversion of A to B to A */
|
|
|
|
|
if (prev->type == node_types[to][from]) {
|
|
|
|
|
ShaderInput *prev_in = prev->inputs[0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-08-02 12:22:43 +03:00
|
|
|
if (SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) &&
|
|
|
|
|
prev_in->link)
|
|
|
|
|
{
|
|
|
|
|
folder.bypass(prev_in->link);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-02 12:22:43 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ConvertNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
/* proxy nodes should have been removed at this point */
|
|
|
|
|
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderInput *in = inputs[0];
|
|
|
|
|
ShaderOutput *out = outputs[0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 01:32:09 +02:00
|
|
|
if (from == SocketType::FLOAT) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (to == SocketType::INT) {
|
2012-10-20 13:11:45 +00:00
|
|
|
/* float to int */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-20 13:11:45 +00:00
|
|
|
/* float to float3 */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-10-20 13:11:45 +00:00
|
|
|
}
|
2016-05-08 01:32:09 +02:00
|
|
|
else if (from == SocketType::INT) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (to == SocketType::FLOAT) {
|
2012-10-20 13:11:45 +00:00
|
|
|
/* int to float */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-20 13:11:45 +00:00
|
|
|
/* int to vector/point/normal */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-10-20 13:11:45 +00:00
|
|
|
}
|
2016-05-08 01:32:09 +02:00
|
|
|
else if (to == SocketType::FLOAT) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (from == SocketType::COLOR) {
|
2011-04-27 11:58:34 +00:00
|
|
|
/* color to float */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
/* vector/point/normal to float */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2016-05-08 01:32:09 +02:00
|
|
|
else if (to == SocketType::INT) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (from == SocketType::COLOR) {
|
2012-10-20 13:11:45 +00:00
|
|
|
/* color to int */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-20 13:11:45 +00:00
|
|
|
/* vector/point/normal to int */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* float3 to float3 */
|
|
|
|
|
if (in->link) {
|
|
|
|
|
/* no op in SVM */
|
|
|
|
|
compiler.stack_link(in, out);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* set 0,0,0 value */
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(NODE_VALUE_V, value_color);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ConvertNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
/* proxy nodes should have been removed at this point */
|
|
|
|
|
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (from == SocketType::FLOAT) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_convert_from_float");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (from == SocketType::INT) {
|
2012-10-20 13:11:45 +00:00
|
|
|
compiler.add(this, "node_convert_from_int");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (from == SocketType::COLOR) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_convert_from_color");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (from == SocketType::VECTOR) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_convert_from_vector");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (from == SocketType::POINT) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_convert_from_point");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (from == SocketType::NORMAL) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_convert_from_normal");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
assert(0);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2017-04-21 12:50:04 +02:00
|
|
|
/* Base type for all closure-type nodes */
|
|
|
|
|
|
|
|
|
|
BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) : ShaderNode(node_type)
|
|
|
|
|
{
|
|
|
|
|
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-20 17:36:16 +02:00
|
|
|
bool BsdfBaseNode::has_bump()
|
|
|
|
|
{
|
|
|
|
|
/* detect if anything is plugged into the normal input besides the default */
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
return (normal_in && normal_in->link &&
|
|
|
|
|
normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* BSDF Closure */
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2013-09-03 22:39:17 +00:00
|
|
|
void BsdfNode::compile(SVMCompiler &compiler,
|
|
|
|
|
ShaderInput *param1,
|
|
|
|
|
ShaderInput *param2,
|
|
|
|
|
ShaderInput *param3,
|
|
|
|
|
ShaderInput *param4)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
2012-10-10 15:56:43 +00:00
|
|
|
ShaderInput *normal_in = input("Normal");
|
2012-10-17 12:17:17 +00:00
|
|
|
ShaderInput *tangent_in = input("Tangent");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (color_in->link) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-11-04 22:31:32 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
|
2016-05-02 20:12:42 +02:00
|
|
|
int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) :
|
|
|
|
|
SVM_STACK_INVALID;
|
|
|
|
|
int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
|
|
|
|
|
int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CLOSURE_BSDF,
|
2011-05-13 12:11:08 +00:00
|
|
|
compiler.encode_uchar4(closure,
|
2016-05-02 20:12:42 +02:00
|
|
|
(param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
|
|
|
|
|
(param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
|
2011-09-12 13:13:56 +00:00
|
|
|
compiler.closure_mix_weight_offset()),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
|
|
|
|
|
__float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
|
2012-10-10 15:56:43 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compile(compiler, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:47:55 +05:00
|
|
|
void BsdfNode::compile(OSLCompiler & /*compiler*/)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
/* Glossy BSDF Closure */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
NODE_DEFINE(GlossyBsdfNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
NodeType *type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
|
2014-06-08 12:16:28 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2014-06-08 12:16:28 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum distribution_enum;
|
2020-05-14 22:12:29 +02:00
|
|
|
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_ID);
|
2020-05-14 22:12:29 +02:00
|
|
|
distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
|
2020-05-14 22:12:29 +02:00
|
|
|
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2018-03-10 16:09:22 +01:00
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
2014-06-08 12:16:28 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2014-06-08 12:16:28 +02:00
|
|
|
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(get_node_type())
|
2014-06-08 12:16:28 +02:00
|
|
|
{
|
2020-05-14 22:12:29 +02:00
|
|
|
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool GlossyBsdfNode::is_isotropic()
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *anisotropy_input = input("Anisotropy");
|
|
|
|
|
/* Keep in sync with the thresholds in OSL's node_glossy_bsdf and SVM's svm_node_closure_bsdf. */
|
|
|
|
|
return (!anisotropy_input->link && fabsf(anisotropy) <= 1e-4f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
void GlossyBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2012-10-10 13:02:20 +00:00
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderInput *tangent_in = input("Tangent");
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!tangent_in->link && !is_isotropic()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-12-31 17:30:34 +01:00
|
|
|
}
|
2012-10-10 13:02:20 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2012-10-10 13:02:20 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-12 12:36:31 +02:00
|
|
|
void GlossyBsdfNode::simplify_settings(Scene * /* scene */)
|
2015-11-18 18:47:56 +01:00
|
|
|
{
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
/* If the anisotropy is close enough to zero, fall back to the isotropic case. */
|
|
|
|
|
ShaderInput *tangent_input = input("Tangent");
|
|
|
|
|
if (tangent_input->link && is_isotropic()) {
|
|
|
|
|
tangent_input->disconnect();
|
|
|
|
|
}
|
2015-11-18 18:47:56 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void GlossyBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
closure = distribution;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
/* TODO: Just use weight for legacy MultiGGX? Would also simplify OSL. */
|
2023-07-12 12:36:31 +02:00
|
|
|
if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) {
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
BsdfNode::compile(
|
|
|
|
|
compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
|
2023-07-12 12:36:31 +02:00
|
|
|
}
|
|
|
|
|
else {
|
Cycles: Merge Anisotropic BSDF node into Glossy BSDF node
Used to be https://archive.blender.org/developer/D17123.
Internally these are already using the same code path anyways, there's no point in maintaining two distinct nodes.
The obvious approach would be to add Anisotropy controls to the Glossy BSDF node and remove the Anisotropic BSDF node. However, that would break forward compability, since older Blender versions don't know how to handle the Anisotropy input on the Glossy BSDF node.
Therefore, this commit technically removes the Glossy BSDF node, uses versioning to replace them with an Anisotropic BSDF node, and renames that node to "Glossy BSDF".
That way, when you open a new file in an older version, all the nodes show up as Anisotropic BSDF nodes and render correctly.
This is a bit ugly internally since we need to preserve the old `idname` which now no longer matches the UI name, but that's not too bad.
Also removes the "Sharp" distribution option and replaces it with GGX, sets Roughness to zero and disconnects any input to the Roughness socket.
Pull Request: https://projects.blender.org/blender/blender/pulls/104445
2023-05-18 23:12:20 +02:00
|
|
|
BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
|
2023-07-12 12:36:31 +02:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlossyBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "distribution");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_glossy_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Glass BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(GlassBsdfNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum distribution_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
|
2023-03-05 17:15:26 +01:00
|
|
|
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(
|
|
|
|
|
distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
|
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
|
2023-12-04 21:12:29 +01:00
|
|
|
SOCKET_IN_FLOAT(IOR, "IOR", 1.5f);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
GlassBsdfNode::GlassBsdfNode() : BsdfNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2023-07-12 12:36:31 +02:00
|
|
|
closure = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
|
2015-11-18 18:47:56 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void GlassBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
closure = distribution;
|
2023-10-09 19:17:15 +02:00
|
|
|
BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GlassBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "distribution");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_glass_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
/* Refraction BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(RefractionBsdfNode)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum distribution_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
|
2023-03-05 17:15:26 +01:00
|
|
|
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(
|
|
|
|
|
distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(get_node_type())
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2023-07-12 12:36:31 +02:00
|
|
|
closure = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
|
2015-11-18 18:47:56 +01:00
|
|
|
}
|
|
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
void RefractionBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
closure = distribution;
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2023-07-12 12:36:31 +02:00
|
|
|
BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RefractionBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "distribution");
|
2012-11-06 19:59:02 +00:00
|
|
|
compiler.add(this, "node_refraction_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-23 17:45:20 +00:00
|
|
|
/* Toon BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ToonBsdfNode)
|
2013-05-23 17:45:20 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
|
2013-05-23 17:45:20 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2013-05-23 17:45:20 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum component_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
|
|
|
|
|
component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
|
|
|
|
|
SOCKET_IN_FLOAT(size, "Size", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
2013-05-23 17:45:20 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2013-05-23 17:45:20 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
ToonBsdfNode::ToonBsdfNode() : BsdfNode(get_node_type())
|
2013-05-23 17:45:20 +00:00
|
|
|
{
|
2015-05-09 18:53:57 +05:00
|
|
|
closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
|
2013-05-23 17:45:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ToonBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
closure = component;
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2013-05-23 17:45:20 +00:00
|
|
|
BsdfNode::compile(compiler, input("Size"), input("Smooth"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ToonBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "component");
|
2013-05-23 17:45:20 +00:00
|
|
|
compiler.add(this, "node_toon_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 15:36:36 +02:00
|
|
|
/* Sheen BSDF Closure */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-07-24 15:36:36 +02:00
|
|
|
NODE_DEFINE(SheenBsdfNode)
|
2016-05-07 19:48:28 +02:00
|
|
|
{
|
2023-07-24 15:36:36 +02:00
|
|
|
NodeType *type = NodeType::add("sheen_bsdf", create, NodeType::SHADER);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2023-07-24 15:36:36 +02:00
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 1.0f);
|
|
|
|
|
|
|
|
|
|
static NodeEnum distribution_enum;
|
|
|
|
|
distribution_enum.insert("ashikhmin", CLOSURE_BSDF_ASHIKHMIN_VELVET_ID);
|
|
|
|
|
distribution_enum.insert("microfiber", CLOSURE_BSDF_SHEEN_ID);
|
|
|
|
|
SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_SHEEN_ID);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 15:36:36 +02:00
|
|
|
SheenBsdfNode::SheenBsdfNode() : BsdfNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2023-07-24 15:36:36 +02:00
|
|
|
closure = CLOSURE_BSDF_SHEEN_ID;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-24 15:36:36 +02:00
|
|
|
void SheenBsdfNode::compile(SVMCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2023-07-24 15:36:36 +02:00
|
|
|
closure = distribution;
|
|
|
|
|
BsdfNode::compile(compiler, input("Roughness"), NULL);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-07-24 15:36:36 +02:00
|
|
|
void SheenBsdfNode::compile(OSLCompiler &compiler)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2023-07-24 15:36:36 +02:00
|
|
|
compiler.parameter(this, "distribution");
|
|
|
|
|
compiler.add(this, "node_sheen_bsdf");
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Diffuse BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(DiffuseBsdfNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
closure = CLOSURE_BSDF_DIFFUSE_ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DiffuseBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2011-11-14 17:31:47 +00:00
|
|
|
BsdfNode::compile(compiler, input("Roughness"), NULL);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DiffuseBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_diffuse_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
/* Disney principled BSDF Closure */
|
|
|
|
|
NODE_DEFINE(PrincipledBsdfNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("principled_bsdf", create, NodeType::SHADER);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
static NodeEnum distribution_enum;
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
|
|
|
|
|
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
2017-04-18 11:43:09 +02:00
|
|
|
SOCKET_ENUM(
|
|
|
|
|
distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-02-08 16:19:04 +01:00
|
|
|
static NodeEnum subsurface_method_enum;
|
2021-10-07 17:27:22 +02:00
|
|
|
subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
2023-09-22 17:32:13 +02:00
|
|
|
subsurface_method_enum.insert("random_walk_skin", CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID);
|
2018-02-08 16:19:04 +01:00
|
|
|
SOCKET_ENUM(subsurface_method,
|
|
|
|
|
"Subsurface Method",
|
|
|
|
|
subsurface_method_enum,
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f))
|
2017-04-18 11:43:09 +02:00
|
|
|
SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
|
2023-09-25 14:43:12 +02:00
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
|
2023-12-04 21:12:29 +01:00
|
|
|
SOCKET_IN_FLOAT(ior, "IOR", 1.5f);
|
2023-09-25 14:43:12 +02:00
|
|
|
SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
|
|
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(subsurface_weight, "Subsurface Weight", 0.0f);
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
SOCKET_IN_FLOAT(subsurface_scale, "Subsurface Scale", 0.1f);
|
2017-04-18 11:43:09 +02:00
|
|
|
SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f));
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
SOCKET_IN_FLOAT(subsurface_ior, "Subsurface IOR", 1.4f);
|
|
|
|
|
SOCKET_IN_FLOAT(subsurface_anisotropy, "Subsurface Anisotropy", 0.0f);
|
2023-09-25 14:43:12 +02:00
|
|
|
|
2023-09-25 12:52:13 +02:00
|
|
|
SOCKET_IN_FLOAT(specular_ior_level, "Specular IOR Level", 0.0f);
|
2023-09-22 16:56:44 +02:00
|
|
|
SOCKET_IN_COLOR(specular_tint, "Specular Tint", one_float3());
|
2017-04-18 11:43:09 +02:00
|
|
|
SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
|
2023-09-25 14:43:12 +02:00
|
|
|
SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
|
|
|
|
|
SOCKET_IN_NORMAL(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(transmission_weight, "Transmission Weight", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(sheen_weight, "Sheen Weight", 0.0f);
|
2023-07-27 02:17:44 +02:00
|
|
|
SOCKET_IN_FLOAT(sheen_roughness, "Sheen Roughness", 0.5f);
|
|
|
|
|
SOCKET_IN_COLOR(sheen_tint, "Sheen Tint", one_float3());
|
2023-09-25 14:43:12 +02:00
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(coat_weight, "Coat Weight", 0.0f);
|
Cycles: Rework Principled BSDF Clearcoat
- Adds tint control, which simulates volumetric absorption inside the coating.
This results in angle-dependent saturation and affects all underlying layers
(diffuse, subsurface, metallic, transmission). It provides a physically-based
alternative to ad-hoc effects such as tinted specular highlights.
- Renames the component from "Clearcoat" to "Coat", since it's no longer
necessarily clear now. This matches naming in e.g. other renderers or OpenPBR.
- Adds an explicit Coat IOR input, in preparation for future smarter IOR logic
around the interaction between Coat and main IOR. This used to be hardcoded
to 1.5.
- Removes hardcoded 0.25 weight multiplier, and adds versioning code to update
existing files accordingly. OBJ import/export still applies the factor.
- Replaces the GTR1 microfacet component with regular GGX. This removes a corner
case in the Microfacet code, solves #53038, and makes us more consistent with
other standard surface shaders. The original Disney BSDF used GTR1, but it
doesn't appear that it caught on in the industry.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/110993
2023-09-13 00:03:11 +02:00
|
|
|
SOCKET_IN_FLOAT(coat_roughness, "Coat Roughness", 0.03f);
|
|
|
|
|
SOCKET_IN_FLOAT(coat_ior, "Coat IOR", 1.5f);
|
|
|
|
|
SOCKET_IN_COLOR(coat_tint, "Coat Tint", one_float3());
|
2023-09-25 14:43:12 +02:00
|
|
|
SOCKET_IN_NORMAL(coat_normal, "Coat Normal", zero_float3(), SocketType::LINK_NORMAL);
|
|
|
|
|
|
2023-09-22 17:05:47 +02:00
|
|
|
SOCKET_IN_COLOR(emission_color, "Emission Color", one_float3());
|
2023-09-13 03:05:27 +02:00
|
|
|
SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
|
2023-09-25 14:43:12 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type())
|
2017-04-18 11:43:09 +02:00
|
|
|
{
|
|
|
|
|
closure = CLOSURE_BSDF_PRINCIPLED_ID;
|
|
|
|
|
distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-13 03:05:27 +02:00
|
|
|
void PrincipledBsdfNode::simplify_settings(Scene * /* scene */)
|
2019-05-12 14:39:30 +02:00
|
|
|
{
|
2023-09-13 03:05:27 +02:00
|
|
|
if (!has_surface_emission()) {
|
|
|
|
|
/* Emission will be zero, so optimize away any connected emission input. */
|
2023-09-22 17:05:47 +02:00
|
|
|
ShaderInput *emission_in = input("Emission Color");
|
2023-09-13 03:05:27 +02:00
|
|
|
ShaderInput *strength_in = input("Emission Strength");
|
2020-11-16 19:28:58 +01:00
|
|
|
if (emission_in->link) {
|
|
|
|
|
emission_in->disconnect();
|
|
|
|
|
}
|
2023-09-13 03:05:27 +02:00
|
|
|
if (strength_in->link) {
|
|
|
|
|
strength_in->disconnect();
|
2020-11-16 19:28:58 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-09-13 03:05:27 +02:00
|
|
|
}
|
2019-05-12 14:39:30 +02:00
|
|
|
|
2023-09-13 03:05:27 +02:00
|
|
|
bool PrincipledBsdfNode::has_surface_transparent()
|
|
|
|
|
{
|
2019-05-12 14:39:30 +02:00
|
|
|
ShaderInput *alpha_in = input("Alpha");
|
2023-09-13 03:05:27 +02:00
|
|
|
return (alpha_in->link != NULL || alpha < (1.0f - CLOSURE_WEIGHT_CUTOFF));
|
|
|
|
|
}
|
2019-05-12 14:39:30 +02:00
|
|
|
|
2023-09-13 03:05:27 +02:00
|
|
|
bool PrincipledBsdfNode::has_surface_emission()
|
|
|
|
|
{
|
2023-09-22 17:05:47 +02:00
|
|
|
ShaderInput *emission_color_in = input("Emission Color");
|
2023-09-13 03:05:27 +02:00
|
|
|
ShaderInput *emission_strength_in = input("Emission Strength");
|
2023-09-22 17:05:47 +02:00
|
|
|
return (emission_color_in->link != NULL || reduce_max(emission_color) > CLOSURE_WEIGHT_CUTOFF) &&
|
2023-09-13 03:05:27 +02:00
|
|
|
(emission_strength_in->link != NULL || emission_strength > CLOSURE_WEIGHT_CUTOFF);
|
2019-05-12 14:39:30 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-12 04:36:46 -04:00
|
|
|
bool PrincipledBsdfNode::has_surface_bssrdf()
|
|
|
|
|
{
|
2023-09-25 14:43:12 +02:00
|
|
|
ShaderInput *subsurface_weight_in = input("Subsurface Weight");
|
|
|
|
|
ShaderInput *subsurface_scale_in = input("Subsurface Scale");
|
|
|
|
|
return (subsurface_weight_in->link != NULL || subsurface_weight > CLOSURE_WEIGHT_CUTOFF) &&
|
|
|
|
|
(subsurface_scale_in->link != NULL || subsurface_scale != 0.0f);
|
2017-07-12 04:36:46 -04:00
|
|
|
}
|
|
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link()) {
|
2017-04-18 11:43:09 +02:00
|
|
|
ShaderInput *tangent_in = input("Tangent");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!tangent_in->link) {
|
2017-04-18 11:43:09 +02:00
|
|
|
attributes->add(ATTR_STD_GENERATED);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2017-04-18 11:43:09 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
void PrincipledBsdfNode::compile(SVMCompiler &compiler)
|
2017-04-18 11:43:09 +02:00
|
|
|
{
|
|
|
|
|
ShaderInput *base_color_in = input("Base Color");
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
|
|
|
|
|
ShaderInput *p_metallic = input("Metallic");
|
2023-09-25 14:43:12 +02:00
|
|
|
ShaderInput *p_subsurface_weight = input("Subsurface Weight");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-13 03:05:27 +02:00
|
|
|
ShaderInput *emission_strength_in = input("Emission Strength");
|
|
|
|
|
ShaderInput *alpha_in = input("Alpha");
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
float3 weight = one_float3();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
int normal_offset = compiler.stack_assign_if_linked(input("Normal"));
|
|
|
|
|
int coat_normal_offset = compiler.stack_assign_if_linked(input("Coat Normal"));
|
|
|
|
|
int tangent_offset = compiler.stack_assign_if_linked(input("Tangent"));
|
2023-09-25 12:52:13 +02:00
|
|
|
int specular_ior_level_offset = compiler.stack_assign(input("Specular IOR Level"));
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
int roughness_offset = compiler.stack_assign(input("Roughness"));
|
|
|
|
|
int specular_tint_offset = compiler.stack_assign(input("Specular Tint"));
|
|
|
|
|
int anisotropic_offset = compiler.stack_assign(input("Anisotropic"));
|
2023-09-25 14:43:12 +02:00
|
|
|
int sheen_weight_offset = compiler.stack_assign(input("Sheen Weight"));
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
int sheen_roughness_offset = compiler.stack_assign(input("Sheen Roughness"));
|
|
|
|
|
int sheen_tint_offset = compiler.stack_assign(input("Sheen Tint"));
|
2023-09-25 14:43:12 +02:00
|
|
|
int coat_weight_offset = compiler.stack_assign(input("Coat Weight"));
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
int coat_roughness_offset = compiler.stack_assign(input("Coat Roughness"));
|
|
|
|
|
int coat_ior_offset = compiler.stack_assign(input("Coat IOR"));
|
|
|
|
|
int coat_tint_offset = compiler.stack_assign(input("Coat Tint"));
|
|
|
|
|
int ior_offset = compiler.stack_assign(input("IOR"));
|
2023-09-25 14:43:12 +02:00
|
|
|
int transmission_weight_offset = compiler.stack_assign(input("Transmission Weight"));
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
int anisotropic_rotation_offset = compiler.stack_assign(input("Anisotropic Rotation"));
|
|
|
|
|
int subsurface_radius_offset = compiler.stack_assign(input("Subsurface Radius"));
|
|
|
|
|
int subsurface_scale_offset = compiler.stack_assign(input("Subsurface Scale"));
|
|
|
|
|
int subsurface_ior_offset = compiler.stack_assign(input("Subsurface IOR"));
|
|
|
|
|
int subsurface_anisotropy_offset = compiler.stack_assign(input("Subsurface Anisotropy"));
|
2023-09-13 03:05:27 +02:00
|
|
|
int alpha_offset = compiler.stack_assign_if_linked(alpha_in);
|
|
|
|
|
int emission_strength_offset = compiler.stack_assign_if_linked(emission_strength_in);
|
2023-09-22 17:05:47 +02:00
|
|
|
int emission_color_offset = compiler.stack_assign(input("Emission Color"));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-25 14:43:12 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CLOSURE_BSDF,
|
|
|
|
|
compiler.encode_uchar4(closure,
|
|
|
|
|
compiler.stack_assign(p_metallic),
|
|
|
|
|
compiler.stack_assign(p_subsurface_weight),
|
|
|
|
|
compiler.closure_mix_weight_offset()),
|
|
|
|
|
__float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
|
|
|
|
|
__float_as_int((p_subsurface_weight) ? get_float(p_subsurface_weight->socket_type) : 0.0f));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
normal_offset,
|
|
|
|
|
tangent_offset,
|
|
|
|
|
compiler.encode_uchar4(
|
2023-09-25 12:52:13 +02:00
|
|
|
specular_ior_level_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
|
2023-09-25 14:43:12 +02:00
|
|
|
compiler.encode_uchar4(sheen_weight_offset, sheen_tint_offset, sheen_roughness_offset));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-22 04:16:49 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
compiler.encode_uchar4(
|
2023-09-25 14:43:12 +02:00
|
|
|
ior_offset, transmission_weight_offset, anisotropic_rotation_offset, coat_normal_offset),
|
2023-07-22 04:16:49 +02:00
|
|
|
distribution,
|
|
|
|
|
subsurface_method,
|
Cycles: Rework Principled BSDF Clearcoat
- Adds tint control, which simulates volumetric absorption inside the coating.
This results in angle-dependent saturation and affects all underlying layers
(diffuse, subsurface, metallic, transmission). It provides a physically-based
alternative to ad-hoc effects such as tinted specular highlights.
- Renames the component from "Clearcoat" to "Coat", since it's no longer
necessarily clear now. This matches naming in e.g. other renderers or OpenPBR.
- Adds an explicit Coat IOR input, in preparation for future smarter IOR logic
around the interaction between Coat and main IOR. This used to be hardcoded
to 1.5.
- Removes hardcoded 0.25 weight multiplier, and adds versioning code to update
existing files accordingly. OBJ import/export still applies the factor.
- Replaces the GTR1 microfacet component with regular GGX. This removes a corner
case in the Microfacet code, solves #53038, and makes us more consistent with
other standard surface shaders. The original Disney BSDF used GTR1, but it
doesn't appear that it caught on in the industry.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/110993
2023-09-13 00:03:11 +02:00
|
|
|
compiler.encode_uchar4(
|
2023-09-25 14:43:12 +02:00
|
|
|
coat_weight_offset, coat_roughness_offset, coat_ior_offset, coat_tint_offset));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
float3 bc_default = get_float3(base_color_in->socket_type);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID),
|
|
|
|
|
__float_as_int(bc_default.x),
|
|
|
|
|
__float_as_int(bc_default.y),
|
|
|
|
|
__float_as_int(bc_default.z));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
compiler.add_node(subsurface_ior_offset,
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
subsurface_radius_offset,
|
Cycles: Tweak Principled BSDF Subsurface parameters
Previously, the Principled BSDF used the Subsurface input to scale the radius.
When it was zero, it used a diffuse closure, otherwise a subsurface closure.
This sort of scaling input makes sense, but it should be specified in distance
units, rather than a 0..1 factor, so this commit changes the unit and renames
the input to Subsurface Scale.
Additionally, it adds support for mixing diffuse and subsurface components.
This is part of e.g. the OpenPBR spec, and the logic behind it is to support
modeling e.g. dirt or paint on top of skin. Before, materials would be either
fully diffuse (radius=0) or fully subsurface.
For typical materials, this mixing factor will be either zero or one
(just like metallic or transmission), but supporting fractional inputs makes
sense for e.g. smooth transitions at boundaries.
Another change is that there is no separate Subsurface Color anymore - before,
this was mixed with the Base Color using the Subsurface input as the factor,
but this was not really useful since that input was generally very small.
And finally, the handling of how the path enters the material for random walk
subsurface scattering is changed. Before, this always used lambertian (diffuse)
transmission, but this caused some problems, like overly white edges.
Instead, two different methods are now used, depending on the selected mode.
In Fixed Radius mode, the code assumes a simple medium boundary, and performs
refraction into the material using the main Roughness and IOR inputs.
Meanwhile, when not using Fixed Radius, the code assumes a more complex
boundary (as typically found on organic materials, e.g. skin), so the entry
bounce has a 50/50 chance of being either diffuse transmission or refraction
using the separate Subsurface IOR input and a fixed roughness of 1.
Credit for this method goes to Christophe Hery.
Pull Request: https://projects.blender.org/blender/blender/pulls/110989
2023-09-13 02:45:33 +02:00
|
|
|
subsurface_scale_offset,
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
subsurface_anisotropy_offset);
|
2023-09-13 03:05:27 +02:00
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
compiler.encode_uchar4(
|
2023-09-22 17:05:47 +02:00
|
|
|
alpha_offset, emission_strength_offset, emission_color_offset, SVM_STACK_INVALID),
|
2023-09-13 03:05:27 +02:00
|
|
|
__float_as_int(get_float(alpha_in->socket_type)),
|
|
|
|
|
__float_as_int(get_float(emission_strength_in->socket_type)),
|
|
|
|
|
SVM_STACK_INVALID);
|
2017-04-18 11:43:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PrincipledBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "distribution");
|
2018-02-08 16:19:04 +01:00
|
|
|
compiler.parameter(this, "subsurface_method");
|
2017-04-18 11:43:09 +02:00
|
|
|
compiler.add(this, "node_principled_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PrincipledBsdfNode::has_bssrdf_bump()
|
|
|
|
|
{
|
2017-08-20 03:25:13 +02:00
|
|
|
return has_surface_bssrdf() && has_bump();
|
2017-04-18 11:43:09 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Translucent BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(TranslucentBsdfNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
closure = CLOSURE_BSDF_TRANSLUCENT_ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TranslucentBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
BsdfNode::compile(compiler, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TranslucentBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_translucent_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Transparent BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(TransparentBsdfNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", one_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
closure = CLOSURE_BSDF_TRANSPARENT_ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TransparentBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
BsdfNode::compile(compiler, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TransparentBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_transparent_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-01 20:26:52 +00:00
|
|
|
/* Subsurface Scattering Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(SubsurfaceScatteringNode)
|
2013-08-18 14:15:57 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
|
2013-08-18 14:15:57 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2013-08-18 14:15:57 +00:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
static NodeEnum method_enum;
|
2021-10-07 17:27:22 +02:00
|
|
|
method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
2023-09-22 17:32:13 +02:00
|
|
|
method_enum.insert("random_walk_skin", CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID);
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
SOCKET_ENUM(method, "Method", method_enum, CLOSURE_BSSRDF_RANDOM_WALK_ID);
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
|
|
|
|
|
SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(subsurface_ior, "IOR", 1.4f);
|
|
|
|
|
SOCKET_IN_FLOAT(subsurface_anisotropy, "Anisotropy", 0.0f);
|
2013-08-18 14:15:57 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2013-08-18 14:15:57 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(get_node_type())
|
2013-04-01 20:26:52 +00:00
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
closure = method;
|
2013-04-01 20:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubsurfaceScatteringNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
closure = method;
|
|
|
|
|
BsdfNode::compile(compiler, input("Scale"), input("IOR"), input("Radius"), input("Anisotropy"));
|
2013-04-01 20:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SubsurfaceScatteringNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
closure = method;
|
|
|
|
|
compiler.parameter(this, "method");
|
2013-04-01 20:26:52 +00:00
|
|
|
compiler.add(this, "node_subsurface_scattering");
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-18 14:15:57 +00:00
|
|
|
bool SubsurfaceScatteringNode::has_bssrdf_bump()
|
|
|
|
|
{
|
|
|
|
|
/* detect if anything is plugged into the normal input besides the default */
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
return (normal_in->link &&
|
|
|
|
|
normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Emissive Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(EmissionNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("emission", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
2016-07-27 14:04:28 +02:00
|
|
|
SOCKET_IN_FLOAT(strength, "Strength", 10.0f);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(emission, "Emission");
|
2012-11-26 21:59:41 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
EmissionNode::EmissionNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void EmissionNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
|
|
|
|
|
if (color_in->link || strength_in->link) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
2016-07-27 14:04:28 +02:00
|
|
|
NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-09-12 13:13:56 +00:00
|
|
|
|
|
|
|
|
compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EmissionNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_emission");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void EmissionNode::constant_fold(const ConstantFolder &folder)
|
2016-05-02 00:05:16 +02:00
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
if ((!color_in->link && color == zero_float3()) || (!strength_in->link && strength == 0.0f)) {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.discard();
|
|
|
|
|
}
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Background Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(BackgroundNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("background_shader", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
|
|
|
|
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(background, "Background");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2012-11-26 21:59:41 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
BackgroundNode::BackgroundNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void BackgroundNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
|
|
|
|
|
if (color_in->link || strength_in->link) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
2016-12-06 15:36:35 +01:00
|
|
|
NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-09-12 13:13:56 +00:00
|
|
|
|
2011-10-19 00:13:41 +00:00
|
|
|
compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BackgroundNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_background");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void BackgroundNode::constant_fold(const ConstantFolder &folder)
|
2016-05-02 00:05:16 +02:00
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
if ((!color_in->link && color == zero_float3()) || (!strength_in->link && strength == 0.0f)) {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.discard();
|
|
|
|
|
}
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
|
2011-08-28 13:55:59 +00:00
|
|
|
/* Holdout Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(HoldoutNode)
|
2011-08-28 13:55:59 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("holdout", create, NodeType::SHADER);
|
2012-11-26 21:59:41 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(holdout, "Holdout");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
HoldoutNode::HoldoutNode() : ShaderNode(get_node_type()) {}
|
2011-08-28 13:55:59 +00:00
|
|
|
|
|
|
|
|
void HoldoutNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2021-02-17 01:47:18 +01:00
|
|
|
float3 value = one_float3();
|
2012-11-30 18:55:04 +00:00
|
|
|
|
|
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value);
|
2011-09-12 13:13:56 +00:00
|
|
|
compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset());
|
2011-08-28 13:55:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HoldoutNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_holdout");
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
/* Ambient Occlusion */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(AmbientOcclusionNode)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
|
2012-11-26 21:59:41 +00:00
|
|
|
|
2018-06-29 15:02:09 +02:00
|
|
|
SOCKET_INT(samples, "Samples", 16);
|
2018-06-15 11:03:29 +02:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", one_float3());
|
2018-06-15 11:03:29 +02:00
|
|
|
SOCKET_IN_FLOAT(distance, "Distance", 1.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2018-06-15 11:03:29 +02:00
|
|
|
SOCKET_BOOLEAN(inside, "Inside", false);
|
2018-06-29 15:02:09 +02:00
|
|
|
SOCKET_BOOLEAN(only_local, "Only Local", false);
|
2018-06-15 11:03:29 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(ao, "AO");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(get_node_type()) {}
|
2012-11-06 19:59:02 +00:00
|
|
|
|
|
|
|
|
void AmbientOcclusionNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
2018-06-15 11:03:29 +02:00
|
|
|
ShaderInput *distance_in = input("Distance");
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *ao_out = output("AO");
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2018-06-15 11:03:29 +02:00
|
|
|
int flags = (inside ? NODE_AO_INSIDE : 0) | (only_local ? NODE_AO_ONLY_LOCAL : 0);
|
|
|
|
|
|
2018-08-24 14:36:18 +02:00
|
|
|
if (!distance_in->link && distance == 0.0f) {
|
2018-06-15 11:03:29 +02:00
|
|
|
flags |= NODE_AO_GLOBAL_RADIUS;
|
|
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2018-06-15 11:03:29 +02:00
|
|
|
compiler.add_node(NODE_AMBIENT_OCCLUSION,
|
|
|
|
|
compiler.encode_uchar4(flags,
|
|
|
|
|
compiler.stack_assign_if_linked(distance_in),
|
|
|
|
|
compiler.stack_assign_if_linked(normal_in),
|
|
|
|
|
compiler.stack_assign(ao_out)),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(color_out),
|
|
|
|
|
samples),
|
|
|
|
|
__float_as_uint(distance));
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AmbientOcclusionNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2018-06-15 11:03:29 +02:00
|
|
|
compiler.parameter(this, "samples");
|
|
|
|
|
compiler.parameter(this, "inside");
|
|
|
|
|
compiler.parameter(this, "only_local");
|
2012-11-06 19:59:02 +00:00
|
|
|
compiler.add(this, "node_ambient_occlusion");
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-27 20:03:16 +00:00
|
|
|
/* Volume Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
VolumeNode::VolumeNode(const NodeType *node_type) : ShaderNode(node_type)
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
2013-12-28 01:54:44 +01:00
|
|
|
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VolumeNode::compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (color_in->link) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2011-09-27 20:03:16 +00:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CLOSURE_VOLUME,
|
|
|
|
|
compiler.encode_uchar4(closure,
|
2016-05-02 20:12:42 +02:00
|
|
|
(param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
|
|
|
|
|
(param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
|
2011-09-27 20:03:16 +00:00
|
|
|
compiler.closure_mix_weight_offset()),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
|
|
|
|
|
__float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VolumeNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compile(compiler, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:47:55 +05:00
|
|
|
void VolumeNode::compile(OSLCompiler & /*compiler*/)
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
/* Absorption Volume Closure */
|
2011-09-27 20:03:16 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(AbsorptionVolumeNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("absorption_volume", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
|
|
|
|
SOCKET_IN_FLOAT(density, "Density", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(volume, "Volume");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(get_node_type())
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
2013-12-28 01:54:44 +01:00
|
|
|
closure = CLOSURE_VOLUME_ABSORPTION_ID;
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
void AbsorptionVolumeNode::compile(SVMCompiler &compiler)
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
|
|
|
|
VolumeNode::compile(compiler, input("Density"), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
void AbsorptionVolumeNode::compile(OSLCompiler &compiler)
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
2013-12-28 01:54:44 +01:00
|
|
|
compiler.add(this, "node_absorption_volume");
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
/* Scatter Volume Closure */
|
2011-09-27 20:03:16 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ScatterVolumeNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("scatter_volume", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
|
|
|
|
SOCKET_IN_FLOAT(density, "Density", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(volume, "Volume");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(get_node_type())
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
2013-12-28 01:54:44 +01:00
|
|
|
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
void ScatterVolumeNode::compile(SVMCompiler &compiler)
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
2013-12-28 01:54:44 +01:00
|
|
|
VolumeNode::compile(compiler, input("Density"), input("Anisotropy"));
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
void ScatterVolumeNode::compile(OSLCompiler &compiler)
|
2011-09-27 20:03:16 +00:00
|
|
|
{
|
2013-12-28 01:54:44 +01:00
|
|
|
compiler.add(this, "node_scatter_volume");
|
2011-09-27 20:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
/* Principled Volume Closure */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(PrincipledVolumeNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("principled_volume", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring());
|
|
|
|
|
SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring());
|
|
|
|
|
SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring());
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f));
|
|
|
|
|
SOCKET_IN_FLOAT(density, "Density", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(absorption_color, "Absorption Color", zero_float3());
|
2018-01-30 15:05:19 +01:00
|
|
|
SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(emission_color, "Emission Color", one_float3());
|
2018-01-30 15:05:19 +01:00
|
|
|
SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", one_float3());
|
2020-03-11 17:49:00 +01:00
|
|
|
SOCKET_IN_FLOAT(temperature, "Temperature", 1000.0f);
|
2018-01-30 15:05:19 +01:00
|
|
|
SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(volume, "Volume");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(get_node_type())
|
2018-01-30 15:05:19 +01:00
|
|
|
{
|
|
|
|
|
closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
|
2020-03-11 17:49:00 +01:00
|
|
|
density_attribute = ustring("density");
|
|
|
|
|
temperature_attribute = ustring("temperature");
|
2018-01-30 15:05:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
|
|
|
|
if (shader->has_volume) {
|
|
|
|
|
ShaderInput *density_in = input("Density");
|
|
|
|
|
ShaderInput *blackbody_in = input("Blackbody Intensity");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
if (density_in->link || density > 0.0f) {
|
|
|
|
|
attributes->add_standard(density_attribute);
|
|
|
|
|
attributes->add_standard(color_attribute);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
if (blackbody_in->link || blackbody_intensity > 0.0f) {
|
|
|
|
|
attributes->add_standard(temperature_attribute);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
void PrincipledVolumeNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *density_in = input("Density");
|
|
|
|
|
ShaderInput *anisotropy_in = input("Anisotropy");
|
|
|
|
|
ShaderInput *absorption_color_in = input("Absorption Color");
|
|
|
|
|
ShaderInput *emission_in = input("Emission Strength");
|
|
|
|
|
ShaderInput *emission_color_in = input("Emission Color");
|
|
|
|
|
ShaderInput *blackbody_in = input("Blackbody Intensity");
|
|
|
|
|
ShaderInput *blackbody_tint_in = input("Blackbody Tint");
|
|
|
|
|
ShaderInput *temperature_in = input("Temperature");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (color_in->link) {
|
2018-01-30 15:05:19 +01:00
|
|
|
compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2018-01-30 15:05:19 +01:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
compiler.add_node(NODE_PRINCIPLED_VOLUME,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(density_in),
|
|
|
|
|
compiler.stack_assign_if_linked(anisotropy_in),
|
|
|
|
|
compiler.stack_assign(absorption_color_in),
|
|
|
|
|
compiler.closure_mix_weight_offset()),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(emission_in),
|
|
|
|
|
compiler.stack_assign(emission_color_in),
|
|
|
|
|
compiler.stack_assign_if_linked(blackbody_in),
|
|
|
|
|
compiler.stack_assign(temperature_in)),
|
|
|
|
|
compiler.stack_assign(blackbody_tint_in));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
int attr_density = compiler.attribute_standard(density_attribute);
|
|
|
|
|
int attr_color = compiler.attribute_standard(color_attribute);
|
|
|
|
|
int attr_temperature = compiler.attribute_standard(temperature_attribute);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
compiler.add_node(__float_as_int(density),
|
|
|
|
|
__float_as_int(anisotropy),
|
|
|
|
|
__float_as_int(emission_strength),
|
|
|
|
|
__float_as_int(blackbody_intensity));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
compiler.add_node(attr_density, attr_color, attr_temperature);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
void PrincipledVolumeNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
if (Attribute::name_standard(density_attribute.c_str())) {
|
|
|
|
|
density_attribute = ustring("geom:" + density_attribute.string());
|
|
|
|
|
}
|
|
|
|
|
if (Attribute::name_standard(color_attribute.c_str())) {
|
|
|
|
|
color_attribute = ustring("geom:" + color_attribute.string());
|
|
|
|
|
}
|
|
|
|
|
if (Attribute::name_standard(temperature_attribute.c_str())) {
|
|
|
|
|
temperature_attribute = ustring("geom:" + temperature_attribute.string());
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-30 15:05:19 +01:00
|
|
|
compiler.add(this, "node_principled_volume");
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
/* Principled Hair BSDF Closure */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(PrincipledHairBsdfNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER);
|
|
|
|
|
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
/* Scattering models. */
|
|
|
|
|
static NodeEnum model_enum;
|
|
|
|
|
model_enum.insert("Chiang", NODE_PRINCIPLED_HAIR_CHIANG);
|
|
|
|
|
model_enum.insert("Huang", NODE_PRINCIPLED_HAIR_HUANG);
|
|
|
|
|
SOCKET_ENUM(model, "Model", model_enum, NODE_PRINCIPLED_HAIR_HUANG);
|
|
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
/* Color parametrization specified as enum. */
|
|
|
|
|
static NodeEnum parametrization_enum;
|
|
|
|
|
parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE);
|
|
|
|
|
parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
|
|
|
|
|
parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
|
|
|
|
|
SOCKET_ENUM(
|
|
|
|
|
parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE);
|
|
|
|
|
|
|
|
|
|
/* Initialize sockets to their default values. */
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f));
|
|
|
|
|
SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f);
|
|
|
|
|
SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f);
|
|
|
|
|
SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f));
|
2023-06-05 12:14:20 +12:00
|
|
|
SOCKET_IN_VECTOR(
|
|
|
|
|
absorption_coefficient, "Absorption Coefficient", make_float3(0.245531f, 0.52f, 1.365f));
|
2018-07-18 11:14:43 +02:00
|
|
|
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
SOCKET_IN_FLOAT(aspect_ratio, "Aspect Ratio", 0.85f);
|
|
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
SOCKET_IN_FLOAT(offset, "Offset", 2.f * M_PI_F / 180.f);
|
|
|
|
|
SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f);
|
|
|
|
|
SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f);
|
|
|
|
|
SOCKET_IN_FLOAT(coat, "Coat", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(ior, "IOR", 1.55f);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(random, "Random", 0.0f);
|
|
|
|
|
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
SOCKET_IN_FLOAT(R, "R lobe", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(TT, "TT lobe", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(TRT, "TRT lobe", 1.0f);
|
|
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
|
2018-07-18 11:14:43 +02:00
|
|
|
{
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
closure = CLOSURE_BSDF_HAIR_HUANG_ID;
|
2018-07-18 11:14:43 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-12 13:30:53 +01:00
|
|
|
/* Treat hair as transparent if the hit is outside of the projected width. */
|
|
|
|
|
bool PrincipledHairBsdfNode::has_surface_transparent()
|
2018-07-18 11:14:43 +02:00
|
|
|
{
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
if (model == NODE_PRINCIPLED_HAIR_HUANG) {
|
|
|
|
|
if (aspect_ratio != 1.0f || input("Aspect Ratio")->link) {
|
2023-12-12 13:30:53 +01:00
|
|
|
return true;
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-12-12 13:30:53 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
|
|
|
|
if (has_surface_transparent()) {
|
|
|
|
|
/* Make sure we have the normal for elliptical cross section tracking. */
|
|
|
|
|
attributes->add(ATTR_STD_VERTEX_NORMAL);
|
|
|
|
|
}
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
if (!input("Random")->link) {
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
/* Enable retrieving Hair Info -> Random if Random isn't linked. */
|
2018-07-18 11:14:43 +02:00
|
|
|
attributes->add(ATTR_STD_CURVE_RANDOM);
|
|
|
|
|
}
|
|
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prepares the input data for the SVM shader. */
|
|
|
|
|
void PrincipledHairBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
closure = (model == NODE_PRINCIPLED_HAIR_HUANG) ? CLOSURE_BSDF_HAIR_HUANG_ID :
|
|
|
|
|
CLOSURE_BSDF_HAIR_CHIANG_ID;
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, one_float3());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
ShaderInput *roughness_in = input("Roughness");
|
|
|
|
|
ShaderInput *radial_roughness_in = input("Radial Roughness");
|
|
|
|
|
ShaderInput *random_roughness_in = input("Random Roughness");
|
|
|
|
|
ShaderInput *offset_in = input("Offset");
|
|
|
|
|
ShaderInput *coat_in = input("Coat");
|
|
|
|
|
ShaderInput *ior_in = input("IOR");
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
ShaderInput *melanin_in = input("Melanin");
|
|
|
|
|
ShaderInput *melanin_redness_in = input("Melanin Redness");
|
|
|
|
|
ShaderInput *random_color_in = input("Random Color");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
ShaderInput *R_in = input("R lobe");
|
|
|
|
|
ShaderInput *TT_in = input("TT lobe");
|
|
|
|
|
ShaderInput *TRT_in = input("TRT lobe");
|
|
|
|
|
|
|
|
|
|
ShaderInput *aspect_ratio_in = input("Aspect Ratio");
|
|
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
int color_ofs = compiler.stack_assign(input("Color"));
|
|
|
|
|
int tint_ofs = compiler.stack_assign(input("Tint"));
|
|
|
|
|
int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient"));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
int roughness_ofs = compiler.stack_assign_if_linked(roughness_in);
|
|
|
|
|
int radial_roughness_ofs = compiler.stack_assign_if_linked(radial_roughness_in);
|
|
|
|
|
|
|
|
|
|
int offset_ofs = compiler.stack_assign_if_linked(offset_in);
|
|
|
|
|
int ior_ofs = compiler.stack_assign_if_linked(ior_in);
|
|
|
|
|
|
|
|
|
|
int coat_ofs = compiler.stack_assign_if_linked(coat_in);
|
|
|
|
|
int melanin_ofs = compiler.stack_assign_if_linked(melanin_in);
|
|
|
|
|
int melanin_redness_ofs = compiler.stack_assign_if_linked(melanin_redness_in);
|
|
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
ShaderInput *random_in = input("Random");
|
|
|
|
|
int attr_random = random_in->link ? SVM_STACK_INVALID :
|
|
|
|
|
compiler.attribute(ATTR_STD_CURVE_RANDOM);
|
2021-11-18 09:21:47 +01:00
|
|
|
int random_in_ofs = compiler.stack_assign_if_linked(random_in);
|
|
|
|
|
int random_color_ofs = compiler.stack_assign_if_linked(random_color_in);
|
|
|
|
|
int random_roughness_ofs = compiler.stack_assign_if_linked(random_roughness_in);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-18 11:14:43 +02:00
|
|
|
/* Encode all parameters into data nodes. */
|
2021-11-18 09:21:47 +01:00
|
|
|
/* node */
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_CLOSURE_BSDF,
|
|
|
|
|
/* Socket IDs can be packed 4 at a time into a single data packet */
|
|
|
|
|
compiler.encode_uchar4(
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
closure, roughness_ofs, random_roughness_ofs, compiler.closure_mix_weight_offset()),
|
2021-11-18 09:21:47 +01:00
|
|
|
/* The rest are stored as unsigned integers */
|
|
|
|
|
__float_as_uint(roughness),
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
__float_as_uint(random_roughness));
|
|
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
/* data node */
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
compiler.add_node(SVM_STACK_INVALID,
|
2021-11-18 09:21:47 +01:00
|
|
|
compiler.encode_uchar4(offset_ofs, ior_ofs, color_ofs, parametrization),
|
2018-07-18 11:14:43 +02:00
|
|
|
__float_as_uint(offset),
|
|
|
|
|
__float_as_uint(ior));
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
/* data node 2 */
|
|
|
|
|
compiler.add_node(compiler.encode_uchar4(
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
tint_ofs, melanin_ofs, melanin_redness_ofs, absorption_coefficient_ofs),
|
|
|
|
|
attr_random,
|
2018-07-18 11:14:43 +02:00
|
|
|
__float_as_uint(melanin),
|
|
|
|
|
__float_as_uint(melanin_redness));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
/* data node 3 */
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
if (model == NODE_PRINCIPLED_HAIR_HUANG) {
|
|
|
|
|
compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(aspect_ratio_in),
|
|
|
|
|
random_in_ofs,
|
|
|
|
|
random_color_ofs,
|
|
|
|
|
compiler.attribute(ATTR_STD_VERTEX_NORMAL)),
|
|
|
|
|
__float_as_uint(random),
|
|
|
|
|
__float_as_uint(random_color),
|
|
|
|
|
__float_as_uint(aspect_ratio));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
compiler.encode_uchar4(coat_ofs, random_in_ofs, random_color_ofs, radial_roughness_ofs),
|
|
|
|
|
__float_as_uint(random),
|
|
|
|
|
__float_as_uint(random_color),
|
|
|
|
|
__float_as_uint(coat));
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-11-18 09:21:47 +01:00
|
|
|
/* data node 4 */
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(R_in),
|
|
|
|
|
compiler.stack_assign_if_linked(TT_in),
|
|
|
|
|
compiler.stack_assign_if_linked(TRT_in),
|
|
|
|
|
SVM_STACK_INVALID),
|
|
|
|
|
__float_as_uint(model == NODE_PRINCIPLED_HAIR_HUANG ? R : radial_roughness),
|
|
|
|
|
__float_as_uint(TT),
|
|
|
|
|
__float_as_uint(TRT));
|
2018-07-18 11:14:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prepares the input data for the OSL shader. */
|
|
|
|
|
void PrincipledHairBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
compiler.parameter(this, "model");
|
2018-07-18 11:14:43 +02:00
|
|
|
compiler.parameter(this, "parametrization");
|
|
|
|
|
compiler.add(this, "node_principled_hair_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-15 23:58:00 +00:00
|
|
|
/* Hair BSDF Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(HairBsdfNode)
|
2013-09-15 23:58:00 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
|
2013-09-15 23:58:00 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
|
|
|
|
|
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
|
2013-09-15 23:58:00 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum component_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
|
|
|
|
|
component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
|
|
|
|
|
SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
|
|
|
|
|
SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3());
|
2013-09-15 23:58:00 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2013-09-15 23:58:00 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
HairBsdfNode::HairBsdfNode() : BsdfNode(get_node_type())
|
2013-09-15 23:58:00 +00:00
|
|
|
{
|
2015-05-09 18:53:57 +05:00
|
|
|
closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
|
2013-09-15 23:58:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HairBsdfNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
closure = component;
|
2013-09-15 23:58:00 +00:00
|
|
|
|
|
|
|
|
BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HairBsdfNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "component");
|
2013-09-15 23:58:00 +00:00
|
|
|
compiler.add(this, "node_hair_bsdf");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Geometry */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(GeometryNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("geometry", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_POINT(position, "Position");
|
|
|
|
|
SOCKET_OUT_NORMAL(normal, "Normal");
|
|
|
|
|
SOCKET_OUT_NORMAL(tangent, "Tangent");
|
|
|
|
|
SOCKET_OUT_NORMAL(true_normal, "True Normal");
|
|
|
|
|
SOCKET_OUT_VECTOR(incoming, "Incoming");
|
|
|
|
|
SOCKET_OUT_POINT(parametric, "Parametric");
|
|
|
|
|
SOCKET_OUT_FLOAT(backfacing, "Backfacing");
|
|
|
|
|
SOCKET_OUT_FLOAT(pointiness, "Pointiness");
|
2019-11-27 12:07:20 +02:00
|
|
|
SOCKET_OUT_FLOAT(random_per_island, "Random Per Island");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
GeometryNode::GeometryNode() : ShaderNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-08-18 14:15:57 +00:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2012-10-10 13:02:20 +00:00
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link()) {
|
2015-02-06 12:35:46 +05:00
|
|
|
if (!output("Tangent")->links.empty()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED);
|
2015-02-06 12:35:46 +05:00
|
|
|
}
|
|
|
|
|
if (!output("Pointiness")->links.empty()) {
|
|
|
|
|
attributes->add(ATTR_STD_POINTINESS);
|
|
|
|
|
}
|
2019-11-27 12:07:20 +02:00
|
|
|
if (!output("Random Per Island")->links.empty()) {
|
|
|
|
|
attributes->add(ATTR_STD_RANDOM_PER_ISLAND);
|
|
|
|
|
}
|
2013-12-31 17:30:34 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2012-10-10 13:02:20 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void GeometryNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out;
|
2016-05-07 19:47:37 +02:00
|
|
|
ShaderNodeType geom_node = NODE_GEOMETRY;
|
|
|
|
|
ShaderNodeType attr_node = NODE_ATTR;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-02-21 12:55:19 +01:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2011-04-27 11:58:34 +00:00
|
|
|
geom_node = NODE_GEOMETRY_BUMP_DX;
|
2015-02-21 12:55:19 +01:00
|
|
|
attr_node = NODE_ATTR_BUMP_DX;
|
|
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2011-04-27 11:58:34 +00:00
|
|
|
geom_node = NODE_GEOMETRY_BUMP_DY;
|
2015-02-21 12:55:19 +01:00
|
|
|
attr_node = NODE_ATTR_BUMP_DY;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Position");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Normal");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Tangent");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("True Normal");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Incoming");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-05-04 15:22:15 +00:00
|
|
|
out = output("Parametric");
|
2011-04-27 11:58:34 +00:00
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Backfacing");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-02-06 12:35:46 +05:00
|
|
|
out = output("Pointiness");
|
|
|
|
|
if (!out->links.empty()) {
|
2015-04-06 14:11:28 +05:00
|
|
|
if (compiler.output_type() != SHADER_TYPE_VOLUME) {
|
|
|
|
|
compiler.add_node(
|
2020-10-26 18:32:48 +01:00
|
|
|
attr_node, ATTR_STD_POINTINESS, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
2015-04-06 14:11:28 +05:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
|
2015-04-06 14:11:28 +05:00
|
|
|
}
|
2015-02-06 12:35:46 +05:00
|
|
|
}
|
2019-11-27 12:07:20 +02:00
|
|
|
|
|
|
|
|
out = output("Random Per Island");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
if (compiler.output_type() != SHADER_TYPE_VOLUME) {
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(attr_node,
|
|
|
|
|
ATTR_STD_RANDOM_PER_ISLAND,
|
|
|
|
|
compiler.stack_assign(out),
|
|
|
|
|
NODE_ATTR_OUTPUT_FLOAT);
|
2019-11-27 12:07:20 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void GeometryNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "dx");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "dy");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "center");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_geometry");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TextureCoordinate */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(TextureCoordinateNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
|
|
|
|
|
SOCKET_BOOLEAN(use_transform, "Use Transform", false);
|
|
|
|
|
SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
|
2012-10-05 14:54:32 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_POINT(generated, "Generated");
|
|
|
|
|
SOCKET_OUT_NORMAL(normal, "Normal");
|
|
|
|
|
SOCKET_OUT_POINT(UV, "UV");
|
|
|
|
|
SOCKET_OUT_POINT(object, "Object");
|
|
|
|
|
SOCKET_OUT_POINT(camera, "Camera");
|
|
|
|
|
SOCKET_OUT_POINT(window, "Window");
|
|
|
|
|
SOCKET_OUT_NORMAL(reflection, "Reflection");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
if (!from_dupli) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output("Generated")->links.empty()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("UV")->links.empty()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_UV);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-12-31 17:30:34 +01:00
|
|
|
}
|
2012-10-06 11:52:54 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-31 17:33:55 +01:00
|
|
|
if (shader->has_volume) {
|
|
|
|
|
if (!from_dupli) {
|
2014-03-29 13:03:48 +01:00
|
|
|
if (!output("Generated")->links.empty()) {
|
2013-12-31 17:33:55 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
|
2014-03-29 13:03:48 +01:00
|
|
|
}
|
2013-12-31 17:33:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void TextureCoordinateNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out;
|
2016-05-07 19:47:37 +02:00
|
|
|
ShaderNodeType texco_node = NODE_TEX_COORD;
|
|
|
|
|
ShaderNodeType attr_node = NODE_ATTR;
|
|
|
|
|
ShaderNodeType geom_node = NODE_GEOMETRY;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
|
|
|
|
texco_node = NODE_TEX_COORD_BUMP_DX;
|
|
|
|
|
attr_node = NODE_ATTR_BUMP_DX;
|
|
|
|
|
geom_node = NODE_GEOMETRY_BUMP_DX;
|
|
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
|
|
|
|
texco_node = NODE_TEX_COORD_BUMP_DY;
|
|
|
|
|
attr_node = NODE_ATTR_BUMP_DY;
|
|
|
|
|
geom_node = NODE_GEOMETRY_BUMP_DY;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Generated");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
if (compiler.background) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-04 21:40:39 +00:00
|
|
|
if (from_dupli) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
|
2012-10-04 21:40:39 +00:00
|
|
|
}
|
2013-12-31 17:33:55 +01:00
|
|
|
else if (compiler.output_type() == SHADER_TYPE_VOLUME) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
|
2013-12-31 17:33:55 +01:00
|
|
|
}
|
2012-10-04 21:40:39 +00:00
|
|
|
else {
|
|
|
|
|
int attr = compiler.attribute(ATTR_STD_GENERATED);
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
|
2012-10-04 21:40:39 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: merging features from tomato branch.
=== BVH build time optimizations ===
* BVH building was multithreaded. Not all building is multithreaded, packing
and the initial bounding/splitting is still single threaded, but recursive
splitting is, which was the main bottleneck.
* Object splitting now uses binning rather than sorting of all elements, using
code from the Embree raytracer from Intel.
http://software.intel.com/en-us/articles/embree-photo-realistic-ray-tracing-kernels/
* Other small changes to avoid allocations, pack memory more tightly, avoid
some unnecessary operations, ...
These optimizations do not work yet when Spatial Splits are enabled, for that
more work is needed. There's also other optimizations still needed, in
particular for the case of many low poly objects, the packing step and node
memory allocation.
BVH raytracing time should remain about the same, but BVH build time should be
significantly reduced, test here show speedup of about 5x to 10x on a dual core
and 5x to 25x on an 8-core machine, depending on the scene.
=== Threads ===
Centralized task scheduler for multithreading, which is basically the
CPU device threading code wrapped into something reusable.
Basic idea is that there is a single TaskScheduler that keeps a pool of threads,
one for each core. Other places in the code can then create a TaskPool that they
can drop Tasks in to be executed by the scheduler, and wait for them to complete
or cancel them early.
=== Normal ====
Added a Normal output to the texture coordinate node. This currently
gives the object space normal, which is the same under object animation.
In the future this might become a "generated" normal so it's also stable for
deforming objects, but for now it's already useful for non-deforming objects.
=== Render Layers ===
Per render layer Samples control, leaving it to 0 will use the common scene
setting.
Environment pass will now render environment even if film is set to transparent.
Exclude Layers" added. Scene layers (all object that influence the render,
directly or indirectly) are shared between all render layers. However sometimes
it's useful to leave out some object influence for a particular render layer.
That's what this option allows you to do.
=== Filter Glossy ===
When using a value higher than 0.0, this will blur glossy reflections after
blurry bounces, to reduce noise at the cost of accuracy. 1.0 is a good
starting value to tweak.
Some light paths have a low probability of being found while contributing much
light to the pixel. As a result these light paths will be found in some pixels
and not in others, causing fireflies. An example of such a difficult path might
be a small light that is causing a small specular highlight on a sharp glossy
material, which we are seeing through a rough glossy material. With path tracing
it is difficult to find the specular highlight, but if we increase the roughness
on the material the highlight gets bigger and softer, and so easier to find.
Often this blurring will be hardly noticeable, because we are seeing it through
a blurry material anyway, but there are also cases where this will lead to a
loss of detail in lighting.
2012-04-28 08:53:59 +00:00
|
|
|
out = output("Normal");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
|
Cycles: merging features from tomato branch.
=== BVH build time optimizations ===
* BVH building was multithreaded. Not all building is multithreaded, packing
and the initial bounding/splitting is still single threaded, but recursive
splitting is, which was the main bottleneck.
* Object splitting now uses binning rather than sorting of all elements, using
code from the Embree raytracer from Intel.
http://software.intel.com/en-us/articles/embree-photo-realistic-ray-tracing-kernels/
* Other small changes to avoid allocations, pack memory more tightly, avoid
some unnecessary operations, ...
These optimizations do not work yet when Spatial Splits are enabled, for that
more work is needed. There's also other optimizations still needed, in
particular for the case of many low poly objects, the packing step and node
memory allocation.
BVH raytracing time should remain about the same, but BVH build time should be
significantly reduced, test here show speedup of about 5x to 10x on a dual core
and 5x to 25x on an 8-core machine, depending on the scene.
=== Threads ===
Centralized task scheduler for multithreading, which is basically the
CPU device threading code wrapped into something reusable.
Basic idea is that there is a single TaskScheduler that keeps a pool of threads,
one for each core. Other places in the code can then create a TaskPool that they
can drop Tasks in to be executed by the scheduler, and wait for them to complete
or cancel them early.
=== Normal ====
Added a Normal output to the texture coordinate node. This currently
gives the object space normal, which is the same under object animation.
In the future this might become a "generated" normal so it's also stable for
deforming objects, but for now it's already useful for non-deforming objects.
=== Render Layers ===
Per render layer Samples control, leaving it to 0 will use the common scene
setting.
Environment pass will now render environment even if film is set to transparent.
Exclude Layers" added. Scene layers (all object that influence the render,
directly or indirectly) are shared between all render layers. However sometimes
it's useful to leave out some object influence for a particular render layer.
That's what this option allows you to do.
=== Filter Glossy ===
When using a value higher than 0.0, this will blur glossy reflections after
blurry bounces, to reduce noise at the cost of accuracy. 1.0 is a good
starting value to tweak.
Some light paths have a low probability of being found while contributing much
light to the pixel. As a result these light paths will be found in some pixels
and not in others, causing fireflies. An example of such a difficult path might
be a small light that is causing a small specular highlight on a sharp glossy
material, which we are seeing through a rough glossy material. With path tracing
it is difficult to find the specular highlight, but if we increase the roughness
on the material the highlight gets bigger and softer, and so easier to find.
Often this blurring will be hardly noticeable, because we are seeing it through
a blurry material anyway, but there are also cases where this will lead to a
loss of detail in lighting.
2012-04-28 08:53:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("UV");
|
|
|
|
|
if (!out->links.empty()) {
|
2012-10-04 21:40:39 +00:00
|
|
|
if (from_dupli) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
|
2012-10-04 21:40:39 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2012-10-06 11:52:54 +00:00
|
|
|
int attr = compiler.attribute(ATTR_STD_UV);
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
|
2012-10-04 21:40:39 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Object");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
|
2015-01-21 22:19:31 +05:00
|
|
|
if (use_transform) {
|
|
|
|
|
Transform ob_itfm = transform_inverse(ob_tfm);
|
|
|
|
|
compiler.add_node(ob_itfm.x);
|
|
|
|
|
compiler.add_node(ob_itfm.y);
|
|
|
|
|
compiler.add_node(ob_itfm.z);
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Camera");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Window");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Reflection");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
if (compiler.background) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void TextureCoordinateNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "dx");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "dy");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "center");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (compiler.background) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("is_background", true);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (compiler.output_type() == SHADER_TYPE_VOLUME) {
|
2013-12-31 17:33:55 +01:00
|
|
|
compiler.parameter("is_volume", true);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "use_transform");
|
2019-02-13 15:01:54 +01:00
|
|
|
Transform ob_itfm = transform_inverse(ob_tfm);
|
2015-01-21 22:19:31 +05:00
|
|
|
compiler.parameter("object_itfm", ob_itfm);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "from_dupli");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_texture_coordinate");
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
/* UV Map */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(UVMapNode)
|
2014-04-02 11:40:29 +02:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("uvmap", create, NodeType::SHADER);
|
|
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(attribute, "attribute", ustring());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_POINT(UV, "UV");
|
2014-04-02 11:40:29 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
UVMapNode::UVMapNode() : ShaderNode(get_node_type()) {}
|
2014-04-02 11:40:29 +02:00
|
|
|
|
|
|
|
|
void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
|
|
|
|
if (shader->has_surface) {
|
|
|
|
|
if (!from_dupli) {
|
|
|
|
|
if (!output("UV")->links.empty()) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (attribute != "") {
|
2014-04-02 11:40:29 +02:00
|
|
|
attributes->add(attribute);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-02 11:40:29 +02:00
|
|
|
attributes->add(ATTR_STD_UV);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2014-04-02 11:40:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-02 11:40:29 +02:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-02 11:40:29 +02:00
|
|
|
void UVMapNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out = output("UV");
|
2016-05-07 19:47:37 +02:00
|
|
|
ShaderNodeType texco_node = NODE_TEX_COORD;
|
|
|
|
|
ShaderNodeType attr_node = NODE_ATTR;
|
2014-04-02 11:40:29 +02:00
|
|
|
int attr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-21 13:15:45 +02:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
|
|
|
|
texco_node = NODE_TEX_COORD_BUMP_DX;
|
|
|
|
|
attr_node = NODE_ATTR_BUMP_DX;
|
|
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
|
|
|
|
texco_node = NODE_TEX_COORD_BUMP_DY;
|
|
|
|
|
attr_node = NODE_ATTR_BUMP_DY;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-02 11:40:29 +02:00
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
if (from_dupli) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
|
2014-04-02 11:40:29 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (attribute != "") {
|
2014-04-02 11:40:29 +02:00
|
|
|
attr = compiler.attribute(attribute);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-02 11:40:29 +02:00
|
|
|
attr = compiler.attribute(ATTR_STD_UV);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
|
2014-04-02 11:40:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-02 11:40:29 +02:00
|
|
|
void UVMapNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2014-04-21 13:15:45 +02:00
|
|
|
compiler.parameter("bump_offset", "dx");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2014-04-21 13:15:45 +02:00
|
|
|
compiler.parameter("bump_offset", "dy");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-04-21 13:15:45 +02:00
|
|
|
compiler.parameter("bump_offset", "center");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "from_dupli");
|
2016-06-11 21:56:47 +02:00
|
|
|
compiler.parameter(this, "attribute");
|
2014-04-02 11:40:29 +02:00
|
|
|
compiler.add(this, "node_uv_map");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Light Path */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(LightPathNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("light_path", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
|
|
|
|
|
SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
|
2016-06-13 14:08:06 +02:00
|
|
|
SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
|
|
|
|
|
SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
|
|
|
|
|
SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
|
|
|
|
|
SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
|
|
|
|
|
SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
|
|
|
|
|
SOCKET_OUT_FLOAT(ray_length, "Ray Length");
|
|
|
|
|
SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
|
2016-12-06 16:15:36 +01:00
|
|
|
SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth");
|
|
|
|
|
SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
|
|
|
|
|
SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
LightPathNode::LightPathNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void LightPathNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out;
|
|
|
|
|
|
|
|
|
|
out = output("Is Camera Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Is Shadow Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Is Diffuse Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-01 15:53:36 +00:00
|
|
|
out = output("Is Glossy Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out));
|
2011-09-01 15:53:36 +00:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Is Singular Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Is Reflection Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2011-09-01 15:53:36 +00:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
out = output("Is Transmission Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2013-12-28 01:54:44 +01:00
|
|
|
out = output("Is Volume Scatter Ray");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out));
|
2013-12-28 01:54:44 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-02 17:03:46 +00:00
|
|
|
out = output("Ray Length");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out));
|
2012-05-02 17:03:46 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2013-07-31 20:30:37 +00:00
|
|
|
out = output("Ray Depth");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
|
2013-07-31 20:30:37 +00:00
|
|
|
}
|
2012-05-02 17:03:46 +00:00
|
|
|
|
2016-12-06 16:15:36 +01:00
|
|
|
out = output("Diffuse Depth");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Glossy Depth");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-21 14:20:29 +02:00
|
|
|
out = output("Transparent Depth");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
|
2014-04-21 14:20:29 +02:00
|
|
|
}
|
2016-01-06 23:38:13 +01:00
|
|
|
|
|
|
|
|
out = output("Transmission Depth");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out));
|
2016-01-06 23:38:13 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LightPathNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_light_path");
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 12:52:28 +00:00
|
|
|
/* Light Falloff */
|
2012-05-07 20:24:38 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(LightFalloffNode)
|
|
|
|
|
{
|
2019-01-14 15:41:24 +01:00
|
|
|
NodeType *type = NodeType::add("light_falloff", create, NodeType::SHADER);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(quadratic, "Quadratic");
|
|
|
|
|
SOCKET_OUT_FLOAT(linear, "Linear");
|
|
|
|
|
SOCKET_OUT_FLOAT(constant, "Constant");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
LightFalloffNode::LightFalloffNode() : ShaderNode(get_node_type()) {}
|
2012-05-07 20:24:38 +00:00
|
|
|
|
|
|
|
|
void LightFalloffNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
ShaderInput *smooth_in = input("Smooth");
|
|
|
|
|
|
|
|
|
|
ShaderOutput *out = output("Quadratic");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_LIGHT_FALLOFF,
|
|
|
|
|
NODE_LIGHT_FALLOFF_QUADRATIC,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(strength_in),
|
|
|
|
|
compiler.stack_assign(smooth_in),
|
|
|
|
|
compiler.stack_assign(out)));
|
2012-05-07 20:24:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Linear");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_LIGHT_FALLOFF,
|
|
|
|
|
NODE_LIGHT_FALLOFF_LINEAR,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(strength_in),
|
|
|
|
|
compiler.stack_assign(smooth_in),
|
|
|
|
|
compiler.stack_assign(out)));
|
2012-05-07 20:24:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Constant");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_LIGHT_FALLOFF,
|
|
|
|
|
NODE_LIGHT_FALLOFF_CONSTANT,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(strength_in),
|
|
|
|
|
compiler.stack_assign(smooth_in),
|
|
|
|
|
compiler.stack_assign(out)));
|
2012-05-07 20:24:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LightFalloffNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_light_falloff");
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 12:52:28 +00:00
|
|
|
/* Object Info */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ObjectInfoNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("object_info", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(location, "Location");
|
2019-08-22 14:26:09 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2022-03-07 17:34:52 +01:00
|
|
|
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(object_index, "Object Index");
|
|
|
|
|
SOCKET_OUT_FLOAT(material_index, "Material Index");
|
|
|
|
|
SOCKET_OUT_FLOAT(random, "Random");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
ObjectInfoNode::ObjectInfoNode() : ShaderNode(get_node_type()) {}
|
2012-05-21 12:52:28 +00:00
|
|
|
|
|
|
|
|
void ObjectInfoNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out = output("Location");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
|
2012-05-21 12:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
2019-08-22 14:26:09 +02:00
|
|
|
out = output("Color");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_COLOR, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 17:34:52 +01:00
|
|
|
out = output("Alpha");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_ALPHA, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 12:52:28 +00:00
|
|
|
out = output("Object Index");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
|
2012-05-21 12:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Material Index");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out));
|
2012-05-21 12:52:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Random");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out));
|
2012-05-21 12:52:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ObjectInfoNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_object_info");
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-08 16:17:57 +00:00
|
|
|
/* Particle Info */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ParticleInfoNode)
|
2012-06-08 16:17:57 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("particle_info", create, NodeType::SHADER);
|
|
|
|
|
|
2018-02-21 13:18:40 +01:00
|
|
|
SOCKET_OUT_FLOAT(index, "Index");
|
2018-02-14 14:32:38 +01:00
|
|
|
SOCKET_OUT_FLOAT(random, "Random");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(age, "Age");
|
|
|
|
|
SOCKET_OUT_FLOAT(lifetime, "Lifetime");
|
|
|
|
|
SOCKET_OUT_POINT(location, "Location");
|
2013-12-22 14:11:10 +11:00
|
|
|
#if 0 /* not yet supported */
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_QUATERNION(rotation, "Rotation");
|
2013-12-22 14:11:10 +11:00
|
|
|
#endif
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(size, "Size");
|
|
|
|
|
SOCKET_OUT_VECTOR(velocity, "Velocity");
|
|
|
|
|
SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
ParticleInfoNode::ParticleInfoNode() : ShaderNode(get_node_type()) {}
|
2012-06-08 16:17:57 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2012-06-08 16:17:57 +00:00
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output("Index")->links.empty()) {
|
2018-02-14 17:02:28 +01:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("Random")->links.empty()) {
|
2012-07-26 11:40:58 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("Age")->links.empty()) {
|
2012-06-08 16:17:57 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("Lifetime")->links.empty()) {
|
2012-06-08 16:17:57 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("Location")->links.empty()) {
|
2012-08-31 19:38:59 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-12-22 14:11:10 +11:00
|
|
|
#if 0 /* not yet supported */
|
2019-04-17 08:16:53 +02:00
|
|
|
if (!output("Rotation")->links.empty())
|
2012-08-31 19:38:59 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2013-12-22 14:11:10 +11:00
|
|
|
#endif
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output("Size")->links.empty()) {
|
2012-08-31 19:38:59 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("Velocity")->links.empty()) {
|
2012-08-31 19:38:59 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
if (!output("Angular Velocity")->links.empty()) {
|
2012-08-31 19:38:59 +00:00
|
|
|
attributes->add(ATTR_STD_PARTICLE);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-06-08 16:17:57 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2012-06-08 16:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ParticleInfoNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out;
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2018-02-14 17:02:28 +01:00
|
|
|
out = output("Index");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-14 14:32:38 +01:00
|
|
|
out = output("Random");
|
2012-07-26 11:40:58 +00:00
|
|
|
if (!out->links.empty()) {
|
2018-02-14 14:32:38 +01:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_RANDOM, compiler.stack_assign(out));
|
2012-07-26 11:40:58 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-06-08 16:17:57 +00:00
|
|
|
out = output("Age");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out));
|
2012-06-08 16:17:57 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-06-08 16:17:57 +00:00
|
|
|
out = output("Lifetime");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out));
|
2012-06-08 16:17:57 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-08-31 19:38:59 +00:00
|
|
|
out = output("Location");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out));
|
2012-08-31 19:38:59 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
/* quaternion data is not yet supported by Cycles */
|
|
|
|
|
#if 0
|
2012-08-31 19:38:59 +00:00
|
|
|
out = output("Rotation");
|
2019-04-17 08:16:53 +02:00
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out));
|
2012-08-31 19:38:59 +00:00
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
#endif
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-08-31 19:38:59 +00:00
|
|
|
out = output("Size");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out));
|
2012-08-31 19:38:59 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-08-31 19:38:59 +00:00
|
|
|
out = output("Velocity");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out));
|
2012-08-31 19:38:59 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-08-31 19:38:59 +00:00
|
|
|
out = output("Angular Velocity");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out));
|
2012-08-31 19:38:59 +00:00
|
|
|
}
|
2012-06-08 16:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ParticleInfoNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_particle_info");
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:21:30 +00:00
|
|
|
/* Hair Info */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(HairInfoNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("hair_info", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(is_strand, "Is Strand");
|
|
|
|
|
SOCKET_OUT_FLOAT(intercept, "Intercept");
|
2021-09-24 07:42:36 +02:00
|
|
|
SOCKET_OUT_FLOAT(size, "Length");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(thickness, "Thickness");
|
2018-02-21 13:18:40 +01:00
|
|
|
SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
|
2018-02-14 14:32:38 +01:00
|
|
|
SOCKET_OUT_FLOAT(index, "Random");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
HairInfoNode::HairInfoNode() : ShaderNode(get_node_type()) {}
|
2012-12-28 14:21:30 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2013-01-03 12:08:54 +00:00
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderOutput *intercept_out = output("Intercept");
|
2013-01-03 12:08:54 +00:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!intercept_out->links.empty()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_CURVE_INTERCEPT);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-02-13 14:20:47 +01:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output("Length")->links.empty()) {
|
2021-09-24 07:42:36 +02:00
|
|
|
attributes->add(ATTR_STD_CURVE_LENGTH);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2021-09-24 07:42:36 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output("Random")->links.empty()) {
|
2018-02-14 14:32:38 +01:00
|
|
|
attributes->add(ATTR_STD_CURVE_RANDOM);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-12-31 17:30:34 +01:00
|
|
|
}
|
2014-03-29 13:03:48 +01:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2013-01-03 12:08:54 +00:00
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:21:30 +00:00
|
|
|
void HairInfoNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out;
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-12-28 14:21:30 +00:00
|
|
|
out = output("Is Strand");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out));
|
2012-12-28 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Intercept");
|
|
|
|
|
if (!out->links.empty()) {
|
2013-01-03 12:08:54 +00:00
|
|
|
int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
2012-12-28 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
2021-09-24 07:42:36 +02:00
|
|
|
out = output("Length");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
int attr = compiler.attribute(ATTR_STD_CURVE_LENGTH);
|
|
|
|
|
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:21:30 +00:00
|
|
|
out = output("Thickness");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
|
2012-12-28 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Tangent Normal");
|
|
|
|
|
if (!out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
|
2012-12-28 14:21:30 +00:00
|
|
|
}
|
2022-01-25 19:45:12 +01:00
|
|
|
|
2018-02-14 14:32:38 +01:00
|
|
|
out = output("Random");
|
2018-02-13 14:20:47 +01:00
|
|
|
if (!out->links.empty()) {
|
2018-02-14 14:32:38 +01:00
|
|
|
int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM);
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
2018-02-13 14:20:47 +01:00
|
|
|
}
|
2012-12-28 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HairInfoNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2012-12-29 01:57:32 +00:00
|
|
|
compiler.add(this, "node_hair_info");
|
2012-12-28 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
|
2022-01-25 13:25:33 +01:00
|
|
|
/* Point Info */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(PointInfoNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("point_info", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_POINT(position, "Position");
|
|
|
|
|
SOCKET_OUT_FLOAT(radius, "Radius");
|
|
|
|
|
SOCKET_OUT_FLOAT(random, "Random");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
PointInfoNode::PointInfoNode() : ShaderNode(get_node_type()) {}
|
2022-01-25 13:25:33 +01:00
|
|
|
|
|
|
|
|
void PointInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
|
|
|
|
if (shader->has_surface_link()) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!output("Random")->links.empty()) {
|
2022-01-25 13:25:33 +01:00
|
|
|
attributes->add(ATTR_STD_POINT_RANDOM);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2022-01-25 13:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PointInfoNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *out;
|
|
|
|
|
|
|
|
|
|
out = output("Position");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_POINT_INFO, NODE_INFO_POINT_POSITION, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Radius");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_POINT_INFO, NODE_INFO_POINT_RADIUS, compiler.stack_assign(out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out = output("Random");
|
|
|
|
|
if (!out->links.empty()) {
|
|
|
|
|
int attr = compiler.attribute(ATTR_STD_POINT_RANDOM);
|
|
|
|
|
compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PointInfoNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_point_info");
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 20:22:24 +02:00
|
|
|
/* Volume Info */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(VolumeInfoNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("volume_info", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(density, "Density");
|
|
|
|
|
SOCKET_OUT_FLOAT(flame, "Flame");
|
|
|
|
|
SOCKET_OUT_FLOAT(temperature, "Temperature");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VolumeInfoNode::VolumeInfoNode() : ShaderNode(get_node_type()) {}
|
2019-08-21 20:22:24 +02:00
|
|
|
|
|
|
|
|
/* The requested attributes are not updated after node expansion.
|
|
|
|
|
* So we explicitly request the required attributes.
|
|
|
|
|
*/
|
|
|
|
|
void VolumeInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
|
|
|
|
if (shader->has_volume) {
|
|
|
|
|
if (!output("Color")->links.empty()) {
|
|
|
|
|
attributes->add(ATTR_STD_VOLUME_COLOR);
|
|
|
|
|
}
|
|
|
|
|
if (!output("Density")->links.empty()) {
|
|
|
|
|
attributes->add(ATTR_STD_VOLUME_DENSITY);
|
|
|
|
|
}
|
|
|
|
|
if (!output("Flame")->links.empty()) {
|
|
|
|
|
attributes->add(ATTR_STD_VOLUME_FLAME);
|
|
|
|
|
}
|
|
|
|
|
if (!output("Temperature")->links.empty()) {
|
|
|
|
|
attributes->add(ATTR_STD_VOLUME_TEMPERATURE);
|
|
|
|
|
}
|
|
|
|
|
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
|
|
|
|
|
}
|
|
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VolumeInfoNode::expand(ShaderGraph *graph)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
if (!color_out->links.empty()) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
AttributeNode *attr = graph->create_node<AttributeNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
attr->set_attribute(ustring("color"));
|
2019-08-21 20:22:24 +02:00
|
|
|
graph->add(attr);
|
|
|
|
|
graph->relink(color_out, attr->output("Color"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderOutput *density_out = output("Density");
|
|
|
|
|
if (!density_out->links.empty()) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
AttributeNode *attr = graph->create_node<AttributeNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
attr->set_attribute(ustring("density"));
|
2019-08-21 20:22:24 +02:00
|
|
|
graph->add(attr);
|
|
|
|
|
graph->relink(density_out, attr->output("Fac"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderOutput *flame_out = output("Flame");
|
|
|
|
|
if (!flame_out->links.empty()) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
AttributeNode *attr = graph->create_node<AttributeNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
attr->set_attribute(ustring("flame"));
|
2019-08-21 20:22:24 +02:00
|
|
|
graph->add(attr);
|
|
|
|
|
graph->relink(flame_out, attr->output("Fac"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ShaderOutput *temperature_out = output("Temperature");
|
|
|
|
|
if (!temperature_out->links.empty()) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
AttributeNode *attr = graph->create_node<AttributeNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
attr->set_attribute(ustring("temperature"));
|
2019-08-21 20:22:24 +02:00
|
|
|
graph->add(attr);
|
|
|
|
|
graph->relink(temperature_out, attr->output("Fac"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void VolumeInfoNode::compile(SVMCompiler &) {}
|
2019-08-21 20:22:24 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void VolumeInfoNode::compile(OSLCompiler &) {}
|
2019-08-21 20:22:24 +02:00
|
|
|
|
2019-09-12 17:42:13 +02:00
|
|
|
NODE_DEFINE(VertexColorNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("vertex_color", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_STRING(layer_name, "Layer Name", ustring());
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VertexColorNode::VertexColorNode() : ShaderNode(get_node_type()) {}
|
2019-09-12 17:42:13 +02:00
|
|
|
|
|
|
|
|
void VertexColorNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
|
|
|
|
if (!(output("Color")->links.empty() && output("Alpha")->links.empty())) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (layer_name != "") {
|
2020-02-18 17:19:16 +01:00
|
|
|
attributes->add_standard(layer_name);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2020-02-18 17:19:16 +01:00
|
|
|
attributes->add(ATTR_STD_VERTEX_COLOR);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-09-12 17:42:13 +02:00
|
|
|
}
|
|
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VertexColorNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2020-02-18 17:19:16 +01:00
|
|
|
int layer_id = 0;
|
|
|
|
|
|
|
|
|
|
if (layer_name != "") {
|
|
|
|
|
layer_id = compiler.attribute(layer_name);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
layer_id = compiler.attribute(ATTR_STD_VERTEX_COLOR);
|
|
|
|
|
}
|
2019-09-12 17:42:13 +02:00
|
|
|
|
|
|
|
|
ShaderNodeType node;
|
|
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2019-09-12 17:42:13 +02:00
|
|
|
node = NODE_VERTEX_COLOR_BUMP_DX;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2019-09-12 17:42:13 +02:00
|
|
|
node = NODE_VERTEX_COLOR_BUMP_DY;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2019-09-12 17:42:13 +02:00
|
|
|
else {
|
|
|
|
|
node = NODE_VERTEX_COLOR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VertexColorNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
if (bump == SHADER_BUMP_DX) {
|
|
|
|
|
compiler.parameter("bump_offset", "dx");
|
|
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
|
|
|
|
compiler.parameter("bump_offset", "dy");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.parameter("bump_offset", "center");
|
|
|
|
|
}
|
2020-02-18 17:19:16 +01:00
|
|
|
|
|
|
|
|
if (layer_name.empty()) {
|
|
|
|
|
compiler.parameter("layer_name", ustring("geom:vertex_color"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (Attribute::name_standard(layer_name.c_str()) != ATTR_STD_NONE) {
|
|
|
|
|
compiler.parameter("name", (string("geom:") + layer_name.c_str()).c_str());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.parameter("layer_name", layer_name.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-12 17:42:13 +02:00
|
|
|
compiler.add(this, "node_vertex_color");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Value */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ValueNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("value", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_FLOAT(value, "Value", 0.0f);
|
|
|
|
|
SOCKET_OUT_FLOAT(value, "Value");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
ValueNode::ValueNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void ValueNode::constant_fold(const ConstantFolder &folder)
|
2015-12-06 23:47:38 +01:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.make_constant(value);
|
2015-12-06 23:47:38 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ValueNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *val_out = output("Value");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ValueNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter("value_value", value);
|
|
|
|
|
compiler.add(this, "node_value");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Color */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(ColorNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("color", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_COLOR(value, "Value", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
ColorNode::ColorNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void ColorNode::constant_fold(const ConstantFolder &folder)
|
2015-12-06 23:47:38 +01:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.make_constant(value);
|
2015-12-06 23:47:38 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void ColorNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
if (!color_out->links.empty()) {
|
|
|
|
|
compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add_node(NODE_VALUE_V, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ColorNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter_color("color_value", value);
|
|
|
|
|
|
|
|
|
|
compiler.add(this, "node_value");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(AddClosureNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("add_closure", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_CLOSURE(closure1, "Closure1");
|
|
|
|
|
SOCKET_IN_CLOSURE(closure2, "Closure2");
|
|
|
|
|
SOCKET_OUT_CLOSURE(closure, "Closure");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
AddClosureNode::AddClosureNode() : ShaderNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-08 00:41:01 +02:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:47:55 +05:00
|
|
|
void AddClosureNode::compile(SVMCompiler & /*compiler*/)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* handled in the SVM compiler */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddClosureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_add_closure");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void AddClosureNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *closure1_in = input("Closure1");
|
|
|
|
|
ShaderInput *closure2_in = input("Closure2");
|
|
|
|
|
|
|
|
|
|
/* remove useless add closures nodes */
|
|
|
|
|
if (!closure1_in->link) {
|
|
|
|
|
folder.bypass_or_discard(closure2_in);
|
|
|
|
|
}
|
|
|
|
|
else if (!closure2_in->link) {
|
|
|
|
|
folder.bypass_or_discard(closure1_in);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Mix Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(MixClosureNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mix_closure", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
|
|
|
|
|
SOCKET_IN_CLOSURE(closure1, "Closure1");
|
|
|
|
|
SOCKET_IN_CLOSURE(closure2, "Closure2");
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_CLOSURE(closure, "Closure");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
MixClosureNode::MixClosureNode() : ShaderNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-08 00:41:01 +02:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:47:55 +05:00
|
|
|
void MixClosureNode::compile(SVMCompiler & /*compiler*/)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* handled in the SVM compiler */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixClosureNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_mix_closure");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void MixClosureNode::constant_fold(const ConstantFolder &folder)
|
2016-05-02 00:05:16 +02:00
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderInput *closure1_in = input("Closure1");
|
|
|
|
|
ShaderInput *closure2_in = input("Closure2");
|
|
|
|
|
|
|
|
|
|
/* remove useless mix closures nodes */
|
|
|
|
|
if (closure1_in->link == closure2_in->link) {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.bypass_or_discard(closure1_in);
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
2016-07-16 13:16:54 +02:00
|
|
|
/* remove unused mix closure input when factor is 0.0 or 1.0
|
|
|
|
|
* check for closure links and make sure factor link is disconnected */
|
|
|
|
|
else if (!fac_in->link) {
|
2016-05-02 00:05:16 +02:00
|
|
|
/* factor 0.0 */
|
2016-07-16 13:16:54 +02:00
|
|
|
if (fac <= 0.0f) {
|
|
|
|
|
folder.bypass_or_discard(closure1_in);
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
/* factor 1.0 */
|
2016-07-16 13:16:54 +02:00
|
|
|
else if (fac >= 1.0f) {
|
|
|
|
|
folder.bypass_or_discard(closure2_in);
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-26 21:59:41 +00:00
|
|
|
/* Mix Closure */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(MixClosureWeightNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(weight1, "Weight1");
|
|
|
|
|
SOCKET_OUT_FLOAT(weight2, "Weight2");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(get_node_type()) {}
|
2012-11-26 21:59:41 +00:00
|
|
|
|
|
|
|
|
void MixClosureWeightNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *weight_in = input("Weight");
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderOutput *weight1_out = output("Weight1");
|
|
|
|
|
ShaderOutput *weight2_out = output("Weight2");
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_MIX_CLOSURE,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(fac_in),
|
|
|
|
|
compiler.stack_assign(weight_in),
|
|
|
|
|
compiler.stack_assign(weight1_out),
|
|
|
|
|
compiler.stack_assign(weight2_out)));
|
2012-11-26 21:59:41 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-27 15:47:55 +05:00
|
|
|
void MixClosureWeightNode::compile(OSLCompiler & /*compiler*/)
|
2012-11-26 21:59:41 +00:00
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-03 23:05:35 +00:00
|
|
|
/* Invert */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(InvertNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("invert", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
InvertNode::InvertNode() : ShaderNode(get_node_type()) {}
|
2011-12-03 23:05:35 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void InvertNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
|
|
|
|
|
if (!fac_in->link) {
|
|
|
|
|
/* evaluate fully constant node */
|
|
|
|
|
if (!color_in->link) {
|
2021-02-17 01:47:18 +01:00
|
|
|
folder.make_constant(interp(color, one_float3() - color, fac));
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
/* remove no-op node */
|
|
|
|
|
else if (fac == 0.0f) {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.bypass(color_in->link);
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-03 23:05:35 +00:00
|
|
|
void InvertNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_INVERT,
|
|
|
|
|
compiler.stack_assign(fac_in),
|
|
|
|
|
compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(color_out));
|
2011-12-03 23:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InvertNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_invert");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Mix */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(MixNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("mix", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("mix", NODE_MIX_BLEND);
|
|
|
|
|
type_enum.insert("add", NODE_MIX_ADD);
|
|
|
|
|
type_enum.insert("multiply", NODE_MIX_MUL);
|
|
|
|
|
type_enum.insert("screen", NODE_MIX_SCREEN);
|
|
|
|
|
type_enum.insert("overlay", NODE_MIX_OVERLAY);
|
|
|
|
|
type_enum.insert("subtract", NODE_MIX_SUB);
|
|
|
|
|
type_enum.insert("divide", NODE_MIX_DIV);
|
|
|
|
|
type_enum.insert("difference", NODE_MIX_DIFF);
|
|
|
|
|
type_enum.insert("darken", NODE_MIX_DARK);
|
|
|
|
|
type_enum.insert("lighten", NODE_MIX_LIGHT);
|
|
|
|
|
type_enum.insert("dodge", NODE_MIX_DODGE);
|
|
|
|
|
type_enum.insert("burn", NODE_MIX_BURN);
|
|
|
|
|
type_enum.insert("hue", NODE_MIX_HUE);
|
|
|
|
|
type_enum.insert("saturation", NODE_MIX_SAT);
|
|
|
|
|
type_enum.insert("value", NODE_MIX_VAL);
|
2022-08-30 11:05:46 +01:00
|
|
|
type_enum.insert("color", NODE_MIX_COL);
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("soft_light", NODE_MIX_SOFT);
|
|
|
|
|
type_enum.insert("linear_light", NODE_MIX_LINEAR);
|
2022-11-18 12:52:14 +00:00
|
|
|
type_enum.insert("exclusion", NODE_MIX_EXCLUSION);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND);
|
2012-08-30 06:31:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color1, "Color1", zero_float3());
|
|
|
|
|
SOCKET_IN_COLOR(color2, "Color2", zero_float3());
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MixNode::MixNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void MixNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderInput *color1_in = input("Color1");
|
|
|
|
|
ShaderInput *color2_in = input("Color2");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_MIX,
|
|
|
|
|
compiler.stack_assign(fac_in),
|
|
|
|
|
compiler.stack_assign(color1_in),
|
|
|
|
|
compiler.stack_assign(color2_in));
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.add_node(NODE_MIX, mix_type, compiler.stack_assign(color_out));
|
2012-08-30 06:31:02 +00:00
|
|
|
|
|
|
|
|
if (use_clamp) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
|
|
|
|
|
compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out));
|
2012-08-30 06:31:02 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "mix_type");
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "use_clamp");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_mix");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void MixNode::constant_fold(const ConstantFolder &folder)
|
2016-05-02 00:05:16 +02:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2022-08-30 11:05:46 +01:00
|
|
|
folder.make_constant_clamp(svm_mix_clamped_factor(mix_type, fac, color1, color2), use_clamp);
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
2016-07-30 20:03:49 +02:00
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
folder.fold_mix(mix_type, use_clamp);
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 11:05:46 +01:00
|
|
|
/* Mix Color */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(MixColorNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mix_color", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("mix", NODE_MIX_BLEND);
|
|
|
|
|
type_enum.insert("add", NODE_MIX_ADD);
|
|
|
|
|
type_enum.insert("multiply", NODE_MIX_MUL);
|
|
|
|
|
type_enum.insert("screen", NODE_MIX_SCREEN);
|
|
|
|
|
type_enum.insert("overlay", NODE_MIX_OVERLAY);
|
|
|
|
|
type_enum.insert("subtract", NODE_MIX_SUB);
|
|
|
|
|
type_enum.insert("divide", NODE_MIX_DIV);
|
|
|
|
|
type_enum.insert("difference", NODE_MIX_DIFF);
|
|
|
|
|
type_enum.insert("darken", NODE_MIX_DARK);
|
|
|
|
|
type_enum.insert("lighten", NODE_MIX_LIGHT);
|
|
|
|
|
type_enum.insert("dodge", NODE_MIX_DODGE);
|
|
|
|
|
type_enum.insert("burn", NODE_MIX_BURN);
|
|
|
|
|
type_enum.insert("hue", NODE_MIX_HUE);
|
|
|
|
|
type_enum.insert("saturation", NODE_MIX_SAT);
|
|
|
|
|
type_enum.insert("value", NODE_MIX_VAL);
|
|
|
|
|
type_enum.insert("color", NODE_MIX_COL);
|
|
|
|
|
type_enum.insert("soft_light", NODE_MIX_SOFT);
|
|
|
|
|
type_enum.insert("linear_light", NODE_MIX_LINEAR);
|
2022-11-18 12:52:14 +00:00
|
|
|
type_enum.insert("exclusion", NODE_MIX_EXCLUSION);
|
2022-08-30 11:05:46 +01:00
|
|
|
SOCKET_ENUM(blend_type, "Type", type_enum, NODE_MIX_BLEND);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Factor", 0.5f);
|
|
|
|
|
SOCKET_IN_COLOR(a, "A", zero_float3());
|
|
|
|
|
SOCKET_IN_COLOR(b, "B", zero_float3());
|
|
|
|
|
SOCKET_BOOLEAN(use_clamp_result, "Use Clamp Result", false);
|
|
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(result, "Result");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MixColorNode::MixColorNode() : ShaderNode(get_node_type()) {}
|
2022-08-30 11:05:46 +01:00
|
|
|
|
|
|
|
|
void MixColorNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Factor");
|
|
|
|
|
ShaderInput *a_in = input("A");
|
|
|
|
|
ShaderInput *b_in = input("B");
|
|
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
|
|
|
|
|
int fac_in_stack_offset = compiler.stack_assign(fac_in);
|
|
|
|
|
int a_in_stack_offset = compiler.stack_assign(a_in);
|
|
|
|
|
int b_in_stack_offset = compiler.stack_assign(b_in);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MIX_COLOR,
|
|
|
|
|
compiler.encode_uchar4(use_clamp, blend_type, use_clamp_result),
|
|
|
|
|
compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
|
|
|
|
|
compiler.stack_assign(result_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixColorNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "blend_type");
|
|
|
|
|
compiler.parameter(this, "use_clamp");
|
|
|
|
|
compiler.parameter(this, "use_clamp_result");
|
|
|
|
|
compiler.add(this, "node_mix_color");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixColorNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
if (use_clamp) {
|
|
|
|
|
fac = clamp(fac, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
folder.make_constant_clamp(svm_mix(blend_type, fac, a, b), use_clamp_result);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
folder.fold_mix_color(blend_type, use_clamp, use_clamp_result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mix Float */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(MixFloatNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mix_float", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Factor", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(a, "A", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(b, "B", 0.0f);
|
|
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
|
|
|
|
|
SOCKET_OUT_FLOAT(result, "Result");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MixFloatNode::MixFloatNode() : ShaderNode(get_node_type()) {}
|
2022-08-30 11:05:46 +01:00
|
|
|
|
|
|
|
|
void MixFloatNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Factor");
|
|
|
|
|
ShaderInput *a_in = input("A");
|
|
|
|
|
ShaderInput *b_in = input("B");
|
|
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
|
|
|
|
|
int fac_in_stack_offset = compiler.stack_assign(fac_in);
|
|
|
|
|
int a_in_stack_offset = compiler.stack_assign(a_in);
|
|
|
|
|
int b_in_stack_offset = compiler.stack_assign(b_in);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MIX_FLOAT,
|
|
|
|
|
use_clamp,
|
|
|
|
|
compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
|
|
|
|
|
compiler.stack_assign(result_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixFloatNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "use_clamp");
|
|
|
|
|
compiler.add(this, "node_mix_float");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixFloatNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
if (use_clamp) {
|
|
|
|
|
fac = clamp(fac, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
folder.make_constant(a * (1 - fac) + b * fac);
|
|
|
|
|
}
|
2022-12-12 17:28:59 +01:00
|
|
|
else {
|
|
|
|
|
folder.fold_mix_float(use_clamp, false);
|
|
|
|
|
}
|
2022-08-30 11:05:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mix Vector */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(MixVectorNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mix_vector", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Factor", 0.5f);
|
|
|
|
|
SOCKET_IN_VECTOR(a, "A", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(b, "B", zero_float3());
|
|
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(result, "Result");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MixVectorNode::MixVectorNode() : ShaderNode(get_node_type()) {}
|
2022-08-30 11:05:46 +01:00
|
|
|
|
|
|
|
|
void MixVectorNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Factor");
|
|
|
|
|
ShaderInput *a_in = input("A");
|
|
|
|
|
ShaderInput *b_in = input("B");
|
|
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
|
|
|
|
|
int fac_in_stack_offset = compiler.stack_assign(fac_in);
|
|
|
|
|
int a_in_stack_offset = compiler.stack_assign(a_in);
|
|
|
|
|
int b_in_stack_offset = compiler.stack_assign(b_in);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MIX_VECTOR,
|
|
|
|
|
compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
|
|
|
|
|
compiler.stack_assign(result_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixVectorNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "use_clamp");
|
|
|
|
|
compiler.add(this, "node_mix_vector");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixVectorNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
if (use_clamp) {
|
|
|
|
|
fac = clamp(fac, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
folder.make_constant(a * (one_float3() - fac) + b * fac);
|
|
|
|
|
}
|
2022-12-12 17:28:59 +01:00
|
|
|
else {
|
|
|
|
|
folder.fold_mix_color(NODE_MIX_BLEND, use_clamp, false);
|
|
|
|
|
}
|
2022-08-30 11:05:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mix Vector Non Uniform */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(MixVectorNonUniformNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("mix_vector_non_uniform", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_VECTOR(fac, "Factor", make_float3(0.5f, 0.5f, 0.5f));
|
|
|
|
|
SOCKET_IN_VECTOR(a, "A", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(b, "B", zero_float3());
|
|
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", true);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(result, "Result");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MixVectorNonUniformNode::MixVectorNonUniformNode() : ShaderNode(get_node_type()) {}
|
2022-08-30 11:05:46 +01:00
|
|
|
|
|
|
|
|
void MixVectorNonUniformNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Factor");
|
|
|
|
|
ShaderInput *a_in = input("A");
|
|
|
|
|
ShaderInput *b_in = input("B");
|
|
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
|
|
|
|
|
int fac_in_stack_offset = compiler.stack_assign(fac_in);
|
|
|
|
|
int a_in_stack_offset = compiler.stack_assign(a_in);
|
|
|
|
|
int b_in_stack_offset = compiler.stack_assign(b_in);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MIX_VECTOR_NON_UNIFORM,
|
|
|
|
|
compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset),
|
|
|
|
|
compiler.stack_assign(result_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixVectorNonUniformNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "use_clamp");
|
|
|
|
|
compiler.add(this, "node_mix_vector_non_uniform");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MixVectorNonUniformNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
if (use_clamp) {
|
|
|
|
|
fac = saturate(fac);
|
|
|
|
|
}
|
|
|
|
|
folder.make_constant(a * (one_float3() - fac) + b * fac);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Nodes: Add general Combine/Separate Color nodes
Inspired by D12936 and D12929, this patch adds general purpose
"Combine Color" and "Separate Color" nodes to Geometry, Compositor,
Shader and Texture nodes.
- Within Geometry Nodes, it replaces the existing "Combine RGB" and
"Separate RGB" nodes.
- Within Compositor Nodes, it replaces the existing
"Combine RGBA/HSVA/YCbCrA/YUVA" and "Separate RGBA/HSVA/YCbCrA/YUVA"
nodes.
- Within Texture Nodes, it replaces the existing "Combine RGBA" and
"Separate RGBA" nodes.
- Within Shader Nodes, it replaces the existing "Combine RGB/HSV" and
"Separate RGB/HSV" nodes.
Python addons have not been updated to the new nodes yet.
**New shader code**
In node_color.h, color.h and gpu_shader_material_color_util.glsl,
missing methods hsl_to_rgb and rgb_to_hsl are added by directly
converting existing C code. They always produce the same result.
**Old code**
As requested by T96219, old nodes still exist but are not displayed in
the add menu. This means Python scripts can still create them as usual.
Otherwise, versioning replaces the old nodes with the new nodes when
opening .blend files.
Differential Revision: https://developer.blender.org/D14034
2022-05-04 18:44:03 +02:00
|
|
|
/* Combine Color */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(CombineColorNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("combine_color", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
|
|
|
|
|
type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
|
|
|
|
|
type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
|
|
|
|
|
SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(r, "Red", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(g, "Green", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(b, "Blue", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CombineColorNode::CombineColorNode() : ShaderNode(get_node_type()) {}
|
Nodes: Add general Combine/Separate Color nodes
Inspired by D12936 and D12929, this patch adds general purpose
"Combine Color" and "Separate Color" nodes to Geometry, Compositor,
Shader and Texture nodes.
- Within Geometry Nodes, it replaces the existing "Combine RGB" and
"Separate RGB" nodes.
- Within Compositor Nodes, it replaces the existing
"Combine RGBA/HSVA/YCbCrA/YUVA" and "Separate RGBA/HSVA/YCbCrA/YUVA"
nodes.
- Within Texture Nodes, it replaces the existing "Combine RGBA" and
"Separate RGBA" nodes.
- Within Shader Nodes, it replaces the existing "Combine RGB/HSV" and
"Separate RGB/HSV" nodes.
Python addons have not been updated to the new nodes yet.
**New shader code**
In node_color.h, color.h and gpu_shader_material_color_util.glsl,
missing methods hsl_to_rgb and rgb_to_hsl are added by directly
converting existing C code. They always produce the same result.
**Old code**
As requested by T96219, old nodes still exist but are not displayed in
the add menu. This means Python scripts can still create them as usual.
Otherwise, versioning replaces the old nodes with the new nodes when
opening .blend files.
Differential Revision: https://developer.blender.org/D14034
2022-05-04 18:44:03 +02:00
|
|
|
|
|
|
|
|
void CombineColorNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
folder.make_constant(svm_combine_color(color_type, make_float3(r, g, b)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CombineColorNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *red_in = input("Red");
|
|
|
|
|
ShaderInput *green_in = input("Green");
|
|
|
|
|
ShaderInput *blue_in = input("Blue");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
|
|
|
|
int red_stack_offset = compiler.stack_assign(red_in);
|
|
|
|
|
int green_stack_offset = compiler.stack_assign(green_in);
|
|
|
|
|
int blue_stack_offset = compiler.stack_assign(blue_in);
|
|
|
|
|
int color_stack_offset = compiler.stack_assign(color_out);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_COLOR,
|
|
|
|
|
color_type,
|
|
|
|
|
compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset),
|
|
|
|
|
color_stack_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CombineColorNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "color_type");
|
|
|
|
|
compiler.add(this, "node_combine_color");
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-01 21:46:10 +00:00
|
|
|
/* Combine RGB */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(CombineRGBNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("combine_rgb", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(r, "R", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(g, "G", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(b, "B", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(image, "Image");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CombineRGBNode::CombineRGBNode() : ShaderNode(get_node_type()) {}
|
2011-12-01 21:46:10 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void CombineRGBNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
folder.make_constant(make_float3(r, g, b));
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-01 21:46:10 +00:00
|
|
|
void CombineRGBNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *red_in = input("R");
|
|
|
|
|
ShaderInput *green_in = input("G");
|
|
|
|
|
ShaderInput *blue_in = input("B");
|
|
|
|
|
ShaderOutput *color_out = output("Image");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_VECTOR, compiler.stack_assign(red_in), 0, compiler.stack_assign(color_out));
|
2011-12-01 21:46:10 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_VECTOR, compiler.stack_assign(green_in), 1, compiler.stack_assign(color_out));
|
2011-12-01 21:46:10 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_VECTOR, compiler.stack_assign(blue_in), 2, compiler.stack_assign(color_out));
|
2011-12-01 21:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CombineRGBNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_combine_rgb");
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 21:44:48 +02:00
|
|
|
/* Combine XYZ */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(CombineXYZNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("combine_xyz", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(x, "X", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(y, "Y", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(z, "Z", 0.0f);
|
|
|
|
|
|
2016-06-18 22:36:42 +02:00
|
|
|
SOCKET_OUT_VECTOR(vector, "Vector");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CombineXYZNode::CombineXYZNode() : ShaderNode(get_node_type()) {}
|
2014-06-13 21:44:48 +02:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void CombineXYZNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
folder.make_constant(make_float3(x, y, z));
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 21:44:48 +02:00
|
|
|
void CombineXYZNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *x_in = input("X");
|
|
|
|
|
ShaderInput *y_in = input("Y");
|
|
|
|
|
ShaderInput *z_in = input("Z");
|
|
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_VECTOR, compiler.stack_assign(x_in), 0, compiler.stack_assign(vector_out));
|
2014-06-13 21:44:48 +02:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_VECTOR, compiler.stack_assign(y_in), 1, compiler.stack_assign(vector_out));
|
2014-06-13 21:44:48 +02:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_COMBINE_VECTOR, compiler.stack_assign(z_in), 2, compiler.stack_assign(vector_out));
|
2014-06-13 21:44:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CombineXYZNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_combine_xyz");
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-03 23:46:56 +00:00
|
|
|
/* Combine HSV */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(CombineHSVNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("combine_hsv", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(h, "H", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(s, "S", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(v, "V", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CombineHSVNode::CombineHSVNode() : ShaderNode(get_node_type()) {}
|
2013-07-03 23:46:56 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void CombineHSVNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-03 23:46:56 +00:00
|
|
|
void CombineHSVNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *hue_in = input("H");
|
|
|
|
|
ShaderInput *saturation_in = input("S");
|
|
|
|
|
ShaderInput *value_in = input("V");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_COMBINE_HSV,
|
|
|
|
|
compiler.stack_assign(hue_in),
|
|
|
|
|
compiler.stack_assign(saturation_in),
|
|
|
|
|
compiler.stack_assign(value_in));
|
|
|
|
|
compiler.add_node(NODE_COMBINE_HSV, compiler.stack_assign(color_out));
|
2013-07-03 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CombineHSVNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_combine_hsv");
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-16 20:35:06 +00:00
|
|
|
/* Gamma */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(GammaNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("gamma", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
GammaNode::GammaNode() : ShaderNode(get_node_type()) {}
|
2011-12-16 20:35:06 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void GammaNode::constant_fold(const ConstantFolder &folder)
|
2015-12-22 13:53:13 +01:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
folder.make_constant(svm_math_gamma_color(color, gamma));
|
2015-12-22 13:53:13 +01:00
|
|
|
}
|
2016-09-29 00:35:53 +03:00
|
|
|
else {
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *gamma_in = input("Gamma");
|
|
|
|
|
|
|
|
|
|
/* 1 ^ X == X ^ 0 == 1 */
|
|
|
|
|
if (folder.is_one(color_in) || folder.is_zero(gamma_in)) {
|
|
|
|
|
folder.make_one();
|
|
|
|
|
}
|
|
|
|
|
/* X ^ 1 == X */
|
|
|
|
|
else if (folder.is_one(gamma_in)) {
|
|
|
|
|
folder.try_bypass_or_make_constant(color_in, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-22 13:53:13 +01:00
|
|
|
}
|
|
|
|
|
|
2011-12-16 20:35:06 +00:00
|
|
|
void GammaNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *gamma_in = input("Gamma");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_GAMMA,
|
|
|
|
|
compiler.stack_assign(gamma_in),
|
|
|
|
|
compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(color_out));
|
2011-12-16 20:35:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GammaNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_gamma");
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-24 16:32:31 +00:00
|
|
|
/* Bright Contrast */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(BrightContrastNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
BrightContrastNode::BrightContrastNode() : ShaderNode(get_node_type()) {}
|
2012-01-24 16:32:31 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void BrightContrastNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
folder.make_constant(svm_brightness_contrast(color, bright, contrast));
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-24 16:32:31 +00:00
|
|
|
void BrightContrastNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderInput *bright_in = input("Bright");
|
|
|
|
|
ShaderInput *contrast_in = input("Contrast");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_BRIGHTCONTRAST,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(color_out),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(bright_in),
|
|
|
|
|
compiler.stack_assign(contrast_in)));
|
2012-01-24 16:32:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BrightContrastNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_brightness");
|
|
|
|
|
}
|
|
|
|
|
|
Nodes: Add general Combine/Separate Color nodes
Inspired by D12936 and D12929, this patch adds general purpose
"Combine Color" and "Separate Color" nodes to Geometry, Compositor,
Shader and Texture nodes.
- Within Geometry Nodes, it replaces the existing "Combine RGB" and
"Separate RGB" nodes.
- Within Compositor Nodes, it replaces the existing
"Combine RGBA/HSVA/YCbCrA/YUVA" and "Separate RGBA/HSVA/YCbCrA/YUVA"
nodes.
- Within Texture Nodes, it replaces the existing "Combine RGBA" and
"Separate RGBA" nodes.
- Within Shader Nodes, it replaces the existing "Combine RGB/HSV" and
"Separate RGB/HSV" nodes.
Python addons have not been updated to the new nodes yet.
**New shader code**
In node_color.h, color.h and gpu_shader_material_color_util.glsl,
missing methods hsl_to_rgb and rgb_to_hsl are added by directly
converting existing C code. They always produce the same result.
**Old code**
As requested by T96219, old nodes still exist but are not displayed in
the add menu. This means Python scripts can still create them as usual.
Otherwise, versioning replaces the old nodes with the new nodes when
opening .blend files.
Differential Revision: https://developer.blender.org/D14034
2022-05-04 18:44:03 +02:00
|
|
|
/* Separate Color */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(SeparateColorNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("separate_color", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
|
|
|
|
|
type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
|
|
|
|
|
type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
|
|
|
|
|
SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(r, "Red");
|
|
|
|
|
SOCKET_OUT_FLOAT(g, "Green");
|
|
|
|
|
SOCKET_OUT_FLOAT(b, "Blue");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
SeparateColorNode::SeparateColorNode() : ShaderNode(get_node_type()) {}
|
Nodes: Add general Combine/Separate Color nodes
Inspired by D12936 and D12929, this patch adds general purpose
"Combine Color" and "Separate Color" nodes to Geometry, Compositor,
Shader and Texture nodes.
- Within Geometry Nodes, it replaces the existing "Combine RGB" and
"Separate RGB" nodes.
- Within Compositor Nodes, it replaces the existing
"Combine RGBA/HSVA/YCbCrA/YUVA" and "Separate RGBA/HSVA/YCbCrA/YUVA"
nodes.
- Within Texture Nodes, it replaces the existing "Combine RGBA" and
"Separate RGBA" nodes.
- Within Shader Nodes, it replaces the existing "Combine RGB/HSV" and
"Separate RGB/HSV" nodes.
Python addons have not been updated to the new nodes yet.
**New shader code**
In node_color.h, color.h and gpu_shader_material_color_util.glsl,
missing methods hsl_to_rgb and rgb_to_hsl are added by directly
converting existing C code. They always produce the same result.
**Old code**
As requested by T96219, old nodes still exist but are not displayed in
the add menu. This means Python scripts can still create them as usual.
Otherwise, versioning replaces the old nodes with the new nodes when
opening .blend files.
Differential Revision: https://developer.blender.org/D14034
2022-05-04 18:44:03 +02:00
|
|
|
|
|
|
|
|
void SeparateColorNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
float3 col = svm_separate_color(color_type, color);
|
|
|
|
|
|
|
|
|
|
for (int channel = 0; channel < 3; channel++) {
|
|
|
|
|
if (outputs[channel] == folder.output) {
|
|
|
|
|
folder.make_constant(col[channel]);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SeparateColorNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderOutput *red_out = output("Red");
|
|
|
|
|
ShaderOutput *green_out = output("Green");
|
|
|
|
|
ShaderOutput *blue_out = output("Blue");
|
|
|
|
|
|
|
|
|
|
int color_stack_offset = compiler.stack_assign(color_in);
|
|
|
|
|
int red_stack_offset = compiler.stack_assign(red_out);
|
|
|
|
|
int green_stack_offset = compiler.stack_assign(green_out);
|
|
|
|
|
int blue_stack_offset = compiler.stack_assign(blue_out);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_COLOR,
|
|
|
|
|
color_type,
|
|
|
|
|
color_stack_offset,
|
|
|
|
|
compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SeparateColorNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "color_type");
|
|
|
|
|
compiler.add(this, "node_separate_color");
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-01 21:46:10 +00:00
|
|
|
/* Separate RGB */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(SeparateRGBNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("separate_rgb", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Image", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2016-11-23 11:33:09 +01:00
|
|
|
SOCKET_OUT_FLOAT(r, "R");
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(g, "G");
|
|
|
|
|
SOCKET_OUT_FLOAT(b, "B");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
SeparateRGBNode::SeparateRGBNode() : ShaderNode(get_node_type()) {}
|
2011-12-01 21:46:10 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void SeparateRGBNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2016-06-19 13:28:50 +03:00
|
|
|
for (int channel = 0; channel < 3; channel++) {
|
2016-07-16 13:16:54 +02:00
|
|
|
if (outputs[channel] == folder.output) {
|
|
|
|
|
folder.make_constant(color[channel]);
|
|
|
|
|
return;
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-01 21:46:10 +00:00
|
|
|
void SeparateRGBNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Image");
|
|
|
|
|
ShaderOutput *red_out = output("R");
|
|
|
|
|
ShaderOutput *green_out = output("G");
|
|
|
|
|
ShaderOutput *blue_out = output("B");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 0, compiler.stack_assign(red_out));
|
2011-12-01 21:46:10 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 1, compiler.stack_assign(green_out));
|
2011-12-01 21:46:10 +00:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 2, compiler.stack_assign(blue_out));
|
2011-12-01 21:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SeparateRGBNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_separate_rgb");
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 21:44:48 +02:00
|
|
|
/* Separate XYZ */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(SeparateXYZNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("separate_xyz", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(vector, "Vector", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(x, "X");
|
|
|
|
|
SOCKET_OUT_FLOAT(y, "Y");
|
|
|
|
|
SOCKET_OUT_FLOAT(z, "Z");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
SeparateXYZNode::SeparateXYZNode() : ShaderNode(get_node_type()) {}
|
2014-06-13 21:44:48 +02:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void SeparateXYZNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2016-06-19 13:28:50 +03:00
|
|
|
for (int channel = 0; channel < 3; channel++) {
|
2016-07-16 13:16:54 +02:00
|
|
|
if (outputs[channel] == folder.output) {
|
|
|
|
|
folder.make_constant(vector[channel]);
|
|
|
|
|
return;
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 21:44:48 +02:00
|
|
|
void SeparateXYZNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *x_out = output("X");
|
|
|
|
|
ShaderOutput *y_out = output("Y");
|
|
|
|
|
ShaderOutput *z_out = output("Z");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 0, compiler.stack_assign(x_out));
|
2014-06-13 21:44:48 +02:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 1, compiler.stack_assign(y_out));
|
2014-06-13 21:44:48 +02:00
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 2, compiler.stack_assign(z_out));
|
2014-06-13 21:44:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SeparateXYZNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_separate_xyz");
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-03 23:46:56 +00:00
|
|
|
/* Separate HSV */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(SeparateHSVNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("separate_hsv", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(h, "H");
|
|
|
|
|
SOCKET_OUT_FLOAT(s, "S");
|
|
|
|
|
SOCKET_OUT_FLOAT(v, "V");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
SeparateHSVNode::SeparateHSVNode() : ShaderNode(get_node_type()) {}
|
2013-07-03 23:46:56 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void SeparateHSVNode::constant_fold(const ConstantFolder &folder)
|
2016-06-19 13:28:50 +03:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2016-06-19 13:28:50 +03:00
|
|
|
float3 hsv = rgb_to_hsv(color);
|
|
|
|
|
|
|
|
|
|
for (int channel = 0; channel < 3; channel++) {
|
2016-07-16 13:16:54 +02:00
|
|
|
if (outputs[channel] == folder.output) {
|
|
|
|
|
folder.make_constant(hsv[channel]);
|
|
|
|
|
return;
|
2016-06-19 13:28:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-03 23:46:56 +00:00
|
|
|
void SeparateHSVNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderOutput *hue_out = output("H");
|
|
|
|
|
ShaderOutput *saturation_out = output("S");
|
|
|
|
|
ShaderOutput *value_out = output("V");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_SEPARATE_HSV,
|
|
|
|
|
compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(hue_out),
|
|
|
|
|
compiler.stack_assign(saturation_out));
|
|
|
|
|
compiler.add_node(NODE_SEPARATE_HSV, compiler.stack_assign(value_out));
|
2013-07-03 23:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SeparateHSVNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_separate_hsv");
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-11 23:48:05 +02:00
|
|
|
/* Hue/Saturation/Value */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
NODE_DEFINE(HSVNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("hsv", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(value, "Value", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
HSVNode::HSVNode() : ShaderNode(get_node_type()) {}
|
2011-12-02 16:57:37 +00:00
|
|
|
|
|
|
|
|
void HSVNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *hue_in = input("Hue");
|
|
|
|
|
ShaderInput *saturation_in = input("Saturation");
|
|
|
|
|
ShaderInput *value_in = input("Value");
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_HSV,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(fac_in),
|
|
|
|
|
compiler.stack_assign(color_out)),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(hue_in),
|
|
|
|
|
compiler.stack_assign(saturation_in),
|
|
|
|
|
compiler.stack_assign(value_in)));
|
2011-12-02 16:57:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HSVNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_hsv");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Attribute */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(AttributeNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("attribute", create, NodeType::SHADER);
|
|
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(attribute, "Attribute", ustring());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_VECTOR(vector, "Vector");
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
2020-10-26 18:32:48 +01:00
|
|
|
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
AttributeNode::AttributeNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2014-03-29 13:03:48 +01:00
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
2020-10-26 18:32:48 +01:00
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-10-26 18:32:48 +01:00
|
|
|
if (!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty() ||
|
|
|
|
|
!alpha_out->links.empty())
|
|
|
|
|
{
|
2018-02-18 03:20:39 +01:00
|
|
|
attributes->add_standard(attribute);
|
2013-12-31 17:30:34 +01:00
|
|
|
}
|
2014-03-29 13:03:48 +01:00
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
if (shader->has_volume) {
|
2014-03-29 13:03:48 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
|
2018-02-18 03:20:39 +01:00
|
|
|
}
|
2014-03-29 13:03:48 +01:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AttributeNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
2020-10-26 18:32:48 +01:00
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2016-05-07 19:47:37 +02:00
|
|
|
ShaderNodeType attr_node = NODE_ATTR;
|
2018-04-29 09:27:44 +02:00
|
|
|
int attr = compiler.attribute_standard(attribute);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2011-04-27 11:58:34 +00:00
|
|
|
attr_node = NODE_ATTR_BUMP_DX;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2011-04-27 11:58:34 +00:00
|
|
|
attr_node = NODE_ATTR_BUMP_DY;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
if (!color_out->links.empty() || !vector_out->links.empty()) {
|
|
|
|
|
if (!color_out->links.empty()) {
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(
|
|
|
|
|
attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_OUTPUT_FLOAT3);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
if (!vector_out->links.empty()) {
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(
|
|
|
|
|
attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_OUTPUT_FLOAT3);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!fac_out->links.empty()) {
|
2020-10-26 18:32:48 +01:00
|
|
|
compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_OUTPUT_FLOAT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!alpha_out->links.empty()) {
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
attr_node, attr, compiler.stack_assign(alpha_out), NODE_ATTR_OUTPUT_FLOAT_ALPHA);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AttributeNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "dx");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "dy");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.parameter("bump_offset", "center");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2023-09-17 09:01:48 +10:00
|
|
|
if (Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE) {
|
2014-03-29 13:03:48 +01:00
|
|
|
compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2014-03-29 13:03:48 +01:00
|
|
|
compiler.parameter("name", attribute.c_str());
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
compiler.add(this, "node_attribute");
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-02 20:36:13 +00:00
|
|
|
/* Camera */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(CameraNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("camera_info", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(view_vector, "View Vector");
|
|
|
|
|
SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
|
|
|
|
|
SOCKET_OUT_FLOAT(view_distance, "View Distance");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CameraNode::CameraNode() : ShaderNode(get_node_type()) {}
|
2011-12-02 20:36:13 +00:00
|
|
|
|
|
|
|
|
void CameraNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *vector_out = output("View Vector");
|
|
|
|
|
ShaderOutput *z_depth_out = output("View Z Depth");
|
|
|
|
|
ShaderOutput *distance_out = output("View Distance");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_CAMERA,
|
|
|
|
|
compiler.stack_assign(vector_out),
|
|
|
|
|
compiler.stack_assign(z_depth_out),
|
|
|
|
|
compiler.stack_assign(distance_out));
|
2011-12-02 20:36:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_camera");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Fresnel */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(FresnelNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("fresnel", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(
|
|
|
|
|
normal, "Normal", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
|
2023-12-04 21:12:29 +01:00
|
|
|
SOCKET_IN_FLOAT(IOR, "IOR", 1.5f);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
FresnelNode::FresnelNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
void FresnelNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2013-11-09 13:14:00 +00:00
|
|
|
ShaderInput *normal_in = input("Normal");
|
2016-05-02 20:12:42 +02:00
|
|
|
ShaderInput *IOR_in = input("IOR");
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderOutput *fac_out = output("Fac");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_FRESNEL,
|
|
|
|
|
compiler.stack_assign(IOR_in),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int(IOR),
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
|
|
|
|
|
compiler.stack_assign(fac_out)));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FresnelNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_fresnel");
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-05 01:24:41 +00:00
|
|
|
/* Layer Weight */
|
2011-09-16 13:14:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(LayerWeightNode)
|
2011-09-16 13:14:02 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("layer_weight", create, NodeType::SHADER);
|
2011-09-16 13:14:02 +00:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(
|
|
|
|
|
normal, "Normal", zero_float3(), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(fresnel, "Fresnel");
|
|
|
|
|
SOCKET_OUT_FLOAT(facing, "Facing");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
LayerWeightNode::LayerWeightNode() : ShaderNode(get_node_type()) {}
|
2011-09-16 13:14:02 +00:00
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void LayerWeightNode::compile(SVMCompiler &compiler)
|
2011-09-16 13:14:02 +00:00
|
|
|
{
|
2013-11-22 00:33:28 +01:00
|
|
|
ShaderInput *normal_in = input("Normal");
|
2011-09-16 13:14:02 +00:00
|
|
|
ShaderInput *blend_in = input("Blend");
|
|
|
|
|
ShaderOutput *fresnel_out = output("Fresnel");
|
2016-05-02 20:12:42 +02:00
|
|
|
ShaderOutput *facing_out = output("Facing");
|
|
|
|
|
|
2011-09-16 13:14:02 +00:00
|
|
|
if (!fresnel_out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LAYER_WEIGHT,
|
|
|
|
|
compiler.stack_assign_if_linked(blend_in),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int(blend),
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
|
|
|
|
|
compiler.stack_assign_if_linked(normal_in),
|
|
|
|
|
compiler.stack_assign(fresnel_out)));
|
2011-09-16 13:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!facing_out->links.empty()) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_LAYER_WEIGHT,
|
|
|
|
|
compiler.stack_assign_if_linked(blend_in),
|
2016-05-07 19:48:28 +02:00
|
|
|
__float_as_int(blend),
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
|
|
|
|
|
compiler.stack_assign_if_linked(normal_in),
|
|
|
|
|
compiler.stack_assign(facing_out)));
|
2011-09-16 13:14:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-06 21:05:58 +00:00
|
|
|
void LayerWeightNode::compile(OSLCompiler &compiler)
|
2011-09-16 13:14:02 +00:00
|
|
|
{
|
2012-10-17 16:16:35 +00:00
|
|
|
compiler.add(this, "node_layer_weight");
|
2011-09-16 13:14:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-05-20 15:58:37 +00:00
|
|
|
/* Wireframe */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(WireframeNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("wireframe", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
|
|
|
|
|
SOCKET_IN_FLOAT(size, "Size", 0.01f);
|
|
|
|
|
SOCKET_OUT_FLOAT(fac, "Fac");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
WireframeNode::WireframeNode() : ShaderNode(get_node_type()) {}
|
2013-05-20 15:58:37 +00:00
|
|
|
|
|
|
|
|
void WireframeNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *size_in = input("Size");
|
|
|
|
|
ShaderOutput *fac_out = output("Fac");
|
2015-02-21 14:49:55 +05:00
|
|
|
NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER;
|
|
|
|
|
if (bump == SHADER_BUMP_DX) {
|
|
|
|
|
bump_offset = NODE_BUMP_OFFSET_DX;
|
|
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
|
|
|
|
bump_offset = NODE_BUMP_OFFSET_DY;
|
|
|
|
|
}
|
|
|
|
|
compiler.add_node(NODE_WIREFRAME,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.stack_assign(size_in),
|
|
|
|
|
compiler.stack_assign(fac_out),
|
2015-02-21 14:49:55 +05:00
|
|
|
compiler.encode_uchar4(use_pixel_size, bump_offset, 0, 0));
|
2013-05-20 15:58:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WireframeNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2015-02-21 14:49:55 +05:00
|
|
|
if (bump == SHADER_BUMP_DX) {
|
|
|
|
|
compiler.parameter("bump_offset", "dx");
|
|
|
|
|
}
|
|
|
|
|
else if (bump == SHADER_BUMP_DY) {
|
|
|
|
|
compiler.parameter("bump_offset", "dy");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.parameter("bump_offset", "center");
|
|
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "use_pixel_size");
|
2013-05-20 15:58:37 +00:00
|
|
|
compiler.add(this, "node_wireframe");
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-09 20:46:22 +00:00
|
|
|
/* Wavelength */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(WavelengthNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("wavelength", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
WavelengthNode::WavelengthNode() : ShaderNode(get_node_type()) {}
|
2013-06-09 20:46:22 +00:00
|
|
|
|
|
|
|
|
void WavelengthNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *wavelength_in = input("Wavelength");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_WAVELENGTH, compiler.stack_assign(wavelength_in), compiler.stack_assign(color_out));
|
2013-06-09 20:46:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WavelengthNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_wavelength");
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-31 20:56:32 +00:00
|
|
|
/* Blackbody */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(BlackbodyNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("blackbody", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
BlackbodyNode::BlackbodyNode() : ShaderNode(get_node_type()) {}
|
2013-07-31 20:56:32 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void BlackbodyNode::constant_fold(const ConstantFolder &folder)
|
2015-11-25 13:52:39 +01:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2022-03-22 20:41:46 +01:00
|
|
|
const float3 rgb_rec709 = svm_math_blackbody_color_rec709(temperature);
|
|
|
|
|
const float3 rgb = folder.scene->shader_manager->rec709_to_scene_linear(rgb_rec709);
|
2022-05-23 20:27:13 +02:00
|
|
|
folder.make_constant(max(rgb, zero_float3()));
|
2015-11-25 13:52:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-31 20:56:32 +00:00
|
|
|
void BlackbodyNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *temperature_in = input("Temperature");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_BLACKBODY, compiler.stack_assign(temperature_in), compiler.stack_assign(color_out));
|
2013-07-31 20:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BlackbodyNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.add(this, "node_blackbody");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Output */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(OutputNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("output", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_CLOSURE(surface, "Surface");
|
|
|
|
|
SOCKET_IN_CLOSURE(volume, "Volume");
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(displacement, "Displacement", zero_float3());
|
|
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
OutputNode::OutputNode() : ShaderNode(get_node_type())
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-08 00:41:01 +02:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_OUTPUT;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OutputNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) {
|
|
|
|
|
ShaderInput *displacement_in = input("Displacement");
|
|
|
|
|
|
|
|
|
|
if (displacement_in->link) {
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OutputNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (compiler.output_type() == SHADER_TYPE_SURFACE) {
|
2011-10-12 23:03:12 +00:00
|
|
|
compiler.add(this, "node_output_surface");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (compiler.output_type() == SHADER_TYPE_VOLUME) {
|
2011-10-12 23:03:12 +00:00
|
|
|
compiler.add(this, "node_output_volume");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) {
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_output_displacement");
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2019-08-13 16:29:32 +02:00
|
|
|
/* Map Range Node */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(MapRangeNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
|
|
|
|
|
|
2019-12-07 12:35:07 +00:00
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
|
|
|
|
|
type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
|
|
|
|
|
type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
|
|
|
|
|
type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
|
2019-12-07 12:35:07 +00:00
|
|
|
|
2019-08-13 16:29:32 +02:00
|
|
|
SOCKET_IN_FLOAT(value, "Value", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(from_max, "From Max", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(to_min, "To Min", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(to_max, "To Max", 1.0f);
|
2019-12-07 12:35:07 +00:00
|
|
|
SOCKET_IN_FLOAT(steps, "Steps", 4.0f);
|
2020-10-30 14:54:40 +01:00
|
|
|
SOCKET_IN_BOOLEAN(clamp, "Clamp", false);
|
2019-08-13 16:29:32 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(result, "Result");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MapRangeNode::MapRangeNode() : ShaderNode(get_node_type()) {}
|
2019-08-13 16:29:32 +02:00
|
|
|
|
2019-08-14 10:53:19 +02:00
|
|
|
void MapRangeNode::expand(ShaderGraph *graph)
|
|
|
|
|
{
|
|
|
|
|
if (clamp) {
|
|
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
if (!result_out->links.empty()) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ClampNode *clamp_node = graph->create_node<ClampNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
clamp_node->set_clamp_type(NODE_CLAMP_RANGE);
|
2019-08-14 10:53:19 +02:00
|
|
|
graph->add(clamp_node);
|
|
|
|
|
graph->relink(result_out, clamp_node->output("Result"));
|
|
|
|
|
graph->connect(result_out, clamp_node->input("Value"));
|
2019-10-04 15:18:08 +02:00
|
|
|
if (input("To Min")->link) {
|
|
|
|
|
graph->connect(input("To Min")->link, clamp_node->input("Min"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
clamp_node->set_min(to_min);
|
2019-10-04 15:18:08 +02:00
|
|
|
}
|
|
|
|
|
if (input("To Max")->link) {
|
|
|
|
|
graph->connect(input("To Max")->link, clamp_node->input("Max"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
clamp_node->set_max(to_max);
|
2019-10-04 15:18:08 +02:00
|
|
|
}
|
2019-08-14 10:53:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-13 16:29:32 +02:00
|
|
|
void MapRangeNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *value_in = input("Value");
|
|
|
|
|
ShaderInput *from_min_in = input("From Min");
|
|
|
|
|
ShaderInput *from_max_in = input("From Max");
|
|
|
|
|
ShaderInput *to_min_in = input("To Min");
|
|
|
|
|
ShaderInput *to_max_in = input("To Max");
|
2019-12-07 12:35:07 +00:00
|
|
|
ShaderInput *steps_in = input("Steps");
|
2019-08-13 16:29:32 +02:00
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
|
|
|
|
|
int value_stack_offset = compiler.stack_assign(value_in);
|
|
|
|
|
int from_min_stack_offset = compiler.stack_assign_if_linked(from_min_in);
|
|
|
|
|
int from_max_stack_offset = compiler.stack_assign_if_linked(from_max_in);
|
|
|
|
|
int to_min_stack_offset = compiler.stack_assign_if_linked(to_min_in);
|
|
|
|
|
int to_max_stack_offset = compiler.stack_assign_if_linked(to_max_in);
|
2019-12-07 12:35:07 +00:00
|
|
|
int steps_stack_offset = compiler.stack_assign(steps_in);
|
2019-08-13 16:29:32 +02:00
|
|
|
int result_stack_offset = compiler.stack_assign(result_out);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MAP_RANGE,
|
|
|
|
|
value_stack_offset,
|
|
|
|
|
compiler.encode_uchar4(
|
|
|
|
|
from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.encode_uchar4(range_type, steps_stack_offset, result_stack_offset));
|
2019-08-13 16:29:32 +02:00
|
|
|
|
|
|
|
|
compiler.add_node(__float_as_int(from_min),
|
|
|
|
|
__float_as_int(from_max),
|
|
|
|
|
__float_as_int(to_min),
|
|
|
|
|
__float_as_int(to_max));
|
2019-12-07 12:35:07 +00:00
|
|
|
compiler.add_node(__float_as_int(steps));
|
2019-08-13 16:29:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapRangeNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "range_type");
|
2019-08-13 16:29:32 +02:00
|
|
|
compiler.add(this, "node_map_range");
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 21:20:07 +00:00
|
|
|
/* Vector Map Range Node */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(VectorMapRangeNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("vector_map_range", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
|
|
|
|
|
type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
|
|
|
|
|
type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
|
|
|
|
|
type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
|
|
|
|
|
SOCKET_ENUM(range_type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(from_min, "From_Min_FLOAT3", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(from_max, "From_Max_FLOAT3", one_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(to_min, "To_Min_FLOAT3", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(to_max, "To_Max_FLOAT3", one_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(steps, "Steps_FLOAT3", make_float3(4.0f));
|
|
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(vector, "Vector");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VectorMapRangeNode::VectorMapRangeNode() : ShaderNode(get_node_type()) {}
|
2021-12-13 21:20:07 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void VectorMapRangeNode::expand(ShaderGraph * /*graph*/) {}
|
2021-12-13 21:20:07 +00:00
|
|
|
|
|
|
|
|
void VectorMapRangeNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderInput *from_min_in = input("From_Min_FLOAT3");
|
|
|
|
|
ShaderInput *from_max_in = input("From_Max_FLOAT3");
|
|
|
|
|
ShaderInput *to_min_in = input("To_Min_FLOAT3");
|
|
|
|
|
ShaderInput *to_max_in = input("To_Max_FLOAT3");
|
|
|
|
|
ShaderInput *steps_in = input("Steps_FLOAT3");
|
|
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
|
|
|
|
|
int value_stack_offset = compiler.stack_assign(vector_in);
|
|
|
|
|
int from_min_stack_offset = compiler.stack_assign(from_min_in);
|
|
|
|
|
int from_max_stack_offset = compiler.stack_assign(from_max_in);
|
|
|
|
|
int to_min_stack_offset = compiler.stack_assign(to_min_in);
|
|
|
|
|
int to_max_stack_offset = compiler.stack_assign(to_max_in);
|
|
|
|
|
int steps_stack_offset = compiler.stack_assign(steps_in);
|
|
|
|
|
int result_stack_offset = compiler.stack_assign(vector_out);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_VECTOR_MAP_RANGE,
|
|
|
|
|
value_stack_offset,
|
|
|
|
|
compiler.encode_uchar4(
|
|
|
|
|
from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
|
|
|
|
|
compiler.encode_uchar4(steps_stack_offset, use_clamp, range_type, result_stack_offset));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VectorMapRangeNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "range_type");
|
|
|
|
|
compiler.parameter(this, "use_clamp");
|
|
|
|
|
compiler.add(this, "node_vector_map_range");
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-13 22:22:15 +02:00
|
|
|
/* Clamp Node */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(ClampNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
|
|
|
|
|
|
2019-12-07 12:35:07 +00:00
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("minmax", NODE_CLAMP_MINMAX);
|
|
|
|
|
type_enum.insert("range", NODE_CLAMP_RANGE);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(clamp_type, "Type", type_enum, NODE_CLAMP_MINMAX);
|
2019-12-07 12:35:07 +00:00
|
|
|
|
2019-08-13 22:22:15 +02:00
|
|
|
SOCKET_IN_FLOAT(value, "Value", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(min, "Min", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(max, "Max", 1.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(result, "Result");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
ClampNode::ClampNode() : ShaderNode(get_node_type()) {}
|
2019-08-13 22:22:15 +02:00
|
|
|
|
|
|
|
|
void ClampNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
2020-11-04 11:17:38 +01:00
|
|
|
if (clamp_type == NODE_CLAMP_RANGE && (min > max)) {
|
2019-12-07 12:35:07 +00:00
|
|
|
folder.make_constant(clamp(value, max, min));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
folder.make_constant(clamp(value, min, max));
|
|
|
|
|
}
|
2019-08-13 22:22:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClampNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *value_in = input("Value");
|
|
|
|
|
ShaderInput *min_in = input("Min");
|
|
|
|
|
ShaderInput *max_in = input("Max");
|
|
|
|
|
ShaderOutput *result_out = output("Result");
|
|
|
|
|
|
|
|
|
|
int value_stack_offset = compiler.stack_assign(value_in);
|
|
|
|
|
int min_stack_offset = compiler.stack_assign(min_in);
|
|
|
|
|
int max_stack_offset = compiler.stack_assign(max_in);
|
|
|
|
|
int result_stack_offset = compiler.stack_assign(result_out);
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_CLAMP,
|
|
|
|
|
value_stack_offset,
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.encode_uchar4(min_stack_offset, max_stack_offset, clamp_type),
|
2019-08-13 22:22:15 +02:00
|
|
|
result_stack_offset);
|
|
|
|
|
compiler.add_node(__float_as_int(min), __float_as_int(max));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClampNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "clamp_type");
|
2019-08-13 22:22:15 +02:00
|
|
|
compiler.add(this, "node_clamp");
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 19:57:28 +01:00
|
|
|
/* AOV Output */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(OutputAOVNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("aov_output", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(color, "Color", zero_float3());
|
2019-12-04 19:57:28 +01:00
|
|
|
SOCKET_IN_FLOAT(value, "Value", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_STRING(name, "AOV Name", ustring(""));
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
OutputAOVNode::OutputAOVNode() : ShaderNode(get_node_type())
|
2019-12-04 19:57:28 +01:00
|
|
|
{
|
|
|
|
|
special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
offset = -1;
|
2019-12-04 19:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OutputAOVNode::simplify_settings(Scene *scene)
|
|
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
offset = scene->film->get_aov_offset(scene, name.string(), is_color);
|
|
|
|
|
if (offset == -1) {
|
|
|
|
|
offset = scene->film->get_aov_offset(scene, name.string(), is_color);
|
2019-12-04 19:57:28 +01:00
|
|
|
}
|
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
if (offset == -1 || is_color) {
|
2019-12-04 19:57:28 +01:00
|
|
|
input("Value")->disconnect();
|
|
|
|
|
}
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
if (offset == -1 || !is_color) {
|
2019-12-04 19:57:28 +01:00
|
|
|
input("Color")->disconnect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OutputAOVNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
assert(offset >= 0);
|
2019-12-04 19:57:28 +01:00
|
|
|
|
|
|
|
|
if (is_color) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
compiler.add_node(NODE_AOV_COLOR, compiler.stack_assign(input("Color")), offset);
|
2019-12-04 19:57:28 +01:00
|
|
|
}
|
|
|
|
|
else {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
compiler.add_node(NODE_AOV_VALUE, compiler.stack_assign(input("Value")), offset);
|
2019-12-04 19:57:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OutputAOVNode::compile(OSLCompiler & /*compiler*/)
|
|
|
|
|
{
|
|
|
|
|
/* TODO */
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Math */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(MathNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("math", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("add", NODE_MATH_ADD);
|
|
|
|
|
type_enum.insert("subtract", NODE_MATH_SUBTRACT);
|
|
|
|
|
type_enum.insert("multiply", NODE_MATH_MULTIPLY);
|
|
|
|
|
type_enum.insert("divide", NODE_MATH_DIVIDE);
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
type_enum.insert("multiply_add", NODE_MATH_MULTIPLY_ADD);
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("sine", NODE_MATH_SINE);
|
|
|
|
|
type_enum.insert("cosine", NODE_MATH_COSINE);
|
|
|
|
|
type_enum.insert("tangent", NODE_MATH_TANGENT);
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
type_enum.insert("sinh", NODE_MATH_SINH);
|
|
|
|
|
type_enum.insert("cosh", NODE_MATH_COSH);
|
|
|
|
|
type_enum.insert("tanh", NODE_MATH_TANH);
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("arcsine", NODE_MATH_ARCSINE);
|
|
|
|
|
type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
|
|
|
|
|
type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
|
|
|
|
|
type_enum.insert("power", NODE_MATH_POWER);
|
|
|
|
|
type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
|
|
|
|
|
type_enum.insert("minimum", NODE_MATH_MINIMUM);
|
|
|
|
|
type_enum.insert("maximum", NODE_MATH_MAXIMUM);
|
|
|
|
|
type_enum.insert("round", NODE_MATH_ROUND);
|
|
|
|
|
type_enum.insert("less_than", NODE_MATH_LESS_THAN);
|
|
|
|
|
type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
|
|
|
|
|
type_enum.insert("modulo", NODE_MATH_MODULO);
|
2023-08-08 12:13:00 +02:00
|
|
|
type_enum.insert("floored_modulo", NODE_MATH_FLOORED_MODULO);
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
|
2018-05-24 02:51:41 +02:00
|
|
|
type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
|
2018-07-12 23:40:18 +02:00
|
|
|
type_enum.insert("floor", NODE_MATH_FLOOR);
|
|
|
|
|
type_enum.insert("ceil", NODE_MATH_CEIL);
|
2019-08-18 11:16:04 +02:00
|
|
|
type_enum.insert("fraction", NODE_MATH_FRACTION);
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
type_enum.insert("trunc", NODE_MATH_TRUNC);
|
|
|
|
|
type_enum.insert("snap", NODE_MATH_SNAP);
|
|
|
|
|
type_enum.insert("wrap", NODE_MATH_WRAP);
|
|
|
|
|
type_enum.insert("pingpong", NODE_MATH_PINGPONG);
|
2018-07-12 23:40:18 +02:00
|
|
|
type_enum.insert("sqrt", NODE_MATH_SQRT);
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
type_enum.insert("inversesqrt", NODE_MATH_INV_SQRT);
|
|
|
|
|
type_enum.insert("sign", NODE_MATH_SIGN);
|
|
|
|
|
type_enum.insert("exponent", NODE_MATH_EXPONENT);
|
|
|
|
|
type_enum.insert("radians", NODE_MATH_RADIANS);
|
|
|
|
|
type_enum.insert("degrees", NODE_MATH_DEGREES);
|
|
|
|
|
type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN);
|
|
|
|
|
type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX);
|
|
|
|
|
type_enum.insert("compare", NODE_MATH_COMPARE);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(math_type, "Type", type_enum, NODE_MATH_ADD);
|
2012-08-29 17:30:14 +00:00
|
|
|
|
2019-08-20 18:19:22 +02:00
|
|
|
SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
|
|
|
|
|
|
2019-08-18 11:16:04 +02:00
|
|
|
SOCKET_IN_FLOAT(value1, "Value1", 0.5f);
|
|
|
|
|
SOCKET_IN_FLOAT(value2, "Value2", 0.5f);
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
SOCKET_IN_FLOAT(value3, "Value3", 0.0f);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(value, "Value");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
MathNode::MathNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-08-18 11:16:04 +02:00
|
|
|
void MathNode::expand(ShaderGraph *graph)
|
|
|
|
|
{
|
|
|
|
|
if (use_clamp) {
|
|
|
|
|
ShaderOutput *result_out = output("Value");
|
|
|
|
|
if (!result_out->links.empty()) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ClampNode *clamp_node = graph->create_node<ClampNode>();
|
2020-11-04 11:17:38 +01:00
|
|
|
clamp_node->set_clamp_type(NODE_CLAMP_MINMAX);
|
|
|
|
|
clamp_node->set_min(0.0f);
|
|
|
|
|
clamp_node->set_max(1.0f);
|
2019-08-18 11:16:04 +02:00
|
|
|
graph->add(clamp_node);
|
|
|
|
|
graph->relink(result_out, clamp_node->output("Result"));
|
|
|
|
|
graph->connect(result_out, clamp_node->input("Value"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void MathNode::constant_fold(const ConstantFolder &folder)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2020-11-04 11:17:38 +01:00
|
|
|
folder.make_constant(svm_math(math_type, value1, value2, value3));
|
2014-10-26 19:40:04 +05:00
|
|
|
}
|
2016-07-30 20:03:49 +02:00
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
folder.fold_math(math_type);
|
2016-07-30 20:03:49 +02:00
|
|
|
}
|
2015-11-25 13:52:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *value1_in = input("Value1");
|
|
|
|
|
ShaderInput *value2_in = input("Value2");
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
ShaderInput *value3_in = input("Value3");
|
2015-11-25 13:52:39 +01:00
|
|
|
ShaderOutput *value_out = output("Value");
|
|
|
|
|
|
2019-08-18 11:16:04 +02:00
|
|
|
int value1_stack_offset = compiler.stack_assign(value1_in);
|
|
|
|
|
int value2_stack_offset = compiler.stack_assign(value2_in);
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
int value3_stack_offset = compiler.stack_assign(value3_in);
|
2019-08-18 11:16:04 +02:00
|
|
|
int value_stack_offset = compiler.stack_assign(value_out);
|
2012-08-29 17:30:14 +00:00
|
|
|
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_MATH,
|
2020-11-04 11:17:38 +01:00
|
|
|
math_type,
|
Maths Node: Additional functions
When creating shaders and using maths functions it is expected that Blender should match functions in other DCC applications, game engines and shading languages such as GLSL and OSL.
This patch adds missing functions to the Blender maths node.
Ideally, it would be nice to have these functions available to vectors too but that is not part of this patch.
This patch adds the following functions trunc, snap, wrap, compare, pingpong, sign, radians, degrees, cosh, sinh, tanh, exp, smoothmin and inversesqrt.
Sign function is based on GLSL and OSL functions and returns zero when x == 0.
Differential Revision: https://developer.blender.org/D5957
2019-12-05 23:02:05 +00:00
|
|
|
compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset),
|
|
|
|
|
value_stack_offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MathNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "math_type");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_math");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* VectorMath */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(VectorMathNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("vector_math", create, NodeType::SHADER);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("add", NODE_VECTOR_MATH_ADD);
|
|
|
|
|
type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY);
|
|
|
|
|
type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE);
|
|
|
|
|
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
type_enum.insert("project", NODE_VECTOR_MATH_PROJECT);
|
|
|
|
|
type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT);
|
2021-03-23 09:21:56 +00:00
|
|
|
type_enum.insert("refract", NODE_VECTOR_MATH_REFRACT);
|
|
|
|
|
type_enum.insert("faceforward", NODE_VECTOR_MATH_FACEFORWARD);
|
2021-06-04 16:53:50 +01:00
|
|
|
type_enum.insert("multiply_add", NODE_VECTOR_MATH_MULTIPLY_ADD);
|
2021-03-23 09:21:56 +00:00
|
|
|
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
|
|
|
|
|
|
|
|
|
|
type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE);
|
|
|
|
|
type_enum.insert("length", NODE_VECTOR_MATH_LENGTH);
|
|
|
|
|
type_enum.insert("scale", NODE_VECTOR_MATH_SCALE);
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
|
|
|
|
|
type_enum.insert("snap", NODE_VECTOR_MATH_SNAP);
|
|
|
|
|
type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR);
|
|
|
|
|
type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL);
|
|
|
|
|
type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO);
|
2020-02-14 21:46:10 +00:00
|
|
|
type_enum.insert("wrap", NODE_VECTOR_MATH_WRAP);
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION);
|
|
|
|
|
type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE);
|
|
|
|
|
type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM);
|
|
|
|
|
type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM);
|
2020-02-14 21:46:10 +00:00
|
|
|
|
|
|
|
|
type_enum.insert("sine", NODE_VECTOR_MATH_SINE);
|
|
|
|
|
type_enum.insert("cosine", NODE_VECTOR_MATH_COSINE);
|
|
|
|
|
type_enum.insert("tangent", NODE_VECTOR_MATH_TANGENT);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(math_type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(vector1, "Vector1", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(vector2, "Vector2", zero_float3());
|
|
|
|
|
SOCKET_IN_VECTOR(vector3, "Vector3", zero_float3());
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_FLOAT(value, "Value");
|
|
|
|
|
SOCKET_OUT_VECTOR(vector, "Vector");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VectorMathNode::VectorMathNode() : ShaderNode(get_node_type()) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void VectorMathNode::constant_fold(const ConstantFolder &folder)
|
2015-11-25 13:52:39 +01:00
|
|
|
{
|
2019-08-26 16:07:32 +02:00
|
|
|
float value = 0.0f;
|
2021-02-17 01:47:18 +01:00
|
|
|
float3 vector = zero_float3();
|
2015-11-25 13:52:39 +01:00
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.all_inputs_constant()) {
|
2020-11-04 11:17:38 +01:00
|
|
|
svm_vector_math(&value, &vector, math_type, vector1, vector2, vector3, scale);
|
2016-07-16 13:16:54 +02:00
|
|
|
if (folder.output == output("Value")) {
|
|
|
|
|
folder.make_constant(value);
|
2015-11-25 13:52:39 +01:00
|
|
|
}
|
2016-07-16 13:16:54 +02:00
|
|
|
else if (folder.output == output("Vector")) {
|
|
|
|
|
folder.make_constant(vector);
|
2015-11-25 13:52:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-07-30 20:03:49 +02:00
|
|
|
else {
|
2020-11-04 11:17:38 +01:00
|
|
|
folder.fold_vector_math(math_type);
|
2016-07-30 20:03:49 +02:00
|
|
|
}
|
2015-11-25 13:52:39 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void VectorMathNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector1_in = input("Vector1");
|
|
|
|
|
ShaderInput *vector2_in = input("Vector2");
|
2021-03-23 09:21:56 +00:00
|
|
|
ShaderInput *param1_in = input("Scale");
|
2011-04-28 11:45:06 +00:00
|
|
|
ShaderOutput *value_out = output("Value");
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
int vector1_stack_offset = compiler.stack_assign(vector1_in);
|
|
|
|
|
int vector2_stack_offset = compiler.stack_assign(vector2_in);
|
2021-03-23 09:21:56 +00:00
|
|
|
int param1_stack_offset = compiler.stack_assign(param1_in);
|
Shading: Add more operators to Vector Math node.
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.
The patch doesn't include tests for the new operators. Tests will be added
in a later patch.
Reviewers: brecht, JacquesLucke
Differential Revision: https://developer.blender.org/D5523
2019-08-21 19:36:33 +02:00
|
|
|
int value_stack_offset = compiler.stack_assign_if_linked(value_out);
|
|
|
|
|
int vector_stack_offset = compiler.stack_assign_if_linked(vector_out);
|
|
|
|
|
|
2020-02-14 21:46:10 +00:00
|
|
|
/* 3 Vector Operators */
|
2021-06-04 16:53:50 +01:00
|
|
|
if (math_type == NODE_VECTOR_MATH_WRAP || math_type == NODE_VECTOR_MATH_FACEFORWARD ||
|
|
|
|
|
math_type == NODE_VECTOR_MATH_MULTIPLY_ADD)
|
|
|
|
|
{
|
2020-02-14 21:46:10 +00:00
|
|
|
ShaderInput *vector3_in = input("Vector3");
|
|
|
|
|
int vector3_stack_offset = compiler.stack_assign(vector3_in);
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_VECTOR_MATH,
|
2020-11-04 11:17:38 +01:00
|
|
|
math_type,
|
2021-03-23 09:21:56 +00:00
|
|
|
compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, param1_stack_offset),
|
2020-02-14 21:46:10 +00:00
|
|
|
compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
|
|
|
|
|
compiler.add_node(vector3_stack_offset);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_VECTOR_MATH,
|
2020-11-04 11:17:38 +01:00
|
|
|
math_type,
|
2021-03-23 09:21:56 +00:00
|
|
|
compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, param1_stack_offset),
|
2020-02-14 21:46:10 +00:00
|
|
|
compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VectorMathNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "math_type");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_vector_math");
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-17 15:15:46 +00:00
|
|
|
/* Vector Rotate */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(VectorRotateNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("vector_rotate", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum type_enum;
|
|
|
|
|
type_enum.insert("axis", NODE_VECTOR_ROTATE_TYPE_AXIS);
|
|
|
|
|
type_enum.insert("x_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_X);
|
|
|
|
|
type_enum.insert("y_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Y);
|
|
|
|
|
type_enum.insert("z_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Z);
|
|
|
|
|
type_enum.insert("euler_xyz", NODE_VECTOR_ROTATE_TYPE_EULER_XYZ);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(rotate_type, "Type", type_enum, NODE_VECTOR_ROTATE_TYPE_AXIS);
|
2020-02-17 15:15:46 +00:00
|
|
|
|
2020-02-25 14:52:01 +00:00
|
|
|
SOCKET_BOOLEAN(invert, "Invert", false);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
|
|
|
|
|
SOCKET_IN_POINT(rotation, "Rotation", zero_float3());
|
|
|
|
|
SOCKET_IN_POINT(center, "Center", zero_float3());
|
2020-02-17 15:15:46 +00:00
|
|
|
SOCKET_IN_VECTOR(axis, "Axis", make_float3(0.0f, 0.0f, 1.0f));
|
|
|
|
|
SOCKET_IN_FLOAT(angle, "Angle", 0.0f);
|
|
|
|
|
SOCKET_OUT_VECTOR(vector, "Vector");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VectorRotateNode::VectorRotateNode() : ShaderNode(get_node_type()) {}
|
2020-02-17 15:15:46 +00:00
|
|
|
|
|
|
|
|
void VectorRotateNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderInput *rotation_in = input("Rotation");
|
|
|
|
|
ShaderInput *center_in = input("Center");
|
|
|
|
|
ShaderInput *axis_in = input("Axis");
|
|
|
|
|
ShaderInput *angle_in = input("Angle");
|
|
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.add_node(NODE_VECTOR_ROTATE,
|
|
|
|
|
compiler.encode_uchar4(rotate_type,
|
|
|
|
|
compiler.stack_assign(vector_in),
|
|
|
|
|
compiler.stack_assign(rotation_in),
|
|
|
|
|
invert),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(center_in),
|
|
|
|
|
compiler.stack_assign(axis_in),
|
|
|
|
|
compiler.stack_assign(angle_in)),
|
|
|
|
|
compiler.stack_assign(vector_out));
|
2020-02-17 15:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VectorRotateNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "rotate_type");
|
2020-02-25 14:52:01 +00:00
|
|
|
compiler.parameter(this, "invert");
|
2020-02-17 15:15:46 +00:00
|
|
|
compiler.add(this, "node_vector_rotate");
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-31 21:18:23 +00:00
|
|
|
/* VectorTransform */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(VectorTransformNode)
|
2013-07-31 21:18:23 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("vector_transform", create, NodeType::SHADER);
|
2013-07-31 21:18:23 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
|
|
|
|
|
type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
|
|
|
|
|
type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
|
2020-11-04 11:17:38 +01:00
|
|
|
SOCKET_ENUM(transform_type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
|
2013-07-31 21:18:23 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum space_enum;
|
|
|
|
|
space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
|
|
|
|
|
space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
|
|
|
|
|
space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
|
|
|
|
|
SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
|
|
|
|
|
SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
|
2013-07-31 21:18:23 +00:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(vector, "Vector", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_VECTOR(vector, "Vector");
|
2013-07-31 21:18:23 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
2013-07-31 21:18:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VectorTransformNode::VectorTransformNode() : ShaderNode(get_node_type()) {}
|
2013-07-31 21:18:23 +00:00
|
|
|
|
|
|
|
|
void VectorTransformNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderOutput *vector_out = output("Vector");
|
|
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_VECTOR_TRANSFORM,
|
2020-11-04 11:17:38 +01:00
|
|
|
compiler.encode_uchar4(transform_type, convert_from, convert_to),
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)));
|
2013-07-31 21:18:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VectorTransformNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2020-11-10 15:18:40 +01:00
|
|
|
compiler.parameter(this, "transform_type");
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "convert_from");
|
|
|
|
|
compiler.parameter(this, "convert_to");
|
2013-07-31 21:18:23 +00:00
|
|
|
compiler.add(this, "node_vector_transform");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* BumpNode */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(BumpNode)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("bump", create, NodeType::SHADER);
|
2013-05-10 16:57:17 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_BOOLEAN(invert, "Invert", false);
|
2016-09-02 00:41:04 -04:00
|
|
|
SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false);
|
2015-06-11 23:09:38 +02:00
|
|
|
|
2012-10-10 15:56:43 +00:00
|
|
|
/* this input is used by the user, but after graph transform it is no longer
|
|
|
|
|
* used and moved to sampler center/x/y instead */
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(height, "Height", 1.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_NORMAL(normal, "Normal");
|
2012-10-10 15:56:43 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-03-15 16:11:12 +01:00
|
|
|
BumpNode::BumpNode() : ShaderNode(get_node_type())
|
2016-05-07 19:48:28 +02:00
|
|
|
{
|
|
|
|
|
special_type = SHADER_SPECIAL_TYPE_BUMP;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BumpNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *center_in = input("SampleCenter");
|
|
|
|
|
ShaderInput *dx_in = input("SampleX");
|
|
|
|
|
ShaderInput *dy_in = input("SampleY");
|
2013-05-08 13:23:13 +00:00
|
|
|
ShaderInput *normal_in = input("Normal");
|
2013-05-10 16:57:17 +00:00
|
|
|
ShaderInput *strength_in = input("Strength");
|
|
|
|
|
ShaderInput *distance_in = input("Distance");
|
2012-10-10 15:56:43 +00:00
|
|
|
ShaderOutput *normal_out = output("Normal");
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-10-10 15:56:43 +00:00
|
|
|
/* pack all parameters in the node */
|
2023-10-02 02:19:51 +02:00
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_SET_BUMP,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
|
|
|
|
|
compiler.stack_assign(distance_in),
|
|
|
|
|
invert,
|
|
|
|
|
use_object_space),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(center_in),
|
|
|
|
|
compiler.stack_assign(dx_in),
|
|
|
|
|
compiler.stack_assign(dy_in),
|
|
|
|
|
compiler.stack_assign(strength_in)),
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(normal_out), compiler.get_bump_state_offset()));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BumpNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "invert");
|
2016-09-02 00:41:04 -04:00
|
|
|
compiler.parameter(this, "use_object_space");
|
2011-04-27 11:58:34 +00:00
|
|
|
compiler.add(this, "node_bump");
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-16 13:16:54 +02:00
|
|
|
void BumpNode::constant_fold(const ConstantFolder &folder)
|
2016-05-02 00:05:16 +02:00
|
|
|
{
|
|
|
|
|
ShaderInput *height_in = input("Height");
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
|
|
|
|
|
if (height_in->link == NULL) {
|
|
|
|
|
if (normal_in->link == NULL) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
GeometryNode *geom = folder.graph->create_node<GeometryNode>();
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.graph->add(geom);
|
|
|
|
|
folder.bypass(geom->output("Normal"));
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2016-07-16 13:16:54 +02:00
|
|
|
folder.bypass(normal_in->link);
|
2016-05-02 00:05:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO(sergey): Ignore bump with zero strength. */
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-30 19:05:08 +01:00
|
|
|
/* Curves node */
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
CurvesNode::CurvesNode(const NodeType *node_type) : ShaderNode(node_type) {}
|
2012-03-26 12:45:14 +00:00
|
|
|
|
2016-07-30 23:30:36 +02:00
|
|
|
void CurvesNode::constant_fold(const ConstantFolder &folder, ShaderInput *value_in)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
|
|
|
|
|
/* evaluate fully constant node */
|
2016-08-22 11:11:45 +03:00
|
|
|
if (folder.all_inputs_constant()) {
|
2016-10-24 12:26:12 +02:00
|
|
|
if (curves.size() == 0) {
|
2016-07-30 23:30:36 +02:00
|
|
|
return;
|
2016-10-24 12:26:12 +02:00
|
|
|
}
|
2016-07-30 23:30:36 +02:00
|
|
|
|
|
|
|
|
float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
|
|
|
|
|
float3 result;
|
|
|
|
|
|
2022-03-21 17:33:24 +01:00
|
|
|
result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, extrapolate, curves.size()).x;
|
|
|
|
|
result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, extrapolate, curves.size()).y;
|
|
|
|
|
result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, extrapolate, curves.size()).z;
|
2016-07-30 23:30:36 +02:00
|
|
|
|
|
|
|
|
folder.make_constant(interp(value, result, fac));
|
|
|
|
|
}
|
2016-08-22 11:11:45 +03:00
|
|
|
/* remove no-op node */
|
|
|
|
|
else if (!fac_in->link && fac == 0.0f) {
|
|
|
|
|
/* link is not null because otherwise all inputs are constant */
|
|
|
|
|
folder.bypass(value_in->link);
|
|
|
|
|
}
|
2016-07-30 23:30:36 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-21 00:19:51 +02:00
|
|
|
void CurvesNode::compile(SVMCompiler &compiler,
|
|
|
|
|
int type,
|
|
|
|
|
ShaderInput *value_in,
|
|
|
|
|
ShaderOutput *value_out)
|
2012-03-26 12:45:14 +00:00
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (curves.size() == 0) {
|
2016-05-08 01:54:35 +02:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-05-08 01:54:35 +02:00
|
|
|
|
2012-03-26 12:45:14 +00:00
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
|
2022-07-12 17:22:36 +02:00
|
|
|
compiler.add_node(ShaderNodeType(type),
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(fac_in),
|
2016-06-21 00:19:51 +02:00
|
|
|
compiler.stack_assign(value_in),
|
2022-03-21 17:33:24 +01:00
|
|
|
compiler.stack_assign(value_out),
|
|
|
|
|
extrapolate),
|
2015-12-04 20:17:25 +05:00
|
|
|
__float_as_int(min_x),
|
|
|
|
|
__float_as_int(max_x));
|
2016-05-08 01:54:35 +02:00
|
|
|
|
|
|
|
|
compiler.add_node(curves.size());
|
2023-09-17 09:01:48 +10:00
|
|
|
for (int i = 0; i < curves.size(); i++) {
|
2016-05-08 01:54:35 +02:00
|
|
|
compiler.add_node(float3_to_float4(curves[i]));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-03-26 12:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-21 00:19:51 +02:00
|
|
|
void CurvesNode::compile(OSLCompiler &compiler, const char *name)
|
2012-03-26 12:45:14 +00:00
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (curves.size() == 0) {
|
2016-05-08 01:54:35 +02:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-12-11 14:39:37 +00:00
|
|
|
|
2016-05-08 01:54:35 +02:00
|
|
|
compiler.parameter_color_array("ramp", curves);
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "min_x");
|
|
|
|
|
compiler.parameter(this, "max_x");
|
2022-03-21 17:33:24 +01:00
|
|
|
compiler.parameter(this, "extrapolate");
|
2016-06-21 00:19:51 +02:00
|
|
|
compiler.add(this, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CurvesNode::compile(SVMCompiler & /*compiler*/)
|
|
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CurvesNode::compile(OSLCompiler & /*compiler*/)
|
|
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* RGBCurvesNode */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(RGBCurvesNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("rgb_curves", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
|
|
|
|
|
SOCKET_FLOAT(min_x, "Min X", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(max_x, "Max X", 1.0f);
|
2022-03-21 17:33:24 +01:00
|
|
|
SOCKET_BOOLEAN(extrapolate, "Extrapolate", true);
|
2016-06-21 00:19:51 +02:00
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(value, "Color", zero_float3());
|
2016-06-21 00:19:51 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(value, "Color");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
RGBCurvesNode::RGBCurvesNode() : CurvesNode(get_node_type()) {}
|
2016-06-21 00:19:51 +02:00
|
|
|
|
2016-07-30 23:30:36 +02:00
|
|
|
void RGBCurvesNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
CurvesNode::constant_fold(folder, input("Color"));
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-21 00:19:51 +02:00
|
|
|
void RGBCurvesNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2022-07-12 17:22:36 +02:00
|
|
|
CurvesNode::compile(compiler, NODE_CURVES, input("Color"), output("Color"));
|
2016-06-21 00:19:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RGBCurvesNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
CurvesNode::compile(compiler, "node_rgb_curves");
|
2012-03-26 12:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
2012-12-11 14:39:37 +00:00
|
|
|
/* VectorCurvesNode */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(VectorCurvesNode)
|
2012-12-11 14:39:37 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("vector_curves", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
|
|
|
|
|
SOCKET_FLOAT(min_x, "Min X", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(max_x, "Max X", 1.0f);
|
2022-03-21 17:33:24 +01:00
|
|
|
SOCKET_BOOLEAN(extrapolate, "Extrapolate", true);
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(value, "Vector", zero_float3());
|
2015-12-15 16:23:33 +05:00
|
|
|
|
2016-06-21 00:19:51 +02:00
|
|
|
SOCKET_OUT_VECTOR(value, "Vector");
|
2016-05-07 19:48:28 +02:00
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VectorCurvesNode::VectorCurvesNode() : CurvesNode(get_node_type()) {}
|
2012-12-11 14:39:37 +00:00
|
|
|
|
2016-07-30 23:30:36 +02:00
|
|
|
void VectorCurvesNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
CurvesNode::constant_fold(folder, input("Vector"));
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 14:39:37 +00:00
|
|
|
void VectorCurvesNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2022-07-12 17:22:36 +02:00
|
|
|
CurvesNode::compile(compiler, NODE_CURVES, input("Vector"), output("Vector"));
|
2012-12-11 14:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VectorCurvesNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-06-21 00:19:51 +02:00
|
|
|
CurvesNode::compile(compiler, "node_vector_curves");
|
2012-12-11 14:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
2021-09-30 19:05:08 +01:00
|
|
|
/* FloatCurveNode */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(FloatCurveNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("float_curve", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_FLOAT_ARRAY(curve, "Curve", array<float>());
|
|
|
|
|
SOCKET_FLOAT(min_x, "Min X", 0.0f);
|
|
|
|
|
SOCKET_FLOAT(max_x, "Max X", 1.0f);
|
2022-03-21 17:33:24 +01:00
|
|
|
SOCKET_BOOLEAN(extrapolate, "Extrapolate", true);
|
2021-09-30 19:05:08 +01:00
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Factor", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(value, "Value", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_FLOAT(value, "Value");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
FloatCurveNode::FloatCurveNode() : ShaderNode(get_node_type()) {}
|
2021-09-30 19:05:08 +01:00
|
|
|
|
|
|
|
|
void FloatCurveNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *value_in = input("Value");
|
|
|
|
|
ShaderInput *fac_in = input("Factor");
|
|
|
|
|
|
|
|
|
|
/* evaluate fully constant node */
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
if (curve.size() == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float pos = (value - min_x) / (max_x - min_x);
|
2022-03-21 17:33:24 +01:00
|
|
|
float result = float_ramp_lookup(curve.data(), pos, true, extrapolate, curve.size());
|
2021-09-30 19:05:08 +01:00
|
|
|
|
|
|
|
|
folder.make_constant(value + fac * (result - value));
|
|
|
|
|
}
|
|
|
|
|
/* remove no-op node */
|
|
|
|
|
else if (!fac_in->link && fac == 0.0f) {
|
|
|
|
|
/* link is not null because otherwise all inputs are constant */
|
|
|
|
|
folder.bypass(value_in->link);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FloatCurveNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (curve.size() == 0) {
|
2021-09-30 19:05:08 +01:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2021-09-30 19:05:08 +01:00
|
|
|
|
|
|
|
|
ShaderInput *value_in = input("Value");
|
|
|
|
|
ShaderInput *fac_in = input("Factor");
|
|
|
|
|
ShaderOutput *value_out = output("Value");
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_FLOAT_CURVE,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(fac_in),
|
|
|
|
|
compiler.stack_assign(value_in),
|
2022-03-21 17:33:24 +01:00
|
|
|
compiler.stack_assign(value_out),
|
|
|
|
|
extrapolate),
|
2021-09-30 19:05:08 +01:00
|
|
|
__float_as_int(min_x),
|
|
|
|
|
__float_as_int(max_x));
|
|
|
|
|
|
|
|
|
|
compiler.add_node(curve.size());
|
2023-09-17 09:01:48 +10:00
|
|
|
for (int i = 0; i < curve.size(); i++) {
|
2021-09-30 19:05:08 +01:00
|
|
|
compiler.add_node(make_float4(curve[i]));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2021-09-30 19:05:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FloatCurveNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (curve.size() == 0) {
|
2021-09-30 19:05:08 +01:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2021-09-30 19:05:08 +01:00
|
|
|
|
|
|
|
|
compiler.parameter_array("ramp", curve.data(), curve.size());
|
|
|
|
|
compiler.parameter(this, "min_x");
|
|
|
|
|
compiler.parameter(this, "max_x");
|
2022-03-21 17:33:24 +01:00
|
|
|
compiler.parameter(this, "extrapolate");
|
2021-09-30 19:05:08 +01:00
|
|
|
compiler.add(this, "node_float_curve");
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-26 12:45:14 +00:00
|
|
|
/* RGBRampNode */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(RGBRampNode)
|
2012-03-26 12:45:14 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
|
|
|
|
|
SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
|
|
|
|
|
SOCKET_BOOLEAN(interpolate, "Interpolate", true);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_COLOR(color, "Color");
|
|
|
|
|
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
2013-05-10 11:44:24 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
RGBRampNode::RGBRampNode() : ShaderNode(get_node_type()) {}
|
2012-03-26 12:45:14 +00:00
|
|
|
|
2016-07-30 23:30:36 +02:00
|
|
|
void RGBRampNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (ramp.size() == 0 || ramp.size() != ramp_alpha.size()) {
|
2016-07-30 23:30:36 +02:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-07-30 23:30:36 +02:00
|
|
|
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
|
|
|
|
|
|
|
|
|
|
/* clamp int as well in case of NaN */
|
|
|
|
|
int i = clamp((int)f, 0, ramp.size() - 1);
|
|
|
|
|
float t = f - (float)i;
|
|
|
|
|
|
|
|
|
|
bool use_lerp = interpolate && t > 0.0f;
|
|
|
|
|
|
|
|
|
|
if (folder.output == output("Color")) {
|
|
|
|
|
float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
|
|
|
|
|
folder.make_constant(color);
|
|
|
|
|
}
|
|
|
|
|
else if (folder.output == output("Alpha")) {
|
|
|
|
|
float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
|
|
|
|
|
folder.make_constant(alpha);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-26 12:45:14 +00:00
|
|
|
void RGBRampNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (ramp.size() == 0 || ramp.size() != ramp_alpha.size()) {
|
2016-05-08 01:54:35 +02:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2016-05-08 01:54:35 +02:00
|
|
|
|
2012-03-26 12:45:14 +00:00
|
|
|
ShaderInput *fac_in = input("Fac");
|
|
|
|
|
ShaderOutput *color_out = output("Color");
|
2012-03-26 13:21:43 +00:00
|
|
|
ShaderOutput *alpha_out = output("Alpha");
|
2012-03-26 12:45:14 +00:00
|
|
|
|
2013-05-10 11:44:24 +00:00
|
|
|
compiler.add_node(NODE_RGB_RAMP,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(fac_in),
|
|
|
|
|
compiler.stack_assign_if_linked(color_out),
|
|
|
|
|
compiler.stack_assign_if_linked(alpha_out)),
|
2013-05-10 11:44:24 +00:00
|
|
|
interpolate);
|
2016-05-08 01:54:35 +02:00
|
|
|
|
|
|
|
|
compiler.add_node(ramp.size());
|
2023-09-17 09:01:48 +10:00
|
|
|
for (int i = 0; i < ramp.size(); i++) {
|
2016-05-08 01:54:35 +02:00
|
|
|
compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-03-26 12:45:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RGBRampNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (ramp.size() == 0 || ramp.size() != ramp_alpha.size()) {
|
2016-05-08 01:54:35 +02:00
|
|
|
return;
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-10-10 15:56:43 +00:00
|
|
|
|
2016-05-08 01:54:35 +02:00
|
|
|
compiler.parameter_color_array("ramp_color", ramp);
|
|
|
|
|
compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "interpolate");
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2012-03-26 12:45:14 +00:00
|
|
|
compiler.add(this, "node_rgb_ramp");
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-10 15:56:43 +00:00
|
|
|
/* Set Normal Node */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(SetNormalNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("set_normal", create, NodeType::SHADER);
|
|
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_VECTOR(direction, "Direction", zero_float3());
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_NORMAL(normal, "Normal");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
SetNormalNode::SetNormalNode() : ShaderNode(get_node_type()) {}
|
2012-10-10 15:56:43 +00:00
|
|
|
|
|
|
|
|
void SetNormalNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *direction_in = input("Direction");
|
|
|
|
|
ShaderOutput *normal_out = output("Normal");
|
|
|
|
|
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.add_node(NODE_CLOSURE_SET_NORMAL,
|
|
|
|
|
compiler.stack_assign(direction_in),
|
|
|
|
|
compiler.stack_assign(normal_out));
|
2012-10-10 15:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetNormalNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2018-07-06 10:17:58 +02:00
|
|
|
compiler.add(this, "node_set_normal");
|
2012-10-10 15:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* OSLNode */
|
2012-11-03 14:32:35 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
OSLNode::OSLNode() : ShaderNode(new NodeType(NodeType::SHADER))
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2019-04-21 02:18:19 +02:00
|
|
|
special_type = SHADER_SPECIAL_TYPE_OSL;
|
2022-11-30 20:50:11 +01:00
|
|
|
has_emission = false;
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
OSLNode::~OSLNode()
|
|
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
delete type;
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
ShaderNode *OSLNode::clone(ShaderGraph *graph) const
|
2016-06-18 12:30:59 +02:00
|
|
|
{
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
return OSLNode::create(graph, this->inputs.size(), this);
|
2016-06-18 12:30:59 +02:00
|
|
|
}
|
|
|
|
|
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
OSLNode *OSLNode::create(ShaderGraph *graph, size_t num_inputs, const OSLNode *from)
|
2016-05-07 19:48:28 +02:00
|
|
|
{
|
|
|
|
|
/* allocate space for the node itself and parameters, aligned to 16 bytes
|
|
|
|
|
* assuming that's the most parameter types need */
|
|
|
|
|
size_t node_size = align_up(sizeof(OSLNode), 16);
|
|
|
|
|
size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
|
|
|
|
|
|
|
|
|
|
char *node_memory = (char *)operator new(node_size + inputs_size);
|
|
|
|
|
memset(node_memory, 0, node_size + inputs_size);
|
|
|
|
|
|
2016-10-24 12:26:12 +02:00
|
|
|
if (!from) {
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
OSLNode *node = new (node_memory) OSLNode();
|
|
|
|
|
node->set_owner(graph);
|
|
|
|
|
return node;
|
2016-07-21 02:50:30 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* copy input default values and node type for cloning */
|
|
|
|
|
memcpy(node_memory + node_size, (char *)from + node_size, inputs_size);
|
|
|
|
|
|
|
|
|
|
OSLNode *node = new (node_memory) OSLNode(*from);
|
|
|
|
|
node->type = new NodeType(*(from->type));
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
node->set_owner(from->owner);
|
2016-07-21 02:50:30 +02:00
|
|
|
return node;
|
|
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *OSLNode::input_default_value()
|
|
|
|
|
{
|
|
|
|
|
/* pointer to default value storage, which is the same as our actual value */
|
|
|
|
|
size_t num_inputs = type->inputs.size();
|
|
|
|
|
size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
|
|
|
|
|
return (char *)this + align_up(sizeof(OSLNode), 16) + inputs_size;
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
|
2022-11-23 18:02:45 +01:00
|
|
|
void OSLNode::add_input(ustring name, SocketType::Type socket_type, const int flags)
|
2016-05-29 15:10:34 +02:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
char *memory = input_default_value();
|
|
|
|
|
size_t offset = memory - (char *)this;
|
|
|
|
|
const_cast<NodeType *>(type)->register_input(
|
2022-11-23 18:02:45 +01:00
|
|
|
name, name, socket_type, offset, memory, NULL, NULL, flags | SocketType::LINKABLE);
|
2016-05-07 19:48:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLNode::add_output(ustring name, SocketType::Type socket_type)
|
|
|
|
|
{
|
|
|
|
|
const_cast<NodeType *>(type)->register_output(name, name, socket_type);
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLNode::compile(SVMCompiler &)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
|
|
|
|
/* doesn't work for SVM, obviously ... */
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
void OSLNode::compile(OSLCompiler &compiler)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2023-09-17 09:01:48 +10:00
|
|
|
if (!filepath.empty()) {
|
2012-11-03 14:32:35 +00:00
|
|
|
compiler.add(this, filepath.c_str(), true);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-11-03 14:32:35 +00:00
|
|
|
compiler.add(this, bytecode_hash.c_str(), false);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
/* Normal Map */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(NormalMapNode)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("normal_map", create, NodeType::SHADER);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum space_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
|
|
|
|
|
space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
|
|
|
|
|
space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
|
|
|
|
|
space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
|
|
|
|
|
space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
|
2019-01-14 15:41:24 +01:00
|
|
|
SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(attribute, "Attribute", ustring());
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
|
|
|
|
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_NORMAL(normal, "Normal");
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
|
|
|
|
}
|
2012-11-08 16:35:20 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
NormalMapNode::NormalMapNode() : ShaderNode(get_node_type()) {}
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
|
2018-02-18 03:20:39 +01:00
|
|
|
if (attribute.empty()) {
|
2012-11-06 19:59:02 +00:00
|
|
|
attributes->add(ATTR_STD_UV_TANGENT);
|
|
|
|
|
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
|
|
|
|
attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
void NormalMapNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *color_in = input("Color");
|
2012-11-08 16:35:20 +00:00
|
|
|
ShaderInput *strength_in = input("Strength");
|
2012-11-06 19:59:02 +00:00
|
|
|
ShaderOutput *normal_out = output("Normal");
|
|
|
|
|
int attr = 0, attr_sign = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 16:13:14 +02:00
|
|
|
if (space == NODE_NORMAL_MAP_TANGENT) {
|
2018-02-18 03:20:39 +01:00
|
|
|
if (attribute.empty()) {
|
2012-11-06 19:59:02 +00:00
|
|
|
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
|
|
|
|
|
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
|
|
|
|
attr_sign = compiler.attribute(
|
|
|
|
|
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
compiler.add_node(NODE_NORMAL_MAP,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(color_in),
|
|
|
|
|
compiler.stack_assign(strength_in),
|
|
|
|
|
compiler.stack_assign(normal_out),
|
2016-05-29 16:13:14 +02:00
|
|
|
space),
|
2012-11-06 19:59:02 +00:00
|
|
|
attr,
|
|
|
|
|
attr_sign);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-06 19:59:02 +00:00
|
|
|
void NormalMapNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
if (space == NODE_NORMAL_MAP_TANGENT) {
|
2018-02-18 03:20:39 +01:00
|
|
|
if (attribute.empty()) {
|
2012-11-06 19:59:02 +00:00
|
|
|
compiler.parameter("attr_name", ustring("geom:tangent"));
|
|
|
|
|
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
|
|
|
|
compiler.parameter("attr_sign_name",
|
|
|
|
|
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "space");
|
2018-07-06 10:17:58 +02:00
|
|
|
compiler.add(this, "node_normal_map");
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tangent */
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
NODE_DEFINE(TangentNode)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2016-05-07 19:48:28 +02:00
|
|
|
NodeType *type = NodeType::add("tangent", create, NodeType::SHADER);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum direction_type_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
direction_type_enum.insert("radial", NODE_TANGENT_RADIAL);
|
|
|
|
|
direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
static NodeEnum axis_enum;
|
2016-06-11 21:56:47 +02:00
|
|
|
axis_enum.insert("x", NODE_TANGENT_AXIS_X);
|
|
|
|
|
axis_enum.insert("y", NODE_TANGENT_AXIS_Y);
|
|
|
|
|
axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(attribute, "Attribute", ustring());
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
SOCKET_OUT_NORMAL(tangent, "Tangent");
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
return type;
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
TangentNode::TangentNode() : ShaderNode(get_node_type()) {}
|
2012-11-06 19:59:02 +00:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link()) {
|
2016-05-29 16:13:14 +02:00
|
|
|
if (direction_type == NODE_TANGENT_UVMAP) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (attribute.empty()) {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_UV_TANGENT);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2013-12-31 17:30:34 +01:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2013-12-31 17:30:34 +01:00
|
|
|
attributes->add(ATTR_STD_GENERATED);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
2018-07-06 10:17:58 +02:00
|
|
|
|
2013-12-31 17:30:34 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TangentNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderOutput *tangent_out = output("Tangent");
|
|
|
|
|
int attr;
|
|
|
|
|
|
2016-05-29 16:13:14 +02:00
|
|
|
if (direction_type == NODE_TANGENT_UVMAP) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (attribute.empty()) {
|
2012-11-06 19:59:02 +00:00
|
|
|
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-11-06 19:59:02 +00:00
|
|
|
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
2023-09-17 09:01:48 +10:00
|
|
|
else {
|
2012-11-06 19:59:02 +00:00
|
|
|
attr = compiler.attribute(ATTR_STD_GENERATED);
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
|
|
|
|
|
compiler.add_node(
|
|
|
|
|
NODE_TANGENT,
|
2016-05-02 20:12:42 +02:00
|
|
|
compiler.encode_uchar4(compiler.stack_assign(tangent_out), direction_type, axis),
|
2016-05-29 16:13:14 +02:00
|
|
|
attr);
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TangentNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2016-05-29 16:13:14 +02:00
|
|
|
if (direction_type == NODE_TANGENT_UVMAP) {
|
2023-09-17 09:01:48 +10:00
|
|
|
if (attribute.empty()) {
|
2012-11-06 19:59:02 +00:00
|
|
|
compiler.parameter("attr_name", ustring("geom:tangent"));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-11-06 19:59:02 +00:00
|
|
|
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
2023-09-17 09:01:48 +10:00
|
|
|
}
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
compiler.parameter(this, "direction_type");
|
|
|
|
|
compiler.parameter(this, "axis");
|
2018-07-06 10:17:58 +02:00
|
|
|
compiler.add(this, "node_tangent");
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
2017-08-18 18:37:05 +02:00
|
|
|
/* Bevel */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(BevelNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("bevel", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
SOCKET_INT(samples, "Samples", 4);
|
|
|
|
|
|
|
|
|
|
SOCKET_IN_FLOAT(radius, "Radius", 0.05f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2017-08-18 18:37:05 +02:00
|
|
|
|
|
|
|
|
SOCKET_OUT_NORMAL(bevel, "Normal");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
BevelNode::BevelNode() : ShaderNode(get_node_type()) {}
|
2017-08-18 18:37:05 +02:00
|
|
|
|
|
|
|
|
void BevelNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *radius_in = input("Radius");
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
ShaderOutput *normal_out = output("Normal");
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_BEVEL,
|
|
|
|
|
compiler.encode_uchar4(samples,
|
|
|
|
|
compiler.stack_assign(radius_in),
|
|
|
|
|
compiler.stack_assign_if_linked(normal_in),
|
|
|
|
|
compiler.stack_assign(normal_out)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BevelNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
compiler.parameter(this, "samples");
|
|
|
|
|
compiler.add(this, "node_bevel");
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-13 13:11:03 +01:00
|
|
|
/* Displacement */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(DisplacementNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("displacement", create, NodeType::SHADER);
|
|
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
static NodeEnum space_enum;
|
|
|
|
|
space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
|
|
|
|
|
space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
|
|
|
|
|
|
2019-01-14 15:41:24 +01:00
|
|
|
SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_OBJECT);
|
2018-01-21 00:40:42 +01:00
|
|
|
|
2018-01-13 13:11:03 +01:00
|
|
|
SOCKET_IN_FLOAT(height, "Height", 0.0f);
|
2018-01-21 00:40:42 +01:00
|
|
|
SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.5f);
|
2018-01-13 13:11:03 +01:00
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
|
2018-01-13 13:11:03 +01:00
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(displacement, "Displacement");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
DisplacementNode::DisplacementNode() : ShaderNode(get_node_type()) {}
|
2018-01-13 13:11:03 +01:00
|
|
|
|
2018-03-11 22:42:38 +01:00
|
|
|
void DisplacementNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
|
|
|
|
if ((height - midlevel == 0.0f) || (scale == 0.0f)) {
|
|
|
|
|
folder.make_zero();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-13 13:11:03 +01:00
|
|
|
void DisplacementNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *height_in = input("Height");
|
2018-01-21 00:40:42 +01:00
|
|
|
ShaderInput *midlevel_in = input("Midlevel");
|
2018-01-13 13:11:03 +01:00
|
|
|
ShaderInput *scale_in = input("Scale");
|
|
|
|
|
ShaderInput *normal_in = input("Normal");
|
|
|
|
|
ShaderOutput *displacement_out = output("Displacement");
|
|
|
|
|
|
|
|
|
|
compiler.add_node(NODE_DISPLACEMENT,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(height_in),
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.stack_assign(midlevel_in),
|
2018-01-13 13:11:03 +01:00
|
|
|
compiler.stack_assign(scale_in),
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.stack_assign_if_linked(normal_in)),
|
|
|
|
|
compiler.stack_assign(displacement_out),
|
|
|
|
|
space);
|
2018-01-13 13:11:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplacementNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.parameter(this, "space");
|
2018-01-13 13:11:03 +01:00
|
|
|
compiler.add(this, "node_displacement");
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
/* Vector Displacement */
|
|
|
|
|
|
|
|
|
|
NODE_DEFINE(VectorDisplacementNode)
|
|
|
|
|
{
|
|
|
|
|
NodeType *type = NodeType::add("vector_displacement", create, NodeType::SHADER);
|
|
|
|
|
|
|
|
|
|
static NodeEnum space_enum;
|
|
|
|
|
space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
|
|
|
|
|
space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
|
|
|
|
|
space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
|
|
|
|
|
|
|
|
|
|
SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
|
2018-02-18 03:20:39 +01:00
|
|
|
SOCKET_STRING(attribute, "Attribute", ustring());
|
2018-01-21 00:40:42 +01:00
|
|
|
|
2021-02-17 01:47:18 +01:00
|
|
|
SOCKET_IN_COLOR(vector, "Vector", zero_float3());
|
2018-01-21 00:40:42 +01:00
|
|
|
SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f);
|
|
|
|
|
SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
|
|
|
|
|
|
|
|
|
|
SOCKET_OUT_VECTOR(displacement, "Displacement");
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(get_node_type()) {}
|
2018-01-21 00:40:42 +01:00
|
|
|
|
2018-03-11 22:42:38 +01:00
|
|
|
void VectorDisplacementNode::constant_fold(const ConstantFolder &folder)
|
|
|
|
|
{
|
|
|
|
|
if (folder.all_inputs_constant()) {
|
2021-02-17 01:47:18 +01:00
|
|
|
if ((vector == zero_float3() && midlevel == 0.0f) || (scale == 0.0f)) {
|
2018-03-11 22:42:38 +01:00
|
|
|
folder.make_zero();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
|
|
|
|
{
|
2021-08-13 13:19:05 +02:00
|
|
|
if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
|
2018-02-18 03:20:39 +01:00
|
|
|
if (attribute.empty()) {
|
2018-01-21 00:40:42 +01:00
|
|
|
attributes->add(ATTR_STD_UV_TANGENT);
|
|
|
|
|
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
|
|
|
|
attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
ShaderNode::attributes(shader, attributes);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
void VectorDisplacementNode::compile(SVMCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
ShaderInput *vector_in = input("Vector");
|
|
|
|
|
ShaderInput *midlevel_in = input("Midlevel");
|
|
|
|
|
ShaderInput *scale_in = input("Scale");
|
|
|
|
|
ShaderOutput *displacement_out = output("Displacement");
|
|
|
|
|
int attr = 0, attr_sign = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
if (space == NODE_NORMAL_MAP_TANGENT) {
|
2018-02-18 03:20:39 +01:00
|
|
|
if (attribute.empty()) {
|
2018-01-21 00:40:42 +01:00
|
|
|
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
|
|
|
|
|
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
|
|
|
|
attr_sign = compiler.attribute(
|
|
|
|
|
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-01-21 00:40:42 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.add_node(NODE_VECTOR_DISPLACEMENT,
|
|
|
|
|
compiler.encode_uchar4(compiler.stack_assign(vector_in),
|
|
|
|
|
compiler.stack_assign(midlevel_in),
|
|
|
|
|
compiler.stack_assign(scale_in),
|
|
|
|
|
compiler.stack_assign(displacement_out)),
|
|
|
|
|
attr,
|
|
|
|
|
attr_sign);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.add_node(space);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
void VectorDisplacementNode::compile(OSLCompiler &compiler)
|
|
|
|
|
{
|
|
|
|
|
if (space == NODE_NORMAL_MAP_TANGENT) {
|
2018-02-18 03:20:39 +01:00
|
|
|
if (attribute.empty()) {
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.parameter("attr_name", ustring("geom:tangent"));
|
|
|
|
|
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
|
|
|
|
|
compiler.parameter("attr_sign_name",
|
|
|
|
|
ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-01-21 00:40:42 +01:00
|
|
|
compiler.parameter(this, "space");
|
|
|
|
|
compiler.add(this, "node_vector_displacement");
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|