Add Chromium-only Blender WebEngine parity work
This commit is contained in:
138
blender-5.2.0/intern/cycles/kernel/svm/ao.h
Normal file
138
blender-5.2.0/intern/cycles/kernel/svm/ao.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/integrator/path_state.h"
|
||||
|
||||
#include "kernel/bvh/bvh.h"
|
||||
|
||||
#include "kernel/sample/mapping.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __SHADER_RAYTRACE__
|
||||
|
||||
# ifdef __KERNEL_OPTIX__
|
||||
extern "C" __device__ float __direct_callable__svm_node_ao(
|
||||
# else
|
||||
ccl_device float svm_ao(
|
||||
# endif
|
||||
KernelGlobals kg,
|
||||
ConstIntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
float3 N,
|
||||
float max_dist,
|
||||
const int num_samples,
|
||||
const int flags)
|
||||
{
|
||||
if (flags & NODE_AO_GLOBAL_RADIUS) {
|
||||
max_dist = kernel_data.integrator.ao_bounces_distance;
|
||||
}
|
||||
|
||||
/* Early out if no sampling needed. */
|
||||
if (max_dist <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
/* Can't ray-trace from shaders like displacement, before BVH exists. */
|
||||
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (flags & NODE_AO_INSIDE) {
|
||||
N = -N;
|
||||
}
|
||||
|
||||
float3 T;
|
||||
float3 B;
|
||||
make_orthonormals(N, &T, &B);
|
||||
|
||||
/* TODO: support ray-tracing in shadow shader evaluation? */
|
||||
RNGState rng_state;
|
||||
path_state_rng_load(state, &rng_state);
|
||||
|
||||
int unoccluded = 0;
|
||||
for (int sample = 0; sample < num_samples; sample++) {
|
||||
const float2 rand_disk = path_branched_rng_2D(
|
||||
kg, &rng_state, sample, num_samples, PRNG_SURFACE_AO);
|
||||
|
||||
const float2 d = sample_uniform_disk(rand_disk);
|
||||
const float3 D = make_float3(d.x, d.y, safe_sqrtf(1.0f - dot(d, d)));
|
||||
|
||||
/* Create ray. */
|
||||
Ray ray;
|
||||
ray.P = sd->P;
|
||||
ray.D = to_global(D, T, B, N);
|
||||
ray.tmin = 0.0f;
|
||||
ray.tmax = max_dist;
|
||||
ray.time = sd->time;
|
||||
ray.self.object = sd->object;
|
||||
ray.self.prim = sd->prim;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
ray.dP = differential_zero_compact();
|
||||
ray.dD = differential_zero_compact();
|
||||
|
||||
if (flags & NODE_AO_ONLY_LOCAL) {
|
||||
if (!scene_intersect_local(kg, &ray, nullptr, sd->object, nullptr, 0)) {
|
||||
unoccluded++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!scene_intersect_shadow(kg, &ray, PATH_RAY_VISIBILITY_SHADOW_OPAQUE)) {
|
||||
unoccluded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ((float)unoccluded) / num_samples;
|
||||
}
|
||||
|
||||
template<uint node_feature_mask, typename ConstIntegratorGenericState>
|
||||
# if defined(__KERNEL_OPTIX__)
|
||||
ccl_device_inline
|
||||
# else
|
||||
ccl_device_noinline
|
||||
# endif
|
||||
void
|
||||
svm_node_ao(KernelGlobals kg,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeAmbientOcclusion &ccl_restrict node)
|
||||
{
|
||||
float ao = 1.0f;
|
||||
|
||||
IF_KERNEL_NODES_FEATURE(RAYTRACE)
|
||||
{
|
||||
float dist = stack_load(stack, node.dist);
|
||||
float3 normal = stack_load_float3_default(stack, node.normal_offset, sd->N);
|
||||
normal = safe_normalize(normal);
|
||||
|
||||
# ifdef __KERNEL_OPTIX__
|
||||
ao = optixDirectCall<float>(0, kg, state, sd, normal, dist, node.samples, node.flags);
|
||||
# else
|
||||
ao = svm_ao(kg, state, sd, normal, dist, node.samples, node.flags);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (stack_valid(node.out_ao_offset)) {
|
||||
stack_store_float(stack, node.out_ao_offset, ao);
|
||||
}
|
||||
|
||||
if (stack_valid(node.out_color_offset)) {
|
||||
const float3 color = stack_load(stack, node.color);
|
||||
stack_store_float3(stack, node.out_color_offset, ao * color);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __SHADER_RAYTRACE__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
62
blender-5.2.0/intern/cycles/kernel/svm/aov.h
Normal file
62
blender-5.2.0/intern/cycles/kernel/svm/aov.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/film/aov_passes.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_inline bool svm_node_aov_check(const uint32_t path_flag,
|
||||
const ccl_global float *render_buffer)
|
||||
{
|
||||
const bool is_primary = (path_flag & PATH_RAY_TRANSPARENT_BACKGROUND) &&
|
||||
(!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
|
||||
|
||||
return ((render_buffer != nullptr) && is_primary);
|
||||
}
|
||||
|
||||
template<uint node_feature_mask, typename ConstIntegratorGenericState>
|
||||
ccl_device void svm_node_aov_color(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeAOVColor &ccl_restrict node,
|
||||
ccl_global float *render_buffer)
|
||||
{
|
||||
IF_KERNEL_NODES_FEATURE(AOV)
|
||||
{
|
||||
/* Don't write AOV on texture cache miss, we'll try again when the texture exists. */
|
||||
if (sd->flag & SD_CACHE_MISS) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float3 val = stack_load(stack, node.color);
|
||||
film_write_aov_pass_color(kg, state, render_buffer, node.aov_offset, val);
|
||||
}
|
||||
}
|
||||
|
||||
template<uint node_feature_mask, typename ConstIntegratorGenericState>
|
||||
ccl_device void svm_node_aov_value(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeAOVValue &ccl_restrict node,
|
||||
ccl_global float *render_buffer)
|
||||
{
|
||||
IF_KERNEL_NODES_FEATURE(AOV)
|
||||
{
|
||||
/* Don't write AOV on texture cache miss, we'll try again when the texture exists. */
|
||||
if (sd->flag & SD_CACHE_MISS) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float val = stack_load(stack, node.value);
|
||||
film_write_aov_pass_value(kg, state, render_buffer, node.aov_offset, val);
|
||||
}
|
||||
}
|
||||
CCL_NAMESPACE_END
|
||||
224
blender-5.2.0/intern/cycles/kernel/svm/attribute.h
Normal file
224
blender-5.2.0/intern/cycles/kernel/svm/attribute.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/geom/attribute.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/primitive.h"
|
||||
#include "kernel/geom/volume.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Attribute Node */
|
||||
|
||||
ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const ccl_global SVMNodeAttr &ccl_restrict node,
|
||||
ccl_private NodeAttributeOutputType *type)
|
||||
{
|
||||
*type = node.output_type;
|
||||
|
||||
AttributeDescriptor desc;
|
||||
|
||||
if (sd->object != OBJECT_NONE) {
|
||||
desc = find_attribute(kg, sd, node.attr);
|
||||
if (!is_attribute_found(desc)) {
|
||||
desc = attribute_not_found();
|
||||
desc.type = (NodeAttributeType)node.output_type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* background */
|
||||
desc = attribute_not_found();
|
||||
desc.type = (NodeAttributeType)node.output_type;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* Store attribute to the stack. Float3Type is float3 or dual3. */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline void svm_node_attr_store(const NodeAttributeOutputType type,
|
||||
ccl_private float *stack,
|
||||
const uint out_offset,
|
||||
const ccl_private Float3Type &f)
|
||||
{
|
||||
using FloatType = dual_scalar_t<Float3Type>;
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT3) {
|
||||
stack_store(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
stack_store(stack, out_offset, FloatType(average(f)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Core surface attribute evaluation, returning Float3Type = float3 or dual3.
|
||||
* Fetches the attribute, applies output type conversion (float3 or scalar-as-float3),
|
||||
* and computes derivatives when Float3Type is a dual type. */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline Float3Type
|
||||
svm_node_attr_surface_eval(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const ccl_global SVMNodeAttr &ccl_restrict node,
|
||||
const NodeAttributeOutputType type,
|
||||
const AttributeDescriptor desc)
|
||||
{
|
||||
using FloatType = dual_scalar_t<Float3Type>;
|
||||
|
||||
if (sd->type == PRIMITIVE_LAMP && node.attr == ATTR_STD_UV) {
|
||||
Float3Type uv(make_float3(1.0f - sd->u - sd->v, sd->u, 0.0f));
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
uv.dx = make_float3(-sd->du.dx - sd->dv.dx, sd->du.dx, 0.0f);
|
||||
uv.dy = make_float3(-sd->du.dy - sd->dv.dy, sd->du.dy, 0.0f);
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
|
||||
if (node.attr == ATTR_STD_GENERATED && !is_attribute_found(desc)) {
|
||||
Float3Type f = shading_position<Float3Type>(sd);
|
||||
object_inverse_position_transform_if_object(kg, sd, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Surface attribute fetch with output type conversion. */
|
||||
if (desc.type == NODE_ATTR_FLOAT) {
|
||||
FloatType f = primitive_surface_attribute<FloatType>(kg, sd, desc);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) {
|
||||
return make_float3(FloatType(1.0f));
|
||||
}
|
||||
return make_float3(f, f, f);
|
||||
}
|
||||
|
||||
if (desc.type == NODE_ATTR_FLOAT2) {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
dual2 f = primitive_surface_attribute<dual2>(kg, sd, desc);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
return make_float3(f.x());
|
||||
}
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) {
|
||||
return make_float3(FloatType(1.0f));
|
||||
}
|
||||
return make_float3(f);
|
||||
}
|
||||
else {
|
||||
float2 f = primitive_surface_attribute<float2>(kg, sd, desc);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
return make_float3(f.x);
|
||||
}
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) {
|
||||
return make_float3(FloatType(1.0f));
|
||||
}
|
||||
return make_float3(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
dual4 f = primitive_surface_attribute<dual4>(kg, sd, desc);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
return make_float3(average(make_float3(f)));
|
||||
}
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) {
|
||||
return make_float3(f.w());
|
||||
}
|
||||
return make_float3(f);
|
||||
}
|
||||
else {
|
||||
float4 f = primitive_surface_attribute<float4>(kg, sd, desc);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
return make_float3(average(make_float3(f)));
|
||||
}
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) {
|
||||
return make_float3(f.w);
|
||||
}
|
||||
return make_float3(f);
|
||||
}
|
||||
}
|
||||
|
||||
Float3Type f = primitive_surface_attribute<Float3Type>(kg, sd, desc);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
return make_float3(average(f));
|
||||
}
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) {
|
||||
return make_float3(FloatType(1.0f));
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Surface attribute node. */
|
||||
ccl_device_noinline void svm_node_attr_surface(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeAttr &ccl_restrict node)
|
||||
{
|
||||
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
|
||||
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type);
|
||||
|
||||
float3 data = svm_node_attr_surface_eval<float3>(kg, sd, node, type, desc);
|
||||
svm_node_attr_store(type, stack, node.out_offset, data);
|
||||
}
|
||||
|
||||
/* Evaluate surface attributes with derivatives and optional bump offset.
|
||||
* Used for derivative tracking and bump mapping. */
|
||||
|
||||
ccl_device_noinline void svm_node_attr_derivative(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeAttr &ccl_restrict node)
|
||||
{
|
||||
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
|
||||
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type);
|
||||
|
||||
dual3 data = svm_node_attr_surface_eval<dual3>(kg, sd, node, type, desc);
|
||||
if (node.bump_offset == NODE_BUMP_OFFSET_DX) {
|
||||
data.val += data.dx * node.bump_filter_width;
|
||||
}
|
||||
else if (node.bump_offset == NODE_BUMP_OFFSET_DY) {
|
||||
data.val += data.dy * node.bump_filter_width;
|
||||
}
|
||||
|
||||
if (node.store_derivatives) {
|
||||
svm_node_attr_store(type, stack, node.out_offset, data);
|
||||
}
|
||||
else {
|
||||
svm_node_attr_store(type, stack, node.out_offset, float3(data.val));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __VOLUME__
|
||||
/* Volume attribute node. Volumes have no derivatives or bump. */
|
||||
ccl_device_noinline void svm_node_attr_volume(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeAttr &ccl_restrict node)
|
||||
{
|
||||
kernel_assert(primitive_is_volume_attribute(sd));
|
||||
|
||||
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
|
||||
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type);
|
||||
|
||||
const bool stochastic_sample = __float_as_uint(node.bump_filter_width);
|
||||
const float4 value = volume_attribute_float4(kg, sd, desc, stochastic_sample);
|
||||
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
stack_store_float(stack, node.out_offset, volume_attribute_value<float>(value));
|
||||
}
|
||||
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
|
||||
stack_store_float3(stack, node.out_offset, volume_attribute_value<float3>(value));
|
||||
}
|
||||
else {
|
||||
stack_store_float(stack, node.out_offset, volume_attribute_alpha(value));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
330
blender-5.2.0/intern/cycles/kernel/svm/bevel.h
Normal file
330
blender-5.2.0/intern/cycles/kernel/svm/bevel.h
Normal file
@@ -0,0 +1,330 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/bvh/bvh.h"
|
||||
|
||||
#include "kernel/geom/motion_triangle.h"
|
||||
#include "kernel/geom/triangle.h"
|
||||
#include "kernel/geom/triangle_intersect.h"
|
||||
|
||||
#include "kernel/integrator/path_state.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __SHADER_RAYTRACE__
|
||||
|
||||
/* Planar Cubic BSSRDF falloff, reused for bevel.
|
||||
*
|
||||
* This is basically (Rm - x)^3, with some factors to normalize it. For sampling
|
||||
* we integrate 2*pi*x * (Rm - x)^3, which gives us a quintic equation that as
|
||||
* far as I can tell has no closed form solution. So we get an iterative solution
|
||||
* instead with newton-raphson. */
|
||||
|
||||
ccl_device float svm_bevel_cubic_eval(const float radius, const float r)
|
||||
{
|
||||
const float Rm = radius;
|
||||
|
||||
if (r >= Rm) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* integrate (2*pi*r * 10*(R - r)^3)/(pi * R^5) from 0 to R = 1 */
|
||||
const float Rm5 = (Rm * Rm) * (Rm * Rm) * Rm;
|
||||
const float f = Rm - r;
|
||||
const float num = f * f * f;
|
||||
|
||||
return (10.0f * num) / (Rm5 * M_PI_F);
|
||||
}
|
||||
|
||||
ccl_device float svm_bevel_cubic_pdf(const float radius, const float r)
|
||||
{
|
||||
return svm_bevel_cubic_eval(radius, r);
|
||||
}
|
||||
|
||||
/* solve 10x^2 - 20x^3 + 15x^4 - 4x^5 - xi == 0 */
|
||||
ccl_device_forceinline float svm_bevel_cubic_quintic_root_find(const float xi)
|
||||
{
|
||||
/* newton-raphson iteration, usually succeeds in 2-4 iterations, except
|
||||
* outside 0.02 ... 0.98 where it can go up to 10, so overall performance
|
||||
* should not be too bad */
|
||||
const float tolerance = 1e-6f;
|
||||
const int max_iteration_count = 10;
|
||||
float x = 0.25f;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max_iteration_count; i++) {
|
||||
const float x2 = x * x;
|
||||
const float x3 = x2 * x;
|
||||
const float nx = (1.0f - x);
|
||||
|
||||
const float f = 10.0f * x2 - 20.0f * x3 + 15.0f * x2 * x2 - 4.0f * x2 * x3 - xi;
|
||||
const float f_ = 20.0f * (x * nx) * (nx * nx);
|
||||
|
||||
if (fabsf(f) < tolerance || f_ == 0.0f) {
|
||||
break;
|
||||
}
|
||||
|
||||
x = saturatef(x - f / f_);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
ccl_device void svm_bevel_cubic_sample(const float radius,
|
||||
const float xi,
|
||||
ccl_private float *r,
|
||||
ccl_private float *h)
|
||||
{
|
||||
const float Rm = radius;
|
||||
float r_ = svm_bevel_cubic_quintic_root_find(xi);
|
||||
|
||||
r_ *= Rm;
|
||||
*r = r_;
|
||||
|
||||
/* h^2 + r^2 = Rm^2 */
|
||||
*h = safe_sqrtf(Rm * Rm - r_ * r_);
|
||||
}
|
||||
|
||||
/* Bevel shader averaging normals from nearby surfaces.
|
||||
*
|
||||
* Sampling strategy from: BSSRDF Importance Sampling, SIGGRAPH 2013
|
||||
* http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
|
||||
*/
|
||||
|
||||
# ifdef __KERNEL_OPTIX__
|
||||
extern "C" __device__ float3 __direct_callable__svm_node_bevel(
|
||||
# else
|
||||
ccl_device float3 svm_bevel(
|
||||
# endif
|
||||
KernelGlobals kg,
|
||||
ConstIntegratorState state,
|
||||
ccl_private ShaderData *sd,
|
||||
const float radius,
|
||||
const int num_samples)
|
||||
{
|
||||
/* Early out if no sampling needed. */
|
||||
if (radius <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) {
|
||||
return sd->N;
|
||||
}
|
||||
|
||||
/* Can't ray-trace from shaders like displacement, before BVH exists. */
|
||||
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
|
||||
return sd->N;
|
||||
}
|
||||
|
||||
/* Don't bevel for blurry indirect rays. */
|
||||
if (INTEGRATOR_STATE(state, path, min_ray_pdf) < 8.0f) {
|
||||
return sd->N;
|
||||
}
|
||||
|
||||
/* Setup for multi intersection. */
|
||||
LocalIntersection isect;
|
||||
uint lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_pixel),
|
||||
INTEGRATOR_STATE(state, path, rng_offset),
|
||||
INTEGRATOR_STATE(state, path, sample),
|
||||
0x64c6a40e);
|
||||
|
||||
/* Sample normals from surrounding points on surface. */
|
||||
float3 sum_N = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
/* TODO: support ray-tracing in shadow shader evaluation? */
|
||||
RNGState rng_state;
|
||||
path_state_rng_load(state, &rng_state);
|
||||
|
||||
for (int sample = 0; sample < num_samples; sample++) {
|
||||
float2 rand_disk = path_branched_rng_2D(
|
||||
kg, &rng_state, sample, num_samples, PRNG_SURFACE_BEVEL);
|
||||
|
||||
/* Pick random axis in local frame and point on disk. */
|
||||
float3 disk_N;
|
||||
float3 disk_T;
|
||||
float3 disk_B;
|
||||
float pick_pdf_N;
|
||||
float pick_pdf_T;
|
||||
float pick_pdf_B;
|
||||
|
||||
disk_N = sd->Ng;
|
||||
make_orthonormals(disk_N, &disk_T, &disk_B);
|
||||
|
||||
const float axisu = rand_disk.x;
|
||||
|
||||
if (axisu < 0.5f) {
|
||||
pick_pdf_N = 0.5f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.25f;
|
||||
rand_disk.x *= 2.0f;
|
||||
}
|
||||
else if (axisu < 0.75f) {
|
||||
const float3 tmp = disk_N;
|
||||
disk_N = disk_T;
|
||||
disk_T = tmp;
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.5f;
|
||||
pick_pdf_B = 0.25f;
|
||||
rand_disk.x = (rand_disk.x - 0.5f) * 4.0f;
|
||||
}
|
||||
else {
|
||||
const float3 tmp = disk_N;
|
||||
disk_N = disk_B;
|
||||
disk_B = tmp;
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.5f;
|
||||
rand_disk.x = (rand_disk.x - 0.75f) * 4.0f;
|
||||
}
|
||||
|
||||
/* Sample point on disk. */
|
||||
const float phi = M_2PI_F * rand_disk.x;
|
||||
float disk_r = rand_disk.y;
|
||||
float disk_height;
|
||||
|
||||
/* Perhaps find something better than Cubic BSSRDF, but happens to work well. */
|
||||
svm_bevel_cubic_sample(radius, disk_r, &disk_r, &disk_height);
|
||||
|
||||
const float3 disk_P = to_global(polar_to_cartesian(disk_r, phi), disk_T, disk_B);
|
||||
|
||||
/* Create ray. */
|
||||
Ray ray ccl_optional_struct_init;
|
||||
ray.P = sd->P + disk_N * disk_height + disk_P;
|
||||
ray.D = -disk_N;
|
||||
ray.tmin = 0.0f;
|
||||
ray.tmax = 2.0f * disk_height;
|
||||
ray.dP = differential_zero_compact();
|
||||
ray.dD = differential_zero_compact();
|
||||
ray.time = sd->time;
|
||||
ray.self.object = OBJECT_NONE;
|
||||
ray.self.prim = PRIM_NONE;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
|
||||
/* Intersect with the same object. if multiple intersections are found it
|
||||
* will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
|
||||
scene_intersect_local(kg, &ray, &isect, sd->object, &lcg_state, LOCAL_MAX_HITS);
|
||||
|
||||
const int num_eval_hits = min(isect.num_hits, LOCAL_MAX_HITS);
|
||||
|
||||
for (int hit = 0; hit < num_eval_hits; hit++) {
|
||||
/* Quickly retrieve P and Ng without setting up ShaderData. */
|
||||
float3 hit_P;
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
hit_P = triangle_point_from_uv(
|
||||
kg, sd, isect.hits[hit].prim, isect.hits[hit].u, isect.hits[hit].v);
|
||||
}
|
||||
# ifdef __OBJECT_MOTION__
|
||||
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
|
||||
float3 verts[3];
|
||||
motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
|
||||
hit_P = triangle_point_from_uv_and_verts(
|
||||
kg, sd, isect.hits[hit].u, isect.hits[hit].v, verts);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
||||
/* Get geometric normal. */
|
||||
float3 hit_Ng = isect.Ng[hit];
|
||||
const int object = isect.hits[hit].object;
|
||||
const uint object_flag = kernel_data_fetch(object_flag, object);
|
||||
if (object_negative_scale_applied(object_flag)) {
|
||||
hit_Ng = -hit_Ng;
|
||||
}
|
||||
|
||||
/* Compute smooth normal. */
|
||||
float3 N = hit_Ng;
|
||||
const int prim = isect.hits[hit].prim;
|
||||
const int shader = kernel_data_fetch(tri_shader, prim);
|
||||
|
||||
if (shader & SHADER_SMOOTH_NORMAL) {
|
||||
const float u = isect.hits[hit].u;
|
||||
const float v = isect.hits[hit].v;
|
||||
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
N = triangle_smooth_normal(kg, N, object, object_flag, prim, u, v);
|
||||
}
|
||||
# ifdef __OBJECT_MOTION__
|
||||
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
|
||||
N = motion_triangle_smooth_normal(kg, N, object, prim, u, v, sd->time);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
}
|
||||
|
||||
/* Transform normals to world space. */
|
||||
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_normal_transform(kg, sd, &N);
|
||||
object_normal_transform(kg, sd, &hit_Ng);
|
||||
}
|
||||
|
||||
/* Probability densities for local frame axes. */
|
||||
const float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
|
||||
const float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
|
||||
const float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
|
||||
|
||||
/* Multiple importance sample between 3 axes, power heuristic
|
||||
* found to be slightly better than balance heuristic. pdf_N
|
||||
* in the MIS weight and denominator canceled out. */
|
||||
float w = pdf_N / (sqr(pdf_N) + sqr(pdf_T) + sqr(pdf_B));
|
||||
if (isect.num_hits > LOCAL_MAX_HITS) {
|
||||
w *= isect.num_hits / (float)LOCAL_MAX_HITS;
|
||||
}
|
||||
|
||||
/* Real distance to sampled point. */
|
||||
const float r = len(hit_P - sd->P);
|
||||
|
||||
/* Compute weight. */
|
||||
const float pdf = svm_bevel_cubic_pdf(radius, r);
|
||||
const float disk_pdf = svm_bevel_cubic_pdf(radius, disk_r);
|
||||
|
||||
w *= pdf / disk_pdf;
|
||||
|
||||
/* Sum normal and weight. */
|
||||
sum_N += w * N;
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize. */
|
||||
const float3 N = safe_normalize(sum_N);
|
||||
return is_zero(N) ? sd->N : (sd->flag & SD_BACKFACING) ? -N : N;
|
||||
}
|
||||
|
||||
template<uint node_feature_mask, typename ConstIntegratorGenericState>
|
||||
# if defined(__KERNEL_OPTIX__)
|
||||
ccl_device_inline
|
||||
# else
|
||||
ccl_device_noinline
|
||||
# endif
|
||||
void
|
||||
svm_node_bevel(KernelGlobals kg,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeBevel &ccl_restrict node)
|
||||
{
|
||||
float3 bevel_N = sd->N;
|
||||
|
||||
IF_KERNEL_NODES_FEATURE(RAYTRACE)
|
||||
{
|
||||
float radius = stack_load(stack, node.radius);
|
||||
|
||||
# ifdef __KERNEL_OPTIX__
|
||||
bevel_N = optixDirectCall<float3>(1, kg, state, sd, radius, node.num_samples);
|
||||
# else
|
||||
bevel_N = svm_bevel(kg, state, sd, radius, node.num_samples);
|
||||
# endif
|
||||
|
||||
if (stack_valid(node.normal_offset)) {
|
||||
/* Preserve input normal. */
|
||||
const float3 ref_N = stack_load_float3(stack, node.normal_offset);
|
||||
bevel_N = normalize(ref_N + (bevel_N - sd->N));
|
||||
}
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.out_offset, bevel_N);
|
||||
}
|
||||
|
||||
#endif /* __SHADER_RAYTRACE__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
35
blender-5.2.0/intern/cycles/kernel/svm/blackbody.h
Normal file
35
blender-5.2.0/intern/cycles/kernel/svm/blackbody.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Adapted code from Open Shading Language. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/svm/math_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/colorspace.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Blackbody Node */
|
||||
|
||||
ccl_device_noinline void svm_node_blackbody(KernelGlobals kg,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeBlackbody &ccl_restrict node)
|
||||
{
|
||||
/* Input */
|
||||
const float temperature = stack_load(stack, node.temperature);
|
||||
|
||||
float3 color_rgb = rec709_to_rgb(kg, svm_math_blackbody_color_rec709(temperature));
|
||||
color_rgb = max(color_rgb, zero_float3());
|
||||
|
||||
stack_store_float3(stack, node.color_offset, color_rgb);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
113
blender-5.2.0/intern/cycles/kernel/svm/brick.h
Normal file
113
blender-5.2.0/intern/cycles/kernel/svm/brick.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Brick */
|
||||
|
||||
ccl_device_inline float brick_noise(uint n) /* fast integer noise */
|
||||
{
|
||||
uint nn;
|
||||
n = (n + 1013) & 0x7fffffff;
|
||||
n = (n >> 13) ^ n;
|
||||
nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
|
||||
return 0.5f * ((float)nn / 1073741824.0f);
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float2 svm_brick(const float3 p,
|
||||
const float mortar_size,
|
||||
const float mortar_smooth,
|
||||
const float bias,
|
||||
float brick_width,
|
||||
const float row_height,
|
||||
const float offset_amount,
|
||||
const int offset_frequency,
|
||||
const float squash_amount,
|
||||
const int squash_frequency)
|
||||
{
|
||||
int bricknum;
|
||||
int rownum;
|
||||
float offset = 0.0f;
|
||||
float x;
|
||||
float y;
|
||||
|
||||
rownum = floor_to_int(p.y / row_height);
|
||||
|
||||
if (offset_frequency && squash_frequency) {
|
||||
brick_width *= (rownum % squash_frequency) ? 1.0f : squash_amount; /* squash */
|
||||
offset = (rownum % offset_frequency) ? 0.0f : (brick_width * offset_amount); /* offset */
|
||||
}
|
||||
|
||||
bricknum = floor_to_int((p.x + offset) / brick_width);
|
||||
|
||||
x = (p.x + offset) - brick_width * bricknum;
|
||||
y = p.y - row_height * rownum;
|
||||
|
||||
const float tint = saturatef((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias));
|
||||
float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
|
||||
|
||||
float mortar;
|
||||
if (min_dist >= mortar_size) {
|
||||
mortar = 0.0f;
|
||||
}
|
||||
else if (mortar_smooth == 0.0f) {
|
||||
mortar = 1.0f;
|
||||
}
|
||||
else {
|
||||
min_dist = 1.0f - min_dist / mortar_size;
|
||||
mortar = smoothstepf(min_dist / mortar_smooth);
|
||||
}
|
||||
|
||||
return make_float2(tint, mortar);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_brick(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexBrick &ccl_restrict node)
|
||||
{
|
||||
const float3 co = stack_load_float3(stack, node.co);
|
||||
|
||||
float3 color1 = stack_load(stack, node.color1);
|
||||
const float3 color2 = stack_load(stack, node.color2);
|
||||
const float3 mortar = stack_load(stack, node.mortar);
|
||||
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
const float mortar_size = stack_load(stack, node.mortar_size);
|
||||
const float mortar_smooth = stack_load(stack, node.mortar_smooth);
|
||||
const float bias = stack_load(stack, node.bias);
|
||||
const float brick_width = stack_load(stack, node.brick_width);
|
||||
const float row_height = stack_load(stack, node.row_height);
|
||||
|
||||
const float2 f2 = svm_brick(co * scale,
|
||||
mortar_size,
|
||||
mortar_smooth,
|
||||
bias,
|
||||
brick_width,
|
||||
row_height,
|
||||
node.offset_amount,
|
||||
node.offset_frequency,
|
||||
node.squash_amount,
|
||||
node.squash_frequency);
|
||||
|
||||
const float tint = f2.x;
|
||||
const float f = f2.y;
|
||||
|
||||
if (f != 1.0f) {
|
||||
const float facm = 1.0f - tint;
|
||||
color1 = facm * color1 + tint * color2;
|
||||
}
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, color1 * (1.0f - f) + mortar * f);
|
||||
}
|
||||
if (stack_valid(node.fac_offset)) {
|
||||
stack_store_float(stack, node.fac_offset, f);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
28
blender-5.2.0/intern/cycles/kernel/svm/brightness.h
Normal file
28
blender-5.2.0/intern/cycles/kernel/svm/brightness.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/color_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_brightness(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeBrightContrast &ccl_restrict
|
||||
node)
|
||||
{
|
||||
float3 color = stack_load(stack, node.color);
|
||||
const float brightness = stack_load(stack, node.bright);
|
||||
const float contrast = stack_load(stack, node.contrast);
|
||||
|
||||
color = svm_brightness_contrast(color, brightness, contrast);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
stack_store_float3(stack, node.out_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
63
blender-5.2.0/intern/cycles/kernel/svm/bump.h
Normal file
63
blender-5.2.0/intern/cycles/kernel/svm/bump.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/geom/attribute.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/primitive.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/differential.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Bump Eval Nodes */
|
||||
|
||||
ccl_device_noinline void svm_node_enter_bump_eval(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeEnterBumpEval &node)
|
||||
{
|
||||
const uint offset = node.state_offset;
|
||||
|
||||
/* save state */
|
||||
stack_store_float3(stack, offset + 0, sd->P);
|
||||
stack_store_float(stack, offset + 3, sd->dP);
|
||||
|
||||
/* Set position as if undisplaced. */
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POSITION_UNDISPLACED);
|
||||
if (is_attribute_found(desc)) {
|
||||
dual3 attr = primitive_surface_attribute<dual3>(kg, sd, desc);
|
||||
object_position_transform(kg, sd, &attr);
|
||||
|
||||
sd->P = attr.val;
|
||||
sd->dP = differential_make_compact(attr);
|
||||
|
||||
/* Save the full differential, the compact form isn't enough for svm_node_set_bump. */
|
||||
stack_store_float3(stack, offset + 4, attr.dx);
|
||||
stack_store_float3(stack, offset + 7, attr.dy);
|
||||
|
||||
/* Set normal as if undisplaced. Note this does not need to be restored,
|
||||
* because the bump evaluation will write to sd->N. */
|
||||
primitive_normal_set_undisplaced(kg, sd, desc.offset);
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_leave_bump_eval(ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeLeaveBumpEval &node)
|
||||
{
|
||||
const uint offset = node.state_offset;
|
||||
|
||||
/* restore state */
|
||||
sd->P = stack_load_float3(stack, offset + 0);
|
||||
sd->dP = stack_load_float(stack, offset + 3);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
37
blender-5.2.0/intern/cycles/kernel/svm/camera.h
Normal file
37
blender-5.2.0/intern/cycles/kernel/svm/camera.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_camera(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeCamera &ccl_restrict node)
|
||||
{
|
||||
const Transform tfm = kernel_data.cam.worldtocamera;
|
||||
const float3 vector = transform_point(&tfm, sd->P);
|
||||
const float zdepth = vector.z;
|
||||
const float distance = len(vector);
|
||||
|
||||
if (stack_valid(node.vector_offset)) {
|
||||
stack_store_float3(stack, node.vector_offset, normalize(vector));
|
||||
}
|
||||
|
||||
if (stack_valid(node.zdepth_offset)) {
|
||||
stack_store_float(stack, node.zdepth_offset, zdepth);
|
||||
}
|
||||
|
||||
if (stack_valid(node.distance_offset)) {
|
||||
stack_store_float(stack, node.distance_offset, distance);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
46
blender-5.2.0/intern/cycles/kernel/svm/checker.h
Normal file
46
blender-5.2.0/intern/cycles/kernel/svm/checker.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Checker */
|
||||
|
||||
ccl_device float svm_checker(float3 p)
|
||||
{
|
||||
/* avoid precision issues on unit coordinates */
|
||||
p.x = (p.x + 0.000001f) * 0.999999f;
|
||||
p.y = (p.y + 0.000001f) * 0.999999f;
|
||||
p.z = (p.z + 0.000001f) * 0.999999f;
|
||||
|
||||
const int xi = abs(float_to_int(floorf(p.x)));
|
||||
const int yi = abs(float_to_int(floorf(p.y)));
|
||||
const int zi = abs(float_to_int(floorf(p.z)));
|
||||
|
||||
return ((xi % 2 == yi % 2) == (zi % 2)) ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_checker(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeTexChecker &ccl_restrict node)
|
||||
{
|
||||
const float3 co = stack_load_float3(stack, node.co);
|
||||
const float3 color1 = stack_load(stack, node.color1);
|
||||
const float3 color2 = stack_load(stack, node.color2);
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
|
||||
const float f = svm_checker(co * scale);
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, (f == 1.0f) ? color1 : color2);
|
||||
}
|
||||
if (stack_valid(node.fac_offset)) {
|
||||
stack_store_float(stack, node.fac_offset, f);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
29
blender-5.2.0/intern/cycles/kernel/svm/clamp.h
Normal file
29
blender-5.2.0/intern/cycles/kernel/svm/clamp.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Clamp Node */
|
||||
|
||||
ccl_device_noinline void svm_node_clamp(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeClamp &ccl_restrict node)
|
||||
{
|
||||
const float value = stack_load(stack, node.value);
|
||||
const float min = stack_load(stack, node.min);
|
||||
const float max = stack_load(stack, node.max);
|
||||
|
||||
if (node.clamp_type == NODE_CLAMP_RANGE && (min > max)) {
|
||||
stack_store_float(stack, node.result_offset, clamp(value, max, min));
|
||||
}
|
||||
else {
|
||||
stack_store_float(stack, node.result_offset, clamp(value, min, max));
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
1528
blender-5.2.0/intern/cycles/kernel/svm/closure.h
Normal file
1528
blender-5.2.0/intern/cycles/kernel/svm/closure.h
Normal file
File diff suppressed because it is too large
Load Diff
409
blender-5.2.0/intern/cycles/kernel/svm/color_util.h
Normal file
409
blender-5.2.0/intern/cycles/kernel/svm/color_util.h
Normal file
@@ -0,0 +1,409 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/types.h"
|
||||
|
||||
#include "util/color.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device float3 svm_mix_blend(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, col2, t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_add(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, col1 + col2, t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_mul(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, col1 * col2, t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_screen(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
const float tm = 1.0f - t;
|
||||
const float3 one = make_float3(1.0f, 1.0f, 1.0f);
|
||||
const float3 tm3 = make_float3(tm, tm, tm);
|
||||
|
||||
return one - (tm3 + t * (one - col2)) * (one - col1);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_overlay(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
const float tm = 1.0f - t;
|
||||
|
||||
float3 outcol = col1;
|
||||
|
||||
if (outcol.x < 0.5f) {
|
||||
outcol.x *= tm + 2.0f * t * col2.x;
|
||||
}
|
||||
else {
|
||||
outcol.x = 1.0f - (tm + 2.0f * t * (1.0f - col2.x)) * (1.0f - outcol.x);
|
||||
}
|
||||
|
||||
if (outcol.y < 0.5f) {
|
||||
outcol.y *= tm + 2.0f * t * col2.y;
|
||||
}
|
||||
else {
|
||||
outcol.y = 1.0f - (tm + 2.0f * t * (1.0f - col2.y)) * (1.0f - outcol.y);
|
||||
}
|
||||
|
||||
if (outcol.z < 0.5f) {
|
||||
outcol.z *= tm + 2.0f * t * col2.z;
|
||||
}
|
||||
else {
|
||||
outcol.z = 1.0f - (tm + 2.0f * t * (1.0f - col2.z)) * (1.0f - outcol.z);
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_sub(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, col1 - col2, t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_div(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
const float tm = 1.0f - t;
|
||||
|
||||
float3 outcol = col1;
|
||||
|
||||
if (col2.x != 0.0f) {
|
||||
outcol.x = tm * outcol.x + t * outcol.x / col2.x;
|
||||
}
|
||||
if (col2.y != 0.0f) {
|
||||
outcol.y = tm * outcol.y + t * outcol.y / col2.y;
|
||||
}
|
||||
if (col2.z != 0.0f) {
|
||||
outcol.z = tm * outcol.z + t * outcol.z / col2.z;
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_diff(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, fabs(col1 - col2), t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_exclusion(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return max(interp(col1, col1 + col2 - 2.0f * col1 * col2, t), zero_float3());
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_dark(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, min(col1, col2), t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_light(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return interp(col1, max(col1, col2), t);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_dodge(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
float3 outcol = col1;
|
||||
|
||||
if (outcol.x != 0.0f) {
|
||||
float tmp = 1.0f - t * col2.x;
|
||||
if (tmp <= 0.0f) {
|
||||
outcol.x = 1.0f;
|
||||
}
|
||||
else {
|
||||
tmp = outcol.x / tmp;
|
||||
if (tmp > 1.0f) {
|
||||
outcol.x = 1.0f;
|
||||
}
|
||||
else {
|
||||
outcol.x = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outcol.y != 0.0f) {
|
||||
float tmp = 1.0f - t * col2.y;
|
||||
if (tmp <= 0.0f) {
|
||||
outcol.y = 1.0f;
|
||||
}
|
||||
else {
|
||||
tmp = outcol.y / tmp;
|
||||
if (tmp > 1.0f) {
|
||||
outcol.y = 1.0f;
|
||||
}
|
||||
else {
|
||||
outcol.y = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outcol.z != 0.0f) {
|
||||
float tmp = 1.0f - t * col2.z;
|
||||
if (tmp <= 0.0f) {
|
||||
outcol.z = 1.0f;
|
||||
}
|
||||
else {
|
||||
tmp = outcol.z / tmp;
|
||||
if (tmp > 1.0f) {
|
||||
outcol.z = 1.0f;
|
||||
}
|
||||
else {
|
||||
outcol.z = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_burn(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
float tmp;
|
||||
const float tm = 1.0f - t;
|
||||
|
||||
float3 outcol = col1;
|
||||
|
||||
tmp = tm + t * col2.x;
|
||||
if (tmp <= 0.0f) {
|
||||
outcol.x = 0.0f;
|
||||
}
|
||||
else {
|
||||
tmp = (1.0f - (1.0f - outcol.x) / tmp);
|
||||
if (tmp < 0.0f) {
|
||||
outcol.x = 0.0f;
|
||||
}
|
||||
else if (tmp > 1.0f) {
|
||||
outcol.x = 1.0f;
|
||||
}
|
||||
else {
|
||||
outcol.x = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = tm + t * col2.y;
|
||||
if (tmp <= 0.0f) {
|
||||
outcol.y = 0.0f;
|
||||
}
|
||||
else {
|
||||
tmp = (1.0f - (1.0f - outcol.y) / tmp);
|
||||
if (tmp < 0.0f) {
|
||||
outcol.y = 0.0f;
|
||||
}
|
||||
else if (tmp > 1.0f) {
|
||||
outcol.y = 1.0f;
|
||||
}
|
||||
else {
|
||||
outcol.y = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = tm + t * col2.z;
|
||||
if (tmp <= 0.0f) {
|
||||
outcol.z = 0.0f;
|
||||
}
|
||||
else {
|
||||
tmp = (1.0f - (1.0f - outcol.z) / tmp);
|
||||
if (tmp < 0.0f) {
|
||||
outcol.z = 0.0f;
|
||||
}
|
||||
else if (tmp > 1.0f) {
|
||||
outcol.z = 1.0f;
|
||||
}
|
||||
else {
|
||||
outcol.z = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_hue(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
float3 outcol = col1;
|
||||
|
||||
const float3 hsv2 = rgb_to_hsv(col2);
|
||||
|
||||
if (hsv2.y != 0.0f) {
|
||||
float3 hsv = rgb_to_hsv(outcol);
|
||||
hsv.x = hsv2.x;
|
||||
const float3 tmp = hsv_to_rgb(hsv);
|
||||
|
||||
outcol = interp(outcol, tmp, t);
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_sat(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
const float tm = 1.0f - t;
|
||||
|
||||
float3 outcol = col1;
|
||||
|
||||
float3 hsv = rgb_to_hsv(outcol);
|
||||
|
||||
if (hsv.y != 0.0f) {
|
||||
const float3 hsv2 = rgb_to_hsv(col2);
|
||||
|
||||
hsv.y = tm * hsv.y + t * hsv2.y;
|
||||
outcol = hsv_to_rgb(hsv);
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_val(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
const float tm = 1.0f - t;
|
||||
|
||||
float3 hsv = rgb_to_hsv(col1);
|
||||
const float3 hsv2 = rgb_to_hsv(col2);
|
||||
|
||||
hsv.z = tm * hsv.z + t * hsv2.z;
|
||||
|
||||
return hsv_to_rgb(hsv);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_color(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
float3 outcol = col1;
|
||||
const float3 hsv2 = rgb_to_hsv(col2);
|
||||
|
||||
if (hsv2.y != 0.0f) {
|
||||
float3 hsv = rgb_to_hsv(outcol);
|
||||
hsv.x = hsv2.x;
|
||||
hsv.y = hsv2.y;
|
||||
const float3 tmp = hsv_to_rgb(hsv);
|
||||
|
||||
outcol = interp(outcol, tmp, t);
|
||||
}
|
||||
|
||||
return outcol;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_soft(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
const float tm = 1.0f - t;
|
||||
|
||||
const float3 one = make_float3(1.0f, 1.0f, 1.0f);
|
||||
const float3 scr = one - (one - col2) * (one - col1);
|
||||
|
||||
return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr);
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_linear(const float t, const float3 col1, const float3 col2)
|
||||
{
|
||||
return col1 + t * (2.0f * col2 + make_float3(-1.0f, -1.0f, -1.0f));
|
||||
}
|
||||
|
||||
ccl_device float3 svm_mix_clamp(const float3 col)
|
||||
{
|
||||
return saturate(col);
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float3 svm_mix(NodeMix type,
|
||||
const float t,
|
||||
const float3 c1,
|
||||
const float3 c2)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_MIX_BLEND:
|
||||
return svm_mix_blend(t, c1, c2);
|
||||
case NODE_MIX_ADD:
|
||||
return svm_mix_add(t, c1, c2);
|
||||
case NODE_MIX_MUL:
|
||||
return svm_mix_mul(t, c1, c2);
|
||||
case NODE_MIX_SCREEN:
|
||||
return svm_mix_screen(t, c1, c2);
|
||||
case NODE_MIX_OVERLAY:
|
||||
return svm_mix_overlay(t, c1, c2);
|
||||
case NODE_MIX_SUB:
|
||||
return svm_mix_sub(t, c1, c2);
|
||||
case NODE_MIX_DIV:
|
||||
return svm_mix_div(t, c1, c2);
|
||||
case NODE_MIX_DIFF:
|
||||
return svm_mix_diff(t, c1, c2);
|
||||
case NODE_MIX_EXCLUSION:
|
||||
return svm_mix_exclusion(t, c1, c2);
|
||||
case NODE_MIX_DARK:
|
||||
return svm_mix_dark(t, c1, c2);
|
||||
case NODE_MIX_LIGHT:
|
||||
return svm_mix_light(t, c1, c2);
|
||||
case NODE_MIX_DODGE:
|
||||
return svm_mix_dodge(t, c1, c2);
|
||||
case NODE_MIX_BURN:
|
||||
return svm_mix_burn(t, c1, c2);
|
||||
case NODE_MIX_HUE:
|
||||
return svm_mix_hue(t, c1, c2);
|
||||
case NODE_MIX_SAT:
|
||||
return svm_mix_sat(t, c1, c2);
|
||||
case NODE_MIX_VAL:
|
||||
return svm_mix_val(t, c1, c2);
|
||||
case NODE_MIX_COL:
|
||||
return svm_mix_color(t, c1, c2);
|
||||
case NODE_MIX_SOFT:
|
||||
return svm_mix_soft(t, c1, c2);
|
||||
case NODE_MIX_LINEAR:
|
||||
return svm_mix_linear(t, c1, c2);
|
||||
case NODE_MIX_CLAMP:
|
||||
return svm_mix_clamp(c1);
|
||||
}
|
||||
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float3 svm_mix_clamped_factor(NodeMix type,
|
||||
const float t,
|
||||
const float3 c1,
|
||||
const float3 c2)
|
||||
{
|
||||
const float fac = saturatef(t);
|
||||
return svm_mix(type, fac, c1, c2);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 svm_brightness_contrast(float3 color,
|
||||
const float brightness,
|
||||
const float contrast)
|
||||
{
|
||||
const float a = 1.0f + contrast;
|
||||
const float b = brightness - contrast * 0.5f;
|
||||
|
||||
color.x = max(a * color.x + b, 0.0f);
|
||||
color.y = max(a * color.y + b, 0.0f);
|
||||
color.z = max(a * color.z + b, 0.0f);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_combine_color(NodeCombSepColorType type, const float3 color)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_COMBSEP_COLOR_HSV:
|
||||
return hsv_to_rgb(color);
|
||||
case NODE_COMBSEP_COLOR_HSL:
|
||||
return hsl_to_rgb(color);
|
||||
case NODE_COMBSEP_COLOR_RGB:
|
||||
default:
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float3 svm_separate_color(NodeCombSepColorType type, const float3 color)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_COMBSEP_COLOR_HSV:
|
||||
return rgb_to_hsv(color);
|
||||
case NODE_COMBSEP_COLOR_HSL:
|
||||
return rgb_to_hsl(color);
|
||||
case NODE_COMBSEP_COLOR_RGB:
|
||||
default:
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
72
blender-5.2.0/intern/cycles/kernel/svm/convert.h
Normal file
72
blender-5.2.0/intern/cycles/kernel/svm/convert.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/colorspace.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Conversion Nodes */
|
||||
|
||||
template<typename FloatType, typename Float3Type>
|
||||
ccl_device_noinline void svm_node_convert(KernelGlobals kg,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeConvert &ccl_restrict node)
|
||||
{
|
||||
|
||||
switch (node.convert_type) {
|
||||
case NODE_CONVERT_FI: {
|
||||
/* TODO(weizhen): should actually store 0 for int, but none of the nodes that we compute
|
||||
* derivatives for has int inputs, so seems fine. */
|
||||
const float f = stack_load_float(stack, node.from_offset);
|
||||
stack_store_int(stack, node.to_offset, float_to_int(f));
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_FV: {
|
||||
const FloatType f = stack_load<FloatType>(stack, node.from_offset);
|
||||
stack_store(stack, node.to_offset, make_float3(f, f, f));
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_CF: {
|
||||
const Float3Type f = stack_load<Float3Type>(stack, node.from_offset);
|
||||
stack_store(stack, node.to_offset, linear_rgb_to_gray(kg, f));
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_CI: {
|
||||
const float3 f = stack_load_float3(stack, node.from_offset);
|
||||
const int i = (int)linear_rgb_to_gray(kg, f);
|
||||
stack_store_int(stack, node.to_offset, i);
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_VF: {
|
||||
const Float3Type f = stack_load<Float3Type>(stack, node.from_offset);
|
||||
stack_store(stack, node.to_offset, average(f));
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_VI: {
|
||||
const float3 f = stack_load_float3(stack, node.from_offset);
|
||||
const int i = (int)average(f);
|
||||
stack_store_int(stack, node.to_offset, i);
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_IF: {
|
||||
const float f = (float)stack_load_int(stack, node.from_offset);
|
||||
stack_store(stack, node.to_offset, FloatType(f));
|
||||
break;
|
||||
}
|
||||
case NODE_CONVERT_IV: {
|
||||
const float f = (float)stack_load_int(stack, node.from_offset);
|
||||
stack_store(stack, node.to_offset, Float3Type(make_float3(f, f, f)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
197
blender-5.2.0/intern/cycles/kernel/svm/displace.h
Normal file
197
blender-5.2.0/intern/cycles/kernel/svm/displace.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/geom/attribute.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/primitive.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/differential.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Bump Node */
|
||||
template<uint node_feature_mask>
|
||||
ccl_device_noinline void svm_node_set_bump(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeSetBump &node)
|
||||
{
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
IF_KERNEL_NODES_FEATURE(BUMP)
|
||||
{
|
||||
/* get normal input */
|
||||
float3 normal_in = stack_load_float3_default(stack, node.normal_offset, sd->N);
|
||||
|
||||
/* If we have saved bump state, read the full differential from there.
|
||||
* Just using the compact form in those cases leads to incorrect normals (see #111588). */
|
||||
differential3 dP;
|
||||
if (node.bump_state_offset == SVM_STACK_INVALID) {
|
||||
dP = differential_from_compact(sd->Ng, sd->dP);
|
||||
}
|
||||
else {
|
||||
dP.dx = stack_load_float3(stack, node.bump_state_offset + 4);
|
||||
dP.dy = stack_load_float3(stack, node.bump_state_offset + 7);
|
||||
}
|
||||
|
||||
if (node.use_object_space) {
|
||||
object_inverse_normal_transform(kg, sd, &normal_in);
|
||||
object_inverse_dir_transform(kg, sd, &dP.dx);
|
||||
object_inverse_dir_transform(kg, sd, &dP.dy);
|
||||
}
|
||||
|
||||
/* get surface tangents from normal */
|
||||
const float3 Rx = cross(dP.dy, normal_in);
|
||||
const float3 Ry = cross(normal_in, dP.dx);
|
||||
|
||||
/* get bump values */
|
||||
const float h_c = stack_load_float(stack, node.center_offset);
|
||||
const float h_x = stack_load_float(stack, node.dx_offset);
|
||||
const float h_y = stack_load_float(stack, node.dy_offset);
|
||||
|
||||
/* compute surface gradient and determinant */
|
||||
const float det = dot(dP.dx, Rx);
|
||||
const float3 surfgrad = (h_x - h_c) * Rx + (h_y - h_c) * Ry;
|
||||
|
||||
const float absdet = fabsf(det);
|
||||
|
||||
float strength = stack_load(stack, node.strength);
|
||||
float scale = stack_load(stack, node.scale);
|
||||
|
||||
if (node.invert) {
|
||||
scale *= -1.0f;
|
||||
}
|
||||
|
||||
strength = max(strength, 0.0f);
|
||||
|
||||
/* Compute and output perturbed normal.
|
||||
* dP'dx = dPdx + scale * (h_x - h_c) / filter_width * normal
|
||||
* dP'dy = dPdy + scale * (h_y - h_c) / filter_width * normal
|
||||
* N' = cross(dP'dx, dP'dy)
|
||||
* = cross(dPdx, dPdy) - scale * ((h_y - h_c) / filter_width * Ry + (h_x - h_c) /
|
||||
* filter_width * Rx) ≈ det * normal_in - scale * surfgrad / filter_width
|
||||
*/
|
||||
float3 normal_out = safe_normalize(node.bump_filter_width * absdet * normal_in -
|
||||
scale * signf(det) * surfgrad);
|
||||
if (is_zero(normal_out)) {
|
||||
normal_out = normal_in;
|
||||
}
|
||||
else {
|
||||
normal_out = normalize(strength * normal_out + (1.0f - strength) * normal_in);
|
||||
}
|
||||
|
||||
if (node.use_object_space) {
|
||||
object_normal_transform(kg, sd, &normal_out);
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.out_offset, normal_out);
|
||||
}
|
||||
else {
|
||||
stack_store_float3(stack, node.out_offset, zero_float3());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Displacement Node */
|
||||
|
||||
template<uint node_feature_mask>
|
||||
ccl_device void svm_node_set_displacement(ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeSetDisplacement &node)
|
||||
{
|
||||
IF_KERNEL_NODES_FEATURE(BUMP)
|
||||
{
|
||||
const float3 dP = stack_load_float3(stack, node.fac_offset);
|
||||
sd->P += dP;
|
||||
}
|
||||
}
|
||||
|
||||
template<uint node_feature_mask>
|
||||
ccl_device_noinline void svm_node_displacement(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeDisplacement &node)
|
||||
{
|
||||
IF_KERNEL_NODES_FEATURE(BUMP)
|
||||
{
|
||||
const float height = stack_load(stack, node.height);
|
||||
const float midlevel = stack_load(stack, node.midlevel);
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
const float3 normal = stack_load_float3_default(stack, node.normal_offset, sd->N);
|
||||
|
||||
float3 dP = normal;
|
||||
|
||||
if (node.space == NODE_NORMAL_MAP_OBJECT) {
|
||||
/* Object space. */
|
||||
object_inverse_normal_transform(kg, sd, &dP);
|
||||
dP *= (height - midlevel) * scale;
|
||||
object_dir_transform(kg, sd, &dP);
|
||||
}
|
||||
else {
|
||||
/* World space. */
|
||||
dP *= (height - midlevel) * scale;
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.out_offset, dP);
|
||||
}
|
||||
else {
|
||||
stack_store_float3(stack, node.out_offset, zero_float3());
|
||||
}
|
||||
}
|
||||
|
||||
template<uint node_feature_mask>
|
||||
ccl_device_noinline void svm_node_vector_displacement(
|
||||
KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeVectorDisplacement &node)
|
||||
{
|
||||
IF_KERNEL_NODES_FEATURE(BUMP)
|
||||
{
|
||||
const float3 vector = stack_load(stack, node.vector);
|
||||
const float midlevel = stack_load(stack, node.midlevel);
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
float3 dP = (vector - make_float3(midlevel, midlevel, midlevel)) * scale;
|
||||
|
||||
if (node.space == NODE_NORMAL_MAP_TANGENT) {
|
||||
/* Tangent space. */
|
||||
float3 normal = sd->N;
|
||||
object_inverse_normal_transform(kg, sd, &normal);
|
||||
|
||||
const AttributeDescriptor attr = find_attribute(kg, sd, node.attr);
|
||||
float3 tangent;
|
||||
if (is_attribute_found(attr)) {
|
||||
tangent = primitive_surface_attribute<float3>(kg, sd, attr);
|
||||
}
|
||||
else {
|
||||
tangent = normalize(sd->dPdu);
|
||||
}
|
||||
|
||||
float3 bitangent = safe_normalize(cross(normal, tangent));
|
||||
const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.attr_sign);
|
||||
if (is_attribute_found(attr_sign)) {
|
||||
const float sign = primitive_surface_attribute<float>(kg, sd, attr_sign);
|
||||
bitangent *= sign;
|
||||
}
|
||||
|
||||
dP = tangent * dP.x + normal * dP.y + bitangent * dP.z;
|
||||
}
|
||||
|
||||
if (node.space != NODE_NORMAL_MAP_WORLD) {
|
||||
/* Tangent or object space. */
|
||||
object_dir_transform(kg, sd, &dP);
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.displacement_offset, dP);
|
||||
}
|
||||
else {
|
||||
stack_store_float3(stack, node.displacement_offset, zero_float3());
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
550
blender-5.2.0/intern/cycles/kernel/svm/fractal_noise.h
Normal file
550
blender-5.2.0/intern/cycles/kernel/svm/fractal_noise.h
Normal file
@@ -0,0 +1,550 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/noise.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Fractal Brownian motion. */
|
||||
|
||||
ccl_device_noinline float noise_fbm(
|
||||
float p, const float detail, const float roughness, const float lacunarity, bool normalize)
|
||||
{
|
||||
float fscale = 1.0f;
|
||||
float amp = 1.0f;
|
||||
float maxamp = 0.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
const float t = snoise_1d(fscale * p);
|
||||
sum += t * amp;
|
||||
maxamp += amp;
|
||||
amp *= roughness;
|
||||
fscale *= lacunarity;
|
||||
}
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float t = snoise_1d(fscale * p);
|
||||
const float sum2 = sum + t * amp;
|
||||
return normalize ? mix(0.5f * sum / maxamp + 0.5f, 0.5f * sum2 / (maxamp + amp) + 0.5f, rmd) :
|
||||
mix(sum, sum2, rmd);
|
||||
}
|
||||
return normalize ? 0.5f * sum / maxamp + 0.5f : sum;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_fbm(
|
||||
float2 p, const float detail, const float roughness, const float lacunarity, bool normalize)
|
||||
{
|
||||
float fscale = 1.0f;
|
||||
float amp = 1.0f;
|
||||
float maxamp = 0.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
const float t = snoise_2d(fscale * p);
|
||||
sum += t * amp;
|
||||
maxamp += amp;
|
||||
amp *= roughness;
|
||||
fscale *= lacunarity;
|
||||
}
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float t = snoise_2d(fscale * p);
|
||||
const float sum2 = sum + t * amp;
|
||||
return normalize ? mix(0.5f * sum / maxamp + 0.5f, 0.5f * sum2 / (maxamp + amp) + 0.5f, rmd) :
|
||||
mix(sum, sum2, rmd);
|
||||
}
|
||||
return normalize ? 0.5f * sum / maxamp + 0.5f : sum;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_fbm(
|
||||
float3 p, const float detail, const float roughness, const float lacunarity, bool normalize)
|
||||
{
|
||||
float fscale = 1.0f;
|
||||
float amp = 1.0f;
|
||||
float maxamp = 0.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
const float t = snoise_3d(fscale * p);
|
||||
sum += t * amp;
|
||||
maxamp += amp;
|
||||
amp *= roughness;
|
||||
fscale *= lacunarity;
|
||||
}
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float t = snoise_3d(fscale * p);
|
||||
const float sum2 = sum + t * amp;
|
||||
return normalize ? mix(0.5f * sum / maxamp + 0.5f, 0.5f * sum2 / (maxamp + amp) + 0.5f, rmd) :
|
||||
mix(sum, sum2, rmd);
|
||||
}
|
||||
return normalize ? 0.5f * sum / maxamp + 0.5f : sum;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_fbm(
|
||||
float4 p, const float detail, const float roughness, const float lacunarity, bool normalize)
|
||||
{
|
||||
float fscale = 1.0f;
|
||||
float amp = 1.0f;
|
||||
float maxamp = 0.0f;
|
||||
float sum = 0.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
const float t = snoise_4d(fscale * p);
|
||||
sum += t * amp;
|
||||
maxamp += amp;
|
||||
amp *= roughness;
|
||||
fscale *= lacunarity;
|
||||
}
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float t = snoise_4d(fscale * p);
|
||||
const float sum2 = sum + t * amp;
|
||||
return normalize ? mix(0.5f * sum / maxamp + 0.5f, 0.5f * sum2 / (maxamp + amp) + 0.5f, rmd) :
|
||||
mix(sum, sum2, rmd);
|
||||
}
|
||||
return normalize ? 0.5f * sum / maxamp + 0.5f : sum;
|
||||
}
|
||||
|
||||
/* Multifractal */
|
||||
|
||||
ccl_device_noinline float noise_multi_fractal(float p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity)
|
||||
{
|
||||
float value = 1.0f;
|
||||
float pwr = 1.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
value *= (pwr * snoise_1d(p) + 1.0f);
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
value *= (rmd * pwr * snoise_1d(p) + 1.0f); /* correct? */
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_multi_fractal(float2 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity)
|
||||
{
|
||||
float value = 1.0f;
|
||||
float pwr = 1.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
value *= (pwr * snoise_2d(p) + 1.0f);
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
value *= (rmd * pwr * snoise_2d(p) + 1.0f); /* correct? */
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_multi_fractal(float3 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity)
|
||||
{
|
||||
float value = 1.0f;
|
||||
float pwr = 1.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
value *= (pwr * snoise_3d(p) + 1.0f);
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_multi_fractal(float4 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity)
|
||||
{
|
||||
float value = 1.0f;
|
||||
float pwr = 1.0f;
|
||||
|
||||
for (int i = 0; i <= float_to_int(detail); i++) {
|
||||
value *= (pwr * snoise_4d(p) + 1.0f);
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
value *= (rmd * pwr * snoise_4d(p) + 1.0f); /* correct? */
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Heterogeneous Terrain */
|
||||
|
||||
ccl_device_noinline float noise_hetero_terrain(
|
||||
float p, const float detail, const float roughness, const float lacunarity, const float offset)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
/* first unscaled octave of function; later octaves are scaled */
|
||||
float value = offset + snoise_1d(p);
|
||||
p *= lacunarity;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
const float increment = (snoise_1d(p) + offset) * pwr * value;
|
||||
value += increment;
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float increment = (snoise_1d(p) + offset) * pwr * value;
|
||||
value += rmd * increment;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_hetero_terrain(float2 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
/* first unscaled octave of function; later octaves are scaled */
|
||||
float value = offset + snoise_2d(p);
|
||||
p *= lacunarity;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
const float increment = (snoise_2d(p) + offset) * pwr * value;
|
||||
value += increment;
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float increment = (snoise_2d(p) + offset) * pwr * value;
|
||||
value += rmd * increment;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_hetero_terrain(float3 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
/* first unscaled octave of function; later octaves are scaled */
|
||||
float value = offset + snoise_3d(p);
|
||||
p *= lacunarity;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
const float increment = (snoise_3d(p) + offset) * pwr * value;
|
||||
value += increment;
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float increment = (snoise_3d(p) + offset) * pwr * value;
|
||||
value += rmd * increment;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_hetero_terrain(float4 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
/* first unscaled octave of function; later octaves are scaled */
|
||||
float value = offset + snoise_4d(p);
|
||||
p *= lacunarity;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
const float increment = (snoise_4d(p) + offset) * pwr * value;
|
||||
value += increment;
|
||||
pwr *= roughness;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if (rmd != 0.0f) {
|
||||
const float increment = (snoise_4d(p) + offset) * pwr * value;
|
||||
value += rmd * increment;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Hybrid Additive/Multiplicative Multifractal Terrain */
|
||||
|
||||
ccl_device_noinline float noise_hybrid_multi_fractal(float p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = 1.0f;
|
||||
float value = 0.0f;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 0; (weight > 0.001f) && (i <= float_to_int(detail)); i++) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
|
||||
const float signal = (snoise_1d(p) + offset) * pwr;
|
||||
pwr *= roughness;
|
||||
value += weight * signal;
|
||||
weight *= gain * signal;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if ((rmd != 0.0f) && (weight > 0.001f)) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
const float signal = (snoise_1d(p) + offset) * pwr;
|
||||
value += rmd * weight * signal;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_hybrid_multi_fractal(float2 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = 1.0f;
|
||||
float value = 0.0f;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 0; (weight > 0.001f) && (i <= float_to_int(detail)); i++) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
|
||||
const float signal = (snoise_2d(p) + offset) * pwr;
|
||||
pwr *= roughness;
|
||||
value += weight * signal;
|
||||
weight *= gain * signal;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if ((rmd != 0.0f) && (weight > 0.001f)) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
const float signal = (snoise_2d(p) + offset) * pwr;
|
||||
value += rmd * weight * signal;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_hybrid_multi_fractal(float3 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = 1.0f;
|
||||
float value = 0.0f;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 0; (weight > 0.001f) && (i <= float_to_int(detail)); i++) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
|
||||
const float signal = (snoise_3d(p) + offset) * pwr;
|
||||
pwr *= roughness;
|
||||
value += weight * signal;
|
||||
weight *= gain * signal;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if ((rmd != 0.0f) && (weight > 0.001f)) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
const float signal = (snoise_3d(p) + offset) * pwr;
|
||||
value += rmd * weight * signal;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_hybrid_multi_fractal(float4 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = 1.0f;
|
||||
float value = 0.0f;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 0; (weight > 0.001f) && (i <= float_to_int(detail)); i++) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
|
||||
const float signal = (snoise_4d(p) + offset) * pwr;
|
||||
pwr *= roughness;
|
||||
value += weight * signal;
|
||||
weight *= gain * signal;
|
||||
p *= lacunarity;
|
||||
}
|
||||
|
||||
const float rmd = detail - floorf(detail);
|
||||
if ((rmd != 0.0f) && (weight > 0.001f)) {
|
||||
weight = fminf(weight, 1.0f);
|
||||
const float signal = (snoise_4d(p) + offset) * pwr;
|
||||
value += rmd * weight * signal;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Ridged Multifractal Terrain */
|
||||
|
||||
ccl_device_noinline float noise_ridged_multi_fractal(float p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
float signal = offset - fabsf(snoise_1d(p));
|
||||
signal *= signal;
|
||||
float value = signal;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
p *= lacunarity;
|
||||
weight = saturatef(signal * gain);
|
||||
signal = offset - fabsf(snoise_1d(p));
|
||||
signal *= signal;
|
||||
signal *= weight;
|
||||
value += signal * pwr;
|
||||
pwr *= roughness;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_ridged_multi_fractal(float2 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
float signal = offset - fabsf(snoise_2d(p));
|
||||
signal *= signal;
|
||||
float value = signal;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
p *= lacunarity;
|
||||
weight = saturatef(signal * gain);
|
||||
signal = offset - fabsf(snoise_2d(p));
|
||||
signal *= signal;
|
||||
signal *= weight;
|
||||
value += signal * pwr;
|
||||
pwr *= roughness;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_ridged_multi_fractal(float3 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
float signal = offset - fabsf(snoise_3d(p));
|
||||
signal *= signal;
|
||||
float value = signal;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
p *= lacunarity;
|
||||
weight = saturatef(signal * gain);
|
||||
signal = offset - fabsf(snoise_3d(p));
|
||||
signal *= signal;
|
||||
signal *= weight;
|
||||
value += signal * pwr;
|
||||
pwr *= roughness;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ccl_device_noinline float noise_ridged_multi_fractal(float4 p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain)
|
||||
{
|
||||
float pwr = roughness;
|
||||
|
||||
float signal = offset - fabsf(snoise_4d(p));
|
||||
signal *= signal;
|
||||
float value = signal;
|
||||
float weight = 1.0f;
|
||||
|
||||
for (int i = 1; i <= float_to_int(detail); i++) {
|
||||
p *= lacunarity;
|
||||
weight = saturatef(signal * gain);
|
||||
signal = offset - fabsf(snoise_4d(p));
|
||||
signal *= signal;
|
||||
signal *= weight;
|
||||
value += signal * pwr;
|
||||
pwr *= roughness;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
65
blender-5.2.0/intern/cycles/kernel/svm/fresnel.h
Normal file
65
blender-5.2.0/intern/cycles/kernel/svm/fresnel.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/closure/bsdf_util.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Fresnel Node */
|
||||
|
||||
ccl_device_noinline void svm_node_fresnel(ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeFresnel &ccl_restrict node)
|
||||
{
|
||||
float eta = stack_load(stack, node.ior);
|
||||
const float3 normal_in = stack_load_float3_default(stack, node.normal_offset, sd->N);
|
||||
|
||||
eta = fmaxf(eta, 1e-5f);
|
||||
eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
|
||||
|
||||
const float f = fresnel_dielectric_cos(dot(sd->wi, normal_in), eta);
|
||||
|
||||
stack_store_float(stack, node.out_offset, f);
|
||||
}
|
||||
|
||||
/* Layer Weight Node */
|
||||
|
||||
ccl_device_noinline void svm_node_layer_weight(ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeLayerWeight &ccl_restrict
|
||||
node)
|
||||
{
|
||||
float blend = stack_load(stack, node.blend);
|
||||
const float3 normal_in = stack_load_float3_default(stack, node.normal_offset, sd->N);
|
||||
|
||||
float f;
|
||||
|
||||
if (node.weight_type == NODE_LAYER_WEIGHT_FRESNEL) {
|
||||
float eta = fmaxf(1.0f - blend, 1e-5f);
|
||||
eta = (sd->flag & SD_BACKFACING) ? eta : 1.0f / eta;
|
||||
|
||||
f = fresnel_dielectric_cos(dot(sd->wi, normal_in), eta);
|
||||
}
|
||||
else {
|
||||
f = fabsf(dot(sd->wi, normal_in));
|
||||
|
||||
if (blend != 0.5f) {
|
||||
blend = clamp(blend, 0.0f, 1.0f - 1e-5f);
|
||||
blend = (blend < 0.5f) ? 2.0f * blend : 0.5f / (1.0f - blend);
|
||||
|
||||
f = powf(f, blend);
|
||||
}
|
||||
|
||||
f = 1.0f - f;
|
||||
}
|
||||
|
||||
stack_store_float(stack, node.out_offset, f);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
362
blender-5.2.0/intern/cycles/kernel/svm/gabor.h
Normal file
362
blender-5.2.0/intern/cycles/kernel/svm/gabor.h
Normal file
@@ -0,0 +1,362 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Implements Gabor noise based on the paper:
|
||||
*
|
||||
* Lagae, Ares, et al. "Procedural noise using sparse Gabor convolution." ACM Transactions on
|
||||
* Graphics (TOG) 28.3 (2009): 1-10.
|
||||
*
|
||||
* But with the improvements from the paper:
|
||||
*
|
||||
* Tavernier, Vincent, et al. "Making gabor noise fast and normalized." Eurographics 2019-40th
|
||||
* Annual Conference of the European Association for Computer Graphics. 2019.
|
||||
*
|
||||
* And compute the Phase and Intensity of the Gabor based on the paper:
|
||||
*
|
||||
* Tricard, Thibault, et al. "Procedural phasor noise." ACM Transactions on Graphics (TOG) 38.4
|
||||
* (2019): 1-13.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "util/hash.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* The original Gabor noise paper specifies that the impulses count for each cell should be
|
||||
* computed by sampling a Poisson distribution whose mean is the impulse density. However,
|
||||
* Tavernier's paper showed that stratified Poisson point sampling is better assuming the weights
|
||||
* are sampled using a Bernoulli distribution, as shown in Figure (3). By stratified sampling, they
|
||||
* mean a constant number of impulses per cell, so the stratification is the grid itself in that
|
||||
* sense, as described in the supplementary material of the paper. */
|
||||
#define IMPULSES_COUNT 8 // NOLINT
|
||||
|
||||
/* Computes a 2D Gabor kernel based on Equation (6) in the original Gabor noise paper. Where the
|
||||
* frequency argument is the F_0 parameter and the orientation argument is the w_0 parameter. We
|
||||
* assume the Gaussian envelope has a unit magnitude, that is, K = 1. That is because we will
|
||||
* eventually normalize the final noise value to the unit range, so the multiplication by the
|
||||
* magnitude will be canceled by the normalization. Further, we also assume a unit Gaussian width,
|
||||
* that is, a = 1. That is because it does not provide much artistic control. It follows that the
|
||||
* Gaussian will be truncated at pi.
|
||||
*
|
||||
* To avoid the discontinuities caused by the aforementioned truncation, the Gaussian is windowed
|
||||
* using a Hann window, that is because contrary to the claim made in the original Gabor paper,
|
||||
* truncating the Gaussian produces significant artifacts especially when differentiated for bump
|
||||
* mapping. The Hann window is C1 continuous and has limited effect on the shape of the Gaussian,
|
||||
* so it felt like an appropriate choice.
|
||||
*
|
||||
* Finally, instead of computing the Gabor value directly, we instead use the complex phasor
|
||||
* formulation described in section 3.1.1 in Tricard's paper. That's done to be able to compute the
|
||||
* phase and intensity of the Gabor noise after summation based on equations (8) and (9). The
|
||||
* return value of the Gabor kernel function is then a complex number whose real value is the
|
||||
* value computed in the original Gabor noise paper, and whose imaginary part is the sine
|
||||
* counterpart of the real part, which is the only extra computation in the new formulation.
|
||||
*
|
||||
* Note that while the original Gabor noise paper uses the cosine part of the phasor, that is, the
|
||||
* real part of the phasor, we use the sine part instead, that is, the imaginary part of the
|
||||
* phasor, as suggested by Tavernier's paper in "Section 3.3. Instance stationarity and
|
||||
* normalization", to ensure a zero mean, which should help with normalization. */
|
||||
ccl_device float2 compute_2d_gabor_kernel(const float2 position,
|
||||
const float frequency,
|
||||
const float orientation)
|
||||
{
|
||||
const float distance_squared = dot(position, position);
|
||||
const float hann_window = 0.5f + 0.5f * cosf(M_PI_F * distance_squared);
|
||||
const float gaussian_envelop = expf(-M_PI_F * distance_squared);
|
||||
const float windowed_gaussian_envelope = gaussian_envelop * hann_window;
|
||||
|
||||
const float angle = 2.0f * M_PI_F * dot(position, polar_to_cartesian(frequency, orientation));
|
||||
return polar_to_cartesian(windowed_gaussian_envelope, angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the approximate standard deviation of the zero mean normal distribution representing
|
||||
* the amplitude distribution of the noise based on Equation (9) in the original Gabor noise paper.
|
||||
* For simplicity, the Hann window is ignored and the orientation is fixed since the variance is
|
||||
* orientation invariant. We start integrating the squared Gabor kernel with respect to x:
|
||||
*
|
||||
* \code{.tex}
|
||||
* \int_{-\infty}^{-\infty} (e^{- \pi (x^2 + y^2)} cos(2 \pi f_0 x))^2 dx
|
||||
* \endcode
|
||||
*
|
||||
* Which gives:
|
||||
*
|
||||
* \code{.tex}
|
||||
* \frac{(e^{2 \pi f_0^2}-1) e^{-2 \pi y^2 - 2 pi f_0^2}}{2^\frac{3}{2}}
|
||||
* \endcode
|
||||
*
|
||||
* Then we similarly integrate with respect to y to get:
|
||||
*
|
||||
* \code{.tex}
|
||||
* \frac{1 - e^{-2 \pi f_0^2}}{4}
|
||||
* \endcode
|
||||
*
|
||||
* Secondly, we note that the second moment of the weights distribution is 0.5 since it is a
|
||||
* fair Bernoulli distribution. So the final standard deviation expression is square root the
|
||||
* integral multiplied by the impulse density multiplied by the second moment.
|
||||
*
|
||||
* Note however that the integral is almost constant for all frequencies larger than one, and
|
||||
* converges to an upper limit as the frequency approaches infinity, so we replace the expression
|
||||
* with the following limit:
|
||||
*
|
||||
* \code{.tex}
|
||||
* \lim_{x \to \infty} \frac{1 - e^{-2 \pi f_0^2}}{4}
|
||||
* \endcode
|
||||
*
|
||||
* To get an approximation of 0.25.
|
||||
*/
|
||||
ccl_device float compute_2d_gabor_standard_deviation()
|
||||
{
|
||||
const float integral_of_gabor_squared = 0.25f;
|
||||
const float second_moment = 0.5f;
|
||||
return sqrtf(IMPULSES_COUNT * second_moment * integral_of_gabor_squared);
|
||||
}
|
||||
|
||||
/* Computes the Gabor noise value at the given position for the given cell. This is essentially the
|
||||
* sum in Equation (8) in the original Gabor noise paper, where we sum Gabor kernels sampled at a
|
||||
* random position with a random weight. The orientation of the kernel is constant for anisotropic
|
||||
* noise while it is random for isotropic noise. The original Gabor noise paper mentions that the
|
||||
* weights should be uniformly distributed in the [-1, 1] range, however, Tavernier's paper showed
|
||||
* that using a Bernoulli distribution yields better results, so that is what we do. */
|
||||
ccl_device float2 compute_2d_gabor_noise_cell(float2 cell,
|
||||
const float2 position,
|
||||
const float frequency,
|
||||
const float isotropy,
|
||||
const float base_orientation)
|
||||
|
||||
{
|
||||
float2 noise = make_float2(0.0f, 0.0f);
|
||||
for (int i = 0; i < IMPULSES_COUNT; ++i) {
|
||||
/* Compute unique seeds for each of the needed random variables. */
|
||||
const float3 seed_for_orientation = make_float3(cell.x, cell.y, i * 3);
|
||||
const float3 seed_for_kernel_center = make_float3(cell.x, cell.y, i * 3 + 1);
|
||||
const float3 seed_for_weight = make_float3(cell.x, cell.y, i * 3 + 2);
|
||||
|
||||
/* For isotropic noise, add a random orientation amount, while for anisotropic noise, use the
|
||||
* base orientation. Linearly interpolate between the two cases using the isotropy factor. Note
|
||||
* that the random orientation range spans pi as opposed to two pi, that's because the Gabor
|
||||
* kernel is symmetric around pi. */
|
||||
const float random_orientation = (hash_float3_to_float(seed_for_orientation) - 0.5f) * M_PI_F;
|
||||
const float orientation = base_orientation + random_orientation * isotropy;
|
||||
|
||||
const float2 kernel_center = hash_float3_to_float2(seed_for_kernel_center);
|
||||
const float2 position_in_kernel_space = position - kernel_center;
|
||||
|
||||
/* The kernel is windowed beyond the unit distance, so early exit with a zero for points that
|
||||
* are further than a unit radius. */
|
||||
if (dot(position_in_kernel_space, position_in_kernel_space) >= 1.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We either add or subtract the Gabor kernel based on a Bernoulli distribution of equal
|
||||
* probability. */
|
||||
const float weight = hash_float3_to_float(seed_for_weight) < 0.5f ? -1.0f : 1.0f;
|
||||
|
||||
noise += weight * compute_2d_gabor_kernel(position_in_kernel_space, frequency, orientation);
|
||||
}
|
||||
return noise;
|
||||
}
|
||||
|
||||
/* Computes the Gabor noise value by dividing the space into a grid and evaluating the Gabor noise
|
||||
* in the space of each cell of the 3x3 cell neighborhood. */
|
||||
ccl_device float2 compute_2d_gabor_noise(const float2 coordinates,
|
||||
const float frequency,
|
||||
const float isotropy,
|
||||
const float base_orientation)
|
||||
{
|
||||
const float2 cell_position = floor(coordinates);
|
||||
const float2 local_position = coordinates - cell_position;
|
||||
|
||||
float2 sum = make_float2(0.0f, 0.0f);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float2 cell_offset = make_float2(i, j);
|
||||
const float2 current_cell_position = cell_position + cell_offset;
|
||||
const float2 position_in_cell_space = local_position - cell_offset;
|
||||
sum += compute_2d_gabor_noise_cell(
|
||||
current_cell_position, position_in_cell_space, frequency, isotropy, base_orientation);
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* Identical to compute_2d_gabor_kernel, except it is evaluated in 3D space. Notice that Equation
|
||||
* (6) in the original Gabor noise paper computes the frequency vector using (cos(w_0), sin(w_0)),
|
||||
* which we also do in the 2D variant, however, for 3D, the orientation is already a unit frequency
|
||||
* vector, so we just need to scale it by the frequency value. */
|
||||
ccl_device float2 compute_3d_gabor_kernel(const float3 position,
|
||||
const float frequency,
|
||||
const float3 orientation)
|
||||
{
|
||||
const float distance_squared = dot(position, position);
|
||||
const float hann_window = 0.5f + 0.5f * cosf(M_PI_F * distance_squared);
|
||||
const float gaussian_envelop = expf(-M_PI_F * distance_squared);
|
||||
const float windowed_gaussian_envelope = gaussian_envelop * hann_window;
|
||||
|
||||
const float3 frequency_vector = frequency * orientation;
|
||||
const float angle = 2.0f * M_PI_F * dot(position, frequency_vector);
|
||||
return polar_to_cartesian(windowed_gaussian_envelope, angle);
|
||||
}
|
||||
|
||||
/* Identical to compute_2d_gabor_standard_deviation except we do triple integration in 3D. The only
|
||||
* difference is the denominator in the integral expression, which is `2^{5 / 2}` for the 3D case
|
||||
* instead of 4 for the 2D case. Similarly, the limit evaluates to `1 / (4 * sqrt(2))`. */
|
||||
ccl_device float compute_3d_gabor_standard_deviation()
|
||||
{
|
||||
const float integral_of_gabor_squared = 1.0f / (4.0f * M_SQRT2_F);
|
||||
const float second_moment = 0.5f;
|
||||
return sqrtf(IMPULSES_COUNT * second_moment * integral_of_gabor_squared);
|
||||
}
|
||||
|
||||
/* Computes the orientation of the Gabor kernel such that it is constant for anisotropic
|
||||
* noise while it is random for isotropic noise. We randomize in spherical coordinates for a
|
||||
* uniform distribution. */
|
||||
ccl_device float3 compute_3d_orientation(const float3 orientation,
|
||||
const float isotropy,
|
||||
const float4 seed)
|
||||
{
|
||||
/* Return the base orientation in case we are completely anisotropic. */
|
||||
if (isotropy == 0.0f) {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
/* Compute the orientation in spherical coordinates. */
|
||||
float inclination = acosf(orientation.z);
|
||||
float azimuth = (orientation.y < 0.0f ? -1.0f : 1.0f) *
|
||||
acosf(orientation.x / len(make_float2(orientation.x, orientation.y)));
|
||||
|
||||
/* For isotropic noise, add a random orientation amount, while for anisotropic noise, use the
|
||||
* base orientation. Linearly interpolate between the two cases using the isotropy factor. Note
|
||||
* that the random orientation range is to pi as opposed to two pi, that's because the Gabor
|
||||
* kernel is symmetric around pi. */
|
||||
const float2 random_angles = hash_float4_to_float2(seed) * M_PI_F;
|
||||
inclination += random_angles.x * isotropy;
|
||||
azimuth += random_angles.y * isotropy;
|
||||
|
||||
/* Convert back to Cartesian coordinates. */
|
||||
return spherical_to_direction(inclination, azimuth);
|
||||
}
|
||||
|
||||
ccl_device float2 compute_3d_gabor_noise_cell(float3 cell,
|
||||
const float3 position,
|
||||
const float frequency,
|
||||
const float isotropy,
|
||||
const float3 base_orientation)
|
||||
|
||||
{
|
||||
float2 noise = make_float2(0.0f, 0.0f);
|
||||
for (int i = 0; i < IMPULSES_COUNT; ++i) {
|
||||
/* Compute unique seeds for each of the needed random variables. */
|
||||
const float4 seed_for_orientation = make_float4(cell, i * 3);
|
||||
const float4 seed_for_kernel_center = make_float4(cell, i * 3 + 1);
|
||||
const float4 seed_for_weight = make_float4(cell, i * 3 + 2);
|
||||
|
||||
const float3 orientation = compute_3d_orientation(
|
||||
base_orientation, isotropy, seed_for_orientation);
|
||||
|
||||
const float3 kernel_center = hash_float4_to_float3(seed_for_kernel_center);
|
||||
const float3 position_in_kernel_space = position - kernel_center;
|
||||
|
||||
/* The kernel is windowed beyond the unit distance, so early exit with a zero for points that
|
||||
* are further than a unit radius. */
|
||||
if (dot(position_in_kernel_space, position_in_kernel_space) >= 1.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We either add or subtract the Gabor kernel based on a Bernoulli distribution of equal
|
||||
* probability. */
|
||||
const float weight = hash_float4_to_float(seed_for_weight) < 0.5f ? -1.0f : 1.0f;
|
||||
|
||||
noise += weight * compute_3d_gabor_kernel(position_in_kernel_space, frequency, orientation);
|
||||
}
|
||||
return noise;
|
||||
}
|
||||
|
||||
/* Identical to compute_2d_gabor_noise but works in the 3D neighborhood of the noise. */
|
||||
ccl_device float2 compute_3d_gabor_noise(const float3 coordinates,
|
||||
const float frequency,
|
||||
const float isotropy,
|
||||
const float3 base_orientation)
|
||||
{
|
||||
const float3 cell_position = floor(coordinates);
|
||||
const float3 local_position = coordinates - cell_position;
|
||||
|
||||
float2 sum = make_float2(0.0f, 0.0f);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float3 cell_offset = make_float3(i, j, k);
|
||||
const float3 current_cell_position = cell_position + cell_offset;
|
||||
const float3 position_in_cell_space = local_position - cell_offset;
|
||||
sum += compute_3d_gabor_noise_cell(
|
||||
current_cell_position, position_in_cell_space, frequency, isotropy, base_orientation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_gabor(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexGabor &ccl_restrict node)
|
||||
{
|
||||
const float3 coordinates = stack_load_float3(stack, node.coordinates);
|
||||
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
float frequency = stack_load(stack, node.frequency);
|
||||
const float anisotropy = stack_load(stack, node.anisotropy);
|
||||
const float orientation_2d = stack_load(stack, node.orientation_2d);
|
||||
const float3 orientation_3d = stack_load(stack, node.orientation_3d);
|
||||
|
||||
const float3 scaled_coordinates = coordinates * scale;
|
||||
const float isotropy = 1.0f - clamp(anisotropy, 0.0f, 1.0f);
|
||||
frequency = max(0.001f, frequency);
|
||||
|
||||
float2 phasor = make_float2(0.0f, 0.0f);
|
||||
float standard_deviation = 1.0f;
|
||||
switch (node.gabor_type) {
|
||||
case NODE_GABOR_TYPE_2D: {
|
||||
phasor = compute_2d_gabor_noise(make_float2(scaled_coordinates.x, scaled_coordinates.y),
|
||||
frequency,
|
||||
isotropy,
|
||||
orientation_2d);
|
||||
standard_deviation = compute_2d_gabor_standard_deviation();
|
||||
break;
|
||||
}
|
||||
case NODE_GABOR_TYPE_3D: {
|
||||
const float3 orientation = normalize(orientation_3d);
|
||||
phasor = compute_3d_gabor_noise(scaled_coordinates, frequency, isotropy, orientation);
|
||||
standard_deviation = compute_3d_gabor_standard_deviation();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Normalize the noise by dividing by six times the standard deviation, which was determined
|
||||
* empirically. */
|
||||
const float normalization_factor = 6.0f * standard_deviation;
|
||||
|
||||
/* As discussed in compute_2d_gabor_kernel, we use the imaginary part of the phasor as the Gabor
|
||||
* value. But remap to [0, 1] from [-1, 1]. */
|
||||
if (stack_valid(node.value_offset)) {
|
||||
stack_store_float(stack, node.value_offset, (phasor.y / normalization_factor) * 0.5f + 0.5f);
|
||||
}
|
||||
|
||||
/* Compute the phase based on equation (9) in Tricard's paper. But remap the phase into the
|
||||
* [0, 1] range. */
|
||||
if (stack_valid(node.phase_offset)) {
|
||||
const float phase = (atan2f(phasor.y, phasor.x) + M_PI_F) / (2.0f * M_PI_F);
|
||||
stack_store_float(stack, node.phase_offset, phase);
|
||||
}
|
||||
|
||||
/* Compute the intensity based on equation (8) in Tricard's paper. */
|
||||
if (stack_valid(node.intensity_offset)) {
|
||||
stack_store_float(stack, node.intensity_offset, len(phasor) / normalization_factor);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
26
blender-5.2.0/intern/cycles/kernel/svm/gamma.h
Normal file
26
blender-5.2.0/intern/cycles/kernel/svm/gamma.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/math_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_gamma(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeGamma &ccl_restrict node)
|
||||
{
|
||||
float3 color = stack_load(stack, node.color);
|
||||
const float gamma = stack_load(stack, node.gamma);
|
||||
|
||||
color = svm_math_gamma_color(color, gamma);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
stack_store_float3(stack, node.out_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
248
blender-5.2.0/intern/cycles/kernel/svm/geometry.h
Normal file
248
blender-5.2.0/intern/cycles/kernel/svm/geometry.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/geom/curve.h"
|
||||
#include "kernel/geom/primitive.h"
|
||||
|
||||
#include "kernel/svm/attribute.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "util/hash.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Geometry Node */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline Float3Type svm_node_geometry_eval(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const NodeGeometry type)
|
||||
{
|
||||
Float3Type data;
|
||||
|
||||
switch (type) {
|
||||
case NODE_GEOM_P:
|
||||
data = shading_position<Float3Type>(sd);
|
||||
break;
|
||||
case NODE_GEOM_N:
|
||||
data = Float3Type(sd->N);
|
||||
break;
|
||||
#ifdef __DPDU__
|
||||
case NODE_GEOM_T:
|
||||
data = primitive_tangent<Float3Type>(kg, sd);
|
||||
break;
|
||||
#endif
|
||||
case NODE_GEOM_I:
|
||||
data = shading_incoming<Float3Type>(sd);
|
||||
break;
|
||||
case NODE_GEOM_Ng:
|
||||
data = Float3Type(sd->Ng);
|
||||
break;
|
||||
case NODE_GEOM_uv:
|
||||
data = Float3Type(make_float3(1.0f - sd->u - sd->v, sd->u, 0.0f));
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
data.dx = make_float3(-sd->du.dx - sd->dv.dx, sd->du.dx, 0.0f);
|
||||
data.dy = make_float3(-sd->du.dy - sd->dv.dy, sd->du.dy, 0.0f);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
data = Float3Type(make_float3(0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_noinline void svm_node_geometry(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeGeometry &ccl_restrict node)
|
||||
{
|
||||
Float3Type data = svm_node_geometry_eval<Float3Type>(kg, sd, node.geom_type);
|
||||
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
/* Apply first-order bump offset. */
|
||||
if (node.bump_offset == NODE_BUMP_OFFSET_DX) {
|
||||
data.val += data.dx * node.bump_filter_width;
|
||||
}
|
||||
else if (node.bump_offset == NODE_BUMP_OFFSET_DY) {
|
||||
data.val += data.dy * node.bump_filter_width;
|
||||
}
|
||||
if (node.store_derivatives) {
|
||||
stack_store(stack, node.out_offset, data);
|
||||
}
|
||||
else {
|
||||
stack_store(stack, node.out_offset, data.val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
stack_store(stack, node.out_offset, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Object Info */
|
||||
|
||||
ccl_device_noinline void svm_node_object_info(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeObjectInfo &ccl_restrict
|
||||
node)
|
||||
{
|
||||
float data;
|
||||
|
||||
switch (node.info_type) {
|
||||
case NODE_INFO_OB_LOCATION: {
|
||||
stack_store_float3(stack, node.out_offset, object_location(kg, sd));
|
||||
return;
|
||||
}
|
||||
case NODE_INFO_OB_COLOR: {
|
||||
stack_store_float3(stack, node.out_offset, object_color(kg, sd->object));
|
||||
return;
|
||||
}
|
||||
case NODE_INFO_OB_ALPHA:
|
||||
data = object_alpha(kg, sd->object);
|
||||
break;
|
||||
case NODE_INFO_OB_INDEX:
|
||||
data = object_pass_id(kg, sd->object);
|
||||
break;
|
||||
case NODE_INFO_MAT_INDEX:
|
||||
data = shader_pass_id(kg, sd);
|
||||
break;
|
||||
case NODE_INFO_OB_RANDOM: {
|
||||
data = object_random_number(kg, sd->object);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
data = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
stack_store_float(stack, node.out_offset, data);
|
||||
}
|
||||
|
||||
/* Particle Info */
|
||||
|
||||
ccl_device_noinline void svm_node_particle_info(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeParticleInfo &ccl_restrict
|
||||
node)
|
||||
{
|
||||
switch (node.info_type) {
|
||||
case NODE_INFO_PAR_INDEX: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float(stack, node.out_offset, particle_index(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_PAR_RANDOM: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
const float random = hash_uint2_to_float(particle_index(kg, particle_id), 0);
|
||||
stack_store_float(stack, node.out_offset, random);
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_PAR_AGE: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float(stack, node.out_offset, particle_age(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_PAR_LIFETIME: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float(stack, node.out_offset, particle_lifetime(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_PAR_LOCATION: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float3(stack, node.out_offset, particle_location(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
#if 0 /* XXX float4 currently not supported in SVM stack */
|
||||
case NODE_INFO_PAR_ROTATION: {
|
||||
int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float4(stack, node.out_offset, particle_rotation(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case NODE_INFO_PAR_SIZE: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float(stack, node.out_offset, particle_size(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_PAR_VELOCITY: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float3(stack, node.out_offset, particle_velocity(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_PAR_ANGULAR_VELOCITY: {
|
||||
const int particle_id = object_particle_id(kg, sd->object);
|
||||
stack_store_float3(stack, node.out_offset, particle_angular_velocity(kg, particle_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __HAIR__
|
||||
|
||||
/* Hair Info */
|
||||
|
||||
ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeHairInfo &ccl_restrict node)
|
||||
{
|
||||
float data;
|
||||
float3 data3;
|
||||
|
||||
switch (node.info_type) {
|
||||
case NODE_INFO_CURVE_IS_STRAND: {
|
||||
data = (sd->type & PRIMITIVE_CURVE) != 0;
|
||||
stack_store_float(stack, node.out_offset, data);
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_CURVE_INTERCEPT:
|
||||
break; /* handled as attribute */
|
||||
case NODE_INFO_CURVE_LENGTH:
|
||||
break; /* handled as attribute */
|
||||
case NODE_INFO_CURVE_RANDOM:
|
||||
break; /* handled as attribute */
|
||||
case NODE_INFO_CURVE_THICKNESS: {
|
||||
data = curve_thickness(kg, sd);
|
||||
stack_store_float(stack, node.out_offset, data);
|
||||
break;
|
||||
}
|
||||
case NODE_INFO_CURVE_TANGENT_NORMAL: {
|
||||
data3 = curve_tangent_normal(sd);
|
||||
stack_store_float3(stack, node.out_offset, data3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __POINTCLOUD__
|
||||
|
||||
/* Point Info */
|
||||
|
||||
ccl_device_noinline void svm_node_point_info(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodePointInfo &ccl_restrict node)
|
||||
{
|
||||
switch (node.info_type) {
|
||||
case NODE_INFO_POINT_POSITION:
|
||||
stack_store_float3(stack, node.out_offset, point_position(kg, sd));
|
||||
break;
|
||||
case NODE_INFO_POINT_RADIUS:
|
||||
stack_store_float(stack, node.out_offset, point_radius(kg, sd));
|
||||
break;
|
||||
case NODE_INFO_POINT_RANDOM:
|
||||
break; /* handled as attribute */
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
75
blender-5.2.0/intern/cycles/kernel/svm/gradient.h
Normal file
75
blender-5.2.0/intern/cycles/kernel/svm/gradient.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Gradient */
|
||||
|
||||
ccl_device float svm_gradient(const float3 p, NodeGradientType type)
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
x = p.x;
|
||||
y = p.y;
|
||||
z = p.z;
|
||||
|
||||
if (type == NODE_BLEND_LINEAR) {
|
||||
return x;
|
||||
}
|
||||
if (type == NODE_BLEND_QUADRATIC) {
|
||||
const float r = fmaxf(x, 0.0f);
|
||||
return r * r;
|
||||
}
|
||||
if (type == NODE_BLEND_EASING) {
|
||||
const float r = fminf(fmaxf(x, 0.0f), 1.0f);
|
||||
const float t = r * r;
|
||||
|
||||
return (3.0f * t - 2.0f * t * r);
|
||||
}
|
||||
if (type == NODE_BLEND_DIAGONAL) {
|
||||
return (x + y) * 0.5f;
|
||||
}
|
||||
if (type == NODE_BLEND_RADIAL) {
|
||||
return atan2f(y, x) / M_2PI_F + 0.5f;
|
||||
}
|
||||
|
||||
/* Bias a little bit for the case where p is a unit length vector,
|
||||
* to get exactly zero instead of a small random value depending
|
||||
* on float precision. */
|
||||
const float r = fmaxf(0.999999f - sqrtf(x * x + y * y + z * z), 0.0f);
|
||||
|
||||
if (type == NODE_BLEND_QUADRATIC_SPHERE) {
|
||||
return r * r;
|
||||
}
|
||||
if (type == NODE_BLEND_SPHERICAL) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_gradient(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeTexGradient &ccl_restrict node)
|
||||
{
|
||||
const float3 co = stack_load_float3(stack, node.co);
|
||||
|
||||
float f = svm_gradient(co, node.gradient_type);
|
||||
f = saturatef(f);
|
||||
|
||||
if (stack_valid(node.fac_offset)) {
|
||||
stack_store_float(stack, node.fac_offset, f);
|
||||
}
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, make_float3(f, f, f));
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
47
blender-5.2.0/intern/cycles/kernel/svm/hsv.h
Normal file
47
blender-5.2.0/intern/cycles/kernel/svm/hsv.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "util/color.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_hsv(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeHSV &ccl_restrict node)
|
||||
{
|
||||
const float fac = stack_load(stack, node.fac);
|
||||
const float3 in_color = stack_load(stack, node.color);
|
||||
float3 color = in_color;
|
||||
|
||||
const float hue = stack_load(stack, node.hue);
|
||||
const float sat = stack_load(stack, node.sat);
|
||||
const float val = stack_load(stack, node.val);
|
||||
|
||||
color = rgb_to_hsv(color);
|
||||
|
||||
color.x = fractf(color.x + hue + 0.5f);
|
||||
color.y = saturatef(color.y * sat);
|
||||
color.z *= val;
|
||||
|
||||
color = hsv_to_rgb(color);
|
||||
|
||||
color.x = fac * color.x + (1.0f - fac) * in_color.x;
|
||||
color.y = fac * color.y + (1.0f - fac) * in_color.y;
|
||||
color.z = fac * color.z + (1.0f - fac) * in_color.z;
|
||||
|
||||
/* Clamp color to prevent negative values caused by over saturation. */
|
||||
color.x = max(color.x, 0.0f);
|
||||
color.y = max(color.y, 0.0f);
|
||||
color.z = max(color.z, 0.0f);
|
||||
|
||||
if (stack_valid(node.out_color_offset)) {
|
||||
stack_store_float3(stack, node.out_color_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
33
blender-5.2.0/intern/cycles/kernel/svm/ies.h
Normal file
33
blender-5.2.0/intern/cycles/kernel/svm/ies.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/ies.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_ies(KernelGlobals kg,
|
||||
ccl_private ShaderData * /*sd*/,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeIES &ccl_restrict node)
|
||||
{
|
||||
float3 vector = stack_load_float3(stack, node.vector_offset);
|
||||
const float strength = stack_load(stack, node.strength);
|
||||
|
||||
vector = normalize(vector);
|
||||
const float v_angle = safe_acosf(-vector.z);
|
||||
const float h_angle = atan2f(vector.x, vector.y) + M_PI_F;
|
||||
|
||||
const float fac = strength * kernel_ies_interp(kg, node.slot, h_angle, v_angle);
|
||||
|
||||
if (stack_valid(node.fac_offset)) {
|
||||
stack_store_float(stack, node.fac_offset, fac);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
207
blender-5.2.0/intern/cycles/kernel/svm/image.h
Normal file
207
blender-5.2.0/intern/cycles/kernel/svm/image.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/image.h"
|
||||
|
||||
#include "kernel/camera/projection.h"
|
||||
|
||||
#include "kernel/geom/object.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "util/color.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device float4 svm_image_texture(
|
||||
KernelGlobals kg, ccl_private ShaderData *sd, const int id, const dual2 uv, const uint flags)
|
||||
{
|
||||
float4 r = kernel_image_interp_with_udim(kg, sd, id, uv);
|
||||
const float alpha = r.w;
|
||||
|
||||
if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) {
|
||||
r /= alpha;
|
||||
r.w = alpha;
|
||||
}
|
||||
|
||||
if (flags & NODE_IMAGE_COMPRESS_AS_SRGB) {
|
||||
r = color_srgb_to_linear_v4(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Remap coordinate from 0..1 box to -1..-1 */
|
||||
template<class Float3Type> ccl_device_inline Float3Type texco_remap_square(const Float3Type co)
|
||||
{
|
||||
return (co - make_float3(0.5f, 0.5f, 0.5f)) * 2.0f;
|
||||
}
|
||||
|
||||
template<class Float3Type>
|
||||
ccl_device_inline auto svm_node_tex_image_mapping(const Float3Type co, const uint proj)
|
||||
{
|
||||
if (proj == NODE_IMAGE_PROJ_SPHERE) {
|
||||
return map_to_sphere(texco_remap_square(co));
|
||||
}
|
||||
if (proj == NODE_IMAGE_PROJ_TUBE) {
|
||||
return map_to_tube(texco_remap_square(co));
|
||||
}
|
||||
|
||||
return make_float2(co);
|
||||
}
|
||||
|
||||
template<class Float3Type>
|
||||
ccl_device_noinline void svm_node_tex_image(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexImage &ccl_restrict node)
|
||||
{
|
||||
const Float3Type co = stack_load<Float3Type>(stack, node.co);
|
||||
const dual2 tex_co(svm_node_tex_image_mapping(co, node.projection));
|
||||
|
||||
const float4 f = svm_image_texture(kg, sd, node.id, tex_co, node.flags);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
stack_store_float3(stack, node.out_offset, make_float3(f));
|
||||
}
|
||||
if (stack_valid(node.alpha_offset)) {
|
||||
stack_store_float(stack, node.alpha_offset, f.w);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Float3Type>
|
||||
ccl_device_noinline void svm_node_tex_image_box(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexImageBox &ccl_restrict
|
||||
node)
|
||||
{
|
||||
/* get object space normal */
|
||||
float3 N = sd->N;
|
||||
|
||||
object_inverse_normal_transform(kg, sd, &N);
|
||||
|
||||
/* project from direction vector to barycentric coordinates in triangles */
|
||||
const float3 signed_N = N;
|
||||
|
||||
N = fabs(N);
|
||||
|
||||
N /= (N.x + N.y + N.z);
|
||||
|
||||
/* basic idea is to think of this as a triangle, each corner representing
|
||||
* one of the 3 faces of the cube. in the corners we have single textures,
|
||||
* in between we blend between two textures, and in the middle we a blend
|
||||
* between three textures.
|
||||
*
|
||||
* The `Nxyz` values are the barycentric coordinates in an equilateral
|
||||
* triangle, which in case of blending, in the middle has a smaller
|
||||
* equilateral triangle where 3 textures blend. this divides things into
|
||||
* 7 zones, with an `if()` test for each zone. */
|
||||
|
||||
float3 weight = make_float3(0.0f, 0.0f, 0.0f);
|
||||
const float blend = node.blend;
|
||||
const float limit = 0.5f * (1.0f + blend);
|
||||
|
||||
/* first test for corners with single texture */
|
||||
if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) {
|
||||
weight.x = 1.0f;
|
||||
}
|
||||
else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) {
|
||||
weight.y = 1.0f;
|
||||
}
|
||||
else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) {
|
||||
weight.z = 1.0f;
|
||||
}
|
||||
else if (blend > 0.0f) {
|
||||
/* in case of blending, test for mixes between two textures */
|
||||
if (N.z < (1.0f - limit) * (N.y + N.x)) {
|
||||
weight.x = N.x / (N.x + N.y);
|
||||
weight.x = saturatef((weight.x - 0.5f * (1.0f - blend)) / blend);
|
||||
weight.y = 1.0f - weight.x;
|
||||
}
|
||||
else if (N.x < (1.0f - limit) * (N.y + N.z)) {
|
||||
weight.y = N.y / (N.y + N.z);
|
||||
weight.y = saturatef((weight.y - 0.5f * (1.0f - blend)) / blend);
|
||||
weight.z = 1.0f - weight.y;
|
||||
}
|
||||
else if (N.y < (1.0f - limit) * (N.x + N.z)) {
|
||||
weight.x = N.x / (N.x + N.z);
|
||||
weight.x = saturatef((weight.x - 0.5f * (1.0f - blend)) / blend);
|
||||
weight.z = 1.0f - weight.x;
|
||||
}
|
||||
else {
|
||||
/* last case, we have a mix between three */
|
||||
weight.x = ((2.0f - limit) * N.x + (limit - 1.0f)) / (2.0f * limit - 1.0f);
|
||||
weight.y = ((2.0f - limit) * N.y + (limit - 1.0f)) / (2.0f * limit - 1.0f);
|
||||
weight.z = ((2.0f - limit) * N.z + (limit - 1.0f)) / (2.0f * limit - 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Desperate mode, no valid choice anyway, fall back to one side. */
|
||||
weight.x = 1.0f;
|
||||
}
|
||||
|
||||
/* now fetch textures */
|
||||
float4 f = zero_float4();
|
||||
|
||||
const dual3 co = dual3(stack_load<Float3Type>(stack, node.co));
|
||||
|
||||
/* Map so that no textures are flipped, rotation is somewhat arbitrary. */
|
||||
if (weight.x > 0.0f) {
|
||||
const dual2 uv = make_float2((signed_N.x < 0.0f) ? 1.0f - co.y() : co.y(), co.z());
|
||||
f += weight.x * svm_image_texture(kg, sd, node.id, uv, node.flags);
|
||||
}
|
||||
if (weight.y > 0.0f) {
|
||||
const dual2 uv = make_float2((signed_N.y > 0.0f) ? 1.0f - co.x() : co.x(), co.z());
|
||||
f += weight.y * svm_image_texture(kg, sd, node.id, uv, node.flags);
|
||||
}
|
||||
if (weight.z > 0.0f) {
|
||||
const dual2 uv = make_float2((signed_N.z > 0.0f) ? 1.0f - co.y() : co.y(), co.x());
|
||||
f += weight.z * svm_image_texture(kg, sd, node.id, uv, node.flags);
|
||||
}
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
stack_store_float3(stack, node.out_offset, make_float3(f.x, f.y, f.z));
|
||||
}
|
||||
if (stack_valid(node.alpha_offset)) {
|
||||
stack_store_float(stack, node.alpha_offset, f.w);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Float3Type>
|
||||
ccl_device_inline auto svm_node_tex_environment_projection(Float3Type co, const uint proj)
|
||||
{
|
||||
co = safe_normalize(co);
|
||||
if (proj == 0) {
|
||||
return direction_to_equirectangular(co);
|
||||
}
|
||||
return direction_to_mirrorball(co);
|
||||
}
|
||||
|
||||
template<class Float3Type>
|
||||
ccl_device_noinline void svm_node_tex_environment(
|
||||
KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexEnvironment &ccl_restrict node)
|
||||
{
|
||||
const Float3Type co = stack_load<Float3Type>(stack, node.co);
|
||||
const dual2 uv(svm_node_tex_environment_projection(co, node.projection));
|
||||
|
||||
const float4 f = svm_image_texture(kg, sd, node.id, uv, node.flags);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
stack_store_float3(stack, node.out_offset, make_float3(f.x, f.y, f.z));
|
||||
}
|
||||
if (stack_valid(node.alpha_offset)) {
|
||||
stack_store_float(stack, node.alpha_offset, f.w);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
32
blender-5.2.0/intern/cycles/kernel/svm/invert.h
Normal file
32
blender-5.2.0/intern/cycles/kernel/svm/invert.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device float invert(const float color, const float factor)
|
||||
{
|
||||
return factor * (1.0f - color) + (1.0f - factor) * color;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_invert(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeInvert &ccl_restrict node)
|
||||
{
|
||||
const float factor = stack_load(stack, node.fac);
|
||||
float3 color = stack_load(stack, node.color);
|
||||
|
||||
color.x = invert(color.x, factor);
|
||||
color.y = invert(color.y, factor);
|
||||
color.z = invert(color.z, factor);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
stack_store_float3(stack, node.out_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
144
blender-5.2.0/intern/cycles/kernel/svm/light_path.h
Normal file
144
blender-5.2.0/intern/cycles/kernel/svm/light_path.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Light Path Node */
|
||||
|
||||
template<uint node_feature_mask, typename ConstIntegratorGenericState>
|
||||
ccl_device_noinline void svm_node_light_path(KernelGlobals kg,
|
||||
ConstIntegratorGenericState state,
|
||||
const ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeLightPath &ccl_restrict node,
|
||||
const PathRayVisibility path_visibility,
|
||||
const uint32_t path_flag)
|
||||
{
|
||||
float info = 0.0f;
|
||||
|
||||
switch (node.path_type) {
|
||||
case NODE_LP_camera:
|
||||
info = (path_visibility & PATH_RAY_VISIBILITY_CAMERA) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_shadow:
|
||||
info = (path_visibility & PATH_RAY_VISIBILITY_SHADOW) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_diffuse:
|
||||
info = (path_visibility & PATH_RAY_VISIBILITY_DIFFUSE) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_glossy:
|
||||
info = (path_visibility & PATH_RAY_VISIBILITY_GLOSSY) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_singular:
|
||||
info = (path_flag & PATH_RAY_SINGULAR) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_reflection:
|
||||
info = (path_flag & PATH_RAY_REFLECT) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_transmission:
|
||||
info = (path_visibility & PATH_RAY_VISIBILITY_TRANSMIT) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_volume_scatter:
|
||||
info = (path_visibility & PATH_RAY_VISIBILITY_VOLUME_SCATTER) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_backfacing:
|
||||
info = (sd->flag & SD_BACKFACING) ? 1.0f : 0.0f;
|
||||
break;
|
||||
case NODE_LP_ray_length:
|
||||
info = sd->ray_length;
|
||||
break;
|
||||
case NODE_LP_ray_depth: {
|
||||
/* Read bounce from different locations depending on if this is a shadow
|
||||
* path. It's a bit dubious to have integrate state details leak into
|
||||
* this function but hard to avoid currently. */
|
||||
IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
|
||||
{
|
||||
info = (float)integrator_state_bounce(state, path_flag);
|
||||
}
|
||||
|
||||
/* For background, light emission and shadow evaluation from a
|
||||
* surface or volume we are effectively one bounce further. */
|
||||
if ((path_visibility & PATH_RAY_VISIBILITY_SHADOW) || (path_flag & PATH_RAY_EMISSION)) {
|
||||
info += 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_LP_ray_transparent: {
|
||||
IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
|
||||
{
|
||||
info = (float)integrator_state_transparent_bounce(state, path_flag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_LP_ray_diffuse:
|
||||
IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
|
||||
{
|
||||
info = (float)integrator_state_diffuse_bounce(state, path_flag);
|
||||
}
|
||||
break;
|
||||
case NODE_LP_ray_glossy:
|
||||
IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
|
||||
{
|
||||
info = (float)integrator_state_glossy_bounce(state, path_flag);
|
||||
}
|
||||
break;
|
||||
case NODE_LP_ray_transmission:
|
||||
IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
|
||||
{
|
||||
info = (float)integrator_state_transmission_bounce(state, path_flag);
|
||||
}
|
||||
break;
|
||||
case NODE_LP_ray_portal:
|
||||
IF_KERNEL_NODES_FEATURE(LIGHT_PATH)
|
||||
{
|
||||
info = (float)integrator_state_portal_bounce(kg, state, path_flag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stack_store_float(stack, node.out_offset, info);
|
||||
}
|
||||
|
||||
/* Light Falloff Node */
|
||||
|
||||
ccl_device_noinline void svm_node_light_falloff(ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeLightFalloff &ccl_restrict
|
||||
node)
|
||||
{
|
||||
float strength = stack_load(stack, node.strength);
|
||||
if (sd->ray_length == FLT_MAX) {
|
||||
/* Distant lights (which have a ray_length of FLT_MAX) overflow when using most outputs of
|
||||
* the light falloff node. So just ignore the node in that case. */
|
||||
stack_store_float(stack, node.out_offset, strength);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (node.falloff_type) {
|
||||
case NODE_LIGHT_FALLOFF_QUADRATIC:
|
||||
break;
|
||||
case NODE_LIGHT_FALLOFF_LINEAR:
|
||||
strength *= sd->ray_length;
|
||||
break;
|
||||
case NODE_LIGHT_FALLOFF_CONSTANT:
|
||||
strength *= sd->ray_length * sd->ray_length;
|
||||
break;
|
||||
}
|
||||
|
||||
const float smooth = stack_load(stack, node.smooth);
|
||||
|
||||
if (smooth > 0.0f) {
|
||||
const float squared = sd->ray_length * sd->ray_length;
|
||||
strength *= squared / (smooth + squared);
|
||||
}
|
||||
|
||||
stack_store_float(stack, node.out_offset, strength);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
119
blender-5.2.0/intern/cycles/kernel/svm/magic.h
Normal file
119
blender-5.2.0/intern/cycles/kernel/svm/magic.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Magic */
|
||||
|
||||
ccl_device_noinline_cpu float3 svm_magic(const float3 p,
|
||||
const float scale,
|
||||
const int n,
|
||||
float distortion)
|
||||
{
|
||||
/*
|
||||
* Prevent NaNs due to input p
|
||||
* Sin and Cosine are periodic about [0 2*PI) so the following
|
||||
* will yield a more accurate result. As it stops the input values
|
||||
* going out of range for floats which caused a NaN. The
|
||||
* calculation of (px + py + pz)*5 can cause an Inf when one or more
|
||||
* values are very large the cos or sin of this results in a NaN
|
||||
* It also addresses the case where one dimension is large relative
|
||||
* to another which caused banding due to the loss of precision in the
|
||||
* smaller value. This is due to the value in the -2*PI to 2*PI range
|
||||
* effectively being lost due to floating point precision.
|
||||
*/
|
||||
const float px = fmodf(p.x * scale, M_2PI_F);
|
||||
const float py = fmodf(p.y * scale, M_2PI_F);
|
||||
const float pz = fmodf(p.z * scale, M_2PI_F);
|
||||
|
||||
float x = sinf((px + py + pz) * 5.0f);
|
||||
float y = cosf((-px + py - pz) * 5.0f);
|
||||
float z = -cosf((-px - py + pz) * 5.0f);
|
||||
|
||||
if (n > 0) {
|
||||
x *= distortion;
|
||||
y *= distortion;
|
||||
z *= distortion;
|
||||
y = -cosf(x - y + z);
|
||||
y *= distortion;
|
||||
|
||||
if (n > 1) {
|
||||
x = cosf(x - y - z);
|
||||
x *= distortion;
|
||||
|
||||
if (n > 2) {
|
||||
z = sinf(-x - y - z);
|
||||
z *= distortion;
|
||||
|
||||
if (n > 3) {
|
||||
x = -cosf(-x + y - z);
|
||||
x *= distortion;
|
||||
|
||||
if (n > 4) {
|
||||
y = -sinf(-x + y + z);
|
||||
y *= distortion;
|
||||
|
||||
if (n > 5) {
|
||||
y = -cosf(-x + y + z);
|
||||
y *= distortion;
|
||||
|
||||
if (n > 6) {
|
||||
x = cosf(x + y + z);
|
||||
x *= distortion;
|
||||
|
||||
if (n > 7) {
|
||||
z = sinf(x + y - z);
|
||||
z *= distortion;
|
||||
|
||||
if (n > 8) {
|
||||
x = -cosf(-x - y + z);
|
||||
x *= distortion;
|
||||
|
||||
if (n > 9) {
|
||||
y = -sinf(x - y + z);
|
||||
y *= distortion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (distortion != 0.0f) {
|
||||
distortion *= 2.0f;
|
||||
x /= distortion;
|
||||
y /= distortion;
|
||||
z /= distortion;
|
||||
}
|
||||
|
||||
return make_float3(0.5f - x, 0.5f - y, 0.5f - z);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_magic(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexMagic &ccl_restrict node)
|
||||
{
|
||||
const float3 co = stack_load_float3(stack, node.co);
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
const float distortion = stack_load(stack, node.distortion);
|
||||
|
||||
const float3 color = svm_magic(co, scale, node.depth, distortion);
|
||||
|
||||
if (stack_valid(node.fac_offset)) {
|
||||
stack_store_float(stack, node.fac_offset, average(color));
|
||||
}
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
119
blender-5.2.0/intern/cycles/kernel/svm/map_range.h
Normal file
119
blender-5.2.0/intern/cycles/kernel/svm/map_range.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Map Range Node */
|
||||
|
||||
ccl_device_inline float smootherstep(const float edge0, const float edge1, float x)
|
||||
{
|
||||
x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0f, 1.0f);
|
||||
return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_map_range(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMapRange &ccl_restrict node)
|
||||
{
|
||||
const float value = stack_load(stack, node.value);
|
||||
const float from_min = stack_load(stack, node.from_min);
|
||||
const float from_max = stack_load(stack, node.from_max);
|
||||
const float to_min = stack_load(stack, node.to_min);
|
||||
const float to_max = stack_load(stack, node.to_max);
|
||||
const float steps = stack_load(stack, node.steps);
|
||||
|
||||
float result;
|
||||
|
||||
if (from_max != from_min) {
|
||||
float factor = value;
|
||||
switch (node.range_type) {
|
||||
default:
|
||||
case NODE_MAP_RANGE_LINEAR:
|
||||
factor = (value - from_min) / (from_max - from_min);
|
||||
break;
|
||||
case NODE_MAP_RANGE_STEPPED: {
|
||||
factor = (value - from_min) / (from_max - from_min);
|
||||
factor = (steps > 0.0f) ? floorf(factor * (steps + 1.0f)) / steps : 0.0f;
|
||||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHSTEP: {
|
||||
factor = (from_min > from_max) ? 1.0f - smoothstep(from_max, from_min, factor) :
|
||||
smoothstep(from_min, from_max, factor);
|
||||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHERSTEP: {
|
||||
factor = (from_min > from_max) ? 1.0f - smootherstep(from_max, from_min, factor) :
|
||||
smootherstep(from_min, from_max, factor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = to_min + factor * (to_max - to_min);
|
||||
}
|
||||
else {
|
||||
result = 0.0f;
|
||||
}
|
||||
stack_store_float(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_vector_map_range(
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeVectorMapRange &ccl_restrict node)
|
||||
{
|
||||
const float3 value = stack_load(stack, node.value);
|
||||
const float3 from_min = stack_load(stack, node.from_min);
|
||||
const float3 from_max = stack_load(stack, node.from_max);
|
||||
const float3 to_min = stack_load(stack, node.to_min);
|
||||
const float3 to_max = stack_load(stack, node.to_max);
|
||||
const float3 steps = stack_load(stack, node.steps);
|
||||
|
||||
const int use_clamp = (node.range_type == NODE_MAP_RANGE_SMOOTHSTEP ||
|
||||
node.range_type == NODE_MAP_RANGE_SMOOTHERSTEP) ?
|
||||
0 :
|
||||
node.use_clamp;
|
||||
float3 result;
|
||||
float3 factor = value;
|
||||
switch (node.range_type) {
|
||||
default:
|
||||
case NODE_MAP_RANGE_LINEAR:
|
||||
factor = safe_divide((value - from_min), (from_max - from_min));
|
||||
break;
|
||||
case NODE_MAP_RANGE_STEPPED: {
|
||||
factor = safe_divide((value - from_min), (from_max - from_min));
|
||||
factor = make_float3((steps.x > 0.0f) ? floorf(factor.x * (steps.x + 1.0f)) / steps.x : 0.0f,
|
||||
(steps.y > 0.0f) ? floorf(factor.y * (steps.y + 1.0f)) / steps.y : 0.0f,
|
||||
(steps.z > 0.0f) ? floorf(factor.z * (steps.z + 1.0f)) / steps.z :
|
||||
0.0f);
|
||||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHSTEP: {
|
||||
factor = safe_divide((value - from_min), (from_max - from_min));
|
||||
factor = clamp(factor, zero_float3(), one_float3());
|
||||
factor = (make_float3(3.0f, 3.0f, 3.0f) - 2.0f * factor) * (factor * factor);
|
||||
break;
|
||||
}
|
||||
case NODE_MAP_RANGE_SMOOTHERSTEP: {
|
||||
factor = safe_divide((value - from_min), (from_max - from_min));
|
||||
factor = clamp(factor, zero_float3(), one_float3());
|
||||
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = to_min + factor * (to_max - to_min);
|
||||
if (use_clamp > 0) {
|
||||
result.x = (to_min.x > to_max.x) ? clamp(result.x, to_max.x, to_min.x) :
|
||||
clamp(result.x, to_min.x, to_max.x);
|
||||
result.y = (to_min.y > to_max.y) ? clamp(result.y, to_max.y, to_min.y) :
|
||||
clamp(result.y, to_min.y, to_max.y);
|
||||
result.z = (to_min.z > to_max.z) ? clamp(result.z, to_max.z, to_min.z) :
|
||||
clamp(result.z, to_min.z, to_max.z);
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
54
blender-5.2.0/intern/cycles/kernel/svm/mapping.h
Normal file
54
blender-5.2.0/intern/cycles/kernel/svm/mapping.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/mapping_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Mapping Node */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_noinline void svm_node_mapping(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMapping &ccl_restrict node)
|
||||
{
|
||||
const float3 location = stack_load(stack, node.location);
|
||||
const float3 rotation = stack_load(stack, node.rotation);
|
||||
const float3 scale = stack_load(stack, node.scale);
|
||||
|
||||
const Float3Type vector = stack_load<Float3Type>(stack, node.vector);
|
||||
const Float3Type result = svm_mapping(node.mapping_type, vector, location, rotation, scale);
|
||||
stack_store(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
/* Texture Mapping */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_noinline void svm_node_texture_mapping(
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTextureMapping &ccl_restrict node)
|
||||
{
|
||||
const Float3Type v = stack_load<Float3Type>(stack, node.vec_offset);
|
||||
const Transform tfm = make_transform(node.tfm);
|
||||
|
||||
const Float3Type r = transform_point(&tfm, v);
|
||||
stack_store(stack, node.out_offset, r);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_min_max(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMinMax &ccl_restrict node)
|
||||
{
|
||||
const float3 v = stack_load_float3(stack, node.vec_offset);
|
||||
|
||||
const float3 mn = node.mn;
|
||||
const float3 mx = node.mx;
|
||||
|
||||
const float3 r = min(max(mn, v), mx);
|
||||
stack_store_float3(stack, node.out_offset, r);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
38
blender-5.2.0/intern/cycles/kernel/svm/mapping_util.h
Normal file
38
blender-5.2.0/intern/cycles/kernel/svm/mapping_util.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/types.h"
|
||||
|
||||
#include "util/math.h"
|
||||
#include "util/transform.h"
|
||||
#include "util/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
template<class Float3Type>
|
||||
ccl_device Float3Type svm_mapping(NodeMappingType type,
|
||||
const Float3Type vector,
|
||||
const float3 location,
|
||||
const float3 rotation,
|
||||
const float3 scale)
|
||||
{
|
||||
const Transform rotationTransform = euler_to_transform(rotation);
|
||||
switch (type) {
|
||||
case NODE_MAPPING_TYPE_POINT:
|
||||
return transform_direction(&rotationTransform, (vector * scale)) + location;
|
||||
case NODE_MAPPING_TYPE_TEXTURE:
|
||||
return safe_divide(transform_direction_transposed(&rotationTransform, (vector - location)),
|
||||
scale);
|
||||
case NODE_MAPPING_TYPE_VECTOR:
|
||||
return transform_direction(&rotationTransform, (vector * scale));
|
||||
case NODE_MAPPING_TYPE_NORMAL:
|
||||
return safe_normalize(transform_direction(&rotationTransform, safe_divide(vector, scale)));
|
||||
default:
|
||||
return Float3Type(zero_float3());
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
47
blender-5.2.0/intern/cycles/kernel/svm/math.h
Normal file
47
blender-5.2.0/intern/cycles/kernel/svm/math.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/math_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_math(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMath &ccl_restrict node)
|
||||
{
|
||||
const float a = stack_load(stack, node.value1);
|
||||
const float b = stack_load(stack, node.value2);
|
||||
const float c = stack_load(stack, node.value3);
|
||||
const float result = svm_math(node.math_type, a, b, c);
|
||||
|
||||
stack_store_float(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_noinline void svm_node_vector_math(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeVectorMath &ccl_restrict node)
|
||||
{
|
||||
using FloatType = dual_scalar_t<Float3Type>;
|
||||
|
||||
const Float3Type a = stack_load<Float3Type>(stack, node.a);
|
||||
const Float3Type b = stack_load<Float3Type>(stack, node.b);
|
||||
const Float3Type c = stack_load<Float3Type>(stack, node.c);
|
||||
const FloatType param1 = stack_load<FloatType>(stack, node.param1);
|
||||
|
||||
FloatType value = make_zero<FloatType>();
|
||||
Float3Type vector = make_zero<Float3Type>();
|
||||
svm_vector_math(&value, &vector, node.math_type, a, b, c, param1);
|
||||
|
||||
if (stack_valid(node.value_offset)) {
|
||||
stack_store(stack, node.value_offset, value);
|
||||
}
|
||||
if (stack_valid(node.vector_offset)) {
|
||||
stack_store(stack, node.vector_offset, vector);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
282
blender-5.2.0/intern/cycles/kernel/svm/math_util.h
Normal file
282
blender-5.2.0/intern/cycles/kernel/svm/math_util.h
Normal file
@@ -0,0 +1,282 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/types.h"
|
||||
#include "kernel/tables.h"
|
||||
|
||||
#include "util/math.h"
|
||||
#include "util/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
template<class Float3Type, class FloatType>
|
||||
ccl_device void svm_vector_math(ccl_private FloatType *value,
|
||||
ccl_private Float3Type *vector,
|
||||
NodeVectorMathType type,
|
||||
const Float3Type a,
|
||||
const Float3Type b,
|
||||
const Float3Type c,
|
||||
const FloatType param1)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_VECTOR_MATH_ADD:
|
||||
*vector = a + b;
|
||||
break;
|
||||
case NODE_VECTOR_MATH_SUBTRACT:
|
||||
*vector = a - b;
|
||||
break;
|
||||
case NODE_VECTOR_MATH_MULTIPLY:
|
||||
*vector = a * b;
|
||||
break;
|
||||
case NODE_VECTOR_MATH_DIVIDE:
|
||||
*vector = safe_divide(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_CROSS_PRODUCT:
|
||||
*vector = cross(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_PROJECT:
|
||||
*vector = project(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_REFLECT:
|
||||
*vector = reflect(a, safe_normalize(b));
|
||||
break;
|
||||
case NODE_VECTOR_MATH_REFRACT:
|
||||
*vector = refract(a, safe_normalize(b), param1);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_FACEFORWARD:
|
||||
*vector = faceforward(a, b, c);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_MULTIPLY_ADD:
|
||||
*vector = a * b + c;
|
||||
break;
|
||||
case NODE_VECTOR_MATH_DOT_PRODUCT:
|
||||
*value = dot(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_DISTANCE:
|
||||
*value = distance(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_LENGTH:
|
||||
*value = len(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_SCALE:
|
||||
*vector = a * param1;
|
||||
break;
|
||||
case NODE_VECTOR_MATH_NORMALIZE:
|
||||
*vector = safe_normalize(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_SNAP:
|
||||
*vector = floor(safe_divide(a, b)) * b;
|
||||
break;
|
||||
case NODE_VECTOR_MATH_ROUND:
|
||||
*vector = floor(a + 0.5f);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_FLOOR:
|
||||
*vector = floor(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_CEIL:
|
||||
*vector = ceil(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_MODULO:
|
||||
*vector = safe_fmod(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_WRAP:
|
||||
*vector = wrap(a, b, c);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_FRACTION:
|
||||
*vector = a - floor(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_ABSOLUTE:
|
||||
*vector = fabs(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_POWER:
|
||||
*vector = safe_pow(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_SIGN:
|
||||
*vector = compatible_sign(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_MINIMUM:
|
||||
*vector = min(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_MAXIMUM:
|
||||
*vector = max(a, b);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_SINE:
|
||||
*vector = sin(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_COSINE:
|
||||
*vector = cos(a);
|
||||
break;
|
||||
case NODE_VECTOR_MATH_TANGENT:
|
||||
*vector = tan(a);
|
||||
break;
|
||||
default:
|
||||
*vector = Float3Type(zero_float3());
|
||||
*value = FloatType(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float svm_math(NodeMathType type, const float a, float b, const float c)
|
||||
{
|
||||
switch (type) {
|
||||
case NODE_MATH_ADD:
|
||||
return a + b;
|
||||
case NODE_MATH_SUBTRACT:
|
||||
return a - b;
|
||||
case NODE_MATH_MULTIPLY:
|
||||
return a * b;
|
||||
case NODE_MATH_DIVIDE:
|
||||
return safe_divide(a, b);
|
||||
case NODE_MATH_POWER:
|
||||
return safe_powf(a, b);
|
||||
case NODE_MATH_LOGARITHM:
|
||||
return safe_logf(a, b);
|
||||
case NODE_MATH_SQRT:
|
||||
return safe_sqrtf(a);
|
||||
case NODE_MATH_INV_SQRT:
|
||||
return inversesqrtf(a);
|
||||
case NODE_MATH_ABSOLUTE:
|
||||
return fabsf(a);
|
||||
case NODE_MATH_RADIANS:
|
||||
return a * (M_PI_F / 180.0f);
|
||||
case NODE_MATH_DEGREES:
|
||||
return a * (180.0f / M_PI_F);
|
||||
case NODE_MATH_MINIMUM:
|
||||
return fminf(a, b);
|
||||
case NODE_MATH_MAXIMUM:
|
||||
return fmaxf(a, b);
|
||||
case NODE_MATH_LESS_THAN:
|
||||
return a < b;
|
||||
case NODE_MATH_GREATER_THAN:
|
||||
return a > b;
|
||||
case NODE_MATH_ROUND:
|
||||
return floorf(a + 0.5f);
|
||||
case NODE_MATH_FLOOR:
|
||||
return floorf(a);
|
||||
case NODE_MATH_CEIL:
|
||||
return ceilf(a);
|
||||
case NODE_MATH_FRACTION:
|
||||
return a - floorf(a);
|
||||
case NODE_MATH_MODULO:
|
||||
return safe_modulo(a, b);
|
||||
case NODE_MATH_FLOORED_MODULO:
|
||||
return safe_floored_modulo(a, b);
|
||||
case NODE_MATH_TRUNC:
|
||||
return a >= 0.0f ? floorf(a) : ceilf(a);
|
||||
case NODE_MATH_SNAP:
|
||||
return floorf(safe_divide(a, b)) * b;
|
||||
case NODE_MATH_WRAP:
|
||||
return wrapf(a, b, c);
|
||||
case NODE_MATH_PINGPONG:
|
||||
return pingpongf(a, b);
|
||||
case NODE_MATH_SINE:
|
||||
return sinf(a);
|
||||
case NODE_MATH_COSINE:
|
||||
return cosf(a);
|
||||
case NODE_MATH_TANGENT:
|
||||
return tanf(a);
|
||||
case NODE_MATH_SINH:
|
||||
return sinhf(a);
|
||||
case NODE_MATH_COSH:
|
||||
return coshf(a);
|
||||
case NODE_MATH_TANH:
|
||||
return tanhf(a);
|
||||
case NODE_MATH_ARCSINE:
|
||||
return safe_asinf(a);
|
||||
case NODE_MATH_ARCCOSINE:
|
||||
return safe_acosf(a);
|
||||
case NODE_MATH_ARCTANGENT:
|
||||
return atanf(a);
|
||||
case NODE_MATH_ARCTAN2:
|
||||
return compatible_atan2(a, b);
|
||||
case NODE_MATH_SIGN:
|
||||
return compatible_signf(a);
|
||||
case NODE_MATH_EXPONENT:
|
||||
return expf(a);
|
||||
case NODE_MATH_COMPARE:
|
||||
return ((a == b) || (fabsf(a - b) <= fmaxf(c, FLT_EPSILON))) ? 1.0f : 0.0f;
|
||||
case NODE_MATH_MULTIPLY_ADD:
|
||||
return a * b + c;
|
||||
case NODE_MATH_SMOOTH_MIN:
|
||||
return smoothminf(a, b, c);
|
||||
case NODE_MATH_SMOOTH_MAX:
|
||||
return -smoothminf(-a, -b, c);
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float3 svm_math_blackbody_color_rec709(const float t)
|
||||
{
|
||||
/* Calculate color in range 800..12000 using an approximation
|
||||
* a/x+bx+c for R and G and ((at + b)t + c)t + d) for B.
|
||||
*
|
||||
* The result of this can be negative to support gamut wider than
|
||||
* than rec.709, just needs to be clamped. */
|
||||
|
||||
if (t >= 12000.0f) {
|
||||
return make_float3(0.8262954810464208f, 0.9945080501520986f, 1.566307710274283f);
|
||||
}
|
||||
if (t < 800.0f) {
|
||||
/* Arbitrary lower limit where light is very dim, matching OSL. */
|
||||
return make_float3(5.413294490189271f, -0.20319390035873933f, -0.0822535242887164f);
|
||||
}
|
||||
|
||||
const int i = (t >= 6365.0f) ? 6 :
|
||||
(t >= 3315.0f) ? 5 :
|
||||
(t >= 1902.0f) ? 4 :
|
||||
(t >= 1449.0f) ? 3 :
|
||||
(t >= 1167.0f) ? 2 :
|
||||
(t >= 965.0f) ? 1 :
|
||||
0;
|
||||
|
||||
ccl_constant float *r = blackbody_table_r[i];
|
||||
ccl_constant float *g = blackbody_table_g[i];
|
||||
ccl_constant float *b = blackbody_table_b[i];
|
||||
|
||||
const float t_inv = 1.0f / t;
|
||||
return make_float3(r[0] * t_inv + r[1] * t + r[2],
|
||||
g[0] * t_inv + g[1] * t + g[2],
|
||||
((b[0] * t + b[1]) * t + b[2]) * t + b[3]);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 svm_math_gamma_color(float3 color, const float gamma)
|
||||
{
|
||||
if (gamma == 0.0f) {
|
||||
return make_float3(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (color.x > 0.0f) {
|
||||
color.x = powf(color.x, gamma);
|
||||
}
|
||||
if (color.y > 0.0f) {
|
||||
color.y = powf(color.y, gamma);
|
||||
}
|
||||
if (color.z > 0.0f) {
|
||||
color.z = powf(color.z, gamma);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
ccl_device float3 svm_math_wavelength_color_xyz(const float lambda_nm)
|
||||
{
|
||||
float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); // scaled 0..80
|
||||
const int i = float_to_int(ii);
|
||||
float3 color;
|
||||
|
||||
if (i < 0 || i >= 80) {
|
||||
color = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
else {
|
||||
ii -= i;
|
||||
ccl_constant float *c = cie_color_match[i];
|
||||
color = interp(make_float3(c[0], c[1], c[2]), make_float3(c[3], c[4], c[5]), ii);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
83
blender-5.2.0/intern/cycles/kernel/svm/mix.h
Normal file
83
blender-5.2.0/intern/cycles/kernel/svm/mix.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/color_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Node */
|
||||
|
||||
ccl_device_noinline void svm_node_mix(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMix &ccl_restrict node)
|
||||
{
|
||||
const float fac = stack_load(stack, node.fac);
|
||||
const float3 c1 = stack_load(stack, node.c1);
|
||||
const float3 c2 = stack_load(stack, node.c2);
|
||||
const float3 result = svm_mix_clamped_factor(node.mix_type, fac, c1, c2);
|
||||
|
||||
stack_store_float3(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_mix_color(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMixColor &ccl_restrict node)
|
||||
{
|
||||
float t = stack_load(stack, node.fac);
|
||||
if (node.use_clamp > 0) {
|
||||
t = saturatef(t);
|
||||
}
|
||||
const float3 a = stack_load(stack, node.a);
|
||||
const float3 b = stack_load(stack, node.b);
|
||||
float3 result = svm_mix(node.blend_type, t, a, b);
|
||||
if (node.use_clamp_result) {
|
||||
result = saturate(result);
|
||||
}
|
||||
stack_store_float3(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_mix_float(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMixFloat &ccl_restrict node)
|
||||
{
|
||||
float t = stack_load(stack, node.fac);
|
||||
if (node.use_clamp > 0) {
|
||||
t = saturatef(t);
|
||||
}
|
||||
const float a = stack_load(stack, node.a);
|
||||
const float b = stack_load(stack, node.b);
|
||||
const float result = a * (1 - t) + b * t;
|
||||
|
||||
stack_store_float(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_mix_vector(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMixVector &ccl_restrict node)
|
||||
{
|
||||
float t = stack_load(stack, node.fac);
|
||||
if (node.use_clamp > 0) {
|
||||
t = saturatef(t);
|
||||
}
|
||||
const float3 a = stack_load(stack, node.a);
|
||||
const float3 b = stack_load(stack, node.b);
|
||||
const float3 result = a * (one_float3() - t) + b * t;
|
||||
stack_store_float3(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_mix_vector_non_uniform(
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeMixVectorNonUniform &ccl_restrict node)
|
||||
{
|
||||
float3 t = stack_load(stack, node.fac);
|
||||
if (node.use_clamp > 0) {
|
||||
t = saturate(t);
|
||||
}
|
||||
const float3 a = stack_load(stack, node.a);
|
||||
const float3 b = stack_load(stack, node.b);
|
||||
const float3 result = a * (one_float3() - t) + b * t;
|
||||
stack_store_float3(stack, node.result_offset, result);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
1309
blender-5.2.0/intern/cycles/kernel/svm/node_types.h
Normal file
1309
blender-5.2.0/intern/cycles/kernel/svm/node_types.h
Normal file
File diff suppressed because it is too large
Load Diff
114
blender-5.2.0/intern/cycles/kernel/svm/node_types_template.h
Normal file
114
blender-5.2.0/intern/cycles/kernel/svm/node_types_template.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifndef SHADER_NODE_TYPE
|
||||
# define SHADER_NODE_TYPE(name)
|
||||
#endif
|
||||
#ifndef SHADER_NODE_TYPE_DERIVATIVE
|
||||
# define SHADER_NODE_TYPE_DERIVATIVE(name) SHADER_NODE_TYPE(name)
|
||||
#endif
|
||||
|
||||
/* NOTE: For good performance with jump tables on some GPU backends, the enum must
|
||||
* match the switch order in `svm.h`. It is also assumed the derivative variation
|
||||
* directly follows the regular node type. */
|
||||
|
||||
SHADER_NODE_TYPE(NODE_END)
|
||||
SHADER_NODE_TYPE(NODE_SHADER_JUMP)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_BSDF)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_EMISSION)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_BACKGROUND)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_SET_WEIGHT)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_WEIGHT)
|
||||
SHADER_NODE_TYPE(NODE_EMISSION_WEIGHT)
|
||||
SHADER_NODE_TYPE(NODE_MIX_CLOSURE)
|
||||
SHADER_NODE_TYPE(NODE_JUMP_IF_ZERO)
|
||||
SHADER_NODE_TYPE(NODE_JUMP_IF_ONE)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_GEOMETRY)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_CONVERT)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_TEX_COORD)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_VALUE_F)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_VALUE_V)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_ATTR)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_VERTEX_COLOR)
|
||||
SHADER_NODE_TYPE(NODE_SET_DISPLACEMENT)
|
||||
SHADER_NODE_TYPE(NODE_DISPLACEMENT)
|
||||
SHADER_NODE_TYPE(NODE_VECTOR_DISPLACEMENT)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_TEX_IMAGE)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_TEX_IMAGE_BOX)
|
||||
SHADER_NODE_TYPE(NODE_TEX_NOISE)
|
||||
SHADER_NODE_TYPE(NODE_SET_BUMP)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_SET_NORMAL)
|
||||
SHADER_NODE_TYPE(NODE_ENTER_BUMP_EVAL)
|
||||
SHADER_NODE_TYPE(NODE_LEAVE_BUMP_EVAL)
|
||||
SHADER_NODE_TYPE(NODE_HSV)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_HOLDOUT)
|
||||
SHADER_NODE_TYPE(NODE_FRESNEL)
|
||||
SHADER_NODE_TYPE(NODE_LAYER_WEIGHT)
|
||||
SHADER_NODE_TYPE(NODE_CLOSURE_VOLUME)
|
||||
SHADER_NODE_TYPE(NODE_VOLUME_COEFFICIENTS)
|
||||
SHADER_NODE_TYPE(NODE_PRINCIPLED_VOLUME)
|
||||
SHADER_NODE_TYPE(NODE_MATH)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_VECTOR_MATH)
|
||||
SHADER_NODE_TYPE(NODE_RGB_RAMP)
|
||||
SHADER_NODE_TYPE(NODE_GAMMA)
|
||||
SHADER_NODE_TYPE(NODE_BRIGHTCONTRAST)
|
||||
SHADER_NODE_TYPE(NODE_LIGHT_PATH)
|
||||
SHADER_NODE_TYPE(NODE_OBJECT_INFO)
|
||||
SHADER_NODE_TYPE(NODE_PARTICLE_INFO)
|
||||
SHADER_NODE_TYPE(NODE_HAIR_INFO)
|
||||
SHADER_NODE_TYPE(NODE_POINT_INFO)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_TEXTURE_MAPPING)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_MAPPING)
|
||||
SHADER_NODE_TYPE(NODE_MIN_MAX)
|
||||
SHADER_NODE_TYPE(NODE_CAMERA)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_TEX_ENVIRONMENT)
|
||||
SHADER_NODE_TYPE(NODE_TEX_SKY)
|
||||
SHADER_NODE_TYPE(NODE_TEX_GRADIENT)
|
||||
SHADER_NODE_TYPE(NODE_TEX_VORONOI)
|
||||
SHADER_NODE_TYPE(NODE_TEX_GABOR)
|
||||
SHADER_NODE_TYPE(NODE_TEX_WAVE)
|
||||
SHADER_NODE_TYPE(NODE_TEX_MAGIC)
|
||||
SHADER_NODE_TYPE(NODE_TEX_CHECKER)
|
||||
SHADER_NODE_TYPE(NODE_TEX_BRICK)
|
||||
SHADER_NODE_TYPE(NODE_TEX_WHITE_NOISE)
|
||||
SHADER_NODE_TYPE(NODE_NORMAL)
|
||||
SHADER_NODE_TYPE(NODE_LIGHT_FALLOFF)
|
||||
SHADER_NODE_TYPE(NODE_IES)
|
||||
SHADER_NODE_TYPE(NODE_CURVES)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_TANGENT)
|
||||
SHADER_NODE_TYPE(NODE_NORMAL_MAP)
|
||||
SHADER_NODE_TYPE(NODE_RADIAL_TILING)
|
||||
SHADER_NODE_TYPE(NODE_INVERT)
|
||||
SHADER_NODE_TYPE(NODE_MIX)
|
||||
SHADER_NODE_TYPE(NODE_SEPARATE_COLOR)
|
||||
SHADER_NODE_TYPE(NODE_COMBINE_COLOR)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_SEPARATE_VECTOR)
|
||||
SHADER_NODE_TYPE_DERIVATIVE(NODE_COMBINE_VECTOR)
|
||||
SHADER_NODE_TYPE(NODE_VECTOR_ROTATE)
|
||||
SHADER_NODE_TYPE(NODE_VECTOR_TRANSFORM)
|
||||
SHADER_NODE_TYPE(NODE_WIREFRAME)
|
||||
SHADER_NODE_TYPE(NODE_WAVELENGTH)
|
||||
SHADER_NODE_TYPE(NODE_BLACKBODY)
|
||||
SHADER_NODE_TYPE(NODE_MAP_RANGE)
|
||||
SHADER_NODE_TYPE(NODE_VECTOR_MAP_RANGE)
|
||||
SHADER_NODE_TYPE(NODE_CLAMP)
|
||||
SHADER_NODE_TYPE(NODE_BEVEL)
|
||||
SHADER_NODE_TYPE(NODE_AMBIENT_OCCLUSION)
|
||||
SHADER_NODE_TYPE(NODE_RAYCAST)
|
||||
SHADER_NODE_TYPE(NODE_AOV_START)
|
||||
SHADER_NODE_TYPE(NODE_AOV_COLOR)
|
||||
SHADER_NODE_TYPE(NODE_AOV_VALUE)
|
||||
SHADER_NODE_TYPE(NODE_FLOAT_CURVE)
|
||||
SHADER_NODE_TYPE(NODE_MIX_COLOR)
|
||||
SHADER_NODE_TYPE(NODE_MIX_FLOAT)
|
||||
SHADER_NODE_TYPE(NODE_MIX_VECTOR)
|
||||
SHADER_NODE_TYPE(NODE_MIX_VECTOR_NON_UNIFORM)
|
||||
SHADER_NODE_TYPE(NODE_SCENE_TIME)
|
||||
SHADER_NODE_TYPE(NODE_NONE)
|
||||
|
||||
/* Padding for struct alignment. */
|
||||
SHADER_NODE_TYPE(NODE_PAD1)
|
||||
|
||||
#undef SHADER_NODE_TYPE
|
||||
#undef SHADER_NODE_TYPE_DERIVATIVE
|
||||
761
blender-5.2.0/intern/cycles/kernel/svm/noise.h
Normal file
761
blender-5.2.0/intern/cycles/kernel/svm/noise.h
Normal file
@@ -0,0 +1,761 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Adapted code from Open Shading Language. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/hash.h"
|
||||
#include "util/math.h"
|
||||
#include "util/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* **** Perlin Noise **** */
|
||||
|
||||
ccl_device float fade(const float t)
|
||||
{
|
||||
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||
}
|
||||
|
||||
ccl_device_inline float negate_if(const float val, const int condition)
|
||||
{
|
||||
return (condition) ? -val : val;
|
||||
}
|
||||
|
||||
ccl_device float grad1(const int hash, const float x)
|
||||
{
|
||||
const int h = hash & 15;
|
||||
const float g = 1 + (h & 7);
|
||||
return negate_if(g, h & 8) * x;
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float perlin_1d(const float x)
|
||||
{
|
||||
int X;
|
||||
const float fx = floorfrac(x, &X);
|
||||
const float u = fade(fx);
|
||||
|
||||
return mix(grad1(hash_uint(X), fx), grad1(hash_uint(X + 1), fx - 1.0f), u);
|
||||
}
|
||||
|
||||
/* 2D, 3D, and 4D noise can be accelerated using SSE, so we first check if
|
||||
* SSE is supported, that is, if __KERNEL_SSE__ is defined. If it is not
|
||||
* supported, we do a standard implementation, but if it is supported, we
|
||||
* do an implementation using SSE intrinsics.
|
||||
*/
|
||||
#if !defined(__KERNEL_SSE__)
|
||||
|
||||
/* ** Standard Implementation ** */
|
||||
|
||||
/* Bilinear Interpolation:
|
||||
*
|
||||
* v2 v3
|
||||
* @ + + + + @ y
|
||||
* + + ^
|
||||
* + + |
|
||||
* + + |
|
||||
* @ + + + + @ @------> x
|
||||
* v0 v1
|
||||
*
|
||||
*/
|
||||
ccl_device float bi_mix(
|
||||
const float v0, const float v1, const float v2, const float v3, const float x, float y)
|
||||
{
|
||||
float x1 = 1.0f - x;
|
||||
return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
|
||||
}
|
||||
|
||||
/* Trilinear Interpolation:
|
||||
*
|
||||
* v6 v7
|
||||
* @ + + + + + + @
|
||||
* +\ +\
|
||||
* + \ + \
|
||||
* + \ + \
|
||||
* + \ v4 + \ v5
|
||||
* + @ + + + +++ + @ z
|
||||
* + + + + y ^
|
||||
* v2 @ + +++ + + + @ v3 + \ |
|
||||
* \ + \ + \ |
|
||||
* \ + \ + \|
|
||||
* \ + \ + +---------> x
|
||||
* \+ \+
|
||||
* @ + + + + + + @
|
||||
* v0 v1
|
||||
*/
|
||||
ccl_device float tri_mix(const float v0,
|
||||
float v1,
|
||||
float v2,
|
||||
float v3,
|
||||
float v4,
|
||||
float v5,
|
||||
float v6,
|
||||
float v7,
|
||||
const float x,
|
||||
const float y,
|
||||
const float z)
|
||||
{
|
||||
float x1 = 1.0f - x;
|
||||
float y1 = 1.0f - y;
|
||||
float z1 = 1.0f - z;
|
||||
return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
|
||||
z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
|
||||
}
|
||||
|
||||
ccl_device float quad_mix(const float v0,
|
||||
float v1,
|
||||
float v2,
|
||||
float v3,
|
||||
float v4,
|
||||
float v5,
|
||||
float v6,
|
||||
float v7,
|
||||
float v8,
|
||||
float v9,
|
||||
float v10,
|
||||
float v11,
|
||||
float v12,
|
||||
float v13,
|
||||
float v14,
|
||||
float v15,
|
||||
const float x,
|
||||
const float y,
|
||||
const float z,
|
||||
const float w)
|
||||
{
|
||||
return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
|
||||
tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
|
||||
w);
|
||||
}
|
||||
|
||||
ccl_device float grad2(const int hash, const float x, float y)
|
||||
{
|
||||
int h = hash & 7;
|
||||
float u = h < 4 ? x : y;
|
||||
float v = 2.0f * (h < 4 ? y : x);
|
||||
return negate_if(u, h & 1) + negate_if(v, h & 2);
|
||||
}
|
||||
|
||||
ccl_device float grad3(const int hash, const float x, float y, const float z)
|
||||
{
|
||||
int h = hash & 15;
|
||||
float u = h < 8 ? x : y;
|
||||
float vt = ((h == 12) || (h == 14)) ? x : z;
|
||||
float v = h < 4 ? y : vt;
|
||||
return negate_if(u, h & 1) + negate_if(v, h & 2);
|
||||
}
|
||||
|
||||
ccl_device float grad4(const int hash, const float x, float y, const float z, float w)
|
||||
{
|
||||
int h = hash & 31;
|
||||
float u = h < 24 ? x : y;
|
||||
float v = h < 16 ? y : z;
|
||||
float s = h < 8 ? z : w;
|
||||
return negate_if(u, h & 1) + negate_if(v, h & 2) + negate_if(s, h & 4);
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float perlin_2d(const float x, const float y)
|
||||
{
|
||||
int X;
|
||||
int Y;
|
||||
|
||||
float fx = floorfrac(x, &X);
|
||||
float fy = floorfrac(y, &Y);
|
||||
|
||||
float u = fade(fx);
|
||||
float v = fade(fy);
|
||||
|
||||
float r = bi_mix(grad2(hash_uint2(X, Y), fx, fy),
|
||||
grad2(hash_uint2(X + 1, Y), fx - 1.0f, fy),
|
||||
grad2(hash_uint2(X, Y + 1), fx, fy - 1.0f),
|
||||
grad2(hash_uint2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f),
|
||||
u,
|
||||
v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float perlin_3d(const float x, const float y, float z)
|
||||
{
|
||||
int X;
|
||||
int Y;
|
||||
int Z;
|
||||
|
||||
float fx = floorfrac(x, &X);
|
||||
float fy = floorfrac(y, &Y);
|
||||
float fz = floorfrac(z, &Z);
|
||||
|
||||
float u = fade(fx);
|
||||
float v = fade(fy);
|
||||
float w = fade(fz);
|
||||
|
||||
float r = tri_mix(grad3(hash_uint3(X, Y, Z), fx, fy, fz),
|
||||
grad3(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz),
|
||||
grad3(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz),
|
||||
grad3(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz),
|
||||
grad3(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f),
|
||||
grad3(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f),
|
||||
grad3(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f),
|
||||
grad3(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f),
|
||||
u,
|
||||
v,
|
||||
w);
|
||||
return r;
|
||||
}
|
||||
|
||||
ccl_device_noinline_cpu float perlin_4d(const float x, const float y, float z, const float w)
|
||||
{
|
||||
int X;
|
||||
int Y;
|
||||
int Z;
|
||||
int W;
|
||||
|
||||
float fx = floorfrac(x, &X);
|
||||
float fy = floorfrac(y, &Y);
|
||||
float fz = floorfrac(z, &Z);
|
||||
float fw = floorfrac(w, &W);
|
||||
|
||||
float u = fade(fx);
|
||||
float v = fade(fy);
|
||||
float t = fade(fz);
|
||||
float s = fade(fw);
|
||||
|
||||
float r = quad_mix(
|
||||
grad4(hash_uint4(X, Y, Z, W), fx, fy, fz, fw),
|
||||
grad4(hash_uint4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw),
|
||||
grad4(hash_uint4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw),
|
||||
grad4(hash_uint4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw),
|
||||
grad4(hash_uint4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw),
|
||||
grad4(hash_uint4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw),
|
||||
grad4(hash_uint4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw),
|
||||
grad4(hash_uint4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw),
|
||||
grad4(hash_uint4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f),
|
||||
grad4(hash_uint4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f),
|
||||
grad4(hash_uint4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f),
|
||||
grad4(hash_uint4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f),
|
||||
grad4(hash_uint4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f),
|
||||
grad4(hash_uint4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f),
|
||||
grad4(hash_uint4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f),
|
||||
grad4(hash_uint4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw - 1.0f),
|
||||
u,
|
||||
v,
|
||||
t,
|
||||
s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#else /* SSE is supported. */
|
||||
|
||||
/* ** SSE Implementation ** */
|
||||
|
||||
/* SSE Bilinear Interpolation:
|
||||
*
|
||||
* The function takes two float4 inputs:
|
||||
* - p : Contains the values at the points (v0, v1, v2, v3).
|
||||
* - f : Contains the values (x, y, _, _). The third and fourth values are unused.
|
||||
*
|
||||
* The interpolation is done in two steps:
|
||||
* 1. Interpolate (v0, v1) and (v2, v3) along the x axis to get g (g0, g1).
|
||||
* (v2, v3) is generated by moving v2 and v3 to the first and second
|
||||
* places of the float4 using the shuffle mask <2, 3, 2, 3>. The third and
|
||||
* fourth values are unused.
|
||||
* 2. Interpolate g0 and g1 along the y axis to get the final value.
|
||||
* g1 is generated by populating an float4 with the second value of g.
|
||||
* Only the first value is important in the final float4.
|
||||
*
|
||||
* v1 v3 g1
|
||||
* @ + + + + @ @ y
|
||||
* + + (1) + (2) ^
|
||||
* + + ---> + ---> final |
|
||||
* + + + |
|
||||
* @ + + + + @ @ @------> x
|
||||
* v0 v2 g0
|
||||
*
|
||||
*/
|
||||
ccl_device_inline float4 bi_mix(const float4 p, const float4 f)
|
||||
{
|
||||
const float4 g = mix(p, shuffle<2, 3, 2, 3>(p), shuffle<0>(f));
|
||||
return mix(g, shuffle<1>(g), shuffle<1>(f));
|
||||
}
|
||||
|
||||
ccl_device_inline float4 fade(const float4 t)
|
||||
{
|
||||
const float4 a = madd(t, make_float4(6.0f), make_float4(-15.0f));
|
||||
const float4 b = madd(t, a, make_float4(10.0f));
|
||||
return (t * t) * (t * b);
|
||||
}
|
||||
|
||||
/* Negate val if the nth bit of h is 1. */
|
||||
# define negate_if_nth_bit(val, h, n) ((val) ^ cast(((h) & (1 << (n))) << (31 - (n))))
|
||||
|
||||
ccl_device_inline float4 grad(const int4 hash, const float4 x, const float4 y)
|
||||
{
|
||||
const int4 h = hash & 7;
|
||||
const float4 u = select(h < 4, x, y);
|
||||
const float4 v = 2.0f * select(h < 4, y, x);
|
||||
return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
|
||||
}
|
||||
|
||||
/* We use SSE to compute and interpolate 4 gradients at once:
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v0 (0, 0)
|
||||
* v1 (0, 1)
|
||||
* v2 (1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(V, V + 1))
|
||||
* v3 (1, 1) ^
|
||||
* | |__________| (0, 0, 1, 1) = shuffle<0, 0, 0, 0>(V, V + 1)
|
||||
* | ^
|
||||
* |__________________________|
|
||||
*
|
||||
*/
|
||||
ccl_device_noinline_cpu float perlin_2d(const float x, const float y)
|
||||
{
|
||||
int4 XY;
|
||||
const float4 fxy = floorfrac(make_float4(x, y, 0.0f, 0.0f), &XY);
|
||||
const float4 uv = fade(fxy);
|
||||
|
||||
const int4 XY1 = XY + make_int4(1);
|
||||
const int4 X = shuffle<0, 0, 0, 0>(XY, XY1);
|
||||
const int4 Y = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(XY, XY1));
|
||||
|
||||
const int4 h = hash_int4_2(X, Y);
|
||||
|
||||
const float4 fxy1 = fxy - make_float4(1.0f);
|
||||
const float4 fx = shuffle<0, 0, 0, 0>(fxy, fxy1);
|
||||
const float4 fy = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(fxy, fxy1));
|
||||
|
||||
const float4 g = grad(h, fx, fy);
|
||||
|
||||
return extract<0>(bi_mix(g, uv));
|
||||
}
|
||||
|
||||
/* SSE Trilinear Interpolation:
|
||||
*
|
||||
* The function takes three float4 inputs:
|
||||
* - p : Contains the values at the points (v0, v1, v2, v3).
|
||||
* - q : Contains the values at the points (v4, v5, v6, v7).
|
||||
* - f : Contains the values (x, y, z, _). The fourth value is unused.
|
||||
*
|
||||
* The interpolation is done in three steps:
|
||||
* 1. Interpolate p and q along the x axis to get s (s0, s1, s2, s3).
|
||||
* 2. Interpolate (s0, s1) and (s2, s3) along the y axis to get g (g0, g1).
|
||||
* (s2, s3) is generated by moving v2 and v3 to the first and second
|
||||
* places of the float4 using the shuffle mask <2, 3, 2, 3>. The third and
|
||||
* fourth values are unused.
|
||||
* 3. Interpolate g0 and g1 along the z axis to get the final value.
|
||||
* g1 is generated by populating an float4 with the second value of g.
|
||||
* Only the first value is important in the final float4.
|
||||
*
|
||||
* v3 v7
|
||||
* @ + + + + + + @ s3 @
|
||||
* +\ +\ +\
|
||||
* + \ + \ + \
|
||||
* + \ + \ + \ g1
|
||||
* + \ v1 + \ v5 + \ s1 @
|
||||
* + @ + + + +++ + @ + @ + z
|
||||
* + + + + (1) + + (2) + (3) y ^
|
||||
* v2 @ + +++ + + + @ v6 + ---> s2 @ + ---> + ---> final \ |
|
||||
* \ + \ + \ + + \ |
|
||||
* \ + \ + \ + + \|
|
||||
* \ + \ + \ + @ +---------> x
|
||||
* \+ \+ \+ g0
|
||||
* @ + + + + + + @ @
|
||||
* v0 v4 s0
|
||||
*/
|
||||
ccl_device_inline float4 tri_mix(const float4 p, const float4 q, float4 f)
|
||||
{
|
||||
const float4 s = mix(p, q, shuffle<0>(f));
|
||||
const float4 g = mix(s, shuffle<2, 3, 2, 3>(s), shuffle<1>(f));
|
||||
return mix(g, shuffle<1>(g), shuffle<2>(f));
|
||||
}
|
||||
|
||||
/* 3D and 4D noise can be accelerated using AVX, so we first check if AVX
|
||||
* is supported, that is, if __KERNEL_AVX__ is defined. If it is not
|
||||
* supported, we do an SSE implementation, but if it is supported,
|
||||
* we do an implementation using AVX intrinsics.
|
||||
*/
|
||||
# if !defined(__KERNEL_AVX2__)
|
||||
|
||||
ccl_device_inline float4 grad(const int4 hash, const float4 x, const float4 y, const float4 z)
|
||||
{
|
||||
const int4 h = hash & 15;
|
||||
const float4 u = select(h < 8, x, y);
|
||||
const float4 vt = select((h == 12) | (h == 14), x, z);
|
||||
const float4 v = select(h < 4, y, vt);
|
||||
return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
|
||||
}
|
||||
|
||||
ccl_device_inline float4
|
||||
grad(const int4 hash, const float4 x, const float4 y, const float4 z, const float4 w)
|
||||
{
|
||||
const int4 h = hash & 31;
|
||||
const float4 u = select(h < 24, x, y);
|
||||
const float4 v = select(h < 16, y, z);
|
||||
const float4 s = select(h < 8, z, w);
|
||||
return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
|
||||
}
|
||||
|
||||
/* SSE Quadrilinear Interpolation:
|
||||
*
|
||||
* Quadrilinear interpolation is as simple as a linear interpolation
|
||||
* between two trilinear interpolations.
|
||||
*
|
||||
*/
|
||||
ccl_device_inline float4
|
||||
quad_mix(const float4 p, const float4 q, float4 r, const float4 s, float4 f)
|
||||
{
|
||||
return mix(tri_mix(p, q, f), tri_mix(r, s, f), shuffle<3>(f));
|
||||
}
|
||||
|
||||
/* We use SSE to compute and interpolate 4 gradients at once. Since we have 8
|
||||
* gradients in 3D, we need to compute two sets of gradients at the points:
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v0 (0, 0, 0)
|
||||
* v1 (0, 0, 1)
|
||||
* v2 (0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
|
||||
* v3 (0, 1, 1) ^
|
||||
* | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
|
||||
* | ^
|
||||
* |__________________________|
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v4 (1, 0, 0)
|
||||
* v5 (1, 0, 1)
|
||||
* v6 (1, 1, 0)
|
||||
* v7 (1, 1, 1)
|
||||
*
|
||||
*/
|
||||
ccl_device_noinline_cpu float perlin_3d(const float x, const float y, float z)
|
||||
{
|
||||
int4 XYZ;
|
||||
const float4 fxyz = floorfrac(make_float4(x, y, z, 0.0f), &XYZ);
|
||||
const float4 uvw = fade(fxyz);
|
||||
|
||||
const int4 XYZ1 = XYZ + make_int4(1);
|
||||
const int4 Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
|
||||
const int4 Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
|
||||
|
||||
const int4 h1 = hash_int4_3(shuffle<0>(XYZ), Y, Z);
|
||||
const int4 h2 = hash_int4_3(shuffle<0>(XYZ1), Y, Z);
|
||||
|
||||
const float4 fxyz1 = fxyz - make_float4(1.0f);
|
||||
const float4 fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
|
||||
const float4 fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
|
||||
|
||||
const float4 g1 = grad(h1, shuffle<0>(fxyz), fy, fz);
|
||||
const float4 g2 = grad(h2, shuffle<0>(fxyz1), fy, fz);
|
||||
|
||||
return extract<0>(tri_mix(g1, g2, uvw));
|
||||
}
|
||||
|
||||
/* We use SSE to compute and interpolate 4 gradients at once. Since we have 16
|
||||
* gradients in 4D, we need to compute four sets of gradients at the points:
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v0 (0, 0, 0, 0)
|
||||
* v1 (0, 0, 1, 0)
|
||||
* v2 (0, 1, 0, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
|
||||
* v3 (0, 1, 1, 0) ^
|
||||
* | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
|
||||
* | ^
|
||||
* |_______________________|
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v4 (1, 0, 0, 0)
|
||||
* v5 (1, 0, 1, 0)
|
||||
* v6 (1, 1, 0, 0)
|
||||
* v7 (1, 1, 1, 0)
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v8 (0, 0, 0, 1)
|
||||
* v9 (0, 0, 1, 1)
|
||||
* v10 (0, 1, 0, 1)
|
||||
* v11 (0, 1, 1, 1)
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v12 (1, 0, 0, 1)
|
||||
* v13 (1, 0, 1, 1)
|
||||
* v14 (1, 1, 0, 1)
|
||||
* v15 (1, 1, 1, 1)
|
||||
*
|
||||
*/
|
||||
ccl_device_noinline_cpu float perlin_4d(const float x, const float y, float z, const float w)
|
||||
{
|
||||
int4 XYZW;
|
||||
const float4 fxyzw = floorfrac(make_float4(x, y, z, w), &XYZW);
|
||||
const float4 uvws = fade(fxyzw);
|
||||
|
||||
const int4 XYZW1 = XYZW + make_int4(1);
|
||||
const int4 Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
|
||||
const int4 Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
|
||||
|
||||
const int4 h1 = hash_int4_4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW));
|
||||
const int4 h2 = hash_int4_4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW));
|
||||
|
||||
const int4 h3 = hash_int4_4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW1));
|
||||
const int4 h4 = hash_int4_4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW1));
|
||||
|
||||
const float4 fxyzw1 = fxyzw - make_float4(1.0f);
|
||||
const float4 fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
|
||||
const float4 fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
|
||||
|
||||
const float4 g1 = grad(h1, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw));
|
||||
const float4 g2 = grad(h2, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw));
|
||||
|
||||
const float4 g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1));
|
||||
const float4 g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1));
|
||||
|
||||
return extract<0>(quad_mix(g1, g2, g3, g4, uvws));
|
||||
}
|
||||
|
||||
# else /* AVX is supported. */
|
||||
|
||||
/* AVX Implementation */
|
||||
|
||||
ccl_device_inline vfloat8 grad(const vint8 hash, const vfloat8 x, const vfloat8 y, const vfloat8 z)
|
||||
{
|
||||
vint8 h = hash & 15;
|
||||
vfloat8 u = select(h < 8, x, y);
|
||||
vfloat8 vt = select((h == 12) | (h == 14), x, z);
|
||||
vfloat8 v = select(h < 4, y, vt);
|
||||
return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1);
|
||||
}
|
||||
|
||||
ccl_device_inline vfloat8
|
||||
grad(const vint8 hash, const vfloat8 x, const vfloat8 y, const vfloat8 z, const vfloat8 w)
|
||||
{
|
||||
vint8 h = hash & 31;
|
||||
vfloat8 u = select(h < 24, x, y);
|
||||
vfloat8 v = select(h < 16, y, z);
|
||||
vfloat8 s = select(h < 8, z, w);
|
||||
return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2);
|
||||
}
|
||||
|
||||
/* SSE Quadrilinear Interpolation:
|
||||
*
|
||||
* The interpolation is done in two steps:
|
||||
* 1. Interpolate p and q along the w axis to get s.
|
||||
* 2. Trilinearly interpolate (s0, s1, s2, s3) and (s4, s5, s6, s7) to get the final
|
||||
* value. (s0, s1, s2, s3) and (s4, s5, s6, s7) are generated by extracting the
|
||||
* low and high float4 from s.
|
||||
*
|
||||
*/
|
||||
ccl_device_inline float4 quad_mix(vfloat8 p, vfloat8 q, const float4 f)
|
||||
{
|
||||
float4 fv = shuffle<3>(f);
|
||||
vfloat8 s = mix(p, q, make_vfloat8(fv, fv));
|
||||
return tri_mix(low(s), high(s), f);
|
||||
}
|
||||
|
||||
/* We use AVX to compute and interpolate 8 gradients at once.
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v0 (0, 0, 0)
|
||||
* v1 (0, 0, 1) The full AVX type is computed by inserting the following
|
||||
* v2 (0, 1, 0) SSE types into both the low and high parts of the AVX.
|
||||
* v3 (0, 1, 1)
|
||||
* v4 (1, 0, 0)
|
||||
* v5 (1, 0, 1) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
|
||||
* v6 (1, 1, 0) ^
|
||||
* v7 (1, 1, 1) |
|
||||
* | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
|
||||
* | ^
|
||||
* |__________________________|
|
||||
*
|
||||
*/
|
||||
ccl_device_noinline_cpu float perlin_3d(const float x, const float y, float z)
|
||||
{
|
||||
int4 XYZ;
|
||||
float4 fxyz = floorfrac(make_float4(x, y, z, 0.0f), &XYZ);
|
||||
float4 uvw = fade(fxyz);
|
||||
|
||||
int4 XYZ1 = XYZ + make_int4(1);
|
||||
int4 X = shuffle<0>(XYZ);
|
||||
int4 X1 = shuffle<0>(XYZ1);
|
||||
int4 Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1);
|
||||
int4 Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1));
|
||||
|
||||
vint8 h = hash_int8_3(make_vint8(X, X1), make_vint8(Y, Y), make_vint8(Z, Z));
|
||||
|
||||
float4 fxyz1 = fxyz - make_float4(1.0f);
|
||||
float4 fx = shuffle<0>(fxyz);
|
||||
float4 fx1 = shuffle<0>(fxyz1);
|
||||
float4 fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1);
|
||||
float4 fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1));
|
||||
|
||||
vfloat8 g = grad(h, make_vfloat8(fx, fx1), make_vfloat8(fy, fy), make_vfloat8(fz, fz));
|
||||
|
||||
return extract<0>(tri_mix(low(g), high(g), uvw));
|
||||
}
|
||||
|
||||
/* We use AVX to compute and interpolate 8 gradients at once. Since we have 16
|
||||
* gradients in 4D, we need to compute two sets of gradients at the points:
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v0 (0, 0, 0, 0)
|
||||
* v1 (0, 0, 1, 0) The full AVX type is computed by inserting the following
|
||||
* v2 (0, 1, 0, 0) SSE types into both the low and high parts of the AVX.
|
||||
* v3 (0, 1, 1, 0)
|
||||
* v4 (1, 0, 0, 0)
|
||||
* v5 (1, 0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1))
|
||||
* v6 (1, 1, 0, 0) ^
|
||||
* v7 (1, 1, 1, 0) |
|
||||
* | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1)
|
||||
* | ^
|
||||
* |_______________________|
|
||||
*
|
||||
* Point Offset from v0
|
||||
* v8 (0, 0, 0, 1)
|
||||
* v9 (0, 0, 1, 1)
|
||||
* v10 (0, 1, 0, 1)
|
||||
* v11 (0, 1, 1, 1)
|
||||
* v12 (1, 0, 0, 1)
|
||||
* v13 (1, 0, 1, 1)
|
||||
* v14 (1, 1, 0, 1)
|
||||
* v15 (1, 1, 1, 1)
|
||||
*
|
||||
*/
|
||||
ccl_device_noinline_cpu float perlin_4d(const float x, const float y, float z, const float w)
|
||||
{
|
||||
int4 XYZW;
|
||||
float4 fxyzw = floorfrac(make_float4(x, y, z, w), &XYZW);
|
||||
float4 uvws = fade(fxyzw);
|
||||
|
||||
int4 XYZW1 = XYZW + make_int4(1);
|
||||
int4 X = shuffle<0>(XYZW);
|
||||
int4 X1 = shuffle<0>(XYZW1);
|
||||
int4 Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1);
|
||||
int4 Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1));
|
||||
int4 W = shuffle<3>(XYZW);
|
||||
int4 W1 = shuffle<3>(XYZW1);
|
||||
|
||||
vint8 h1 = hash_int8_4(make_vint8(X, X1), make_vint8(Y, Y), make_vint8(Z, Z), make_vint8(W, W));
|
||||
vint8 h2 = hash_int8_4(
|
||||
make_vint8(X, X1), make_vint8(Y, Y), make_vint8(Z, Z), make_vint8(W1, W1));
|
||||
|
||||
float4 fxyzw1 = fxyzw - make_float4(1.0f);
|
||||
float4 fx = shuffle<0>(fxyzw);
|
||||
float4 fx1 = shuffle<0>(fxyzw1);
|
||||
float4 fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1);
|
||||
float4 fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1));
|
||||
float4 fw = shuffle<3>(fxyzw);
|
||||
float4 fw1 = shuffle<3>(fxyzw1);
|
||||
|
||||
vfloat8 g1 = grad(
|
||||
h1, make_vfloat8(fx, fx1), make_vfloat8(fy, fy), make_vfloat8(fz, fz), make_vfloat8(fw, fw));
|
||||
vfloat8 g2 = grad(h2,
|
||||
make_vfloat8(fx, fx1),
|
||||
make_vfloat8(fy, fy),
|
||||
make_vfloat8(fz, fz),
|
||||
make_vfloat8(fw1, fw1));
|
||||
|
||||
return extract<0>(quad_mix(g1, g2, uvws));
|
||||
}
|
||||
# endif
|
||||
|
||||
# undef negate_if_nth_bit
|
||||
|
||||
#endif
|
||||
|
||||
/* Remap the output of noise to a predictable range [-1, 1].
|
||||
* The scale values were computed experimentally by the OSL developers.
|
||||
*/
|
||||
|
||||
ccl_device_inline float noise_scale1(const float result)
|
||||
{
|
||||
return 0.2500f * result;
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_scale2(const float result)
|
||||
{
|
||||
return 0.6616f * result;
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_scale3(const float result)
|
||||
{
|
||||
return 0.9820f * result;
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_scale4(const float result)
|
||||
{
|
||||
return 0.8344f * result;
|
||||
}
|
||||
|
||||
/* Safe Signed And Unsigned Noise */
|
||||
|
||||
ccl_device_inline float snoise_1d(float p)
|
||||
{
|
||||
const float precision_correction = 0.5f * float(fabsf(p) >= 1000000.0f);
|
||||
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
|
||||
* representation issues. */
|
||||
/* The 1D variant of fmod is called fmodf. */
|
||||
p = fmodf(p, 100000.0f) + precision_correction;
|
||||
|
||||
return noise_scale1(perlin_1d(p));
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_1d(const float p)
|
||||
{
|
||||
return 0.5f * snoise_1d(p) + 0.5f;
|
||||
}
|
||||
|
||||
ccl_device_inline float snoise_2d(float2 p)
|
||||
{
|
||||
const float2 precision_correction = 0.5f *
|
||||
mask(fabs(p) >= make_float2(1000000.0f), one_float2());
|
||||
|
||||
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
|
||||
* representation issues. This causes discontinuities every 100000.0f, however at such scales
|
||||
* this usually shouldn't be noticeable. */
|
||||
p = fmod(p, 100000.0f) + precision_correction;
|
||||
|
||||
return noise_scale2(perlin_2d(p.x, p.y));
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_2d(const float2 p)
|
||||
{
|
||||
return 0.5f * snoise_2d(p) + 0.5f;
|
||||
}
|
||||
|
||||
ccl_device_inline float snoise_3d(float3 p)
|
||||
{
|
||||
const float3 precision_correction = 0.5f *
|
||||
mask(fabs(p) >= make_float3(1000000.0f), one_float3());
|
||||
|
||||
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
|
||||
* representation issues. This causes discontinuities every 100000.0f, however at such scales
|
||||
* this usually shouldn't be noticeable. */
|
||||
p = fmod(p, 100000.0f) + precision_correction;
|
||||
|
||||
return noise_scale3(perlin_3d(p.x, p.y, p.z));
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_3d(const float3 p)
|
||||
{
|
||||
return 0.5f * snoise_3d(p) + 0.5f;
|
||||
}
|
||||
|
||||
ccl_device_inline float snoise_4d(float4 p)
|
||||
{
|
||||
const float4 precision_correction = 0.5f *
|
||||
mask(fabs(p) >= make_float4(1000000.0f), one_float4());
|
||||
|
||||
/* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
|
||||
* representation issues. This causes discontinuities every 100000.0f, however at such scales
|
||||
* this usually shouldn't be noticeable. */
|
||||
p = fmod(p, 100000.0f) + precision_correction;
|
||||
|
||||
return noise_scale4(perlin_4d(p.x, p.y, p.z, p.w));
|
||||
}
|
||||
|
||||
ccl_device_inline float noise_4d(const float4 p)
|
||||
{
|
||||
return 0.5f * snoise_4d(p) + 0.5f;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
336
blender-5.2.0/intern/cycles/kernel/svm/noisetex.h
Normal file
336
blender-5.2.0/intern/cycles/kernel/svm/noisetex.h
Normal file
@@ -0,0 +1,336 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/fractal_noise.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* The following offset functions generate random offsets to be added to texture
|
||||
* coordinates to act as a seed since the noise functions don't have seed values.
|
||||
* A seed value is needed for generating distortion textures and color outputs.
|
||||
* The offset's components are in the range [100, 200], not too high to cause
|
||||
* bad precision and not too small to be noticeable. We use float seed because
|
||||
* OSL only support float hashes.
|
||||
*/
|
||||
|
||||
ccl_device_inline float random_float_offset(const float seed)
|
||||
{
|
||||
return 100.0f + hash_float_to_float(seed) * 100.0f;
|
||||
}
|
||||
|
||||
ccl_device_inline float2 random_float2_offset(const float seed)
|
||||
{
|
||||
return make_float2(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
|
||||
100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 random_float3_offset(const float seed)
|
||||
{
|
||||
return make_float3(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
|
||||
100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
|
||||
100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f);
|
||||
}
|
||||
|
||||
ccl_device_inline float4 random_float4_offset(const float seed)
|
||||
{
|
||||
return make_float4(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f,
|
||||
100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f,
|
||||
100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f,
|
||||
100.0f + hash_float2_to_float(make_float2(seed, 3.0f)) * 100.0f);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ccl_device float noise_select(T p,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain,
|
||||
const int type,
|
||||
bool normalize)
|
||||
{
|
||||
switch ((NodeNoiseType)type) {
|
||||
case NODE_NOISE_MULTIFRACTAL: {
|
||||
return noise_multi_fractal(p, detail, roughness, lacunarity);
|
||||
}
|
||||
case NODE_NOISE_FBM: {
|
||||
return noise_fbm(p, detail, roughness, lacunarity, normalize);
|
||||
}
|
||||
case NODE_NOISE_HYBRID_MULTIFRACTAL: {
|
||||
return noise_hybrid_multi_fractal(p, detail, roughness, lacunarity, offset, gain);
|
||||
}
|
||||
case NODE_NOISE_RIDGED_MULTIFRACTAL: {
|
||||
return noise_ridged_multi_fractal(p, detail, roughness, lacunarity, offset, gain);
|
||||
}
|
||||
case NODE_NOISE_HETERO_TERRAIN: {
|
||||
return noise_hetero_terrain(p, detail, roughness, lacunarity, offset);
|
||||
}
|
||||
default: {
|
||||
kernel_assert(0);
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device void noise_texture_1d(const float co,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain,
|
||||
const float distortion,
|
||||
const int type,
|
||||
bool normalize,
|
||||
bool color_is_needed,
|
||||
ccl_private float *value,
|
||||
ccl_private float3 *color)
|
||||
{
|
||||
float p = co;
|
||||
if (distortion != 0.0f) {
|
||||
p += snoise_1d(p + random_float_offset(0.0f)) * distortion;
|
||||
}
|
||||
|
||||
*value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, normalize);
|
||||
if (color_is_needed) {
|
||||
*color = make_float3(*value,
|
||||
noise_select(p + random_float_offset(1.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize),
|
||||
noise_select(p + random_float_offset(2.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize));
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device void noise_texture_2d(const float2 co,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain,
|
||||
const float distortion,
|
||||
const int type,
|
||||
const bool normalize,
|
||||
const bool color_is_needed,
|
||||
ccl_private float *value,
|
||||
ccl_private float3 *color)
|
||||
{
|
||||
float2 p = co;
|
||||
if (distortion != 0.0f) {
|
||||
p += make_float2(snoise_2d(p + random_float2_offset(0.0f)) * distortion,
|
||||
snoise_2d(p + random_float2_offset(1.0f)) * distortion);
|
||||
}
|
||||
|
||||
*value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, normalize);
|
||||
if (color_is_needed) {
|
||||
*color = make_float3(*value,
|
||||
noise_select(p + random_float2_offset(2.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize),
|
||||
noise_select(p + random_float2_offset(3.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize));
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device void noise_texture_3d(const float3 co,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain,
|
||||
const float distortion,
|
||||
const int type,
|
||||
const bool normalize,
|
||||
const bool color_is_needed,
|
||||
ccl_private float *value,
|
||||
ccl_private float3 *color)
|
||||
{
|
||||
float3 p = co;
|
||||
if (distortion != 0.0f) {
|
||||
p += make_float3(snoise_3d(p + random_float3_offset(0.0f)) * distortion,
|
||||
snoise_3d(p + random_float3_offset(1.0f)) * distortion,
|
||||
snoise_3d(p + random_float3_offset(2.0f)) * distortion);
|
||||
}
|
||||
|
||||
*value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, normalize);
|
||||
if (color_is_needed) {
|
||||
*color = make_float3(*value,
|
||||
noise_select(p + random_float3_offset(3.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize),
|
||||
noise_select(p + random_float3_offset(4.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize));
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device void noise_texture_4d(const float4 co,
|
||||
const float detail,
|
||||
const float roughness,
|
||||
const float lacunarity,
|
||||
const float offset,
|
||||
const float gain,
|
||||
const float distortion,
|
||||
const int type,
|
||||
const bool normalize,
|
||||
const bool color_is_needed,
|
||||
ccl_private float *value,
|
||||
ccl_private float3 *color)
|
||||
{
|
||||
float4 p = co;
|
||||
if (distortion != 0.0f) {
|
||||
p += make_float4(snoise_4d(p + random_float4_offset(0.0f)) * distortion,
|
||||
snoise_4d(p + random_float4_offset(1.0f)) * distortion,
|
||||
snoise_4d(p + random_float4_offset(2.0f)) * distortion,
|
||||
snoise_4d(p + random_float4_offset(3.0f)) * distortion);
|
||||
}
|
||||
|
||||
*value = noise_select(p, detail, roughness, lacunarity, offset, gain, type, normalize);
|
||||
if (color_is_needed) {
|
||||
*color = make_float3(*value,
|
||||
noise_select(p + random_float4_offset(4.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize),
|
||||
noise_select(p + random_float4_offset(5.0f),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
type,
|
||||
normalize));
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_noise(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexNoise &ccl_restrict node)
|
||||
{
|
||||
float3 vector = stack_load_float3(stack, node.vector);
|
||||
float w = stack_load(stack, node.w);
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
float detail = stack_load(stack, node.detail);
|
||||
float roughness = stack_load(stack, node.roughness);
|
||||
const float lacunarity = stack_load(stack, node.lacunarity);
|
||||
const float offset = stack_load(stack, node.offset);
|
||||
const float gain = stack_load(stack, node.gain);
|
||||
const float distortion = stack_load(stack, node.distortion);
|
||||
|
||||
detail = clamp(detail, 0.0f, 15.0f);
|
||||
roughness = fmaxf(roughness, 0.0f);
|
||||
|
||||
vector *= scale;
|
||||
w *= scale;
|
||||
|
||||
float value;
|
||||
float3 color;
|
||||
switch (node.dimensions) {
|
||||
case 1:
|
||||
noise_texture_1d(w,
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
distortion,
|
||||
node.noise_type,
|
||||
node.normalize,
|
||||
stack_valid(node.color_offset),
|
||||
&value,
|
||||
&color);
|
||||
break;
|
||||
case 2:
|
||||
noise_texture_2d(make_float2(vector.x, vector.y),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
distortion,
|
||||
node.noise_type,
|
||||
node.normalize,
|
||||
stack_valid(node.color_offset),
|
||||
&value,
|
||||
&color);
|
||||
break;
|
||||
case 3:
|
||||
noise_texture_3d(vector,
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
distortion,
|
||||
node.noise_type,
|
||||
node.normalize,
|
||||
stack_valid(node.color_offset),
|
||||
&value,
|
||||
&color);
|
||||
break;
|
||||
case 4:
|
||||
noise_texture_4d(make_float4(vector, w),
|
||||
detail,
|
||||
roughness,
|
||||
lacunarity,
|
||||
offset,
|
||||
gain,
|
||||
distortion,
|
||||
node.noise_type,
|
||||
node.normalize,
|
||||
stack_valid(node.color_offset),
|
||||
&value,
|
||||
&color);
|
||||
break;
|
||||
default:
|
||||
kernel_assert(0);
|
||||
}
|
||||
|
||||
if (stack_valid(node.value_offset)) {
|
||||
stack_store_float(stack, node.value_offset, value);
|
||||
}
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
29
blender-5.2.0/intern/cycles/kernel/svm/normal.h
Normal file
29
blender-5.2.0/intern/cycles/kernel/svm/normal.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_normal(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeNormal &ccl_restrict node)
|
||||
{
|
||||
const float3 normal = stack_load(stack, node.in_normal);
|
||||
|
||||
float3 direction = make_float3(node.direction_x, node.direction_y, node.direction_z);
|
||||
direction = normalize(direction);
|
||||
|
||||
if (stack_valid(node.out_normal_offset)) {
|
||||
stack_store_float3(stack, node.out_normal_offset, direction);
|
||||
}
|
||||
|
||||
if (stack_valid(node.out_dot_offset)) {
|
||||
stack_store_float(stack, node.out_dot_offset, dot(direction, normalize(normal)));
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
65
blender-5.2.0/intern/cycles/kernel/svm/radial_tiling.h
Normal file
65
blender-5.2.0/intern/cycles/kernel/svm/radial_tiling.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* SPDX-FileCopyrightText: 2024-2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Define macro flags for code adaption. */
|
||||
#define ADAPT_TO_SVM
|
||||
|
||||
/* The rounded polygon calculation functions are defined in radial_tiling_shared.h. */
|
||||
#include "radial_tiling_shared.h"
|
||||
|
||||
/* Undefine macro flags used for code adaption. */
|
||||
#undef ADAPT_TO_SVM
|
||||
|
||||
template<uint node_feature_mask>
|
||||
ccl_device_noinline void svm_node_radial_tiling(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeRadialTiling &ccl_restrict node)
|
||||
{
|
||||
const bool calculate_r_gon_parameter_field = stack_valid(node.segment_coordinates_offset);
|
||||
const bool calculate_segment_id = stack_valid(node.segment_id_offset);
|
||||
const bool calculate_max_unit_parameter = stack_valid(node.max_unit_parameter_offset);
|
||||
const bool calculate_x_axis_A_angle_bisector = stack_valid(node.x_axis_A_angle_bisector_offset);
|
||||
|
||||
const float3 coord = stack_load(stack, node.vector);
|
||||
const float r_gon_sides = stack_load(stack, node.r_gon_sides);
|
||||
const float r_gon_roundness = stack_load(stack, node.r_gon_roundness);
|
||||
|
||||
if (calculate_r_gon_parameter_field || calculate_max_unit_parameter ||
|
||||
calculate_x_axis_A_angle_bisector)
|
||||
{
|
||||
float4 out_variables = calculate_out_variables(calculate_r_gon_parameter_field,
|
||||
calculate_max_unit_parameter,
|
||||
node.normalize_r_gon_parameter,
|
||||
fmaxf(r_gon_sides, 2.0f),
|
||||
clamp(r_gon_roundness, 0.0f, 1.0f),
|
||||
make_float2(coord.x, coord.y));
|
||||
|
||||
if (calculate_r_gon_parameter_field) {
|
||||
stack_store_float3(stack,
|
||||
node.segment_coordinates_offset,
|
||||
make_float3(out_variables.y, out_variables.x, 0.0f));
|
||||
}
|
||||
if (calculate_max_unit_parameter) {
|
||||
stack_store_float(stack, node.max_unit_parameter_offset, out_variables.z);
|
||||
}
|
||||
if (calculate_x_axis_A_angle_bisector) {
|
||||
stack_store_float(stack, node.x_axis_A_angle_bisector_offset, out_variables.w);
|
||||
}
|
||||
}
|
||||
|
||||
if (calculate_segment_id) {
|
||||
stack_store_float(
|
||||
stack,
|
||||
node.segment_id_offset,
|
||||
calculate_out_segment_id(fmaxf(r_gon_sides, 2.0f), make_float2(coord.x, coord.y)));
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
1183
blender-5.2.0/intern/cycles/kernel/svm/radial_tiling_shared.h
Normal file
1183
blender-5.2.0/intern/cycles/kernel/svm/radial_tiling_shared.h
Normal file
File diff suppressed because it is too large
Load Diff
156
blender-5.2.0/intern/cycles/kernel/svm/ramp.h
Normal file
156
blender-5.2.0/intern/cycles/kernel/svm/ramp.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
|
||||
|
||||
ccl_device_inline float fetch_float(KernelGlobals kg, const int offset)
|
||||
{
|
||||
return __uint_as_float(kernel_data_fetch(svm_nodes, offset));
|
||||
}
|
||||
|
||||
ccl_device_inline float float_ramp_lookup(KernelGlobals kg,
|
||||
const int offset,
|
||||
float f,
|
||||
bool interpolate,
|
||||
bool extrapolate,
|
||||
const int table_size)
|
||||
{
|
||||
if ((f < 0.0f || f > 1.0f) && extrapolate) {
|
||||
float t0;
|
||||
float dy;
|
||||
if (f < 0.0f) {
|
||||
t0 = fetch_float(kg, offset);
|
||||
dy = t0 - fetch_float(kg, offset + 1);
|
||||
f = -f;
|
||||
}
|
||||
else {
|
||||
t0 = fetch_float(kg, offset + table_size - 1);
|
||||
dy = t0 - fetch_float(kg, offset + table_size - 2);
|
||||
f = f - 1.0f;
|
||||
}
|
||||
return t0 + dy * f * (table_size - 1);
|
||||
}
|
||||
|
||||
f = saturatef(f) * (table_size - 1);
|
||||
|
||||
/* clamp int as well in case of NaN */
|
||||
const int i = clamp(float_to_int(f), 0, table_size - 1);
|
||||
const float t = f - (float)i;
|
||||
|
||||
float a = fetch_float(kg, offset + i);
|
||||
|
||||
if (interpolate && t > 0.0f) {
|
||||
a = (1.0f - t) * a + t * fetch_float(kg, offset + i + 1);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
ccl_device_inline float4 rgb_ramp_lookup(KernelGlobals kg,
|
||||
const int offset,
|
||||
float f,
|
||||
bool interpolate,
|
||||
bool extrapolate,
|
||||
const int table_size)
|
||||
{
|
||||
if ((f < 0.0f || f > 1.0f) && extrapolate) {
|
||||
float4 t0;
|
||||
float4 dy;
|
||||
if (f < 0.0f) {
|
||||
t0 = svm_node_get_data_float4(kg, offset);
|
||||
dy = t0 - svm_node_get_data_float4(kg, offset + 4);
|
||||
f = -f;
|
||||
}
|
||||
else {
|
||||
t0 = svm_node_get_data_float4(kg, offset + (table_size - 1) * 4);
|
||||
dy = t0 - svm_node_get_data_float4(kg, offset + (table_size - 2) * 4);
|
||||
f = f - 1.0f;
|
||||
}
|
||||
return t0 + dy * f * (table_size - 1);
|
||||
}
|
||||
|
||||
f = saturatef(f) * (table_size - 1);
|
||||
|
||||
/* clamp int as well in case of NaN */
|
||||
const int i = clamp(float_to_int(f), 0, table_size - 1);
|
||||
const float t = f - (float)i;
|
||||
|
||||
float4 a = svm_node_get_data_float4(kg, offset + i * 4);
|
||||
|
||||
if (interpolate && t > 0.0f) {
|
||||
a = (1.0f - t) * a + t * svm_node_get_data_float4(kg, offset + (i + 1) * 4);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
ccl_device_noinline int svm_node_rgb_ramp(KernelGlobals kg,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeRGBRamp &node,
|
||||
int offset)
|
||||
{
|
||||
const float fac = stack_load(stack, node.fac);
|
||||
const float4 color = rgb_ramp_lookup(kg, offset, fac, node.interpolate, false, node.table_size);
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, make_float3(color));
|
||||
}
|
||||
if (stack_valid(node.alpha_offset)) {
|
||||
stack_store_float(stack, node.alpha_offset, color.w);
|
||||
}
|
||||
|
||||
offset += node.table_size * 4;
|
||||
return offset;
|
||||
}
|
||||
|
||||
ccl_device_noinline int svm_node_curves(KernelGlobals kg,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeCurves &node,
|
||||
int offset)
|
||||
{
|
||||
const float fac = stack_load(stack, node.fac);
|
||||
float3 color = stack_load(stack, node.color);
|
||||
|
||||
const float range_x = node.max_x - node.min_x;
|
||||
const float3 relpos = (color - make_float3(node.min_x, node.min_x, node.min_x)) / range_x;
|
||||
|
||||
const float r = rgb_ramp_lookup(kg, offset, relpos.x, true, node.extrapolate, node.table_size).x;
|
||||
const float g = rgb_ramp_lookup(kg, offset, relpos.y, true, node.extrapolate, node.table_size).y;
|
||||
const float b = rgb_ramp_lookup(kg, offset, relpos.z, true, node.extrapolate, node.table_size).z;
|
||||
|
||||
color = (1.0f - fac) * color + fac * make_float3(r, g, b);
|
||||
stack_store_float3(stack, node.out_offset, color);
|
||||
|
||||
offset += node.table_size * 4;
|
||||
return offset;
|
||||
}
|
||||
|
||||
ccl_device_noinline int svm_node_curve(KernelGlobals kg,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeFloatCurve &node,
|
||||
int offset)
|
||||
{
|
||||
const float fac = stack_load(stack, node.fac);
|
||||
float in = stack_load(stack, node.value_in);
|
||||
|
||||
const float range = node.max_x - node.min_x;
|
||||
const float relpos = (in - node.min_x) / range;
|
||||
|
||||
const float v = float_ramp_lookup(kg, offset, relpos, true, node.extrapolate, node.table_size);
|
||||
|
||||
in = (1.0f - fac) * in + fac * v;
|
||||
stack_store_float(stack, node.out_offset, in);
|
||||
|
||||
offset += node.table_size;
|
||||
return offset;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
80
blender-5.2.0/intern/cycles/kernel/svm/ramp_util.h
Normal file
80
blender-5.2.0/intern/cycles/kernel/svm/ramp_util.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/math.h"
|
||||
#include "util/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
|
||||
|
||||
ccl_device_inline float3 rgb_ramp_lookup(
|
||||
const packed_float3 *ramp, float f, bool interpolate, bool extrapolate, const int table_size)
|
||||
{
|
||||
if ((f < 0.0f || f > 1.0f) && extrapolate) {
|
||||
float3 t0;
|
||||
float3 dy;
|
||||
if (f < 0.0f) {
|
||||
t0 = ramp[0];
|
||||
dy = t0 - ramp[1], f = -f;
|
||||
}
|
||||
else {
|
||||
t0 = ramp[table_size - 1];
|
||||
dy = t0 - ramp[table_size - 2];
|
||||
f = f - 1.0f;
|
||||
}
|
||||
return t0 + dy * f * (table_size - 1);
|
||||
}
|
||||
|
||||
f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
|
||||
|
||||
/* clamp int as well in case of NaN */
|
||||
const int i = clamp(float_to_int(f), 0, table_size - 1);
|
||||
const float t = f - (float)i;
|
||||
|
||||
float3 result = ramp[i];
|
||||
|
||||
if (interpolate && t > 0.0f) {
|
||||
result = (1.0f - t) * result + t * ramp[i + 1];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ccl_device float float_ramp_lookup(
|
||||
const float *ramp, float f, bool interpolate, bool extrapolate, const int table_size)
|
||||
{
|
||||
if ((f < 0.0f || f > 1.0f) && extrapolate) {
|
||||
float t0;
|
||||
float dy;
|
||||
if (f < 0.0f) {
|
||||
t0 = ramp[0];
|
||||
dy = t0 - ramp[1], f = -f;
|
||||
}
|
||||
else {
|
||||
t0 = ramp[table_size - 1];
|
||||
dy = t0 - ramp[table_size - 2];
|
||||
f = f - 1.0f;
|
||||
}
|
||||
return t0 + dy * f * (table_size - 1);
|
||||
}
|
||||
|
||||
f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
|
||||
|
||||
/* clamp int as well in case of NaN */
|
||||
const int i = clamp(float_to_int(f), 0, table_size - 1);
|
||||
const float t = f - (float)i;
|
||||
|
||||
float result = ramp[i];
|
||||
|
||||
if (interpolate && t > 0.0f) {
|
||||
result = (1.0f - t) * result + t * ramp[i + 1];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
195
blender-5.2.0/intern/cycles/kernel/svm/raycast.h
Normal file
195
blender-5.2.0/intern/cycles/kernel/svm/raycast.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/integrator/path_state.h"
|
||||
|
||||
#include "kernel/bvh/bvh.h"
|
||||
|
||||
#include "kernel/sample/mapping.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/geom/shader_data.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __SHADER_RAYTRACE__
|
||||
|
||||
ccl_device bool svm_raycast(KernelGlobals kg,
|
||||
ConstIntegratorState /*state*/,
|
||||
ccl_private ShaderData *sd,
|
||||
const float3 position,
|
||||
const float3 direction,
|
||||
const float distance,
|
||||
const bool only_local,
|
||||
const float bump_filter_width,
|
||||
ccl_private ShaderData &hit_sd)
|
||||
{
|
||||
/* Early out if no sampling needed. */
|
||||
if (distance <= 0.0f || sd->object == OBJECT_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Can't ray-trace from shaders like displacement, before BVH exists. */
|
||||
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float tmin = 0.0f;
|
||||
bool avoid_self_intersection = false;
|
||||
if (bump_filter_width > 0.0f) {
|
||||
/* If evaluating for bump mapping at a shifted position, increase min distance by slightly more
|
||||
* than the shift distance to avoid self intersections. */
|
||||
tmin = bump_filter_width * sd->dP * 1.1f;
|
||||
}
|
||||
else {
|
||||
avoid_self_intersection = isequal(position, sd->P);
|
||||
}
|
||||
|
||||
/* Create ray. */
|
||||
Ray ray;
|
||||
ray.P = position;
|
||||
ray.D = direction;
|
||||
ray.tmin = tmin;
|
||||
ray.tmax = distance;
|
||||
ray.time = sd->time;
|
||||
ray.self.object = avoid_self_intersection ? sd->object : OBJECT_NONE;
|
||||
ray.self.prim = avoid_self_intersection ? sd->prim : PRIM_NONE;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
ray.dP = differential_zero_compact();
|
||||
ray.dD = differential_zero_compact();
|
||||
|
||||
Intersection isect;
|
||||
if (only_local) {
|
||||
LocalIntersection local_isect;
|
||||
scene_intersect_local(kg, &ray, &local_isect, sd->object, nullptr, 1);
|
||||
if (local_isect.num_hits == 0) {
|
||||
return false;
|
||||
}
|
||||
isect = local_isect.hits[0];
|
||||
}
|
||||
else {
|
||||
/* Ray-trace, leaving out shadow opaque to avoid early exit. */
|
||||
const PathRayVisibility visibility = PATH_RAY_VISIBILITY_ALL &
|
||||
~PATH_RAY_VISIBILITY_SHADOW_OPAQUE;
|
||||
if (!scene_intersect(kg, &ray, visibility, &isect)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
shader_setup_from_ray(kg, &hit_sd, &ray, &isect);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ccl_device_inline void svm_raycast_attr_eval_and_store(
|
||||
KernelGlobals kg,
|
||||
ccl_private float *stack,
|
||||
ccl_global const SVMNodeAttr &attribute_node,
|
||||
ccl_private ShaderData &hit_sd)
|
||||
{
|
||||
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
|
||||
const AttributeDescriptor desc = svm_node_attr_init(kg, &hit_sd, attribute_node, &type);
|
||||
|
||||
const float3 data = svm_node_attr_surface_eval<float3>(kg, &hit_sd, attribute_node, type, desc);
|
||||
svm_node_attr_store(type, stack, attribute_node.out_offset, data);
|
||||
}
|
||||
|
||||
template<uint node_feature_mask, typename ConstIntegratorGenericState>
|
||||
# if defined(__KERNEL_OPTIX__)
|
||||
ccl_device_inline
|
||||
# else
|
||||
ccl_device_noinline
|
||||
# endif
|
||||
int
|
||||
svm_node_raycast(KernelGlobals kg,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeRaycast &ccl_restrict node,
|
||||
int offset)
|
||||
{
|
||||
const float distance = stack_load(stack, node.distance);
|
||||
|
||||
float is_hit = 0.0f;
|
||||
float is_self_hit = 0.0f;
|
||||
float hit_distance = distance;
|
||||
float3 hit_position = make_float3(0.0f);
|
||||
float3 hit_normal = make_float3(0.0f);
|
||||
|
||||
IF_KERNEL_NODES_FEATURE(RAYTRACE)
|
||||
{
|
||||
const float3 position = stack_load(stack, node.position);
|
||||
const float3 direction = stack_load(stack, node.direction);
|
||||
|
||||
ShaderDataTinyStorage hit_sd_storage;
|
||||
ccl_private ShaderData &hit_sd = *AS_SHADER_DATA(&hit_sd_storage);
|
||||
|
||||
if (svm_raycast(kg,
|
||||
state,
|
||||
sd,
|
||||
position,
|
||||
direction,
|
||||
distance,
|
||||
node.only_local,
|
||||
node.bump_filter_width,
|
||||
hit_sd))
|
||||
{
|
||||
is_hit = 1.0f;
|
||||
is_self_hit = (sd->object == hit_sd.object) ? 1.0f : 0.0f;
|
||||
hit_distance = hit_sd.ray_length;
|
||||
hit_position = position + direction * hit_distance;
|
||||
hit_normal = hit_sd.N;
|
||||
|
||||
for (uint16_t i = 0; i < node.num_attributes; i++) {
|
||||
const uint node_type = kernel_data_fetch(svm_nodes, offset++);
|
||||
(void)node_type;
|
||||
kernel_assert(node_type == NODE_ATTR);
|
||||
|
||||
const ccl_global auto &attribute_node = svm_node_get<SVMNodeAttr>(kg, &offset);
|
||||
svm_raycast_attr_eval_and_store(kg, stack, attribute_node, hit_sd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_hit == 0.0f) {
|
||||
for (uint16_t i = 0; i < node.num_attributes; i++) {
|
||||
const uint node_type = kernel_data_fetch(svm_nodes, offset++);
|
||||
(void)node_type;
|
||||
kernel_assert(node_type == NODE_ATTR);
|
||||
|
||||
const ccl_global auto &attribute_node = svm_node_get<SVMNodeAttr>(kg, &offset);
|
||||
svm_node_attr_store(
|
||||
attribute_node.output_type, stack, attribute_node.out_offset, make_zero<float3>());
|
||||
}
|
||||
}
|
||||
|
||||
if (stack_valid(node.is_hit_offset)) {
|
||||
stack_store_float(stack, node.is_hit_offset, is_hit);
|
||||
}
|
||||
if (stack_valid(node.is_self_hit_offset)) {
|
||||
stack_store_float(stack, node.is_self_hit_offset, is_self_hit);
|
||||
}
|
||||
if (stack_valid(node.hit_distance_offset)) {
|
||||
stack_store_float(stack, node.hit_distance_offset, hit_distance);
|
||||
}
|
||||
if (stack_valid(node.hit_position_offset)) {
|
||||
stack_store_float3(stack, node.hit_position_offset, hit_position);
|
||||
}
|
||||
if (stack_valid(node.hit_normal_offset)) {
|
||||
stack_store_float3(stack, node.hit_normal_offset, hit_normal);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#endif /* __SHADER_RAYTRACE__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
26
blender-5.2.0/intern/cycles/kernel/svm/scene_time.h
Normal file
26
blender-5.2.0/intern/cycles/kernel/svm/scene_time.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* SPDX-FileCopyrightText: 2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_scene_time(KernelGlobals kg,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeSceneTime &ccl_restrict node)
|
||||
{
|
||||
if (stack_valid(node.seconds_out)) {
|
||||
stack_store_float(stack, node.seconds_out, kernel_data.scene_time.time);
|
||||
}
|
||||
if (stack_valid(node.frame_out)) {
|
||||
stack_store_float(stack, node.frame_out, kernel_data.scene_time.frame);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
48
blender-5.2.0/intern/cycles/kernel/svm/sepcomb_color.h
Normal file
48
blender-5.2.0/intern/cycles/kernel/svm/sepcomb_color.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/color_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_combine_color(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeCombineColor &ccl_restrict node)
|
||||
{
|
||||
const float r = stack_load(stack, node.red);
|
||||
const float g = stack_load(stack, node.green);
|
||||
const float b = stack_load(stack, node.blue);
|
||||
|
||||
/* Combine, and convert back to RGB */
|
||||
const float3 color = svm_combine_color(node.color_type, make_float3(r, g, b));
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_separate_color(
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeSeparateColor &ccl_restrict node)
|
||||
{
|
||||
float3 color = stack_load(stack, node.color);
|
||||
|
||||
/* Convert color space */
|
||||
color = svm_separate_color(node.color_type, color);
|
||||
|
||||
if (stack_valid(node.red_offset)) {
|
||||
stack_store_float(stack, node.red_offset, color.x);
|
||||
}
|
||||
if (stack_valid(node.green_offset)) {
|
||||
stack_store_float(stack, node.green_offset, color.y);
|
||||
}
|
||||
if (stack_valid(node.blue_offset)) {
|
||||
stack_store_float(stack, node.blue_offset, color.z);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
65
blender-5.2.0/intern/cycles/kernel/svm/sepcomb_vector.h
Normal file
65
blender-5.2.0/intern/cycles/kernel/svm/sepcomb_vector.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Vector combine / separate, used for the RGB and XYZ nodes */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device void svm_node_combine_vector(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeCombineVector &ccl_restrict node)
|
||||
{
|
||||
using FloatType = dual_scalar_t<Float3Type>;
|
||||
const FloatType value = stack_load<FloatType>(stack, node.in);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
stack_store_float(stack, node.out_offset + node.vector_index, value.val);
|
||||
stack_store_float(stack, node.out_offset + node.vector_index + 3, value.dx);
|
||||
stack_store_float(stack, node.out_offset + node.vector_index + 6, value.dy);
|
||||
}
|
||||
else {
|
||||
stack_store_float(stack, node.out_offset + node.vector_index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device void svm_node_separate_vector(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeSeparateVector &ccl_restrict node)
|
||||
{
|
||||
const Float3Type vector = stack_load<Float3Type>(stack, node.vector);
|
||||
|
||||
if (stack_valid(node.out_offset)) {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
if (node.vector_index == 0) {
|
||||
stack_store(stack, node.out_offset, vector.x());
|
||||
}
|
||||
else if (node.vector_index == 1) {
|
||||
stack_store(stack, node.out_offset, vector.y());
|
||||
}
|
||||
else {
|
||||
stack_store(stack, node.out_offset, vector.z());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.vector_index == 0) {
|
||||
stack_store(stack, node.out_offset, vector.x);
|
||||
}
|
||||
else if (node.vector_index == 1) {
|
||||
stack_store(stack, node.out_offset, vector.y);
|
||||
}
|
||||
else {
|
||||
stack_store(stack, node.out_offset, vector.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
265
blender-5.2.0/intern/cycles/kernel/svm/sky.h
Normal file
265
blender-5.2.0/intern/cycles/kernel/svm/sky.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/image.h"
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/colorspace.h"
|
||||
#include "kernel/util/differential.h"
|
||||
|
||||
#include "util/color.h"
|
||||
#include "util/defines.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Sky texture */
|
||||
|
||||
ccl_device float sky_angle_between(const float thetav,
|
||||
const float phiv,
|
||||
const float theta,
|
||||
const float phi)
|
||||
{
|
||||
const float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
|
||||
return safe_acosf(cospsi);
|
||||
}
|
||||
|
||||
/*
|
||||
* "A Practical Analytic Model for Daylight"
|
||||
* A. J. Preetham, Peter Shirley, Brian Smits
|
||||
*/
|
||||
ccl_device float sky_perez_function(const ccl_private float *lam,
|
||||
const float theta,
|
||||
const float gamma)
|
||||
{
|
||||
const float ctheta = cosf(theta);
|
||||
const float cgamma = cosf(gamma);
|
||||
|
||||
return (1.0f + lam[0] * expf(lam[1] / ctheta)) *
|
||||
(1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cgamma * cgamma);
|
||||
}
|
||||
|
||||
ccl_device float3 sky_radiance_preetham(KernelGlobals kg,
|
||||
const float3 dir,
|
||||
const float sunphi,
|
||||
const float suntheta,
|
||||
const float radiance_x,
|
||||
const float radiance_y,
|
||||
const float radiance_z,
|
||||
ccl_private float *config_x,
|
||||
ccl_private float *config_y,
|
||||
ccl_private float *config_z)
|
||||
{
|
||||
/* convert vector to spherical coordinates */
|
||||
const float2 spherical = direction_to_spherical(dir);
|
||||
float theta = spherical.x;
|
||||
const float phi = -spherical.y + M_PI_2_F;
|
||||
|
||||
/* angle between sun direction and dir */
|
||||
const float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
|
||||
|
||||
/* clamp theta to horizon */
|
||||
theta = min(theta, M_PI_2_F - 0.001f);
|
||||
|
||||
/* compute xyY color space values */
|
||||
const float x = radiance_y * sky_perez_function(config_y, theta, gamma);
|
||||
const float y = radiance_z * sky_perez_function(config_z, theta, gamma);
|
||||
const float Y = radiance_x * sky_perez_function(config_x, theta, gamma);
|
||||
|
||||
/* convert to RGB */
|
||||
const float3 xyz = xyY_to_xyz(x, y, Y);
|
||||
return xyz_to_rgb_clamped(kg, xyz);
|
||||
}
|
||||
|
||||
/*
|
||||
* "An Analytic Model for Full Spectral Sky-Dome Radiance"
|
||||
* Lukas Hosek, Alexander Wilkie
|
||||
*/
|
||||
ccl_device float sky_radiance_internal(const ccl_private float *configuration,
|
||||
const float theta,
|
||||
const float gamma)
|
||||
{
|
||||
const float ctheta = cosf(theta);
|
||||
const float cgamma = cosf(gamma);
|
||||
|
||||
const float expM = expf(configuration[4] * gamma);
|
||||
const float rayM = cgamma * cgamma;
|
||||
const float mieM = (1.0f + rayM) / powf((1.0f + configuration[8] * configuration[8] -
|
||||
2.0f * configuration[8] * cgamma),
|
||||
1.5f);
|
||||
const float zenith = sqrtf(ctheta);
|
||||
|
||||
return (1.0f + configuration[0] * expf(configuration[1] / (ctheta + 0.01f))) *
|
||||
(configuration[2] + configuration[3] * expM + configuration[5] * rayM +
|
||||
configuration[6] * mieM + configuration[7] * zenith);
|
||||
}
|
||||
|
||||
ccl_device float3 sky_radiance_hosek(KernelGlobals kg,
|
||||
const float3 dir,
|
||||
const float sunphi,
|
||||
const float suntheta,
|
||||
const float radiance_x,
|
||||
const float radiance_y,
|
||||
const float radiance_z,
|
||||
ccl_private float *config_x,
|
||||
ccl_private float *config_y,
|
||||
ccl_private float *config_z)
|
||||
{
|
||||
/* convert vector to spherical coordinates */
|
||||
const float2 spherical = direction_to_spherical(dir);
|
||||
float theta = spherical.x;
|
||||
const float phi = -spherical.y + M_PI_2_F;
|
||||
|
||||
/* angle between sun direction and dir */
|
||||
const float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
|
||||
|
||||
/* clamp theta to horizon */
|
||||
theta = min(theta, M_PI_2_F - 0.001f);
|
||||
|
||||
/* compute xyz color space values */
|
||||
const float x = sky_radiance_internal(config_x, theta, gamma) * radiance_x;
|
||||
const float y = sky_radiance_internal(config_y, theta, gamma) * radiance_y;
|
||||
const float z = sky_radiance_internal(config_z, theta, gamma) * radiance_z;
|
||||
|
||||
/* convert to RGB and adjust strength */
|
||||
return xyz_to_rgb_clamped(kg, make_float3(x, y, z)) * (M_2PI_F / 683);
|
||||
}
|
||||
|
||||
/* Nishita improved sky model */
|
||||
ccl_device float3 geographical_to_direction(const float lat, const float lon)
|
||||
{
|
||||
return spherical_to_direction(lat - M_PI_2_F, lon - M_PI_2_F);
|
||||
}
|
||||
|
||||
ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const float3 dir,
|
||||
const uint32_t path_flag,
|
||||
const float3 pixel_bottom,
|
||||
const float3 pixel_top,
|
||||
const ccl_private float *sky_data,
|
||||
const uint texture_id)
|
||||
{
|
||||
/* Definitions */
|
||||
const float sun_elevation = sky_data[0];
|
||||
const float sun_rotation = sky_data[1];
|
||||
const float angular_diameter = sky_data[2];
|
||||
const float sun_intensity = sky_data[3];
|
||||
const float earth_intersection_angle = sky_data[4];
|
||||
const bool sun_disc = (angular_diameter >= 0.0f);
|
||||
float3 xyz = zero_float3();
|
||||
const float2 direction = direction_to_spherical(dir);
|
||||
const float3 sun_dir = spherical_to_direction(sun_elevation - M_PI_2_F, sun_rotation - M_PI_2_F);
|
||||
const float sun_dir_angle = precise_angle(dir, sun_dir);
|
||||
const float half_angular = angular_diameter * 0.5f;
|
||||
const float dir_elevation = M_PI_2_F - direction.x;
|
||||
|
||||
/* If the ray is inside the Sun disc, render it, otherwise render the sky.
|
||||
* Alternatively, ignore the Sun if we're evaluating the background texture. */
|
||||
if (sun_disc && sun_dir_angle < half_angular && dir_elevation > earth_intersection_angle &&
|
||||
!((path_flag & PATH_RAY_IMPORTANCE_BAKE) && kernel_data.background.use_sun_guiding))
|
||||
{
|
||||
/* Sun interpolation */
|
||||
const float y = ((dir_elevation - sun_elevation) / angular_diameter) + 0.5f;
|
||||
/* Limb darkening, coefficient is 0.6f */
|
||||
const float limb_darkening = (1.0f -
|
||||
0.6f * (1.0f - sqrtf(1.0f - sqr(sun_dir_angle / half_angular))));
|
||||
xyz = mix(pixel_bottom, pixel_top, y) * sun_intensity * limb_darkening;
|
||||
}
|
||||
|
||||
/* Sky */
|
||||
const float x = fractf((-direction.y - M_PI_2_F + sun_rotation) * M_1_2PI_F);
|
||||
/* Undo the non-linear transformation from the sky LUT */
|
||||
const float y = copysignf(sqrtf(fabsf(dir_elevation) * M_2_PI_F), dir_elevation) * 0.5f + 0.5f;
|
||||
xyz += make_float3(kernel_image_interp(kg, sd, texture_id, dual2(make_float2(x, y))));
|
||||
|
||||
/* Convert to RGB */
|
||||
return xyz_to_rgb_clamped(kg, xyz);
|
||||
}
|
||||
|
||||
ccl_device_noinline int svm_node_tex_sky(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const uint32_t path_flag,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexSky &ccl_restrict node,
|
||||
int offset)
|
||||
{
|
||||
/* Load data */
|
||||
const NodeSkyType sky_type = node.sky_type;
|
||||
|
||||
const float3 dir = stack_load_float3(stack, node.dir_offset);
|
||||
float3 rgb;
|
||||
|
||||
/* Preetham and Hosek share the same data */
|
||||
if (sky_type == NODE_SKY_PREETHAM || sky_type == NODE_SKY_HOSEK) {
|
||||
const ccl_global SVMNodeTexSkyPreethamData &preetham =
|
||||
*reinterpret_cast<const ccl_global SVMNodeTexSkyPreethamData *>(
|
||||
&kernel_data_fetch(svm_nodes, offset));
|
||||
offset += sizeof(SVMNodeTexSkyPreethamData) / sizeof(uint);
|
||||
|
||||
/* Copy config arrays to private memory for GPU compatibility. */
|
||||
float config_x[9], config_y[9], config_z[9];
|
||||
for (int i = 0; i < 9; i++) {
|
||||
config_x[i] = preetham.config_x[i];
|
||||
config_y[i] = preetham.config_y[i];
|
||||
config_z[i] = preetham.config_z[i];
|
||||
}
|
||||
|
||||
/* Compute Sky */
|
||||
if (sky_type == NODE_SKY_PREETHAM) {
|
||||
rgb = sky_radiance_preetham(kg,
|
||||
dir,
|
||||
preetham.phi,
|
||||
preetham.theta,
|
||||
preetham.radiance_x,
|
||||
preetham.radiance_y,
|
||||
preetham.radiance_z,
|
||||
config_x,
|
||||
config_y,
|
||||
config_z);
|
||||
}
|
||||
else {
|
||||
rgb = sky_radiance_hosek(kg,
|
||||
dir,
|
||||
preetham.phi,
|
||||
preetham.theta,
|
||||
preetham.radiance_x,
|
||||
preetham.radiance_y,
|
||||
preetham.radiance_z,
|
||||
config_x,
|
||||
config_y,
|
||||
config_z);
|
||||
}
|
||||
}
|
||||
/* Nishita */
|
||||
else {
|
||||
const ccl_global SVMNodeTexSkyNishitaData &nishita =
|
||||
*reinterpret_cast<const ccl_global SVMNodeTexSkyNishitaData *>(
|
||||
&kernel_data_fetch(svm_nodes, offset));
|
||||
offset += sizeof(SVMNodeTexSkyNishitaData) / sizeof(uint);
|
||||
|
||||
const float3 pixel_bottom = make_float3(
|
||||
nishita.pixel_bottom_x, nishita.pixel_bottom_y, nishita.pixel_bottom_z);
|
||||
const float3 pixel_top = make_float3(
|
||||
nishita.pixel_top_x, nishita.pixel_top_y, nishita.pixel_top_z);
|
||||
const float sky_data[5] = {nishita.sun_elevation,
|
||||
nishita.sun_rotation,
|
||||
nishita.angular_diameter,
|
||||
nishita.sun_intensity,
|
||||
nishita.earth_intersection_angle};
|
||||
|
||||
/* Compute Sky */
|
||||
rgb = sky_radiance_nishita(
|
||||
kg, sd, dir, path_flag, pixel_bottom, pixel_top, sky_data, nishita.texture_id);
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.out_offset, rgb);
|
||||
return offset;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
624
blender-5.2.0/intern/cycles/kernel/svm/svm.h
Normal file
624
blender-5.2.0/intern/cycles/kernel/svm/svm.h
Normal file
@@ -0,0 +1,624 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Shader Virtual Machine
|
||||
*
|
||||
* A shader is a list of nodes to be executed. These are simply read one after
|
||||
* the other and executed, using an node counter. Each node and its associated
|
||||
* data is encoded as one or more uint4's in a 1D texture. If the data is larger
|
||||
* than an uint4, the node can increase the node counter to compensate for this.
|
||||
* Floats are encoded as int and then converted to float again.
|
||||
*
|
||||
* Nodes write their output into a stack. All stack data in the stack is
|
||||
* floats, since it's all factors, colors and vectors. The stack will be stored
|
||||
* in local memory on the GPU, as it would take too many register and indexes in
|
||||
* ways not known at compile time. This seems the only solution even though it
|
||||
* may be slow, with two positive factors. If the same shader is being executed,
|
||||
* memory access will be coalesced and cached.
|
||||
*
|
||||
* The result of shader execution will be a single closure. This means the
|
||||
* closure type, associated label, data and weight. Sampling from multiple
|
||||
* closures is supported through the mix closure node, the logic for that is
|
||||
* mostly taken care of in the SVM compiler.
|
||||
*/
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
#include "kernel/svm/types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
/* Nodes */
|
||||
|
||||
#include "kernel/svm/aov.h"
|
||||
#include "kernel/svm/attribute.h"
|
||||
#include "kernel/svm/blackbody.h"
|
||||
#include "kernel/svm/brick.h"
|
||||
#include "kernel/svm/brightness.h"
|
||||
#include "kernel/svm/bump.h"
|
||||
#include "kernel/svm/camera.h"
|
||||
#include "kernel/svm/checker.h"
|
||||
#include "kernel/svm/clamp.h"
|
||||
#include "kernel/svm/closure.h"
|
||||
#include "kernel/svm/convert.h"
|
||||
#include "kernel/svm/displace.h"
|
||||
#include "kernel/svm/fresnel.h"
|
||||
#include "kernel/svm/gabor.h"
|
||||
#include "kernel/svm/gamma.h"
|
||||
#include "kernel/svm/geometry.h"
|
||||
#include "kernel/svm/gradient.h"
|
||||
#include "kernel/svm/hsv.h"
|
||||
#include "kernel/svm/ies.h"
|
||||
#include "kernel/svm/image.h"
|
||||
#include "kernel/svm/invert.h"
|
||||
#include "kernel/svm/light_path.h"
|
||||
#include "kernel/svm/magic.h"
|
||||
#include "kernel/svm/map_range.h"
|
||||
#include "kernel/svm/mapping.h"
|
||||
#include "kernel/svm/math.h"
|
||||
#include "kernel/svm/mix.h"
|
||||
#include "kernel/svm/noisetex.h"
|
||||
#include "kernel/svm/normal.h"
|
||||
#include "kernel/svm/radial_tiling.h"
|
||||
#include "kernel/svm/ramp.h"
|
||||
#include "kernel/svm/scene_time.h"
|
||||
#include "kernel/svm/sepcomb_color.h"
|
||||
#include "kernel/svm/sepcomb_vector.h"
|
||||
#include "kernel/svm/sky.h"
|
||||
#include "kernel/svm/tex_coord.h"
|
||||
#include "kernel/svm/value.h"
|
||||
#include "kernel/svm/vector_rotate.h"
|
||||
#include "kernel/svm/vector_transform.h"
|
||||
#include "kernel/svm/vertex_color.h"
|
||||
#include "kernel/svm/voronoi.h"
|
||||
#include "kernel/svm/wave.h"
|
||||
#include "kernel/svm/wavelength.h"
|
||||
#include "kernel/svm/white_noise.h"
|
||||
#include "kernel/svm/wireframe.h"
|
||||
#include "util/defines.h"
|
||||
|
||||
#ifdef __SHADER_RAYTRACE__
|
||||
# include "kernel/svm/ao.h"
|
||||
# include "kernel/svm/bevel.h"
|
||||
# include "kernel/svm/raycast.h"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __KERNEL_USE_DATA_CONSTANTS__
|
||||
# define SVM_CASE(node) \
|
||||
case node: \
|
||||
if (!kernel_data_svm_usage_##node) \
|
||||
break;
|
||||
#else
|
||||
# define SVM_CASE(node) case node:
|
||||
#endif
|
||||
|
||||
/* Main Interpreter Loop */
|
||||
template<uint node_feature_mask, ShaderType type, typename ConstIntegratorGenericState>
|
||||
ccl_device void svm_eval_nodes(KernelGlobals kg,
|
||||
ConstIntegratorGenericState state,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_global float *render_buffer,
|
||||
const PathRayVisibility path_visibility,
|
||||
const uint32_t path_flag)
|
||||
{
|
||||
float stack[SVM_STACK_SIZE];
|
||||
/* Initialize to silence (false positive?) warning about uninitialized use on Windows. */
|
||||
Spectrum closure_weight = zero_spectrum();
|
||||
int offset = (sd->shader & SHADER_MASK) * (1 + sizeof(SVMNodeShaderJump) / sizeof(uint));
|
||||
|
||||
while (true) {
|
||||
const uint node_type = kernel_data_fetch(svm_nodes, offset++);
|
||||
|
||||
switch (node_type) {
|
||||
SVM_CASE(NODE_END)
|
||||
return;
|
||||
SVM_CASE(NODE_SHADER_JUMP)
|
||||
{
|
||||
const SVMNodeShaderJump jump = svm_node_get<SVMNodeShaderJump>(kg, &offset);
|
||||
if (type == SHADER_TYPE_SURFACE) {
|
||||
offset = jump.offset_surface;
|
||||
}
|
||||
else if (type == SHADER_TYPE_VOLUME) {
|
||||
offset = jump.offset_volume;
|
||||
}
|
||||
else if (type == SHADER_TYPE_DISPLACEMENT) {
|
||||
offset = jump.offset_displacement;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
SVM_CASE(NODE_CLOSURE_BSDF)
|
||||
{
|
||||
const ccl_global SVMNodeClosureBsdf &bsdf_node = svm_node_get<SVMNodeClosureBsdf>(kg,
|
||||
&offset);
|
||||
offset = svm_node_closure_bsdf<node_feature_mask, type>(
|
||||
kg, sd, stack, closure_weight, bsdf_node, path_visibility, path_flag, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_EMISSION)
|
||||
IF_KERNEL_NODES_FEATURE(EMISSION)
|
||||
{
|
||||
svm_node_closure_emission(
|
||||
kg, sd, stack, closure_weight, svm_node_get<SVMNodeClosureEmission>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_BACKGROUND)
|
||||
IF_KERNEL_NODES_FEATURE(EMISSION)
|
||||
{
|
||||
svm_node_closure_background(
|
||||
sd, stack, closure_weight, svm_node_get<SVMNodeClosureBackground>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_SET_WEIGHT)
|
||||
svm_node_closure_set_weight(&closure_weight,
|
||||
svm_node_get<SVMNodeClosureSetWeight>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_WEIGHT)
|
||||
svm_node_closure_weight(
|
||||
stack, &closure_weight, svm_node_get<SVMNodeClosureWeight>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_EMISSION_WEIGHT)
|
||||
IF_KERNEL_NODES_FEATURE(EMISSION)
|
||||
{
|
||||
svm_node_emission_weight(
|
||||
stack, &closure_weight, svm_node_get<SVMNodeEmissionWeight>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_MIX_CLOSURE)
|
||||
svm_node_mix_closure(stack, svm_node_get<SVMNodeMixClosure>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_JUMP_IF_ZERO)
|
||||
{
|
||||
const SVMNodeJumpIfZero jump = svm_node_get<SVMNodeJumpIfZero>(kg, &offset);
|
||||
if (stack_load_float(stack, jump.stack_offset) <= 0.0f) {
|
||||
offset += jump.jump_offset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_JUMP_IF_ONE)
|
||||
{
|
||||
const SVMNodeJumpIfOne jump = svm_node_get<SVMNodeJumpIfOne>(kg, &offset);
|
||||
if (stack_load_float(stack, jump.stack_offset) >= 1.0f) {
|
||||
offset += jump.jump_offset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_GEOMETRY)
|
||||
svm_node_geometry<float3>(kg, sd, stack, svm_node_get<SVMNodeGeometry>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_GEOMETRY_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_geometry<dual3>(kg, sd, stack, svm_node_get<SVMNodeGeometry>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_CONVERT)
|
||||
svm_node_convert<float, float3>(kg, stack, svm_node_get<SVMNodeConvert>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CONVERT_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_convert<dual1, dual3>(kg, stack, svm_node_get<SVMNodeConvert>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_COORD)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeTexCoord>(kg, &offset);
|
||||
offset = svm_node_tex_coord(kg, sd, path_visibility, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_COORD_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeTexCoord>(kg, &offset);
|
||||
offset = svm_node_tex_coord_derivative(kg, sd, path_visibility, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_VALUE_F)
|
||||
svm_node_value_f<float>(stack, svm_node_get<SVMNodeValueF>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VALUE_F_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_value_f<dual1>(stack, svm_node_get<SVMNodeValueF>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_VALUE_V)
|
||||
svm_node_value_v<float3>(stack, svm_node_get<SVMNodeValueV>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VALUE_V_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_value_v<dual3>(stack, svm_node_get<SVMNodeValueV>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_ATTR)
|
||||
IF_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
#ifdef __VOLUME__
|
||||
svm_node_attr_volume(kg, sd, stack, svm_node_get<SVMNodeAttr>(kg, &offset));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
svm_node_attr_surface(kg, sd, stack, svm_node_get<SVMNodeAttr>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_ATTR_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_attr_derivative(kg, sd, stack, svm_node_get<SVMNodeAttr>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_VERTEX_COLOR)
|
||||
svm_node_vertex_color(kg, sd, stack, svm_node_get<SVMNodeVertexColor>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VERTEX_COLOR_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_vertex_color_derivative(
|
||||
kg, sd, stack, svm_node_get<SVMNodeVertexColor>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_SET_DISPLACEMENT)
|
||||
svm_node_set_displacement<node_feature_mask>(
|
||||
sd, stack, svm_node_get<SVMNodeSetDisplacement>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_DISPLACEMENT)
|
||||
svm_node_displacement<node_feature_mask>(
|
||||
kg, sd, stack, svm_node_get<SVMNodeDisplacement>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_DISPLACEMENT)
|
||||
svm_node_vector_displacement<node_feature_mask>(
|
||||
kg, sd, stack, svm_node_get<SVMNodeVectorDisplacement>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_IMAGE)
|
||||
svm_node_tex_image<float3>(kg, sd, stack, svm_node_get<SVMNodeTexImage>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_IMAGE_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_tex_image<dual3>(kg, sd, stack, svm_node_get<SVMNodeTexImage>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_IMAGE_BOX)
|
||||
svm_node_tex_image_box<float3>(kg, sd, stack, svm_node_get<SVMNodeTexImageBox>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_IMAGE_BOX_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_tex_image_box<dual3>(
|
||||
kg, sd, stack, svm_node_get<SVMNodeTexImageBox>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_NOISE)
|
||||
svm_node_tex_noise(stack, svm_node_get<SVMNodeTexNoise>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_SET_BUMP)
|
||||
svm_node_set_bump<node_feature_mask>(
|
||||
kg, sd, stack, svm_node_get<SVMNodeSetBump>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_SET_NORMAL)
|
||||
IF_KERNEL_NODES_FEATURE(BUMP)
|
||||
{
|
||||
svm_node_set_normal(sd, stack, svm_node_get<SVMNodeClosureSetNormal>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_ENTER_BUMP_EVAL)
|
||||
IF_KERNEL_NODES_FEATURE(BUMP_STATE)
|
||||
{
|
||||
svm_node_enter_bump_eval(kg, sd, stack, svm_node_get<SVMNodeEnterBumpEval>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_LEAVE_BUMP_EVAL)
|
||||
IF_KERNEL_NODES_FEATURE(BUMP_STATE)
|
||||
{
|
||||
svm_node_leave_bump_eval(sd, stack, svm_node_get<SVMNodeLeaveBumpEval>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_HSV)
|
||||
svm_node_hsv(stack, svm_node_get<SVMNodeHSV>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_HOLDOUT)
|
||||
svm_node_closure_holdout(
|
||||
sd, stack, closure_weight, svm_node_get<SVMNodeClosureHoldout>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_FRESNEL)
|
||||
svm_node_fresnel(sd, stack, svm_node_get<SVMNodeFresnel>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_LAYER_WEIGHT)
|
||||
svm_node_layer_weight(sd, stack, svm_node_get<SVMNodeLayerWeight>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CLOSURE_VOLUME)
|
||||
IF_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_closure_volume<type>(
|
||||
kg, sd, stack, closure_weight, svm_node_get<SVMNodeClosureVolume>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_VOLUME_COEFFICIENTS)
|
||||
IF_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_volume_coefficients<type>(kg,
|
||||
sd,
|
||||
stack,
|
||||
closure_weight,
|
||||
svm_node_get<SVMNodeVolumeCoefficients>(kg, &offset),
|
||||
path_visibility);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_PRINCIPLED_VOLUME)
|
||||
IF_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_principled_volume<type>(kg,
|
||||
sd,
|
||||
stack,
|
||||
closure_weight,
|
||||
svm_node_get<SVMNodePrincipledVolume>(kg, &offset),
|
||||
path_visibility);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_MATH)
|
||||
svm_node_math(stack, svm_node_get<SVMNodeMath>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_MATH)
|
||||
svm_node_vector_math<float3>(stack, svm_node_get<SVMNodeVectorMath>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_MATH_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_vector_math<dual3>(stack, svm_node_get<SVMNodeVectorMath>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_RGB_RAMP)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeRGBRamp>(kg, &offset);
|
||||
offset = svm_node_rgb_ramp(kg, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_GAMMA)
|
||||
svm_node_gamma(stack, svm_node_get<SVMNodeGamma>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_BRIGHTCONTRAST)
|
||||
svm_node_brightness(stack, svm_node_get<SVMNodeBrightContrast>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_LIGHT_PATH)
|
||||
svm_node_light_path<node_feature_mask>(kg,
|
||||
state,
|
||||
sd,
|
||||
stack,
|
||||
svm_node_get<SVMNodeLightPath>(kg, &offset),
|
||||
path_visibility,
|
||||
path_flag);
|
||||
break;
|
||||
SVM_CASE(NODE_OBJECT_INFO)
|
||||
svm_node_object_info(kg, sd, stack, svm_node_get<SVMNodeObjectInfo>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_PARTICLE_INFO)
|
||||
svm_node_particle_info(kg, sd, stack, svm_node_get<SVMNodeParticleInfo>(kg, &offset));
|
||||
break;
|
||||
#if defined(__HAIR__)
|
||||
SVM_CASE(NODE_HAIR_INFO)
|
||||
svm_node_hair_info(kg, sd, stack, svm_node_get<SVMNodeHairInfo>(kg, &offset));
|
||||
break;
|
||||
#endif
|
||||
#if defined(__POINTCLOUD__)
|
||||
SVM_CASE(NODE_POINT_INFO)
|
||||
svm_node_point_info(kg, sd, stack, svm_node_get<SVMNodePointInfo>(kg, &offset));
|
||||
break;
|
||||
#endif
|
||||
SVM_CASE(NODE_TEXTURE_MAPPING)
|
||||
svm_node_texture_mapping<float3>(stack, svm_node_get<SVMNodeTextureMapping>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEXTURE_MAPPING_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_texture_mapping<dual3>(stack, svm_node_get<SVMNodeTextureMapping>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_MAPPING)
|
||||
svm_node_mapping<float3>(stack, svm_node_get<SVMNodeMapping>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_MAPPING_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_mapping<dual3>(stack, svm_node_get<SVMNodeMapping>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_MIN_MAX)
|
||||
svm_node_min_max(stack, svm_node_get<SVMNodeMinMax>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CAMERA)
|
||||
svm_node_camera(kg, sd, stack, svm_node_get<SVMNodeCamera>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_ENVIRONMENT)
|
||||
svm_node_tex_environment<float3>(
|
||||
kg, sd, stack, svm_node_get<SVMNodeTexEnvironment>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_ENVIRONMENT_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_tex_environment<dual3>(
|
||||
kg, sd, stack, svm_node_get<SVMNodeTexEnvironment>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_SKY)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeTexSky>(kg, &offset);
|
||||
offset = svm_node_tex_sky(kg, sd, path_flag, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_GRADIENT)
|
||||
svm_node_tex_gradient(stack, svm_node_get<SVMNodeTexGradient>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_VORONOI)
|
||||
svm_node_tex_voronoi<node_feature_mask>(stack, svm_node_get<SVMNodeTexVoronoi>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_GABOR)
|
||||
svm_node_tex_gabor(stack, svm_node_get<SVMNodeTexGabor>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_WAVE)
|
||||
svm_node_tex_wave(stack, svm_node_get<SVMNodeTexWave>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_MAGIC)
|
||||
svm_node_tex_magic(stack, svm_node_get<SVMNodeTexMagic>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_CHECKER)
|
||||
svm_node_tex_checker(stack, svm_node_get<SVMNodeTexChecker>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_BRICK)
|
||||
svm_node_tex_brick(stack, svm_node_get<SVMNodeTexBrick>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TEX_WHITE_NOISE)
|
||||
svm_node_tex_white_noise(stack, svm_node_get<SVMNodeTexWhiteNoise>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_NORMAL)
|
||||
svm_node_normal(stack, svm_node_get<SVMNodeNormal>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_LIGHT_FALLOFF)
|
||||
svm_node_light_falloff(sd, stack, svm_node_get<SVMNodeLightFalloff>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_IES)
|
||||
svm_node_ies(kg, sd, stack, svm_node_get<SVMNodeIES>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CURVES)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeCurves>(kg, &offset);
|
||||
offset = svm_node_curves(kg, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_TANGENT)
|
||||
svm_node_tangent<float3>(kg, sd, stack, svm_node_get<SVMNodeTangent>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_TANGENT_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_tangent<dual3>(kg, sd, stack, svm_node_get<SVMNodeTangent>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_NORMAL_MAP)
|
||||
svm_node_normal_map(kg, sd, stack, svm_node_get<SVMNodeNormalMap>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_RADIAL_TILING)
|
||||
svm_node_radial_tiling<node_feature_mask>(stack,
|
||||
svm_node_get<SVMNodeRadialTiling>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_INVERT)
|
||||
svm_node_invert(stack, svm_node_get<SVMNodeInvert>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_MIX)
|
||||
svm_node_mix(stack, svm_node_get<SVMNodeMix>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_SEPARATE_COLOR)
|
||||
svm_node_separate_color(stack, svm_node_get<SVMNodeSeparateColor>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_COMBINE_COLOR)
|
||||
svm_node_combine_color(stack, svm_node_get<SVMNodeCombineColor>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_SEPARATE_VECTOR)
|
||||
svm_node_separate_vector<float3>(stack, svm_node_get<SVMNodeSeparateVector>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_SEPARATE_VECTOR_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_separate_vector<dual3>(stack, svm_node_get<SVMNodeSeparateVector>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_COMBINE_VECTOR)
|
||||
svm_node_combine_vector<float3>(stack, svm_node_get<SVMNodeCombineVector>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_COMBINE_VECTOR_DERIVATIVE)
|
||||
IF_NOT_KERNEL_NODES_FEATURE(VOLUME)
|
||||
{
|
||||
svm_node_combine_vector<dual3>(stack, svm_node_get<SVMNodeCombineVector>(kg, &offset));
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_ROTATE)
|
||||
svm_node_vector_rotate(stack, svm_node_get<SVMNodeVectorRotate>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_TRANSFORM)
|
||||
svm_node_vector_transform(kg, sd, stack, svm_node_get<SVMNodeVectorTransform>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_WIREFRAME)
|
||||
svm_node_wireframe(kg, sd, stack, svm_node_get<SVMNodeWireframe>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_WAVELENGTH)
|
||||
svm_node_wavelength(kg, stack, svm_node_get<SVMNodeWavelength>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_BLACKBODY)
|
||||
svm_node_blackbody(kg, stack, svm_node_get<SVMNodeBlackbody>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_MAP_RANGE)
|
||||
svm_node_map_range(stack, svm_node_get<SVMNodeMapRange>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_VECTOR_MAP_RANGE)
|
||||
svm_node_vector_map_range(stack, svm_node_get<SVMNodeVectorMapRange>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_CLAMP)
|
||||
svm_node_clamp(stack, svm_node_get<SVMNodeClamp>(kg, &offset));
|
||||
break;
|
||||
#ifdef __SHADER_RAYTRACE__
|
||||
SVM_CASE(NODE_BEVEL)
|
||||
svm_node_bevel<node_feature_mask>(
|
||||
kg, state, sd, stack, svm_node_get<SVMNodeBevel>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_AMBIENT_OCCLUSION)
|
||||
svm_node_ao<node_feature_mask>(
|
||||
kg, state, sd, stack, svm_node_get<SVMNodeAmbientOcclusion>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_RAYCAST)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeRaycast>(kg, &offset);
|
||||
offset = svm_node_raycast<node_feature_mask>(kg, state, sd, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
SVM_CASE(NODE_AOV_START)
|
||||
if (!svm_node_aov_check(path_flag, render_buffer)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_AOV_COLOR)
|
||||
svm_node_aov_color<node_feature_mask>(
|
||||
kg, sd, state, stack, svm_node_get<SVMNodeAOVColor>(kg, &offset), render_buffer);
|
||||
break;
|
||||
SVM_CASE(NODE_AOV_VALUE)
|
||||
svm_node_aov_value<node_feature_mask>(
|
||||
kg, sd, state, stack, svm_node_get<SVMNodeAOVValue>(kg, &offset), render_buffer);
|
||||
break;
|
||||
SVM_CASE(NODE_FLOAT_CURVE)
|
||||
{
|
||||
const ccl_global auto &node = svm_node_get<SVMNodeFloatCurve>(kg, &offset);
|
||||
offset = svm_node_curve(kg, stack, node, offset);
|
||||
}
|
||||
break;
|
||||
SVM_CASE(NODE_MIX_COLOR)
|
||||
svm_node_mix_color(stack, svm_node_get<SVMNodeMixColor>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_MIX_FLOAT)
|
||||
svm_node_mix_float(stack, svm_node_get<SVMNodeMixFloat>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_MIX_VECTOR)
|
||||
svm_node_mix_vector(stack, svm_node_get<SVMNodeMixVector>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_MIX_VECTOR_NON_UNIFORM)
|
||||
svm_node_mix_vector_non_uniform(stack,
|
||||
svm_node_get<SVMNodeMixVectorNonUniform>(kg, &offset));
|
||||
break;
|
||||
SVM_CASE(NODE_SCENE_TIME)
|
||||
svm_node_scene_time(kg, stack, svm_node_get<SVMNodeSceneTime>(kg, &offset));
|
||||
break;
|
||||
default:
|
||||
kernel_assert(!"Unknown node type was passed to the SVM machine");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
419
blender-5.2.0/intern/cycles/kernel/svm/tex_coord.h
Normal file
419
blender-5.2.0/intern/cycles/kernel/svm/tex_coord.h
Normal file
@@ -0,0 +1,419 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/camera/camera.h"
|
||||
|
||||
#include "kernel/geom/motion_triangle.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/primitive.h"
|
||||
|
||||
#include "kernel/svm/attribute.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
#include "util/math_base.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Smooth normal with screen-space derivatives for texture coordinate use.
|
||||
* Returns the interpolated normal in object space, with dx/dy representing
|
||||
* the per-pixel change from ray differentials. */
|
||||
ccl_device_inline dual3 svm_texco_smooth_normal(KernelGlobals kg, const ccl_private ShaderData *sd)
|
||||
{
|
||||
if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
|
||||
float3 N_x, N_y;
|
||||
float3 N;
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
N = triangle_smooth_normal(kg,
|
||||
sd->Ng,
|
||||
sd->object,
|
||||
sd->object_flag,
|
||||
sd->prim,
|
||||
sd->u,
|
||||
sd->v,
|
||||
sd->du,
|
||||
sd->dv,
|
||||
N_x,
|
||||
N_y);
|
||||
}
|
||||
else {
|
||||
N = motion_triangle_smooth_normal(
|
||||
kg, sd->Ng, sd->object, sd->prim, sd->time, sd->u, sd->v, sd->du, sd->dv, N_x, N_y);
|
||||
}
|
||||
if (sd->flag & SD_BACKFACING) {
|
||||
N = -N;
|
||||
N_x = -N_x;
|
||||
N_y = -N_y;
|
||||
}
|
||||
if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
|
||||
object_inverse_normal_transform(kg, sd, &N);
|
||||
object_inverse_normal_transform(kg, sd, &N_x);
|
||||
object_inverse_normal_transform(kg, sd, &N_y);
|
||||
}
|
||||
return dual3(N, N_x - N, N_y - N);
|
||||
}
|
||||
|
||||
/* Flat normal or non-triangle: no derivative. */
|
||||
float3 N = sd->N;
|
||||
object_inverse_normal_transform(kg, sd, &N);
|
||||
return dual3(N);
|
||||
}
|
||||
|
||||
/* Texture Coordinate Node */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline Float3Type svm_texco_reflection(const ccl_private ShaderData *sd)
|
||||
{
|
||||
Float3Type data = shading_incoming<Float3Type>(sd);
|
||||
if (sd->object != OBJECT_NONE) {
|
||||
data = -reflect(data, sd->N);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline Float3Type svm_texco_camera(KernelGlobals kg,
|
||||
const ccl_private ShaderData *sd,
|
||||
const ccl_private Float3Type &P)
|
||||
{
|
||||
Float3Type data(P);
|
||||
const Transform tfm = kernel_data.cam.worldtocamera;
|
||||
if (sd->object == OBJECT_NONE) {
|
||||
data = data + camera_position(kg);
|
||||
}
|
||||
data = transform_point(&tfm, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_noinline Float3Type svm_node_tex_coord_eval(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const PathRayVisibility path_visibility,
|
||||
const NodeTexCoord type,
|
||||
ccl_private int *offset)
|
||||
{
|
||||
Float3Type data;
|
||||
|
||||
switch (type) {
|
||||
case NODE_TEXCO_OBJECT:
|
||||
case NODE_TEXCO_OBJECT_WITH_TRANSFORM: {
|
||||
data = shading_position<Float3Type>(sd);
|
||||
if (type == NODE_TEXCO_OBJECT) {
|
||||
object_inverse_position_transform_if_object(kg, sd, &data);
|
||||
}
|
||||
else {
|
||||
const Transform tfm = make_transform(svm_node_get<PackedTransform>(kg, offset));
|
||||
data = transform_point(&tfm, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_NORMAL: {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
data = svm_texco_smooth_normal(kg, sd);
|
||||
}
|
||||
else {
|
||||
data = sd->N;
|
||||
object_inverse_normal_transform(kg, sd, &data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_CAMERA: {
|
||||
const Float3Type P = shading_position<Float3Type>(sd);
|
||||
data = svm_texco_camera<Float3Type>(kg, sd, P);
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_WINDOW: {
|
||||
if ((path_visibility & PATH_RAY_VISIBILITY_CAMERA) && sd->object == OBJECT_NONE &&
|
||||
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
|
||||
{
|
||||
data = Float3Type(camera_world_to_ndc(kg, sd, sd->ray_P));
|
||||
}
|
||||
else {
|
||||
data = Float3Type(camera_world_to_ndc(kg, sd, sd->P));
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
data.dx.x = 1.0f / kernel_data.cam.width;
|
||||
data.dy.y = 1.0f / kernel_data.cam.height;
|
||||
}
|
||||
}
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
data.val.z = 0.0f;
|
||||
}
|
||||
else {
|
||||
data.z = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_REFLECTION: {
|
||||
data = svm_texco_reflection<Float3Type>(sd);
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_DUPLI_GENERATED: {
|
||||
data = Float3Type(object_dupli_generated(kg, sd->object));
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_DUPLI_UV: {
|
||||
data = Float3Type(object_dupli_uv(kg, sd->object));
|
||||
break;
|
||||
}
|
||||
case NODE_TEXCO_VOLUME_GENERATED: {
|
||||
data = shading_position<Float3Type>(sd);
|
||||
|
||||
#ifdef __VOLUME__
|
||||
if (sd->object != OBJECT_NONE) {
|
||||
data = volume_normalized_position<Float3Type>(kg, sd, data);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
data = make_zero<Float3Type>();
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ccl_device_noinline int svm_node_tex_coord(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const PathRayVisibility path_visibility,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexCoord &ccl_restrict node,
|
||||
int offset)
|
||||
{
|
||||
const float3 data = svm_node_tex_coord_eval<float3>(
|
||||
kg, sd, path_visibility, node.texco_type, &offset);
|
||||
stack_store(stack, node.out_offset, data);
|
||||
return offset;
|
||||
}
|
||||
|
||||
ccl_device_noinline int svm_node_tex_coord_derivative(
|
||||
KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const PathRayVisibility path_visibility,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexCoord &ccl_restrict node,
|
||||
int offset)
|
||||
{
|
||||
dual3 data = svm_node_tex_coord_eval<dual3>(kg, sd, path_visibility, node.texco_type, &offset);
|
||||
if (node.bump_offset == NODE_BUMP_OFFSET_DX) {
|
||||
data.val += data.dx * node.bump_filter_width;
|
||||
}
|
||||
else if (node.bump_offset == NODE_BUMP_OFFSET_DY) {
|
||||
data.val += data.dy * node.bump_filter_width;
|
||||
}
|
||||
/* Normal texture coordinate must be normalized after bump offset, matching OSL. */
|
||||
if (node.texco_type == NODE_TEXCO_NORMAL) {
|
||||
data = safe_normalize(data);
|
||||
}
|
||||
if (node.store_derivatives) {
|
||||
stack_store(stack, node.out_offset, data);
|
||||
}
|
||||
else {
|
||||
stack_store(stack, node.out_offset, data.val);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeNormalMap &ccl_restrict node)
|
||||
{
|
||||
float3 color = stack_load(stack, node.color);
|
||||
color = 2.0f * make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
|
||||
|
||||
if (node.invert_green) {
|
||||
color.y = -color.y;
|
||||
}
|
||||
|
||||
const bool is_backfacing = (sd->flag & SD_BACKFACING) != 0;
|
||||
float3 N;
|
||||
float strength = stack_load(stack, node.strength);
|
||||
bool linear_interpolate_strength = false;
|
||||
|
||||
if (node.space == NODE_NORMAL_MAP_TANGENT) {
|
||||
/* tangent space */
|
||||
if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_TRIANGLE) == 0) {
|
||||
/* Fall back to unperturbed normal. */
|
||||
stack_store_float3(stack, node.normal_offset, sd->N);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first try to get tangent attribute */
|
||||
const AttributeDescriptor attr = find_attribute(kg, sd, node.attr);
|
||||
const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.attr_sign);
|
||||
|
||||
if (!is_attribute_found(attr) || !is_attribute_found(attr_sign)) {
|
||||
/* Fall back to unperturbed normal. */
|
||||
stack_store_float3(stack, node.normal_offset, sd->N);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get _unnormalized_ interpolated normal and tangent */
|
||||
const float3 tangent = primitive_surface_attribute<float3>(kg, sd, attr);
|
||||
const float sign = primitive_surface_attribute<float>(kg, sd, attr_sign);
|
||||
float3 normal;
|
||||
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
const AttributeDescriptor attr_undisplaced_normal =
|
||||
(node.use_original_base) ?
|
||||
find_attribute(kg, sd->object, sd->prim, ATTR_STD_NORMAL_UNDISPLACED) :
|
||||
attribute_not_found();
|
||||
if (is_attribute_found(attr_undisplaced_normal)) {
|
||||
normal = primitive_surface_attribute<float3>(kg, sd, attr_undisplaced_normal);
|
||||
/* Can't interpolate in tangent space as the displaced normal is not used
|
||||
* for the tangent frame. */
|
||||
linear_interpolate_strength = true;
|
||||
}
|
||||
else {
|
||||
normal = triangle_smooth_normal_unnormalized_object_space(kg, sd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
normal = sd->Ng;
|
||||
|
||||
/* the normal is already inverted, which is too soon for the math here */
|
||||
if (is_backfacing) {
|
||||
normal = -normal;
|
||||
}
|
||||
|
||||
object_inverse_normal_transform(kg, sd, &normal);
|
||||
}
|
||||
/* Apply strength in the tangent case. */
|
||||
if (!linear_interpolate_strength) {
|
||||
color.x *= strength;
|
||||
color.y *= strength;
|
||||
color.z = mix(1.0f, color.z, saturatef(strength));
|
||||
}
|
||||
|
||||
/* apply normal map */
|
||||
const float3 B = sign * cross(normal, tangent);
|
||||
N = safe_normalize(to_global(color, tangent, B, normal));
|
||||
|
||||
/* transform to world space */
|
||||
object_normal_transform(kg, sd, &N);
|
||||
|
||||
/* invert normal for backfacing polygons */
|
||||
if (is_backfacing) {
|
||||
N = -N;
|
||||
}
|
||||
}
|
||||
else {
|
||||
linear_interpolate_strength = true;
|
||||
|
||||
/* strange blender convention */
|
||||
if (node.space == NODE_NORMAL_MAP_BLENDER_OBJECT ||
|
||||
node.space == NODE_NORMAL_MAP_BLENDER_WORLD)
|
||||
{
|
||||
color.y = -color.y;
|
||||
color.z = -color.z;
|
||||
}
|
||||
|
||||
/* object, world space */
|
||||
N = color;
|
||||
|
||||
if (node.space == NODE_NORMAL_MAP_OBJECT || node.space == NODE_NORMAL_MAP_BLENDER_OBJECT) {
|
||||
object_normal_transform(kg, sd, &N);
|
||||
}
|
||||
else {
|
||||
N = safe_normalize(N);
|
||||
}
|
||||
|
||||
/* invert normal for backfacing polygons */
|
||||
if (is_backfacing) {
|
||||
N = -N;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use simple linear interpolation if we can't do it in tangent space. */
|
||||
if (linear_interpolate_strength && strength != 1.0f) {
|
||||
strength = max(strength, 0.0f);
|
||||
N = safe_normalize(sd->N + (N - sd->N) * strength);
|
||||
}
|
||||
|
||||
if (is_zero(N) || !isfinite_safe(N)) {
|
||||
N = sd->N;
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.normal_offset, N);
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_noinline void svm_node_tangent(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeTangent &ccl_restrict node)
|
||||
{
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, node.attr);
|
||||
|
||||
Float3Type tangent;
|
||||
if (node.direction_type == NODE_TANGENT_UVMAP) {
|
||||
/* UV map */
|
||||
if (!is_attribute_found(desc)) {
|
||||
stack_store(stack, node.tangent_offset, Float3Type());
|
||||
return;
|
||||
}
|
||||
if (desc.type == NODE_ATTR_FLOAT2) {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
tangent = make_float3(primitive_surface_attribute<dual2>(kg, sd, desc));
|
||||
}
|
||||
else {
|
||||
tangent = make_float3(primitive_surface_attribute<float2>(kg, sd, desc));
|
||||
}
|
||||
}
|
||||
else {
|
||||
tangent = primitive_surface_attribute<Float3Type>(kg, sd, desc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* radial */
|
||||
Float3Type generated;
|
||||
if (!is_attribute_found(desc)) {
|
||||
generated = shading_position<Float3Type>(sd);
|
||||
}
|
||||
else if (desc.type == NODE_ATTR_FLOAT2) {
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
generated = make_float3(primitive_surface_attribute<dual2>(kg, sd, desc));
|
||||
}
|
||||
else {
|
||||
generated = make_float3(primitive_surface_attribute<float2>(kg, sd, desc));
|
||||
}
|
||||
}
|
||||
else {
|
||||
generated = primitive_surface_attribute<Float3Type>(kg, sd, desc);
|
||||
}
|
||||
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
using FloatType = dual_scalar_t<Float3Type>;
|
||||
if (node.axis == NODE_TANGENT_AXIS_X) {
|
||||
tangent = make_float3(FloatType(), -(generated.z() - 0.5f), (generated.y() - 0.5f));
|
||||
}
|
||||
else if (node.axis == NODE_TANGENT_AXIS_Y) {
|
||||
tangent = make_float3(-(generated.z() - 0.5f), FloatType(), (generated.x() - 0.5f));
|
||||
}
|
||||
else {
|
||||
tangent = make_float3(-(generated.y() - 0.5f), (generated.x() - 0.5f), FloatType());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node.axis == NODE_TANGENT_AXIS_X) {
|
||||
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
|
||||
}
|
||||
else if (node.axis == NODE_TANGENT_AXIS_Y) {
|
||||
tangent = make_float3(-(generated.z - 0.5f), 0.0f, (generated.x - 0.5f));
|
||||
}
|
||||
else {
|
||||
tangent = make_float3(-(generated.y - 0.5f), (generated.x - 0.5f), 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object_normal_transform(kg, sd, &tangent);
|
||||
tangent = cross(sd->N, normalize(cross(tangent, sd->N)));
|
||||
stack_store(stack, node.tangent_offset, tangent);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
579
blender-5.2.0/intern/cycles/kernel/svm/types.h
Normal file
579
blender-5.2.0/intern/cycles/kernel/svm/types.h
Normal file
@@ -0,0 +1,579 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/transform.h"
|
||||
#include "util/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Stack */
|
||||
|
||||
/* Stack offset type. Stack offsets are in the range [0, SVM_STACK_SIZE]. */
|
||||
using SVMStackOffset = uint8_t;
|
||||
|
||||
/* Store int value and stack offset. */
|
||||
struct SVMInputInt {
|
||||
int value;
|
||||
SVMStackOffset offset;
|
||||
uint8_t _pad[3];
|
||||
};
|
||||
|
||||
/* Encodes a node float input, as either float value or a stack offset
|
||||
* encoded in a NaN bit pattern. */
|
||||
struct SVMInputFloat {
|
||||
uint bits;
|
||||
};
|
||||
|
||||
/* Encodes a node float input, as either float3 value or a stack offset
|
||||
* encoded in a NaN bit pattern in the x component. */
|
||||
struct SVMInputFloat3 {
|
||||
SVMInputFloat x, y, z;
|
||||
};
|
||||
|
||||
/* Bit mask for encoding stack offset as NaN. */
|
||||
#define SVM_INPUT_STACK_OFFSET_MASK 0x7FC00000u
|
||||
|
||||
// NOLINTBEGIN
|
||||
/* SVM stack has a fixed size */
|
||||
#define SVM_STACK_SIZE 255
|
||||
/* SVM stack offsets with this value indicate that it's not on the stack */
|
||||
#define SVM_STACK_INVALID SVMStackOffset(255)
|
||||
|
||||
#define SVM_BUMP_EVAL_STATE_SIZE 10
|
||||
// NOLINTEND
|
||||
|
||||
/* Nodes */
|
||||
|
||||
enum ShaderNodeType : uint {
|
||||
#define SHADER_NODE_TYPE(name) name,
|
||||
#define SHADER_NODE_TYPE_DERIVATIVE(name) name, name##_DERIVATIVE,
|
||||
#include "node_types_template.h"
|
||||
|
||||
NODE_NUM
|
||||
};
|
||||
|
||||
enum NodeAttributeOutputType : uint8_t {
|
||||
NODE_ATTR_OUTPUT_FLOAT3 = 0,
|
||||
NODE_ATTR_OUTPUT_FLOAT,
|
||||
NODE_ATTR_OUTPUT_FLOAT_ALPHA,
|
||||
};
|
||||
|
||||
enum NodeAttributeType : uint8_t {
|
||||
NODE_ATTR_FLOAT = 0,
|
||||
NODE_ATTR_FLOAT2,
|
||||
NODE_ATTR_FLOAT3,
|
||||
NODE_ATTR_FLOAT4,
|
||||
NODE_ATTR_RGBA,
|
||||
NODE_ATTR_MATRIX
|
||||
};
|
||||
|
||||
enum NodeGeometry : uint8_t {
|
||||
NODE_GEOM_P = 0,
|
||||
NODE_GEOM_N,
|
||||
NODE_GEOM_T,
|
||||
NODE_GEOM_I,
|
||||
NODE_GEOM_Ng,
|
||||
NODE_GEOM_uv
|
||||
};
|
||||
|
||||
enum NodeObjectInfo : uint {
|
||||
NODE_INFO_OB_LOCATION,
|
||||
NODE_INFO_OB_COLOR,
|
||||
NODE_INFO_OB_ALPHA,
|
||||
NODE_INFO_OB_INDEX,
|
||||
NODE_INFO_MAT_INDEX,
|
||||
NODE_INFO_OB_RANDOM
|
||||
};
|
||||
|
||||
enum NodeParticleInfo : uint {
|
||||
NODE_INFO_PAR_INDEX,
|
||||
NODE_INFO_PAR_RANDOM,
|
||||
NODE_INFO_PAR_AGE,
|
||||
NODE_INFO_PAR_LIFETIME,
|
||||
NODE_INFO_PAR_LOCATION,
|
||||
// NODE_INFO_PAR_ROTATION,
|
||||
NODE_INFO_PAR_SIZE,
|
||||
NODE_INFO_PAR_VELOCITY,
|
||||
NODE_INFO_PAR_ANGULAR_VELOCITY
|
||||
};
|
||||
|
||||
enum NodeHairInfo : uint {
|
||||
NODE_INFO_CURVE_IS_STRAND,
|
||||
NODE_INFO_CURVE_INTERCEPT,
|
||||
NODE_INFO_CURVE_LENGTH,
|
||||
NODE_INFO_CURVE_THICKNESS,
|
||||
NODE_INFO_CURVE_TANGENT_NORMAL,
|
||||
NODE_INFO_CURVE_RANDOM,
|
||||
};
|
||||
|
||||
enum NodePointInfo : uint {
|
||||
NODE_INFO_POINT_POSITION,
|
||||
NODE_INFO_POINT_RADIUS,
|
||||
NODE_INFO_POINT_RANDOM,
|
||||
};
|
||||
|
||||
enum NodeLightPath : uint {
|
||||
NODE_LP_camera = 0,
|
||||
NODE_LP_shadow,
|
||||
NODE_LP_diffuse,
|
||||
NODE_LP_glossy,
|
||||
NODE_LP_singular,
|
||||
NODE_LP_reflection,
|
||||
NODE_LP_transmission,
|
||||
NODE_LP_volume_scatter,
|
||||
NODE_LP_backfacing,
|
||||
NODE_LP_ray_length,
|
||||
NODE_LP_ray_depth,
|
||||
NODE_LP_ray_diffuse,
|
||||
NODE_LP_ray_glossy,
|
||||
NODE_LP_ray_transparent,
|
||||
NODE_LP_ray_transmission,
|
||||
NODE_LP_ray_portal,
|
||||
};
|
||||
|
||||
enum NodeLightFalloff : uint {
|
||||
NODE_LIGHT_FALLOFF_QUADRATIC,
|
||||
NODE_LIGHT_FALLOFF_LINEAR,
|
||||
NODE_LIGHT_FALLOFF_CONSTANT
|
||||
};
|
||||
|
||||
enum NodeTexCoord : uint8_t {
|
||||
NODE_TEXCO_NORMAL,
|
||||
NODE_TEXCO_OBJECT,
|
||||
NODE_TEXCO_OBJECT_WITH_TRANSFORM,
|
||||
NODE_TEXCO_CAMERA,
|
||||
NODE_TEXCO_WINDOW,
|
||||
NODE_TEXCO_REFLECTION,
|
||||
NODE_TEXCO_DUPLI_GENERATED,
|
||||
NODE_TEXCO_DUPLI_UV,
|
||||
NODE_TEXCO_VOLUME_GENERATED
|
||||
};
|
||||
|
||||
enum NodeMix : uint {
|
||||
NODE_MIX_BLEND = 0,
|
||||
NODE_MIX_ADD,
|
||||
NODE_MIX_MUL,
|
||||
NODE_MIX_SUB,
|
||||
NODE_MIX_SCREEN,
|
||||
NODE_MIX_DIV,
|
||||
NODE_MIX_DIFF,
|
||||
NODE_MIX_DARK,
|
||||
NODE_MIX_LIGHT,
|
||||
NODE_MIX_OVERLAY,
|
||||
NODE_MIX_DODGE,
|
||||
NODE_MIX_BURN,
|
||||
NODE_MIX_HUE,
|
||||
NODE_MIX_SAT,
|
||||
NODE_MIX_VAL,
|
||||
NODE_MIX_COL,
|
||||
NODE_MIX_SOFT,
|
||||
NODE_MIX_LINEAR,
|
||||
NODE_MIX_EXCLUSION,
|
||||
NODE_MIX_CLAMP /* used for the clamp UI option */
|
||||
};
|
||||
|
||||
enum NodeMathType : uint {
|
||||
NODE_MATH_ADD,
|
||||
NODE_MATH_SUBTRACT,
|
||||
NODE_MATH_MULTIPLY,
|
||||
NODE_MATH_DIVIDE,
|
||||
NODE_MATH_SINE,
|
||||
NODE_MATH_COSINE,
|
||||
NODE_MATH_TANGENT,
|
||||
NODE_MATH_ARCSINE,
|
||||
NODE_MATH_ARCCOSINE,
|
||||
NODE_MATH_ARCTANGENT,
|
||||
NODE_MATH_POWER,
|
||||
NODE_MATH_LOGARITHM,
|
||||
NODE_MATH_MINIMUM,
|
||||
NODE_MATH_MAXIMUM,
|
||||
NODE_MATH_ROUND,
|
||||
NODE_MATH_LESS_THAN,
|
||||
NODE_MATH_GREATER_THAN,
|
||||
NODE_MATH_MODULO,
|
||||
NODE_MATH_ABSOLUTE,
|
||||
NODE_MATH_ARCTAN2,
|
||||
NODE_MATH_FLOOR,
|
||||
NODE_MATH_CEIL,
|
||||
NODE_MATH_FRACTION,
|
||||
NODE_MATH_SQRT,
|
||||
NODE_MATH_INV_SQRT,
|
||||
NODE_MATH_SIGN,
|
||||
NODE_MATH_EXPONENT,
|
||||
NODE_MATH_RADIANS,
|
||||
NODE_MATH_DEGREES,
|
||||
NODE_MATH_SINH,
|
||||
NODE_MATH_COSH,
|
||||
NODE_MATH_TANH,
|
||||
NODE_MATH_TRUNC,
|
||||
NODE_MATH_SNAP,
|
||||
NODE_MATH_WRAP,
|
||||
NODE_MATH_COMPARE,
|
||||
NODE_MATH_MULTIPLY_ADD,
|
||||
NODE_MATH_PINGPONG,
|
||||
NODE_MATH_SMOOTH_MIN,
|
||||
NODE_MATH_SMOOTH_MAX,
|
||||
NODE_MATH_FLOORED_MODULO,
|
||||
};
|
||||
|
||||
enum NodeVectorMathType : uint {
|
||||
NODE_VECTOR_MATH_ADD,
|
||||
NODE_VECTOR_MATH_SUBTRACT,
|
||||
NODE_VECTOR_MATH_MULTIPLY,
|
||||
NODE_VECTOR_MATH_DIVIDE,
|
||||
|
||||
NODE_VECTOR_MATH_CROSS_PRODUCT,
|
||||
NODE_VECTOR_MATH_PROJECT,
|
||||
NODE_VECTOR_MATH_REFLECT,
|
||||
NODE_VECTOR_MATH_DOT_PRODUCT,
|
||||
|
||||
NODE_VECTOR_MATH_DISTANCE,
|
||||
NODE_VECTOR_MATH_LENGTH,
|
||||
NODE_VECTOR_MATH_SCALE,
|
||||
NODE_VECTOR_MATH_NORMALIZE,
|
||||
|
||||
NODE_VECTOR_MATH_SNAP,
|
||||
NODE_VECTOR_MATH_FLOOR,
|
||||
NODE_VECTOR_MATH_CEIL,
|
||||
NODE_VECTOR_MATH_MODULO,
|
||||
NODE_VECTOR_MATH_FRACTION,
|
||||
NODE_VECTOR_MATH_ABSOLUTE,
|
||||
NODE_VECTOR_MATH_MINIMUM,
|
||||
NODE_VECTOR_MATH_MAXIMUM,
|
||||
NODE_VECTOR_MATH_WRAP,
|
||||
NODE_VECTOR_MATH_SINE,
|
||||
NODE_VECTOR_MATH_COSINE,
|
||||
NODE_VECTOR_MATH_TANGENT,
|
||||
NODE_VECTOR_MATH_REFRACT,
|
||||
NODE_VECTOR_MATH_FACEFORWARD,
|
||||
NODE_VECTOR_MATH_MULTIPLY_ADD,
|
||||
NODE_VECTOR_MATH_POWER,
|
||||
NODE_VECTOR_MATH_SIGN,
|
||||
NODE_VECTOR_MATH_ROUND,
|
||||
};
|
||||
|
||||
enum NodeClampType : uint {
|
||||
NODE_CLAMP_MINMAX,
|
||||
NODE_CLAMP_RANGE,
|
||||
};
|
||||
|
||||
enum NodeMapRangeType : uint {
|
||||
NODE_MAP_RANGE_LINEAR,
|
||||
NODE_MAP_RANGE_STEPPED,
|
||||
NODE_MAP_RANGE_SMOOTHSTEP,
|
||||
NODE_MAP_RANGE_SMOOTHERSTEP,
|
||||
};
|
||||
|
||||
enum NodeMappingType : uint {
|
||||
NODE_MAPPING_TYPE_POINT,
|
||||
NODE_MAPPING_TYPE_TEXTURE,
|
||||
NODE_MAPPING_TYPE_VECTOR,
|
||||
NODE_MAPPING_TYPE_NORMAL
|
||||
};
|
||||
|
||||
enum NodeVectorRotateType : uint {
|
||||
NODE_VECTOR_ROTATE_TYPE_AXIS,
|
||||
NODE_VECTOR_ROTATE_TYPE_AXIS_X,
|
||||
NODE_VECTOR_ROTATE_TYPE_AXIS_Y,
|
||||
NODE_VECTOR_ROTATE_TYPE_AXIS_Z,
|
||||
NODE_VECTOR_ROTATE_TYPE_EULER_XYZ,
|
||||
};
|
||||
|
||||
enum NodeVectorTransformType : uint {
|
||||
NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
|
||||
NODE_VECTOR_TRANSFORM_TYPE_POINT,
|
||||
NODE_VECTOR_TRANSFORM_TYPE_NORMAL
|
||||
};
|
||||
|
||||
enum NodeVectorTransformConvertSpace : uint {
|
||||
NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD,
|
||||
NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT,
|
||||
NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA
|
||||
};
|
||||
|
||||
enum NodeConvert : uint {
|
||||
NODE_CONVERT_FV,
|
||||
NODE_CONVERT_FI,
|
||||
NODE_CONVERT_CF,
|
||||
NODE_CONVERT_CI,
|
||||
NODE_CONVERT_VF,
|
||||
NODE_CONVERT_VI,
|
||||
NODE_CONVERT_IF,
|
||||
NODE_CONVERT_IV,
|
||||
NODE_CONVERT_NONE,
|
||||
};
|
||||
|
||||
enum NodeNoiseType : uint {
|
||||
NODE_NOISE_MULTIFRACTAL,
|
||||
NODE_NOISE_FBM,
|
||||
NODE_NOISE_HYBRID_MULTIFRACTAL,
|
||||
NODE_NOISE_RIDGED_MULTIFRACTAL,
|
||||
NODE_NOISE_HETERO_TERRAIN
|
||||
};
|
||||
|
||||
enum NodeGaborType : uint {
|
||||
NODE_GABOR_TYPE_2D,
|
||||
NODE_GABOR_TYPE_3D,
|
||||
};
|
||||
|
||||
enum NodeWaveType : uint { NODE_WAVE_BANDS, NODE_WAVE_RINGS };
|
||||
|
||||
enum NodeWaveBandsDirection : uint {
|
||||
NODE_WAVE_BANDS_DIRECTION_X,
|
||||
NODE_WAVE_BANDS_DIRECTION_Y,
|
||||
NODE_WAVE_BANDS_DIRECTION_Z,
|
||||
NODE_WAVE_BANDS_DIRECTION_DIAGONAL
|
||||
};
|
||||
|
||||
enum NodeWaveRingsDirection : uint {
|
||||
NODE_WAVE_RINGS_DIRECTION_X,
|
||||
NODE_WAVE_RINGS_DIRECTION_Y,
|
||||
NODE_WAVE_RINGS_DIRECTION_Z,
|
||||
NODE_WAVE_RINGS_DIRECTION_SPHERICAL
|
||||
};
|
||||
|
||||
enum NodeWaveProfile : uint {
|
||||
NODE_WAVE_PROFILE_SIN,
|
||||
NODE_WAVE_PROFILE_SAW,
|
||||
NODE_WAVE_PROFILE_TRI,
|
||||
};
|
||||
|
||||
enum NodeSkyType : uint {
|
||||
NODE_SKY_PREETHAM,
|
||||
NODE_SKY_HOSEK,
|
||||
NODE_SKY_SINGLE_SCATTERING,
|
||||
NODE_SKY_MULTIPLE_SCATTERING
|
||||
};
|
||||
|
||||
enum NodeGradientType : uint {
|
||||
NODE_BLEND_LINEAR,
|
||||
NODE_BLEND_QUADRATIC,
|
||||
NODE_BLEND_EASING,
|
||||
NODE_BLEND_DIAGONAL,
|
||||
NODE_BLEND_RADIAL,
|
||||
NODE_BLEND_QUADRATIC_SPHERE,
|
||||
NODE_BLEND_SPHERICAL
|
||||
};
|
||||
|
||||
enum NodeVoronoiDistanceMetric : uint {
|
||||
NODE_VORONOI_EUCLIDEAN,
|
||||
NODE_VORONOI_MANHATTAN,
|
||||
NODE_VORONOI_CHEBYCHEV,
|
||||
NODE_VORONOI_MINKOWSKI,
|
||||
};
|
||||
|
||||
enum NodeVoronoiFeature : uint {
|
||||
NODE_VORONOI_F1,
|
||||
NODE_VORONOI_F2,
|
||||
NODE_VORONOI_SMOOTH_F1,
|
||||
NODE_VORONOI_DISTANCE_TO_EDGE,
|
||||
NODE_VORONOI_N_SPHERE_RADIUS,
|
||||
};
|
||||
|
||||
enum NodeBlendWeightType : uint { NODE_LAYER_WEIGHT_FRESNEL, NODE_LAYER_WEIGHT_FACING };
|
||||
|
||||
enum NodeTangentDirectionType : uint { NODE_TANGENT_RADIAL, NODE_TANGENT_UVMAP };
|
||||
|
||||
enum NodeTangentAxis : uint { NODE_TANGENT_AXIS_X, NODE_TANGENT_AXIS_Y, NODE_TANGENT_AXIS_Z };
|
||||
|
||||
enum NodeNormalMapSpace : uint {
|
||||
NODE_NORMAL_MAP_TANGENT,
|
||||
NODE_NORMAL_MAP_OBJECT,
|
||||
NODE_NORMAL_MAP_WORLD,
|
||||
NODE_NORMAL_MAP_BLENDER_OBJECT,
|
||||
NODE_NORMAL_MAP_BLENDER_WORLD,
|
||||
};
|
||||
|
||||
enum NodeNormalMapConvention {
|
||||
NODE_NORMAL_MAP_CONVENTION_OPENGL = 0,
|
||||
NODE_NORMAL_MAP_CONVENTION_DIRECTX = 1,
|
||||
};
|
||||
|
||||
enum NodeNormalMapBase {
|
||||
NODE_NORMAL_MAP_BASE_ORIGINAL = 0,
|
||||
NODE_NORMAL_MAP_BASE_DISPLACED = 1,
|
||||
};
|
||||
|
||||
/* Flags for SVM node encoding, packing space/convention/base into one byte. */
|
||||
enum NodeNormalMapFlags {
|
||||
NODE_NORMAL_MAP_FLAG_SPACE_MASK = 0x7,
|
||||
NODE_NORMAL_MAP_FLAG_DIRECTX = (1 << 3),
|
||||
NODE_NORMAL_MAP_FLAG_ORIGINAL = (1 << 4),
|
||||
};
|
||||
|
||||
enum NodeImageProjection : uint {
|
||||
NODE_IMAGE_PROJ_FLAT = 0,
|
||||
NODE_IMAGE_PROJ_BOX = 1,
|
||||
NODE_IMAGE_PROJ_SPHERE = 2,
|
||||
NODE_IMAGE_PROJ_TUBE = 3,
|
||||
};
|
||||
|
||||
enum NodeImageFlags {
|
||||
NODE_IMAGE_COMPRESS_AS_SRGB = 1,
|
||||
NODE_IMAGE_ALPHA_UNASSOCIATE = 2,
|
||||
};
|
||||
|
||||
enum NodeEnvironmentProjection : uint {
|
||||
NODE_ENVIRONMENT_EQUIRECTANGULAR = 0,
|
||||
NODE_ENVIRONMENT_MIRROR_BALL = 1,
|
||||
};
|
||||
|
||||
enum NodeBumpOffset : uint8_t {
|
||||
NODE_BUMP_OFFSET_CENTER,
|
||||
NODE_BUMP_OFFSET_DX,
|
||||
NODE_BUMP_OFFSET_DY,
|
||||
};
|
||||
|
||||
enum NodeAO {
|
||||
NODE_AO_ONLY_LOCAL = (1 << 0),
|
||||
NODE_AO_INSIDE = (1 << 1),
|
||||
NODE_AO_GLOBAL_RADIUS = (1 << 2),
|
||||
};
|
||||
|
||||
enum ShaderType {
|
||||
SHADER_TYPE_SURFACE,
|
||||
SHADER_TYPE_VOLUME,
|
||||
SHADER_TYPE_DISPLACEMENT,
|
||||
SHADER_TYPE_BUMP,
|
||||
};
|
||||
|
||||
enum NodePrincipledHairModel : uint {
|
||||
NODE_PRINCIPLED_HAIR_CHIANG = 0,
|
||||
NODE_PRINCIPLED_HAIR_HUANG = 1,
|
||||
NODE_PRINCIPLED_HAIR_MODEL_NUM,
|
||||
};
|
||||
|
||||
enum NodePrincipledHairParametrization : uint {
|
||||
NODE_PRINCIPLED_HAIR_REFLECTANCE = 0,
|
||||
NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION = 1,
|
||||
NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION = 2,
|
||||
NODE_PRINCIPLED_HAIR_PARAMETRIZATION_NUM,
|
||||
};
|
||||
|
||||
enum NodeCombSepColorType : uint {
|
||||
NODE_COMBSEP_COLOR_RGB,
|
||||
NODE_COMBSEP_COLOR_HSV,
|
||||
NODE_COMBSEP_COLOR_HSL,
|
||||
};
|
||||
|
||||
/* Closure */
|
||||
|
||||
enum ClosureType : uint {
|
||||
/* Special type, flags generic node as a non-BSDF. */
|
||||
CLOSURE_NONE_ID,
|
||||
|
||||
CLOSURE_BSDF_ID,
|
||||
|
||||
/* Diffuse */
|
||||
CLOSURE_BSDF_DIFFUSE_ID,
|
||||
CLOSURE_BSDF_OREN_NAYAR_ID,
|
||||
CLOSURE_BSDF_ROUGH_TRANSLUCENT_ID,
|
||||
CLOSURE_BSDF_BURLEY_ID,
|
||||
CLOSURE_BSDF_DIFFUSE_RAMP_ID,
|
||||
CLOSURE_BSDF_SHEEN_ID,
|
||||
CLOSURE_BSDF_DIFFUSE_TOON_ID,
|
||||
CLOSURE_BSDF_TRANSLUCENT_ID,
|
||||
|
||||
/* Glossy */
|
||||
CLOSURE_BSDF_PHYSICAL_CONDUCTOR, /* virtual closure */
|
||||
CLOSURE_BSDF_F82_CONDUCTOR, /* virtual closure */
|
||||
CLOSURE_BSDF_MICROFACET_GGX_ID,
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
|
||||
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
|
||||
CLOSURE_BSDF_PHONG_RAMP_ID,
|
||||
CLOSURE_BSDF_GLOSSY_TOON_ID,
|
||||
CLOSURE_BSDF_HAIR_REFLECTION_ID,
|
||||
|
||||
/* Transmission */
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
|
||||
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
|
||||
CLOSURE_BSDF_THIN_GLASS_TRANSMISSION_ID,
|
||||
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
|
||||
|
||||
/* Glass */
|
||||
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */
|
||||
CLOSURE_BSDF_HAIR_CHIANG_ID,
|
||||
CLOSURE_BSDF_HAIR_HUANG_ID,
|
||||
|
||||
/* Special cases */
|
||||
CLOSURE_BSDF_RAY_PORTAL_ID,
|
||||
CLOSURE_BSDF_TRANSPARENT_ID,
|
||||
|
||||
/* BSSRDF */
|
||||
CLOSURE_BSSRDF_BURLEY_ID,
|
||||
CLOSURE_BSSRDF_RANDOM_WALK_ID,
|
||||
CLOSURE_BSSRDF_RANDOM_WALK_LEGACY_ID,
|
||||
CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID,
|
||||
|
||||
/* Other */
|
||||
CLOSURE_HOLDOUT_ID,
|
||||
|
||||
/* Volume */
|
||||
CLOSURE_VOLUME_ID,
|
||||
CLOSURE_VOLUME_ABSORPTION_ID,
|
||||
CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID,
|
||||
CLOSURE_VOLUME_MIE_ID, /* virtual closure */
|
||||
CLOSURE_VOLUME_FOURNIER_FORAND_ID,
|
||||
CLOSURE_VOLUME_RAYLEIGH_ID,
|
||||
CLOSURE_VOLUME_DRAINE_ID,
|
||||
|
||||
CLOSURE_BSDF_PRINCIPLED_ID,
|
||||
|
||||
NBUILTIN_CLOSURES
|
||||
};
|
||||
|
||||
static_assert(NBUILTIN_CLOSURES < 256, "Too many Closure types (need to change SVM packing)");
|
||||
|
||||
/* watch this, being lazy with memory usage */
|
||||
#define CLOSURE_IS_BSDF(type) (type != CLOSURE_NONE_ID && type <= CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
#define CLOSURE_IS_BSDF_DIFFUSE(type) \
|
||||
(type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_TRANSLUCENT_ID)
|
||||
#define CLOSURE_IS_BSDF_GLOSSY(type) \
|
||||
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) || \
|
||||
(type == CLOSURE_BSDF_HAIR_CHIANG_ID) || (type == CLOSURE_BSDF_HAIR_HUANG_ID))
|
||||
#define CLOSURE_IS_BSDF_TRANSMISSION(type) \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
|
||||
type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
|
||||
#define CLOSURE_IS_BSDF_SINGULAR(type) \
|
||||
(type == CLOSURE_BSDF_TRANSPARENT_ID || type == CLOSURE_BSDF_RAY_PORTAL_ID)
|
||||
#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
|
||||
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
|
||||
type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_BSDF_MICROFACET(type) \
|
||||
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
|
||||
type <= CLOSURE_BSDF_THIN_GLASS_TRANSMISSION_ID) || \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
|
||||
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
|
||||
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) \
|
||||
(type != CLOSURE_NONE_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID)
|
||||
#define CLOSURE_IS_BSSRDF(type) \
|
||||
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID)
|
||||
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_DRAINE_ID)
|
||||
#define CLOSURE_IS_VOLUME_SCATTER(type) \
|
||||
(type >= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID && type <= CLOSURE_VOLUME_DRAINE_ID)
|
||||
#define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID)
|
||||
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
|
||||
#define CLOSURE_IS_PHASE(type) \
|
||||
(type >= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID && type <= CLOSURE_VOLUME_DRAINE_ID)
|
||||
#define CLOSURE_IS_REFRACTION(type) \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
|
||||
type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)
|
||||
#define CLOSURE_IS_GLASS(type) \
|
||||
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
|
||||
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
|
||||
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
|
||||
#define CLOSURE_IS_RAY_PORTAL(type) (type == CLOSURE_BSDF_RAY_PORTAL_ID)
|
||||
|
||||
#define CLOSURE_WEIGHT_CUTOFF 1e-5f
|
||||
#define THINFILM_THICKNESS_CUTOFF 0.1f
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
269
blender-5.2.0/intern/cycles/kernel/svm/util.h
Normal file
269
blender-5.2.0/intern/cycles/kernel/svm/util.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/types.h"
|
||||
|
||||
#include "kernel/svm/types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Stack Load */
|
||||
|
||||
ccl_device_inline float stack_load_float(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
kernel_assert(a < SVM_STACK_SIZE);
|
||||
|
||||
return stack[a];
|
||||
}
|
||||
|
||||
ccl_device_inline float stack_load_float_default(const ccl_private float *stack,
|
||||
const uint a,
|
||||
const float value)
|
||||
{
|
||||
return (a == (uint)SVM_STACK_INVALID) ? value : stack_load_float(stack, a);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 stack_load_float3(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
kernel_assert(a + 2 < SVM_STACK_SIZE);
|
||||
|
||||
const ccl_private float *stack_a = stack + a;
|
||||
return make_float3(stack_a[0], stack_a[1], stack_a[2]);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 stack_load_float3_default(const ccl_private float *stack,
|
||||
const uint a,
|
||||
const float3 value)
|
||||
{
|
||||
return (a == (uint)SVM_STACK_INVALID) ? value : stack_load_float3(stack, a);
|
||||
}
|
||||
|
||||
ccl_device_inline int stack_load_int(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
kernel_assert(a < SVM_STACK_SIZE);
|
||||
|
||||
return __float_as_int(stack[a]);
|
||||
}
|
||||
|
||||
/* Type-based stack load. T can be float, float3, dual1, or dual3.
|
||||
* When T is a dual type, derivatives are loaded from adjacent stack slots. */
|
||||
|
||||
template<typename T> ccl_device_inline T stack_load(const ccl_private float *stack, const uint a);
|
||||
|
||||
ccl_device_template_spec float stack_load(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
return stack_load_float(stack, a);
|
||||
}
|
||||
|
||||
ccl_device_template_spec float3 stack_load(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
return stack_load_float3(stack, a);
|
||||
}
|
||||
|
||||
ccl_device_template_spec dual1 stack_load(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
return {
|
||||
stack_load_float(stack, a), stack_load_float(stack, a + 1), stack_load_float(stack, a + 2)};
|
||||
}
|
||||
|
||||
ccl_device_template_spec dual3 stack_load(const ccl_private float *stack, const uint a)
|
||||
{
|
||||
return {stack_load_float3(stack, a),
|
||||
stack_load_float3(stack, a + 3),
|
||||
stack_load_float3(stack, a + 6)};
|
||||
}
|
||||
|
||||
/* Load from SVMInputFloat and SVMInputFloat3. With template versions to support duals
|
||||
* for loading derivatives from adjacent stack slots. */
|
||||
|
||||
ccl_device_inline float stack_load(const ccl_private float *ccl_restrict stack,
|
||||
const SVMInputFloat v)
|
||||
{
|
||||
if ((v.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) {
|
||||
return stack_load_float(stack, v.bits & 0xFFu);
|
||||
}
|
||||
return __uint_as_float(v.bits);
|
||||
}
|
||||
|
||||
ccl_device_inline float3 stack_load(const ccl_private float *ccl_restrict stack,
|
||||
const SVMInputFloat3 v)
|
||||
{
|
||||
if ((v.x.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) {
|
||||
return stack_load_float3(stack, v.x.bits & 0xFFu);
|
||||
}
|
||||
return make_float3(
|
||||
__uint_as_float(v.x.bits), __uint_as_float(v.y.bits), __uint_as_float(v.z.bits));
|
||||
}
|
||||
|
||||
ccl_device_inline int stack_load(const ccl_private float *stack, const SVMInputInt v)
|
||||
{
|
||||
if (v.offset == SVM_STACK_INVALID) {
|
||||
return v.value;
|
||||
}
|
||||
return stack_load_int(stack, v.offset);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ccl_device_inline T stack_load(const ccl_private float *stack, const SVMInputFloat v);
|
||||
|
||||
ccl_device_template_spec float stack_load(const ccl_private float *stack, const SVMInputFloat v)
|
||||
{
|
||||
return stack_load(stack, v);
|
||||
}
|
||||
|
||||
ccl_device_template_spec dual1 stack_load(const ccl_private float *stack, const SVMInputFloat v)
|
||||
{
|
||||
if ((v.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) {
|
||||
return stack_load<dual1>(stack, v.bits & 0xFFu);
|
||||
}
|
||||
return dual1(__uint_as_float(v.bits));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ccl_device_inline T stack_load(const ccl_private float *stack, const SVMInputFloat3 v);
|
||||
|
||||
ccl_device_template_spec float3 stack_load(const ccl_private float *stack, const SVMInputFloat3 v)
|
||||
{
|
||||
return stack_load(stack, v);
|
||||
}
|
||||
|
||||
ccl_device_template_spec dual3 stack_load(const ccl_private float *stack, const SVMInputFloat3 v)
|
||||
{
|
||||
if ((v.x.bits >> 8) == (SVM_INPUT_STACK_OFFSET_MASK >> 8)) {
|
||||
return stack_load<dual3>(stack, v.x.bits & 0xFFu);
|
||||
}
|
||||
return dual3(make_float3(
|
||||
__uint_as_float(v.x.bits), __uint_as_float(v.y.bits), __uint_as_float(v.z.bits)));
|
||||
}
|
||||
|
||||
/* Stack Store */
|
||||
|
||||
ccl_device_inline void stack_store_float(ccl_private float *stack, const uint a, const float f)
|
||||
{
|
||||
kernel_assert(a < SVM_STACK_SIZE);
|
||||
|
||||
stack[a] = f;
|
||||
}
|
||||
|
||||
ccl_device_inline void stack_store_float3(ccl_private float *stack, const uint a, const float3 f)
|
||||
{
|
||||
kernel_assert(a + 2 < SVM_STACK_SIZE);
|
||||
copy_v3_v3(stack + a, f);
|
||||
}
|
||||
|
||||
ccl_device_inline void stack_store_int(ccl_private float *stack, const uint a, const int i)
|
||||
{
|
||||
kernel_assert(a < SVM_STACK_SIZE);
|
||||
|
||||
stack[a] = __int_as_float(i);
|
||||
}
|
||||
|
||||
/* Type-based stack store. Overloaded for plain and dual types.
|
||||
* For dual types, derivatives are stored in adjacent stack slots. */
|
||||
|
||||
ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const float f)
|
||||
{
|
||||
stack_store_float(stack, a, f);
|
||||
}
|
||||
|
||||
ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const float3 f)
|
||||
{
|
||||
stack_store_float3(stack, a, f);
|
||||
}
|
||||
|
||||
ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const dual1 f)
|
||||
{
|
||||
stack_store_float(stack, a, f.val);
|
||||
stack_store_float(stack, a + 1, f.dx);
|
||||
stack_store_float(stack, a + 2, f.dy);
|
||||
}
|
||||
|
||||
ccl_device_inline void stack_store(ccl_private float *stack, const uint a, const dual3 f)
|
||||
{
|
||||
stack_store_float3(stack, a, f.val);
|
||||
stack_store_float3(stack, a + 3, f.dx);
|
||||
stack_store_float3(stack, a + 6, f.dy);
|
||||
}
|
||||
|
||||
/* Stack Utility */
|
||||
|
||||
ccl_device_inline bool stack_valid(const uint a)
|
||||
{
|
||||
return a != (uint)SVM_STACK_INVALID;
|
||||
}
|
||||
|
||||
/* Reading Nodes */
|
||||
|
||||
/* Read a typed node struct directly from the SVM byte-code stream. The struct T must be a
|
||||
* multiple of sizeof(uint) and its memory layout must match the byte-code encoding. Returns
|
||||
* a const reference into the byte-code array and advances the offset past the struct. */
|
||||
template<typename T>
|
||||
ccl_device_inline const ccl_global T &svm_node_get(KernelGlobals kg, ccl_private int *const offset)
|
||||
{
|
||||
static_assert(alignof(T) <= alignof(uint));
|
||||
static_assert(sizeof(T) % sizeof(uint) == 0);
|
||||
const ccl_global T &node = *reinterpret_cast<const ccl_global T *>(
|
||||
&kernel_data_fetch(svm_nodes, *offset));
|
||||
*offset += sizeof(T) / sizeof(uint);
|
||||
return node;
|
||||
}
|
||||
|
||||
ccl_device_inline float4 svm_node_get_data_float4(KernelGlobals kg, const int offset)
|
||||
{
|
||||
return make_float4(__uint_as_float(kernel_data_fetch(svm_nodes, offset)),
|
||||
__uint_as_float(kernel_data_fetch(svm_nodes, offset + 1)),
|
||||
__uint_as_float(kernel_data_fetch(svm_nodes, offset + 2)),
|
||||
__uint_as_float(kernel_data_fetch(svm_nodes, offset + 3)));
|
||||
}
|
||||
|
||||
/* Shading Helpers */
|
||||
|
||||
ccl_device_forceinline float3 dPdx(const ccl_private ShaderData *sd)
|
||||
{
|
||||
return sd->dPdu * sd->du.dx + sd->dPdv * sd->dv.dx;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float3 dPdy(const ccl_private ShaderData *sd)
|
||||
{
|
||||
return sd->dPdu * sd->du.dy + sd->dPdv * sd->dv.dy;
|
||||
}
|
||||
|
||||
/* Shading position, returns Float3Type = float3 (no derivatives) or dual3 (with derivatives). */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline Float3Type shading_position(const ccl_private ShaderData *sd)
|
||||
{
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
dual3 P(sd->P);
|
||||
P.dx = dPdx(sd);
|
||||
P.dy = dPdy(sd);
|
||||
return P;
|
||||
}
|
||||
else {
|
||||
return sd->P;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shading incoming direction, returns Float3Type = float3 or dual3. */
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device_inline Float3Type shading_incoming(const ccl_private ShaderData *sd)
|
||||
{
|
||||
if constexpr (is_dual_v<Float3Type>) {
|
||||
dual3 I(sd->wi);
|
||||
float3 dIdx, dIdy;
|
||||
make_orthonormals(sd->wi, &dIdx, &dIdy);
|
||||
I.dx = sd->dI * dIdx;
|
||||
I.dy = sd->dI * dIdy;
|
||||
return I;
|
||||
}
|
||||
else {
|
||||
return sd->wi;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
30
blender-5.2.0/intern/cycles/kernel/svm/value.h
Normal file
30
blender-5.2.0/intern/cycles/kernel/svm/value.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Value Nodes */
|
||||
|
||||
template<typename FloatType>
|
||||
ccl_device void svm_node_value_f(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeValueF &ccl_restrict node)
|
||||
{
|
||||
/* Derivative of a constant is zero. */
|
||||
stack_store(stack, node.out_offset, FloatType(node.value));
|
||||
}
|
||||
|
||||
template<typename Float3Type>
|
||||
ccl_device void svm_node_value_v(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeValueV &ccl_restrict node)
|
||||
{
|
||||
/* Derivative of a constant is zero. */
|
||||
stack_store(stack, node.out_offset, Float3Type(node.value));
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
65
blender-5.2.0/intern/cycles/kernel/svm/vector_rotate.h
Normal file
65
blender-5.2.0/intern/cycles/kernel/svm/vector_rotate.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Vector Rotate */
|
||||
|
||||
ccl_device_noinline void svm_node_vector_rotate(
|
||||
ccl_private float *ccl_restrict stack, const ccl_global SVMNodeVectorRotate &ccl_restrict node)
|
||||
{
|
||||
if (stack_valid(node.result_offset)) {
|
||||
|
||||
const float3 vector = stack_load(stack, node.vector);
|
||||
const float3 center = stack_load(stack, node.center);
|
||||
float3 result = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if (node.rotate_type == NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
|
||||
const float3 rotation = stack_load(stack, node.rotation); // Default XYZ.
|
||||
const Transform rotationTransform = euler_to_transform(rotation);
|
||||
if (node.invert) {
|
||||
result = transform_direction_transposed(&rotationTransform, vector - center) + center;
|
||||
}
|
||||
else {
|
||||
result = transform_direction(&rotationTransform, vector - center) + center;
|
||||
}
|
||||
}
|
||||
else {
|
||||
float3 axis;
|
||||
float axis_length;
|
||||
switch (node.rotate_type) {
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_X:
|
||||
axis = make_float3(1.0f, 0.0f, 0.0f);
|
||||
axis_length = 1.0f;
|
||||
break;
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
|
||||
axis = make_float3(0.0f, 1.0f, 0.0f);
|
||||
axis_length = 1.0f;
|
||||
break;
|
||||
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
|
||||
axis = make_float3(0.0f, 0.0f, 1.0f);
|
||||
axis_length = 1.0f;
|
||||
break;
|
||||
default:
|
||||
axis = stack_load(stack, node.axis);
|
||||
axis_length = len(axis);
|
||||
break;
|
||||
}
|
||||
float angle = stack_load(stack, node.angle);
|
||||
angle = node.invert ? -angle : angle;
|
||||
result = (axis_length != 0.0f) ?
|
||||
rotate_around_axis(vector - center, axis / axis_length, angle) + center :
|
||||
vector;
|
||||
}
|
||||
|
||||
stack_store_float3(stack, node.result_offset, result);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
123
blender-5.2.0/intern/cycles/kernel/svm/vector_transform.h
Normal file
123
blender-5.2.0/intern/cycles/kernel/svm/vector_transform.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Vector Transform */
|
||||
|
||||
ccl_device_noinline void svm_node_vector_transform(
|
||||
KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeVectorTransform &ccl_restrict node)
|
||||
{
|
||||
float3 in = stack_load(stack, node.vector_in);
|
||||
|
||||
const NodeVectorTransformType type = node.transform_type;
|
||||
const NodeVectorTransformConvertSpace from = node.convert_from;
|
||||
const NodeVectorTransformConvertSpace to = node.convert_to;
|
||||
|
||||
Transform tfm;
|
||||
const bool is_object = (sd->object != OBJECT_NONE);
|
||||
const bool is_normal = (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
|
||||
const bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
|
||||
|
||||
/* From world */
|
||||
if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD) {
|
||||
if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
|
||||
if (is_normal) {
|
||||
tfm = kernel_data.cam.cameratoworld;
|
||||
in = normalize(transform_direction_transposed(&tfm, in));
|
||||
}
|
||||
else {
|
||||
tfm = kernel_data.cam.worldtocamera;
|
||||
in = is_direction ? transform_direction(&tfm, in) : transform_point(&tfm, in);
|
||||
}
|
||||
}
|
||||
else if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
|
||||
if (is_normal) {
|
||||
object_inverse_normal_transform(kg, sd, &in);
|
||||
}
|
||||
else if (is_direction) {
|
||||
object_inverse_dir_transform(kg, sd, &in);
|
||||
}
|
||||
else {
|
||||
object_inverse_position_transform(kg, sd, &in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* From camera */
|
||||
else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
|
||||
if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD ||
|
||||
to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT)
|
||||
{
|
||||
if (is_normal) {
|
||||
tfm = kernel_data.cam.worldtocamera;
|
||||
in = normalize(transform_direction_transposed(&tfm, in));
|
||||
}
|
||||
else {
|
||||
tfm = kernel_data.cam.cameratoworld;
|
||||
in = is_direction ? transform_direction(&tfm, in) : transform_point(&tfm, in);
|
||||
}
|
||||
}
|
||||
if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) {
|
||||
if (is_normal) {
|
||||
object_inverse_normal_transform(kg, sd, &in);
|
||||
}
|
||||
else if (is_direction) {
|
||||
object_inverse_dir_transform(kg, sd, &in);
|
||||
}
|
||||
else {
|
||||
object_inverse_position_transform(kg, sd, &in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* From object */
|
||||
else if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) {
|
||||
if ((to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD ||
|
||||
to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) &&
|
||||
is_object)
|
||||
{
|
||||
if (is_normal) {
|
||||
object_normal_transform(kg, sd, &in);
|
||||
}
|
||||
else if (is_direction) {
|
||||
object_dir_transform(kg, sd, &in);
|
||||
}
|
||||
else {
|
||||
object_position_transform(kg, sd, &in);
|
||||
}
|
||||
}
|
||||
if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) {
|
||||
if (is_normal) {
|
||||
tfm = kernel_data.cam.cameratoworld;
|
||||
in = normalize(transform_direction_transposed(&tfm, in));
|
||||
}
|
||||
else {
|
||||
tfm = kernel_data.cam.worldtocamera;
|
||||
if (is_direction) {
|
||||
in = transform_direction(&tfm, in);
|
||||
}
|
||||
else {
|
||||
in = transform_point(&tfm, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Output */
|
||||
if (stack_valid(node.vector_out_offset)) {
|
||||
stack_store_float3(stack, node.vector_out_offset, in);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
96
blender-5.2.0/intern/cycles/kernel/svm/vertex_color.h
Normal file
96
blender-5.2.0/intern/cycles/kernel/svm/vertex_color.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/geom/attribute.h"
|
||||
#include "kernel/geom/primitive.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
#include "util/math_base.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_vertex_color(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeVertexColor &ccl_restrict
|
||||
node)
|
||||
{
|
||||
float3 color;
|
||||
float alpha;
|
||||
|
||||
const AttributeDescriptor descriptor = find_attribute(kg, sd, node.layer_id);
|
||||
if (is_attribute_found(descriptor)) {
|
||||
if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
|
||||
const float4 vertex_color = primitive_surface_attribute<float4>(kg, sd, descriptor);
|
||||
color = make_float3(vertex_color);
|
||||
alpha = vertex_color.w;
|
||||
}
|
||||
else {
|
||||
color = primitive_surface_attribute<float3>(kg, sd, descriptor);
|
||||
alpha = 1.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
color = make_float3(0.0f, 0.0f, 0.0f);
|
||||
alpha = 0.0f;
|
||||
}
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
if (stack_valid(node.alpha_offset)) {
|
||||
stack_store_float(stack, node.alpha_offset, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_vertex_color_derivative(
|
||||
KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeVertexColor &ccl_restrict node)
|
||||
{
|
||||
float3 color;
|
||||
float alpha;
|
||||
|
||||
const AttributeDescriptor descriptor = find_attribute(kg, sd, node.layer_id);
|
||||
if (is_attribute_found(descriptor)) {
|
||||
if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
|
||||
dual4 vertex_color = primitive_surface_attribute<dual4>(kg, sd, descriptor);
|
||||
if (node.bump_offset == NODE_BUMP_OFFSET_DX) {
|
||||
vertex_color.val += vertex_color.dx * node.bump_filter_width;
|
||||
}
|
||||
else if (node.bump_offset == NODE_BUMP_OFFSET_DY) {
|
||||
vertex_color.val += vertex_color.dy * node.bump_filter_width;
|
||||
}
|
||||
color = make_float3(vertex_color.val);
|
||||
alpha = vertex_color.val.w;
|
||||
}
|
||||
else {
|
||||
dual3 vertex_color = primitive_surface_attribute<dual3>(kg, sd, descriptor);
|
||||
if (node.bump_offset == NODE_BUMP_OFFSET_DX) {
|
||||
vertex_color.val += vertex_color.dx * node.bump_filter_width;
|
||||
}
|
||||
else if (node.bump_offset == NODE_BUMP_OFFSET_DY) {
|
||||
vertex_color.val += vertex_color.dy * node.bump_filter_width;
|
||||
}
|
||||
color = vertex_color.val;
|
||||
alpha = 1.0f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
color = make_float3(0.0f, 0.0f, 0.0f);
|
||||
alpha = 0.0f;
|
||||
}
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
if (stack_valid(node.alpha_offset)) {
|
||||
stack_store_float(stack, node.alpha_offset, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
1203
blender-5.2.0/intern/cycles/kernel/svm/voronoi.h
Normal file
1203
blender-5.2.0/intern/cycles/kernel/svm/voronoi.h
Normal file
File diff suppressed because it is too large
Load Diff
109
blender-5.2.0/intern/cycles/kernel/svm/wave.h
Normal file
109
blender-5.2.0/intern/cycles/kernel/svm/wave.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/fractal_noise.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Wave */
|
||||
|
||||
ccl_device_noinline_cpu float svm_wave(NodeWaveType type,
|
||||
NodeWaveBandsDirection bands_dir,
|
||||
NodeWaveRingsDirection rings_dir,
|
||||
NodeWaveProfile profile,
|
||||
float3 p,
|
||||
const float distortion,
|
||||
const float detail,
|
||||
const float dscale,
|
||||
const float droughness,
|
||||
const float phase)
|
||||
{
|
||||
/* Prevent precision issues on unit coordinates. */
|
||||
p = (p + 0.000001f) * 0.999999f;
|
||||
|
||||
float n;
|
||||
|
||||
if (type == NODE_WAVE_BANDS) {
|
||||
if (bands_dir == NODE_WAVE_BANDS_DIRECTION_X) {
|
||||
n = p.x * 20.0f;
|
||||
}
|
||||
else if (bands_dir == NODE_WAVE_BANDS_DIRECTION_Y) {
|
||||
n = p.y * 20.0f;
|
||||
}
|
||||
else if (bands_dir == NODE_WAVE_BANDS_DIRECTION_Z) {
|
||||
n = p.z * 20.0f;
|
||||
}
|
||||
else { /* NODE_WAVE_BANDS_DIRECTION_DIAGONAL */
|
||||
n = (p.x + p.y + p.z) * 10.0f;
|
||||
}
|
||||
}
|
||||
else { /* NODE_WAVE_RINGS */
|
||||
float3 rp = p;
|
||||
if (rings_dir == NODE_WAVE_RINGS_DIRECTION_X) {
|
||||
rp *= make_float3(0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
else if (rings_dir == NODE_WAVE_RINGS_DIRECTION_Y) {
|
||||
rp *= make_float3(1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
else if (rings_dir == NODE_WAVE_RINGS_DIRECTION_Z) {
|
||||
rp *= make_float3(1.0f, 1.0f, 0.0f);
|
||||
}
|
||||
/* else: NODE_WAVE_RINGS_DIRECTION_SPHERICAL */
|
||||
|
||||
n = len(rp) * 20.0f;
|
||||
}
|
||||
|
||||
n += phase;
|
||||
|
||||
if (distortion != 0.0f) {
|
||||
n += distortion * (noise_fbm(p * dscale, detail, droughness, 2.0f, true) * 2.0f - 1.0f);
|
||||
}
|
||||
|
||||
if (profile == NODE_WAVE_PROFILE_SIN) {
|
||||
return 0.5f + 0.5f * sinf(n - M_PI_2_F);
|
||||
}
|
||||
if (profile == NODE_WAVE_PROFILE_SAW) {
|
||||
n /= M_2PI_F;
|
||||
return n - floorf(n);
|
||||
}
|
||||
/* NODE_WAVE_PROFILE_TRI */
|
||||
n /= M_2PI_F;
|
||||
return fabsf(n - floorf(n + 0.5f)) * 2.0f;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_tex_wave(ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexWave &ccl_restrict node)
|
||||
{
|
||||
const float3 co = stack_load_float3(stack, node.co);
|
||||
const float scale = stack_load(stack, node.scale);
|
||||
const float distortion = stack_load(stack, node.distortion);
|
||||
const float detail = stack_load(stack, node.detail);
|
||||
const float dscale = stack_load(stack, node.dscale);
|
||||
const float droughness = stack_load(stack, node.droughness);
|
||||
const float phase = stack_load(stack, node.phase);
|
||||
|
||||
const float f = svm_wave(node.wave_type,
|
||||
node.bands_direction,
|
||||
node.rings_direction,
|
||||
node.profile,
|
||||
co * scale,
|
||||
distortion,
|
||||
detail,
|
||||
dscale,
|
||||
droughness,
|
||||
phase);
|
||||
|
||||
if (stack_valid(node.fac_offset)) {
|
||||
stack_store_float(stack, node.fac_offset, f);
|
||||
}
|
||||
if (stack_valid(node.color_offset)) {
|
||||
stack_store_float3(stack, node.color_offset, make_float3(f, f, f));
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
36
blender-5.2.0/intern/cycles/kernel/svm/wavelength.h
Normal file
36
blender-5.2.0/intern/cycles/kernel/svm/wavelength.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Adapted code from Open Shading Language. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/math_util.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
|
||||
#include "kernel/util/colorspace.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Wavelength to RGB */
|
||||
|
||||
ccl_device_noinline void svm_node_wavelength(KernelGlobals kg,
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeWavelength &ccl_restrict node)
|
||||
{
|
||||
const float lambda_nm = stack_load(stack, node.wavelength);
|
||||
|
||||
float3 color = svm_math_wavelength_color_xyz(lambda_nm);
|
||||
color = xyz_to_rgb(kg, color);
|
||||
color *= 1.0f / 2.52f; // Empirical scale from lg to make all comps <= 1
|
||||
|
||||
/* Clamp to zero if values are smaller */
|
||||
color = max(color, make_float3(0.0f, 0.0f, 0.0f));
|
||||
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
67
blender-5.2.0/intern/cycles/kernel/svm/white_noise.h
Normal file
67
blender-5.2.0/intern/cycles/kernel/svm/white_noise.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_noinline void svm_node_tex_white_noise(
|
||||
ccl_private float *ccl_restrict stack,
|
||||
const ccl_global SVMNodeTexWhiteNoise &ccl_restrict node)
|
||||
{
|
||||
const float3 vector = stack_load(stack, node.vector);
|
||||
const float w = stack_load(stack, node.w);
|
||||
|
||||
if (stack_valid(node.color_offset)) {
|
||||
float3 color;
|
||||
switch (node.dimensions) {
|
||||
case 1:
|
||||
color = hash_float_to_float3(w);
|
||||
break;
|
||||
case 2:
|
||||
color = hash_float2_to_float3(make_float2(vector.x, vector.y));
|
||||
break;
|
||||
case 3:
|
||||
color = hash_float3_to_float3(vector);
|
||||
break;
|
||||
case 4:
|
||||
color = hash_float4_to_float3(make_float4(vector, w));
|
||||
break;
|
||||
default:
|
||||
color = make_float3(1.0f, 0.0f, 1.0f);
|
||||
kernel_assert(0);
|
||||
break;
|
||||
}
|
||||
stack_store_float3(stack, node.color_offset, color);
|
||||
}
|
||||
|
||||
if (stack_valid(node.value_offset)) {
|
||||
float value;
|
||||
switch (node.dimensions) {
|
||||
case 1:
|
||||
value = hash_float_to_float(w);
|
||||
break;
|
||||
case 2:
|
||||
value = hash_float2_to_float(make_float2(vector.x, vector.y));
|
||||
break;
|
||||
case 3:
|
||||
value = hash_float3_to_float(vector);
|
||||
break;
|
||||
case 4:
|
||||
value = hash_float4_to_float(make_float4(vector, w));
|
||||
break;
|
||||
default:
|
||||
value = 0.0f;
|
||||
kernel_assert(0);
|
||||
break;
|
||||
}
|
||||
stack_store_float(stack, node.value_offset, value);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
110
blender-5.2.0/intern/cycles/kernel/svm/wireframe.h
Normal file
110
blender-5.2.0/intern/cycles/kernel/svm/wireframe.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Adapted code from Open Shading Language. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/geom/motion_triangle.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/geom/triangle.h"
|
||||
#include "kernel/svm/node_types.h"
|
||||
#include "kernel/svm/util.h"
|
||||
#include "kernel/util/differential.h"
|
||||
#include "util/math_base.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Wireframe Node */
|
||||
|
||||
ccl_device_inline float wireframe(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const differential3 dP,
|
||||
const float size,
|
||||
const int pixel_size,
|
||||
ccl_private float3 *P)
|
||||
{
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_TRIANGLE)
|
||||
#else
|
||||
if (sd->prim != PRIM_NONE)
|
||||
#endif
|
||||
{
|
||||
float3 Co[3];
|
||||
float pixelwidth = 1.0f;
|
||||
|
||||
/* Triangles */
|
||||
const int np = 3;
|
||||
|
||||
if (sd->type & PRIMITIVE_MOTION) {
|
||||
motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
|
||||
}
|
||||
else {
|
||||
triangle_vertices(kg, sd->object, sd->prim, Co);
|
||||
}
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_position_transform(kg, sd, &Co[0]);
|
||||
object_position_transform(kg, sd, &Co[1]);
|
||||
object_position_transform(kg, sd, &Co[2]);
|
||||
}
|
||||
|
||||
if (pixel_size) {
|
||||
// Project the derivatives of P to the viewing plane defined
|
||||
// by I so we have a measure of how big is a pixel at this point
|
||||
const float pixelwidth_x = len(dP.dx - dot(dP.dx, sd->wi) * sd->wi);
|
||||
const float pixelwidth_y = len(dP.dy - dot(dP.dy, sd->wi) * sd->wi);
|
||||
// Take the average of both axis' length
|
||||
pixelwidth = (pixelwidth_x + pixelwidth_y) * 0.5f;
|
||||
}
|
||||
|
||||
// Use half the width as the neighbor face will render the
|
||||
// other half. And take the square for fast comparison
|
||||
pixelwidth *= 0.5f * size;
|
||||
pixelwidth *= pixelwidth;
|
||||
for (int i = 0; i < np; i++) {
|
||||
const int i2 = i ? i - 1 : np - 1;
|
||||
const float3 dir = *P - Co[i];
|
||||
const float3 edge = Co[i] - Co[i2];
|
||||
const float3 crs = cross(edge, dir);
|
||||
// At this point dot(crs, crs) / dot(edge, edge) is
|
||||
// the square of area / length(edge) == square of the
|
||||
// distance to the edge.
|
||||
if (dot(crs, crs) < (dot(edge, edge) * pixelwidth)) {
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
ccl_device_noinline void svm_node_wireframe(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
ccl_private float *stack,
|
||||
const ccl_global SVMNodeWireframe &ccl_restrict node)
|
||||
{
|
||||
/* Input Data */
|
||||
const float size = stack_load(stack, node.in_size);
|
||||
const int pixel_size = (int)node.use_pixel_size;
|
||||
|
||||
/* Calculate wireframe */
|
||||
const differential3 dP = differential_from_compact(sd->Ng, sd->dP);
|
||||
|
||||
float3 P = sd->P;
|
||||
if (node.bump_offset == NODE_BUMP_OFFSET_DX) {
|
||||
P += dP.dx * node.bump_filter_width;
|
||||
}
|
||||
else if (node.bump_offset == NODE_BUMP_OFFSET_DY) {
|
||||
P += dP.dy * node.bump_filter_width;
|
||||
}
|
||||
|
||||
const float f = wireframe(kg, sd, dP, size, pixel_size, &P);
|
||||
|
||||
if (stack_valid(node.out_fac_offset)) {
|
||||
stack_store_float(stack, node.out_fac_offset, f);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
Reference in New Issue
Block a user