Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_add_shader(Closure shader1, Closure shader2, Closure &shader)
{
shader = closure_add(shader1, shader2);
}

View File

@@ -0,0 +1,114 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_constants_lib.glsl"
#include "gpu_shader_math_rotation_conversion_lib.glsl"
#include "gpu_shader_math_rotation_lib.glsl"
#include "gpu_shader_math_vector_compare_lib.glsl"
float angle_normalized_v3v3(float3 v1, float3 v2)
{
v1 = normalize(v1);
v2 = normalize(v2);
if (dot(v1, v2) >= 0.0f) {
return 2.0f * asin(clamp(length(v2 - v1) / 2.0f, -1.0f, 1.0f));
}
const float3 v2_n = -v2;
return M_PI - 2.0f * asin(clamp(length(v2_n - v1) / 2.0f, -1.0f, 1.0f));
}
float3 project_plane_normalized_v3_v3v3(float3 p, float3 v_plane)
{
const float3 v_plane_n = normalize(v_plane);
const float mul = dot(p, v_plane_n);
return p - v_plane_n * mul;
}
float angle_signed_on_axis_v3v3_v3(float3 v1, float3 v2, float3 axis)
{
const float3 axis_n = normalize(axis);
const float3 v1_proj = project_plane_normalized_v3_v3v3(v1, axis_n);
const float3 v2_proj = project_plane_normalized_v3_v3v3(v2, axis_n);
float angle = angle_normalized_v3v3(v1_proj, v2_proj);
const float3 tproj = cross(v2_proj, v1_proj);
if (dot(tproj, axis) < 0.0f) {
angle = M_PI * 2.0f - angle;
}
return angle;
}
[[node]]
void align_rotation_to_vector_auto_pivot(float4 rotation_in,
float factor,
float3 input_vector,
float3 local_main_axis,
out float4 rotation)
{
if (is_zero(input_vector)) {
rotation = rotation_in;
return;
}
const Quaternion quat_in = Quaternion{UNPACK4(rotation_in)};
const float3 old_axis = transform_point_by_quaternion(quat_in, local_main_axis);
const float3 new_axis = normalize(input_vector);
float3 rotation_axis = cross(old_axis, new_axis);
if (is_zero(rotation_axis)) {
/* The vectors are linearly dependent, so we fall back to another axis. */
rotation_axis = cross(old_axis, float3(1.0f, 0.0f, 0.0f));
if (is_zero(rotation_axis)) {
/* This is now guaranteed to not be zero. */
rotation_axis = cross(old_axis, float3(0.0f, 1.0f, 0.0f));
}
}
const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
const float angle = factor * full_angle;
AxisAngle aa;
aa.axis = normalize(rotation_axis);
aa.angle = angle;
rotation = math_quaternion_multiply(to_quaternion(aa), quat_in).as_float4();
}
[[node]]
void align_rotation_to_vector_fixed_pivot(float4 rotation_in,
float factor,
float3 input_vector,
float3 local_main_axis,
float3 local_pivot_axis,
out float4 rotation)
{
if (all(equal(local_main_axis, local_pivot_axis))) {
/* Can't compute any meaningful rotation angle in this case. */
rotation = rotation_in;
return;
}
if (is_zero(input_vector)) {
rotation = rotation_in;
return;
}
const Quaternion quat_in = Quaternion{UNPACK4(rotation_in)};
const float3 old_axis = transform_point_by_quaternion(quat_in, local_main_axis);
const float3 pivot_axis = transform_point_by_quaternion(quat_in, local_pivot_axis);
float full_angle = angle_signed_on_axis_v3v3_v3(input_vector, old_axis, pivot_axis);
if (full_angle > M_PI) {
/* Make sure the point is rotated as little as possible. */
full_angle -= 2.0f * M_PI;
}
const float angle = factor * full_angle;
AxisAngle aa;
aa.axis = normalize(pivot_axis);
aa.angle = angle;
rotation = math_quaternion_multiply(to_quaternion(aa), quat_in).as_float4();
}

View File

@@ -0,0 +1,18 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void node_ambient_occlusion(float4 color,
float dist,
float3 normal,
const float inverted,
const float sample_count,
float4 &result_color,
float &result_ao)
{
result_ao = ambient_occlusion_eval(safe_normalize(normal), dist, inverted, sample_count);
result_color = result_ao * color;
}

View File

@@ -0,0 +1,75 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_math.glsl"
[[node]]
void node_attribute_color(float4 attr, float4 &out_attr)
{
out_attr = attr_load_color_post(attr);
}
[[node]]
void node_attribute_temperature(float4 attr, float4 &out_attr)
{
float temperature = attr_load_temperature_post(attr.x);
out_attr.x = temperature;
out_attr.y = temperature;
out_attr.z = temperature;
out_attr.w = 1.0f;
}
[[node]]
void node_attribute_density(float4 attr, float &out_attr)
{
out_attr = attr.x;
}
[[node]]
void node_attribute_flame(float4 attr, float &out_attr)
{
out_attr = attr.x;
}
[[node]]
void node_attribute_uniform(float4 attr, const float attr_hash, float4 &out_attr)
{
/* Temporary solution to support both old UBO attributes and new SSBO loading.
* Old UBO load is already done through `attr` and will just be passed through. */
out_attr = attr_load_uniform(attr, floatBitsToUint(attr_hash));
}
float4 attr_load_layer(const uint attr_hash)
{
#ifdef VLATTR_LIB
/* The first record of the buffer stores the length. */
uint left = 0, right = drw_layer_attrs[0].buffer_length;
while (left < right) {
uint mid = (left + right) / 2;
uint hash = drw_layer_attrs[mid].hash_code;
if (hash < attr_hash) {
left = mid + 1;
}
else if (hash > attr_hash) {
right = mid;
}
else {
return drw_layer_attrs[mid].data;
}
}
#endif
return float4(0.0f);
}
[[node]]
void node_attribute(float4 attr, float4 &outcol, float3 &outvec, float &outf, float &outalpha)
{
outcol = float4(attr.xyz, 1.0f);
outvec = attr.xyz;
outf = math_average(attr.xyz);
outalpha = attr.w;
}

View File

@@ -0,0 +1,65 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_rotation_conversion_lib.glsl"
#include "gpu_shader_math_vector_compare_lib.glsl"
#include "gpu_shader_math_vector_lib.glsl"
[[node]]
void axes_to_rotation(float3 primary_in,
float3 secondary_in,
float primary_idx_f,
float secondary_idx_f,
float tertiary_idx_f,
float tertiary_factor,
out float4 rotation)
{
float3 primary = normalize(primary_in);
float3 secondary = secondary_in;
float3 tertiary;
const bool primary_is_non_zero = !is_zero(primary);
const bool secondary_is_non_zero = !is_zero(secondary);
if (primary_is_non_zero && secondary_is_non_zero) {
tertiary = cross(primary, secondary);
if (is_zero(tertiary)) {
tertiary = orthogonal<float3>(primary);
}
tertiary = normalize(tertiary);
secondary = cross(tertiary, primary);
}
else if (primary_is_non_zero) {
secondary = orthogonal<float3>(primary);
secondary = normalize(secondary);
tertiary = cross(primary, secondary);
}
else if (secondary_is_non_zero) {
secondary = normalize(secondary);
primary = orthogonal<float3>(secondary);
primary = normalize(primary);
tertiary = cross(primary, secondary);
}
else {
rotation = float4(1.0f, 0.0f, 0.0f, 0.0f);
return;
}
const int primary_axis = int(primary_idx_f);
const int secondary_axis = int(secondary_idx_f);
const int tertiary_axis = int(tertiary_idx_f);
float3x3 mat;
mat[primary_axis] = primary;
mat[secondary_axis] = secondary;
mat[tertiary_axis] = tertiary_factor * tertiary;
rotation = to_quaternion(mat).as_float4();
}
[[node]]
void axes_to_rotation_identity(float3 primary_in, float3 secondary_in, out float4 rotation)
{
rotation = float4(1.0f, 0.0f, 0.0f, 0.0f);
}

View File

@@ -0,0 +1,11 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_rotation_conversion_lib.glsl"
[[node]]
void axis_angle_to_rotation(float3 axis, float angle, out float4 rotation)
{
rotation = to_quaternion(axis, angle).as_float4();
}

View File

@@ -0,0 +1,13 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_background(float4 color, float strength, float weight, Closure &result)
{
ClosureEmission emission_data;
emission_data.weight = weight;
emission_data.emission = color.rgb * strength;
result = closure_eval(emission_data);
}

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_bevel(float radius, float3 N, float3 &result)
{
result = N;
}

View File

@@ -0,0 +1,10 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_blackbody(float temperature, sampler1DArray spectrummap, float layer, float4 &color)
{
float t = (temperature - 800.0f) / (12000.0f - 800.0f);
color = float4(texture(spectrummap, float2(t, layer)).rgb, 1.0f);
}

View File

@@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void brightness_contrast(float4 col, float brightness, float contrast, float4 &outcol)
{
float a = 1.0f + contrast;
float b = brightness - contrast * 0.5f;
outcol.r = max(a * col.r + b, 0.0f);
outcol.g = max(a * col.g + b, 0.0f);
outcol.b = max(a * col.b + b, 0.0f);
outcol.a = col.a;
}

View File

@@ -0,0 +1,54 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void differentiate_texco(float3 v, float3 &df)
{
/* Implementation defined. */
df = v + dF_impl(v);
}
/* Overload for UVs which are loaded as generic attributes. */
[[node]]
void differentiate_texco(float4 v, float3 &df)
{
/* Implementation defined. */
df = v.xyz + dF_impl(v.xyz);
}
[[node]]
void node_bump(float strength,
float dist,
float filter_width,
float height,
float3 N,
float2 height_xy,
float invert,
float3 &result)
{
N = normalize(N);
dist *= FrontFacing ? invert : -invert;
#ifdef GPU_FRAGMENT_SHADER
float3 dPdx = gpu_dfdx(g_data.P) * derivative_scale_get();
float3 dPdy = gpu_dfdy(g_data.P) * derivative_scale_get();
/* Get surface tangents from normal. */
float3 Rx = cross(dPdy, N);
float3 Ry = cross(N, dPdx);
/* Compute surface gradient and determinant. */
float det = dot(dPdx, Rx);
float2 dHd = height_xy - float2(height);
float3 surfgrad = dHd.x * Rx + dHd.y * Ry;
strength = max(strength, 0.0f);
result = normalize(filter_width * abs(det) * N - dist * sign(det) * surfgrad);
result = normalize(mix(N, result, strength));
#else
result = N;
#endif
}

View File

@@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_transform_utils.glsl"
[[node]]
void camera(float3 &outview, float &outdepth, float &outdist)
{
float3 vP;
point_transform_world_to_view(g_data.P, vP);
vP.z = -vP.z;
outdepth = abs(vP.z);
outdist = length(vP);
outview = normalize(vP);
}

View File

@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: 2019-2020 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void clamp_value(float value, float min, float max, float &result)
{
result = clamp(value, min, max);
}
[[node]]
void clamp_minmax(float value, float min_allowed, float max_allowed, float &result)
{
result = min(max(value, min_allowed), max_allowed);
}
[[node]]
void clamp_range(float value, float min, float max, float &result)
{
result = (max > min) ? clamp(value, min, max) : clamp(value, max, min);
}

View File

@@ -0,0 +1,23 @@
/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_color_utils.glsl"
[[node]]
void combine_color_rgb(float r, float g, float b, float4 &col)
{
col = float4(r, g, b, 1.0f);
}
[[node]]
void combine_color_hsv(float h, float s, float v, float4 &col)
{
hsv_to_rgb(float4(h, s, v, 1.0f), col);
}
[[node]]
void combine_color_hsl(float h, float s, float l, float4 &col)
{
hsl_to_rgb(float4(h, s, l, 1.0f), col);
}

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void combine_xyz(float x, float y, float z, float3 &vec)
{
vec = float3(x, y, z);
}

View File

@@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void node_bsdf_diffuse(float4 color, float roughness, float3 N, float weight, Closure &result)
{
ClosureDiffuse diffuse_data;
diffuse_data.weight = weight;
diffuse_data.color = color.rgb;
diffuse_data.N = safe_normalize(N);
result = closure_eval(diffuse_data);
}

View File

@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_transform_utils.glsl"
[[node]]
void node_displacement_object(float height, float midlevel, float scale, float3 N, float3 &result)
{
float3 lN;
direction_transform_world_to_object(N, lN);
float3 l_displacement = (height - midlevel) * scale * normalize(lN);
/* Apply object scale and orientation. */
direction_transform_object_to_world(l_displacement, result);
}
[[node]]
void node_displacement_world(float height, float midlevel, float scale, float3 N, float3 &result)
{
result = (height - midlevel) * scale * normalize(N);
}

View File

@@ -0,0 +1,87 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
[[node]]
void node_eevee_specular(float4 diffuse,
float4 specular,
float roughness,
float4 emissive,
float transp,
float3 N,
float clearcoat,
float clearcoat_roughness,
float3 CN,
float weight,
const float use_clearcoat,
Closure &result)
{
diffuse = max(diffuse, float4(0));
specular = max(specular, float4(0));
roughness = saturate(roughness);
emissive = max(emissive, float4(0));
N = safe_normalize(N);
clearcoat = saturate(clearcoat);
clearcoat_roughness = saturate(clearcoat_roughness);
CN = safe_normalize(CN);
float3 V = coordinate_incoming(g_data.P);
ClosureEmission emission_data;
emission_data.weight = weight;
emission_data.emission = emissive.rgb;
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = float3(transp);
transparency_data.holdout = 0.0f;
float alpha = (1.0f - transp) * weight;
[[resource_table]] UtilityTexture &util_tx = resource_table_get(UtilityTexture);
ClosureDiffuse diffuse_data;
diffuse_data.weight = alpha;
diffuse_data.color = diffuse.rgb;
diffuse_data.N = N;
ClosureReflection reflection_data;
reflection_data.weight = alpha;
if (true) {
float NV = dot(N, V);
eevee::lut::GGXBrdfData lut = eevee::lut::GGXBrdfData::sample_utility_tx(
util_tx, NV, roughness);
float3 brdf = F_brdf_single_scatter(specular.rgb, float3(1.0f), lut);
reflection_data.color = brdf;
reflection_data.N = N;
reflection_data.roughness = roughness;
}
ClosureReflection clearcoat_data;
clearcoat_data.weight = alpha * clearcoat * 0.25f;
if (true) {
float NV = dot(CN, V);
eevee::lut::GGXBrdfData lut = eevee::lut::GGXBrdfData::sample_utility_tx(
util_tx, NV, clearcoat_roughness);
float3 brdf = F_brdf_single_scatter(float3(0.04f), float3(1.0f), lut);
clearcoat_data.color = brdf;
clearcoat_data.N = CN;
clearcoat_data.roughness = clearcoat_roughness;
}
if (use_clearcoat != 0.0f) {
result = closure_eval(diffuse_data, reflection_data, clearcoat_data);
}
else {
result = closure_eval(diffuse_data, reflection_data);
}
Closure emission_cl = closure_eval(emission_data);
Closure transparency_cl = closure_eval(transparency_data);
result = closure_add(result, emission_cl);
result = closure_add(result, transparency_cl);
}

View File

@@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_emission(float4 color, float strength, float weight, Closure &result)
{
color = max(color, float4(0.0f));
strength = max(strength, 0.0f);
ClosureEmission emission_data;
emission_data.weight = weight;
emission_data.emission = color.rgb * strength;
result = closure_eval(emission_data);
}

View File

@@ -0,0 +1,12 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_euler_lib.glsl"
#include "gpu_shader_math_rotation_conversion_lib.glsl"
[[node]]
void euler_to_rotation(float3 euler, out float4 rotation)
{
rotation = to_quaternion(EulerXYZ::from_float3(euler)).as_float4();
}

View File

@@ -0,0 +1,203 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
#include "gpu_shader_material_noise.glsl"
#define NOISE_FBM(T) \
float noise_fbm(T co, \
float detail, \
float roughness, \
float lacunarity, \
float offset, \
float gain, \
bool normalize) \
{ \
T p = co; \
float fscale = 1.0f; \
float amp = 1.0f; \
float maxamp = 0.0f; \
float sum = 0.0f; \
\
for (int i = 0; i <= int(detail); i++) { \
float t = snoise(fscale * p); \
sum += t * amp; \
maxamp += amp; \
amp *= roughness; \
fscale *= lacunarity; \
} \
float rmd = detail - floor(detail); \
if (rmd != 0.0f) { \
float t = snoise(fscale * p); \
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); \
} \
else { \
return normalize ? 0.5f * sum / maxamp + 0.5f : sum; \
} \
}
#define NOISE_MULTI_FRACTAL(T) \
float noise_multi_fractal(T co, \
float detail, \
float roughness, \
float lacunarity, \
float offset, \
float gain, \
bool normalize) \
{ \
T p = co; \
float value = 1.0f; \
float pwr = 1.0f; \
\
for (int i = 0; i <= int(detail); i++) { \
value *= (pwr * snoise(p) + 1.0f); \
pwr *= roughness; \
p *= lacunarity; \
} \
\
float rmd = detail - floor(detail); \
if (rmd != 0.0f) { \
value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */ \
} \
\
return value; \
}
#define NOISE_HETERO_TERRAIN(T) \
float noise_hetero_terrain(T co, \
float detail, \
float roughness, \
float lacunarity, \
float offset, \
float gain, \
bool normalize) \
{ \
T p = co; \
float pwr = roughness; \
\
/* first unscaled octave of function; later octaves are scaled */ \
float value = offset + snoise(p); \
p *= lacunarity; \
\
for (int i = 1; i <= int(detail); i++) { \
float increment = (snoise(p) + offset) * pwr * value; \
value += increment; \
pwr *= roughness; \
p *= lacunarity; \
} \
\
float rmd = detail - floor(detail); \
if (rmd != 0.0f) { \
float increment = (snoise(p) + offset) * pwr * value; \
value += rmd * increment; \
} \
\
return value; \
}
#define NOISE_HYBRID_MULTI_FRACTAL(T) \
float noise_hybrid_multi_fractal(T co, \
float detail, \
float roughness, \
float lacunarity, \
float offset, \
float gain, \
bool normalize) \
{ \
T p = co; \
float pwr = 1.0f; \
float value = 0.0f; \
float weight = 1.0f; \
\
for (int i = 0; (weight > 0.001f) && (i <= int(detail)); i++) { \
if (weight > 1.0f) { \
weight = 1.0f; \
} \
\
float signal = (snoise(p) + offset) * pwr; \
pwr *= roughness; \
value += weight * signal; \
weight *= gain * signal; \
p *= lacunarity; \
} \
\
float rmd = detail - floor(detail); \
if ((rmd != 0.0f) && (weight > 0.001f)) { \
if (weight > 1.0f) { \
weight = 1.0f; \
} \
float signal = (snoise(p) + offset) * pwr; \
value += rmd * weight * signal; \
} \
\
return value; \
}
#define NOISE_RIDGED_MULTI_FRACTAL(T) \
float noise_ridged_multi_fractal(T co, \
float detail, \
float roughness, \
float lacunarity, \
float offset, \
float gain, \
bool normalize) \
{ \
T p = co; \
float pwr = roughness; \
\
float signal = offset - abs(snoise(p)); \
signal *= signal; \
float value = signal; \
float weight = 1.0f; \
\
for (int i = 1; i <= int(detail); i++) { \
p *= lacunarity; \
weight = clamp(signal * gain, 0.0f, 1.0f); \
signal = offset - abs(snoise(p)); \
signal *= signal; \
signal *= weight; \
value += signal * pwr; \
pwr *= roughness; \
} \
\
return value; \
}
/* Noise fBM. */
NOISE_FBM(float)
NOISE_FBM(float2)
NOISE_FBM(float3)
NOISE_FBM(float4)
/* Noise Multi-fractal. */
NOISE_MULTI_FRACTAL(float)
NOISE_MULTI_FRACTAL(float2)
NOISE_MULTI_FRACTAL(float3)
NOISE_MULTI_FRACTAL(float4)
/* Noise Hetero Terrain. */
NOISE_HETERO_TERRAIN(float)
NOISE_HETERO_TERRAIN(float2)
NOISE_HETERO_TERRAIN(float3)
NOISE_HETERO_TERRAIN(float4)
/* Noise Hybrid Multi-fractal. */
NOISE_HYBRID_MULTI_FRACTAL(float)
NOISE_HYBRID_MULTI_FRACTAL(float2)
NOISE_HYBRID_MULTI_FRACTAL(float3)
NOISE_HYBRID_MULTI_FRACTAL(float4)
/* Noise Ridged Multi-fractal. */
NOISE_RIDGED_MULTI_FRACTAL(float)
NOISE_RIDGED_MULTI_FRACTAL(float2)
NOISE_RIDGED_MULTI_FRACTAL(float3)
NOISE_RIDGED_MULTI_FRACTAL(float4)

View File

@@ -0,0 +1,317 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_voronoi.glsl"
#include "gpu_shader_math_vector_safe_lib.glsl"
/* TODO(jbakker): Deduplicate code when OpenGL backend has been removed.
* `fractal_voronoi_x_fx` functions are identical, except for the input parameter.
* It used to be a macro, but didn't work on legacy drivers. */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
{ \
float amplitude = 1.0f; \
float max_amplitude = params.max_distance; \
float scale = 1.0f; \
float distance = 8.0f; \
\
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
\
if (zero_input) { \
distance = octave_distance; \
break; \
} \
else if (i <= params.detail) { \
max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude); \
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
scale *= params.lacunarity; \
amplitude *= params.roughness; \
} \
else { \
float remainder = params.detail - floor(params.detail); \
if (remainder != 0.0f) { \
float lerp_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude); \
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
distance = mix(distance, min(distance, lerp_distance), remainder); \
} \
} \
} \
\
if (params.normalize) { \
distance /= max_amplitude; \
} \
\
return distance; \
}
/* **** 1D Fractal Voronoi **** */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float coord)
{
float amplitude = 1.0f;
float max_amplitude = 0.0f;
float scale = 1.0f;
VoronoiOutput Output;
Output.Distance = 0.0f;
Output.Color = float3(0.0f, 0.0f, 0.0f);
Output.Position = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceil(params.detail); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0f) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0f;
Output = octave;
break;
}
else if (i <= params.detail) {
max_amplitude += amplitude;
Output.Distance += octave.Distance * amplitude;
Output.Color += octave.Color * amplitude;
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
scale *= params.lacunarity;
amplitude *= params.roughness;
}
else {
float remainder = params.detail - floor(params.detail);
if (remainder != 0.0f) {
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
Output.Distance = mix(
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
Output.Position = mix(
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
}
}
}
if (params.normalize) {
Output.Distance /= max_amplitude * params.max_distance;
Output.Color /= max_amplitude;
}
Output.Position = safe_divide(Output.Position, params.scale);
return Output;
}
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
/* **** 2D Fractal Voronoi **** */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float2 coord)
{
float amplitude = 1.0f;
float max_amplitude = 0.0f;
float scale = 1.0f;
VoronoiOutput Output;
Output.Distance = 0.0f;
Output.Color = float3(0.0f, 0.0f, 0.0f);
Output.Position = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceil(params.detail); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0f) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0f;
Output = octave;
break;
}
else if (i <= params.detail) {
max_amplitude += amplitude;
Output.Distance += octave.Distance * amplitude;
Output.Color += octave.Color * amplitude;
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
scale *= params.lacunarity;
amplitude *= params.roughness;
}
else {
float remainder = params.detail - floor(params.detail);
if (remainder != 0.0f) {
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
Output.Distance = mix(
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
Output.Position = mix(
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
}
}
}
if (params.normalize) {
Output.Distance /= max_amplitude * params.max_distance;
Output.Color /= max_amplitude;
}
Output.Position = safe_divide(Output.Position, params.scale);
return Output;
}
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float2)
/* **** 3D Fractal Voronoi **** */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float3 coord)
{
float amplitude = 1.0f;
float max_amplitude = 0.0f;
float scale = 1.0f;
VoronoiOutput Output;
Output.Distance = 0.0f;
Output.Color = float3(0.0f, 0.0f, 0.0f);
Output.Position = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceil(params.detail); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0f) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0f;
Output = octave;
break;
}
else if (i <= params.detail) {
max_amplitude += amplitude;
Output.Distance += octave.Distance * amplitude;
Output.Color += octave.Color * amplitude;
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
scale *= params.lacunarity;
amplitude *= params.roughness;
}
else {
float remainder = params.detail - floor(params.detail);
if (remainder != 0.0f) {
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
Output.Distance = mix(
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
Output.Position = mix(
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
}
}
}
if (params.normalize) {
Output.Distance /= max_amplitude * params.max_distance;
Output.Color /= max_amplitude;
}
Output.Position = safe_divide(Output.Position, params.scale);
return Output;
}
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float3)
/* **** 4D Fractal Voronoi **** */
/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
* by lerps. */
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float4 coord)
{
float amplitude = 1.0f;
float max_amplitude = 0.0f;
float scale = 1.0f;
VoronoiOutput Output;
Output.Distance = 0.0f;
Output.Color = float3(0.0f, 0.0f, 0.0f);
Output.Position = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (int i = 0; i <= ceil(params.detail); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0f) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0f;
Output = octave;
break;
}
else if (i <= params.detail) {
max_amplitude += amplitude;
Output.Distance += octave.Distance * amplitude;
Output.Color += octave.Color * amplitude;
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
scale *= params.lacunarity;
amplitude *= params.roughness;
}
else {
float remainder = params.detail - floor(params.detail);
if (remainder != 0.0f) {
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
Output.Distance = mix(
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
Output.Position = mix(
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
}
}
}
if (params.normalize) {
Output.Distance /= max_amplitude * params.max_distance;
Output.Color /= max_amplitude;
}
Output.Position = safe_divide(Output.Position, params.scale);
return Output;
}
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float4)

View File

@@ -0,0 +1,41 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
float fresnel_dielectric_cos(float cosi, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
float c = abs(cosi);
float g = eta * eta - 1.0f + c * c;
float result;
if (g > 0.0f) {
g = sqrt(g);
float A = (g - c) / (g + c);
float B = (c * (g + c) - 1.0f) / (c * (g - c) + 1.0f);
result = 0.5f * A * A * (1.0f + B * B);
}
else {
result = 1.0f; /* TIR (no refracted component) */
}
return result;
}
float fresnel_dielectric(float3 Incoming, float3 Normal, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
}
[[node]]
void node_fresnel(float ior, float3 N, float &result)
{
N = normalize(N);
float3 V = coordinate_incoming(g_data.P);
float eta = max(ior, 0.00001f);
result = fresnel_dielectric(V, N, (FrontFacing) ? eta : 1.0f / eta);
}

View File

@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_safe_lib.glsl"
[[node]]
void node_gamma(float4 col, float gamma, float4 &outcol)
{
outcol = col;
if (col.r > 0.0f) {
outcol.r = compatible_pow(col.r, gamma);
}
if (col.g > 0.0f) {
outcol.g = compatible_pow(col.g, gamma);
}
if (col.b > 0.0f) {
outcol.b = compatible_pow(col.b, gamma);
}
}

View File

@@ -0,0 +1,37 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_tangent.glsl"
[[node]]
void node_geometry(float3 orco_attr,
float3 &position,
float3 &normal,
float3 &tangent,
float3 &true_normal,
float3 &incoming,
float3 &parametric,
float &backfacing,
float &pointiness,
float &random_per_island)
{
/* handle perspective/orthographic */
incoming = coordinate_incoming(g_data.P);
position = g_data.P;
normal = g_data.N;
true_normal = g_data.Ng;
if (g_data.is_strand) {
tangent = g_data.curve_T;
}
else {
tangent_orco_z(orco_attr, orco_attr);
node_tangent(orco_attr, tangent);
}
parametric = float3(g_data.barycentric_coords, 0.0f);
backfacing = (FrontFacing) ? 0.0f : 1.0f;
pointiness = 0.5f;
random_per_island = 0.0f;
}

View File

@@ -0,0 +1,43 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
[[node]]
void node_bsdf_glass(float4 color,
float roughness,
float ior,
float3 N,
float weight,
float thin_film_thickness,
float thin_film_ior,
const float do_multiscatter,
Closure &result)
{
color = max(color, float4(0.0f));
roughness = saturate(roughness);
ior = max(ior, 1e-5f);
N = safe_normalize(N);
float3 V = coordinate_incoming(g_data.P);
float NV = dot(N, V);
float2 bsdf = bsdf_lut(NV, roughness, ior, do_multiscatter != 0.0f);
ClosureReflection reflection_data;
reflection_data.weight = bsdf.x * weight;
reflection_data.color = color.rgb;
reflection_data.N = N;
reflection_data.roughness = roughness;
ClosureRefraction refraction_data;
refraction_data.weight = bsdf.y * weight;
refraction_data.color = color.rgb;
refraction_data.N = N;
refraction_data.roughness = roughness;
refraction_data.ior = ior;
result = closure_eval(reflection_data, refraction_data);
}

View File

@@ -0,0 +1,39 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
[[node]]
void node_bsdf_glossy(float4 color,
float roughness,
float anisotropy,
float rotation,
float3 N,
float3 T,
float weight,
const float do_multiscatter,
Closure &result)
{
color = max(color, float4(0.0f));
roughness = saturate(roughness);
N = safe_normalize(N);
/* anisotropy = clamp(anisotropy, -0.99f, 0.99f) */
float3 V = coordinate_incoming(g_data.P);
float NV = dot(N, V);
[[resource_table]] UtilityTexture &util_tx = resource_table_get(UtilityTexture);
eevee::lut::GGXBrdfData lut = eevee::lut::GGXBrdfData::sample_utility_tx(util_tx, NV, roughness);
ClosureReflection reflection_data;
reflection_data.weight = weight;
reflection_data.color = (do_multiscatter != 0.0f) ?
F_brdf_multi_scatter(color.rgb, color.rgb, lut) :
F_brdf_single_scatter(color.rgb, color.rgb, lut);
reflection_data.N = N;
reflection_data.roughness = roughness;
result = closure_eval(reflection_data);
}

View File

@@ -0,0 +1,73 @@
/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_bsdf_hair(float4 color,
float offset,
float roughness_u,
float roughness_v,
float3 T,
float weight,
Closure &result)
{
color = max(color, float4(0.0f));
#if 0
/* NOTE(fclem): This is the way it should be. But we don't have proper implementation of the hair
* closure yet. For now fall back to a simpler diffuse surface so that we have at least a color
* feedback. */
ClosureHair hair_data;
hair_data.weight = weight;
hair_data.color = color.rgb;
hair_data.offset = offset;
hair_data.roughness = float2(roughness_u, roughness_v);
hair_data.T = T;
#else
ClosureDiffuse hair_data;
hair_data.weight = weight;
hair_data.color = color.rgb;
hair_data.N = g_data.N;
#endif
result = closure_eval(hair_data);
}
[[node]]
void node_bsdf_hair_principled(float4 color,
float melanin,
float melanin_redness,
float4 tint,
float3 absorption_coefficient,
float roughness,
float radial_roughness,
float coat,
float ior,
float offset,
float aspect_ratio,
float R,
float TT,
float TRT,
float random_color,
float random_roughness,
float random,
float weight,
Closure &result)
{
/* Placeholder closure.
* Some computation will have to happen here just like the Principled BSDF.
* For now fall back to a simpler diffuse surface so that we have at least a color feedback. */
#if 0
ClosureHair hair_data;
hair_data.weight = weight;
hair_data.color = color.rgb;
hair_data.offset = offset;
hair_data.roughness = float2(0.0f);
hair_data.T = g_data.curve_B;
#else
ClosureDiffuse hair_data;
hair_data.weight = weight;
hair_data.color = color.rgb;
hair_data.N = g_data.N;
#endif
result = closure_eval(hair_data);
}

View File

@@ -0,0 +1,24 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
[[node]]
void node_hair_info(float hair_intercept,
float hair_length,
float &is_strand,
float &out_intercept,
float &out_length,
float &thickness,
float3 &normal,
float &random)
{
is_strand = float(g_data.is_strand);
out_intercept = hair_intercept;
out_length = hair_length;
thickness = g_data.hair_diameter;
normal = g_data.curve_N;
/* TODO: could be precomputed per strand instead. */
random = wang_hash_noise(uint(g_data.hair_strand_id));
}

View File

@@ -0,0 +1,14 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_holdout(float weight, Closure &result)
{
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = float3(0.0f);
transparency_data.holdout = 1.0f;
result = closure_eval(transparency_data);
}

View File

@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_color_utils.glsl"
[[node]]
void hue_sat(float hue, float sat, float value, float fac, float4 col, float4 &outcol)
{
float4 hsv;
rgb_to_hsv(col, hsv);
hsv[0] = fract(hsv[0] + hue + 0.5f);
hsv[1] = clamp(hsv[1] * sat, 0.0f, 1.0f);
hsv[2] = hsv[2] * value;
hsv_to_rgb(hsv, outcol);
outcol = mix(col, outcol, fac);
}

View File

@@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void world_normals_get(float3 &N)
{
N = g_data.N;
}
[[node]]
void world_position_get(out float3 P)
{
P = g_data.P;
}

View File

@@ -0,0 +1,10 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void invert(float fac, float4 col, float4 &outcol)
{
outcol.xyz = mix(col.xyz, float3(1.0f) - col.xyz, fac);
outcol.w = col.w;
}

View File

@@ -0,0 +1,11 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_quaternion_lib.glsl"
[[node]]
void invert_rotation(float4 rotation, out float4 result)
{
result = quaternion_conjugate(Quaternion{UNPACK4(rotation)}).as_float4();
}

View File

@@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_fresnel.glsl"
[[node]]
void node_layer_weight(float blend, float3 N, float &fresnel, float &facing)
{
N = normalize(N);
/* fresnel */
float eta = max(1.0f - blend, 0.00001f);
float3 V = coordinate_incoming(g_data.P);
fresnel = fresnel_dielectric(V, N, (FrontFacing) ? 1.0f / eta : eta);
/* facing */
facing = abs(dot(V, N));
if (blend != 0.5f) {
blend = clamp(blend, 0.0f, 0.99999f);
blend = (blend < 0.5f) ? 2.0f * blend : 0.5f / (1.0f - blend);
facing = pow(facing, blend);
}
facing = 1.0f - facing;
}

View File

@@ -0,0 +1,12 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_light_falloff(
float strength, float tsmooth, float &quadratic, float &linear, float &falloff_constant)
{
quadratic = strength;
linear = strength;
falloff_constant = strength;
}

View File

@@ -0,0 +1,40 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_light_path(float &is_camera_ray,
float &is_shadow_ray,
float &is_diffuse_ray,
float &is_glossy_ray,
float &is_singular_ray,
float &is_reflection_ray,
float &is_transmission_ray,
float &is_volume_scatter_ray,
float &ray_length,
float &ray_depth,
float &diffuse_depth,
float &glossy_depth,
float &transparent_depth,
float &transmission_depth,
float &path_depth)
{
/* Supported. */
is_camera_ray = float(g_data.ray_type == RAY_TYPE_CAMERA);
is_shadow_ray = float(g_data.ray_type == RAY_TYPE_SHADOW);
is_diffuse_ray = float(g_data.ray_type == RAY_TYPE_DIFFUSE);
is_glossy_ray = float(g_data.ray_type == RAY_TYPE_GLOSSY);
/* Kind of supported. */
is_singular_ray = is_glossy_ray;
is_reflection_ray = is_glossy_ray;
is_transmission_ray = is_glossy_ray;
ray_depth = g_data.ray_depth;
diffuse_depth = (is_diffuse_ray == 1.0f) ? g_data.ray_depth : 0.0f;
glossy_depth = (is_glossy_ray == 1.0f) ? g_data.ray_depth : 0.0f;
transmission_depth = (is_transmission_ray == 1.0f) ? glossy_depth : 0.0f;
ray_length = g_data.ray_length;
/* Not supported. */
transparent_depth = 0.0f;
is_volume_scatter_ray = 0.0f;
path_depth = 0.0f;
}

View File

@@ -0,0 +1,229 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_safe_lib.glsl"
#include "gpu_shader_math_vector_safe_lib.glsl"
float smootherstep(float edge0, 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);
}
float3 smootherstep(float3 edge0, float3 edge1, float3 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);
}
[[node]]
void vector_map_range_linear(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
float3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
v_result = v_to_min + factor * (v_to_max - v_to_min);
if (use_clamp > 0.0f) {
v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
clamp(v_result.x, v_to_min.x, v_to_max.x);
v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
clamp(v_result.y, v_to_min.y, v_to_max.y);
v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
clamp(v_result.z, v_to_min.z, v_to_max.z);
}
}
[[node]]
void vector_map_range_stepped(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
float3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
factor = safe_divide(floor(factor * (v_steps + 1.0f)), v_steps);
v_result = v_to_min + factor * (v_to_max - v_to_min);
if (use_clamp > 0.0f) {
v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) :
clamp(v_result.x, v_to_min.x, v_to_max.x);
v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) :
clamp(v_result.y, v_to_min.y, v_to_max.y);
v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) :
clamp(v_result.z, v_to_min.z, v_to_max.z);
}
}
[[node]]
void vector_map_range_smoothstep(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
float3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
factor = clamp(factor, 0.0f, 1.0f);
factor = (3.0f - 2.0f * factor) * (factor * factor);
v_result = v_to_min + factor * (v_to_max - v_to_min);
}
[[node]]
void vector_map_range_smootherstep(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
float3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min));
factor = clamp(factor, 0.0f, 1.0f);
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
v_result = v_to_min + factor * (v_to_max - v_to_min);
}
[[node]]
void map_range_linear(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
}
else {
result = 0.0f;
}
}
[[node]]
void map_range_stepped(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
if (fromMax != fromMin) {
float factor = (value - fromMin) / (fromMax - fromMin);
factor = (steps > 0.0f) ? floor(factor * (steps + 1.0f)) / steps : 0.0f;
result = toMin + factor * (toMax - toMin);
}
else {
result = 0.0f;
}
}
[[node]]
void map_range_smoothstep(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0f - smoothstep(fromMax, fromMin, value) :
smoothstep(fromMin, fromMax, value);
result = toMin + factor * (toMax - toMin);
}
else {
result = 0.0f;
}
}
[[node]]
void map_range_smootherstep(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
float3 v_value,
float3 v_from_min,
float3 v_from_max,
float3 v_to_min,
float3 v_to_max,
float3 v_steps,
float use_clamp,
float &result,
float3 &v_result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0f - smootherstep(fromMax, fromMin, value) :
smootherstep(fromMin, fromMax, value);
result = toMin + factor * (toMax - toMin);
}
else {
result = 0.0f;
}
}

View File

@@ -0,0 +1,47 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_euler_lib.glsl"
#include "gpu_shader_math_matrix_construct_lib.glsl"
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void mapping_mat4(float3 vec,
float4 m0,
float4 m1,
float4 m2,
float4 m3,
float3 minvec,
float3 maxvec,
float3 &outvec)
{
float4x4 mat = float4x4(m0, m1, m2, m3);
outvec = (mat * float4(vec, 1.0f)).xyz;
outvec = clamp(outvec, minvec, maxvec);
}
[[node]]
void mapping_point(float3 vector, float3 location, float3 rotation, float3 scale, float3 &result)
{
result = (from_rotation(EulerXYZ::from_float3(rotation)) * (vector * scale)) + location;
}
[[node]]
void mapping_texture(float3 vector, float3 location, float3 rotation, float3 scale, float3 &result)
{
result = safe_divide(
transpose(from_rotation(EulerXYZ::from_float3(rotation))) * (vector - location), scale);
}
[[node]]
void mapping_vector(float3 vector, float3 location, float3 rotation, float3 scale, float3 &result)
{
result = from_rotation(EulerXYZ::from_float3(rotation)) * (vector * scale);
}
[[node]]
void mapping_normal(float3 vector, float3 location, float3 rotation, float3 scale, float3 &result)
{
result = normalize(from_rotation(EulerXYZ::from_float3(rotation)) * safe_divide(vector, scale));
}

View File

@@ -0,0 +1,69 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
float3 fresnel_conductor(float cosi, float3 eta, float3 k)
{
float3 cosi_sqr = float3(cosi * cosi);
float3 one = float3(1.0f);
float3 tmp_f = (eta * eta) + (k * k);
float3 tmp_two_eta_cosi = 2.0f * eta * float3(cosi);
float3 tmp = tmp_f * cosi_sqr;
float3 Rparl2 = (tmp - tmp_two_eta_cosi + one) / (tmp + tmp_two_eta_cosi + one);
float3 Rperp2 = (tmp_f - tmp_two_eta_cosi + cosi_sqr) / (tmp_f + tmp_two_eta_cosi + cosi_sqr);
return (Rparl2 + Rperp2) * 0.5f;
}
[[node]]
void node_bsdf_metallic(float4 base_color,
float4 edge_tint,
float3 ior,
float3 extinction,
float roughness,
float anisotropy,
float rotation,
float3 N,
float3 T,
float weight,
float thin_film_thickness,
float thin_film_ior,
const float do_multiscatter,
const float use_complex_ior,
Closure &result)
{
float3 F0 = base_color.rgb;
float3 F82 = edge_tint.rgb;
if (use_complex_ior != 0.0f) {
/* Compute incidence at 0 and 82 degrees from conductor Fresnel. */
F0 = fresnel_conductor(1.0f, ior, extinction);
F82 = fresnel_conductor(1.0f / 7.0f, ior, extinction);
}
/* Clamp to match Cycles */
F0 = saturate(F0);
F82 = saturate(F82);
roughness = saturate(roughness);
/* Not used by EEVEE */
/* anisotropy = saturate(anisotropy); */
N = safe_normalize(N);
float3 V = coordinate_incoming(g_data.P);
float NV = dot(N, V);
ClosureReflection reflection_data;
reflection_data.N = N;
reflection_data.roughness = roughness;
float3 metallic_brdf;
brdf_f82_tint_lut(F0, F82, NV, roughness, do_multiscatter != 0.0f, metallic_brdf);
reflection_data.color = metallic_brdf;
reflection_data.weight = weight;
result = closure_eval(reflection_data);
}

View File

@@ -0,0 +1,359 @@
/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_color_utils.glsl"
#include "gpu_shader_math_rotation_lib.glsl"
[[node]]
void node_mix_blend(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = mix(col1, col2, fac);
}
[[node]]
void node_mix_add(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = mix(col1, col1 + col2, fac);
outcol.a = col1.a;
}
[[node]]
void node_mix_mult(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = mix(col1, col1 * col2, fac);
outcol.a = col1.a;
}
[[node]]
void node_mix_screen(float fac, float4 col1, float4 col2, float4 &outcol)
{
float facm = 1.0f - fac;
outcol = float4(1.0f) - (float4(facm) + fac * (float4(1.0f) - col2)) * (float4(1.0f) - col1);
outcol.a = col1.a;
}
[[node]]
void node_mix_overlay(float fac, float4 col1, float4 col2, float4 &outcol)
{
float facm = 1.0f - fac;
outcol = col1;
if (outcol.r < 0.5f) {
outcol.r *= facm + 2.0f * fac * col2.r;
}
else {
outcol.r = 1.0f - (facm + 2.0f * fac * (1.0f - col2.r)) * (1.0f - outcol.r);
}
if (outcol.g < 0.5f) {
outcol.g *= facm + 2.0f * fac * col2.g;
}
else {
outcol.g = 1.0f - (facm + 2.0f * fac * (1.0f - col2.g)) * (1.0f - outcol.g);
}
if (outcol.b < 0.5f) {
outcol.b *= facm + 2.0f * fac * col2.b;
}
else {
outcol.b = 1.0f - (facm + 2.0f * fac * (1.0f - col2.b)) * (1.0f - outcol.b);
}
}
[[node]]
void node_mix_sub(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = mix(col1, col1 - col2, fac);
outcol.a = col1.a;
}
/* A variant of mix_div that fallback to the first color upon zero division. */
[[node]]
void node_mix_div_fallback(float fac, float4 col1, float4 col2, float4 &outcol)
{
float facm = 1.0f - fac;
outcol = col1;
if (col2.r != 0.0f) {
outcol.r = facm * outcol.r + fac * outcol.r / col2.r;
}
if (col2.g != 0.0f) {
outcol.g = facm * outcol.g + fac * outcol.g / col2.g;
}
if (col2.b != 0.0f) {
outcol.b = facm * outcol.b + fac * outcol.b / col2.b;
}
}
[[node]]
void node_mix_diff(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = mix(col1, abs(col1 - col2), fac);
outcol.a = col1.a;
}
[[node]]
void node_mix_exclusion(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = max(mix(col1, col1 + col2 - 2.0f * col1 * col2, fac), 0.0f);
outcol.a = col1.a;
}
[[node]]
void node_mix_dark(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac);
outcol.a = col1.a;
}
[[node]]
void node_mix_light(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac);
outcol.a = col1.a;
}
[[node]]
void node_mix_dodge(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = col1;
if (outcol.r != 0.0f) {
float tmp = 1.0f - fac * col2.r;
if (tmp <= 0.0f) {
outcol.r = 1.0f;
}
else if ((tmp = outcol.r / tmp) > 1.0f) {
outcol.r = 1.0f;
}
else {
outcol.r = tmp;
}
}
if (outcol.g != 0.0f) {
float tmp = 1.0f - fac * col2.g;
if (tmp <= 0.0f) {
outcol.g = 1.0f;
}
else if ((tmp = outcol.g / tmp) > 1.0f) {
outcol.g = 1.0f;
}
else {
outcol.g = tmp;
}
}
if (outcol.b != 0.0f) {
float tmp = 1.0f - fac * col2.b;
if (tmp <= 0.0f) {
outcol.b = 1.0f;
}
else if ((tmp = outcol.b / tmp) > 1.0f) {
outcol.b = 1.0f;
}
else {
outcol.b = tmp;
}
}
}
[[node]]
void node_mix_burn(float fac, float4 col1, float4 col2, float4 &outcol)
{
float tmp, facm = 1.0f - fac;
outcol = col1;
tmp = facm + fac * col2.r;
if (tmp <= 0.0f) {
outcol.r = 0.0f;
}
else if ((tmp = (1.0f - (1.0f - outcol.r) / tmp)) < 0.0f) {
outcol.r = 0.0f;
}
else if (tmp > 1.0f) {
outcol.r = 1.0f;
}
else {
outcol.r = tmp;
}
tmp = facm + fac * col2.g;
if (tmp <= 0.0f) {
outcol.g = 0.0f;
}
else if ((tmp = (1.0f - (1.0f - outcol.g) / tmp)) < 0.0f) {
outcol.g = 0.0f;
}
else if (tmp > 1.0f) {
outcol.g = 1.0f;
}
else {
outcol.g = tmp;
}
tmp = facm + fac * col2.b;
if (tmp <= 0.0f) {
outcol.b = 0.0f;
}
else if ((tmp = (1.0f - (1.0f - outcol.b) / tmp)) < 0.0f) {
outcol.b = 0.0f;
}
else if (tmp > 1.0f) {
outcol.b = 1.0f;
}
else {
outcol.b = tmp;
}
}
[[node]]
void node_mix_hue(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = col1;
float4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
if (hsv2.y != 0.0f) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
}
}
[[node]]
void node_mix_sat(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = col1;
float4 hsv, hsv2;
rgb_to_hsv(outcol, hsv);
if (hsv.y != 0.0f) {
rgb_to_hsv(col2, hsv2);
hsv.y = (1.0f - fac) * hsv.y + fac * hsv2.y;
hsv_to_rgb(hsv, outcol);
}
}
[[node]]
void node_mix_val(float fac, float4 col1, float4 col2, float4 &outcol)
{
float4 hsv, hsv2;
rgb_to_hsv(col1, hsv);
rgb_to_hsv(col2, hsv2);
hsv.z = (1.0f - fac) * hsv.z + fac * hsv2.z;
hsv_to_rgb(hsv, outcol);
}
[[node]]
void node_mix_color(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = col1;
float4 hsv, hsv2, tmp;
rgb_to_hsv(col2, hsv2);
if (hsv2.y != 0.0f) {
rgb_to_hsv(outcol, hsv);
hsv.x = hsv2.x;
hsv.y = hsv2.y;
hsv_to_rgb(hsv, tmp);
outcol = mix(outcol, tmp, fac);
outcol.a = col1.a;
}
}
[[node]]
void node_mix_soft(float fac, float4 col1, float4 col2, float4 &outcol)
{
float facm = 1.0f - fac;
float4 one = float4(1.0f);
float4 scr = one - (one - col2) * (one - col1);
outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
outcol.a = col1.a;
}
[[node]]
void node_mix_linear(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = col1 + fac * (2.0f * (col2 - float4(0.5f)));
outcol.a = col1.a;
}
[[node]]
void node_mix_float(float fac, float f1, float f2, float &outfloat)
{
/* Avoid using mix() due to float precision issues caused by different implementations. */
outfloat = f1 * (1.0f - fac) + f2 * fac;
}
[[node]]
void node_mix_vector(float fac, float3 v1, float3 v2, float3 &outvec)
{
/* Avoid using mix() due to float precision issues caused by different implementations. */
outvec = v1 * (1.0f - fac) + v2 * fac;
}
[[node]]
void node_mix_vector_non_uniform(float3 facvec, float3 v1, float3 v2, float3 &outvec)
{
/* Avoid using mix() due to float precision issues caused by different implementations. */
outvec = v1 * (float3(1.0f) - facvec) + v2 * facvec;
}
[[node]]
void node_mix_rgba(float fac, float4 col1, float4 col2, float4 &outcol)
{
outcol = mix(col1, col2, fac);
}
[[node]]
void node_mix_clamp_color(float4 col, float4 min, float4 max, float4 &out_col)
{
out_col = clamp(col, min, max);
}
[[node]]
void node_mix_clamp_vector(float3 vec, float3 min, float3 max, float3 &outvec)
{
outvec = clamp(vec, min, max);
}
[[node]]
void node_mix_clamp_value(float value, float min, float max, float &outfloat)
{
outfloat = clamp(value, min, max);
}
[[node]]
void node_mix_rotation(float fac, float4 rot1, float4 rot2, float4 &outrot)
{
outrot = interpolate(Quaternion{UNPACK4(rot1)}, Quaternion{UNPACK4(rot2)}, fac).as_float4();
}

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_mix_shader(float fac, Closure shader1, Closure shader2, Closure &shader)
{
shader = closure_mix(shader1, shader2, fac);
}

View File

@@ -0,0 +1,330 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
#include "gpu_shader_math_vector_safe_lib.glsl"
/* clang-format off */
#define FLOORFRAC(x, x_int, x_fract) { float x_floor = floor(x); x_int = int(x_floor); x_fract = x - x_floor; }
/* clang-format on */
/* Bilinear Interpolation:
*
* v2 v3
* @ + + + + @ y
* + + ^
* + + |
* + + |
* @ + + + + @ @------> x
* v0 v1
*/
float bi_mix(float v0, float v1, float v2, float v3, 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
*/
float tri_mix(float v0,
float v1,
float v2,
float v3,
float v4,
float v5,
float v6,
float v7,
float x,
float y,
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));
}
float quad_mix(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,
float x,
float y,
float z,
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);
}
float fade(float t)
{
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}
float negate_if(float value, uint condition)
{
return (condition != 0u) ? -value : value;
}
float noise_grad(uint hash, float x)
{
uint h = hash & 15u;
float g = 1u + (h & 7u);
return negate_if(g, h & 8u) * x;
}
float noise_grad(uint hash, float x, float y)
{
uint h = hash & 7u;
float u = h < 4u ? x : y;
float v = 2.0f * (h < 4u ? y : x);
return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
float noise_grad(uint hash, float x, float y, float z)
{
uint h = hash & 15u;
float u = h < 8u ? x : y;
float vt = ((h == 12u) || (h == 14u)) ? x : z;
float v = h < 4u ? y : vt;
return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
float noise_grad(uint hash, float x, float y, float z, float w)
{
uint h = hash & 31u;
float u = h < 24u ? x : y;
float v = h < 16u ? y : z;
float s = h < 8u ? z : w;
return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
}
float noise_perlin(float x)
{
int X;
float fx;
FLOORFRAC(x, X, fx);
float u = fade(fx);
float r = mix(noise_grad(hash_int(X), fx), noise_grad(hash_int(X + 1), fx - 1.0f), u);
return r;
}
float noise_perlin(float2 vec)
{
int X, Y;
float fx, fy;
FLOORFRAC(vec.x, X, fx);
FLOORFRAC(vec.y, Y, fy);
float u = fade(fx);
float v = fade(fy);
float r = bi_mix(noise_grad(hash_int2(X, Y), fx, fy),
noise_grad(hash_int2(X + 1, Y), fx - 1.0f, fy),
noise_grad(hash_int2(X, Y + 1), fx, fy - 1.0f),
noise_grad(hash_int2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f),
u,
v);
return r;
}
float noise_perlin(float3 vec)
{
int X, Y, Z;
float fx, fy, fz;
FLOORFRAC(vec.x, X, fx);
FLOORFRAC(vec.y, Y, fy);
FLOORFRAC(vec.z, Z, fz);
float u = fade(fx);
float v = fade(fy);
float w = fade(fz);
float r = tri_mix(noise_grad(hash_int3(X, Y, Z), fx, fy, fz),
noise_grad(hash_int3(X + 1, Y, Z), fx - 1, fy, fz),
noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1, fz),
noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1, fy - 1, fz),
noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1),
noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1, fy, fz - 1),
noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1, fz - 1),
noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1),
u,
v,
w);
return r;
}
float noise_perlin(float4 vec)
{
int X, Y, Z, W;
float fx, fy, fz, fw;
FLOORFRAC(vec.x, X, fx);
FLOORFRAC(vec.y, Y, fy);
FLOORFRAC(vec.z, Z, fz);
FLOORFRAC(vec.w, W, fw);
float u = fade(fx);
float v = fade(fy);
float t = fade(fz);
float s = fade(fw);
float r = quad_mix(
noise_grad(hash_int4(X, Y, Z, W), fx, fy, fz, fw),
noise_grad(hash_int4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw),
noise_grad(hash_int4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw),
noise_grad(hash_int4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw),
noise_grad(hash_int4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw),
noise_grad(hash_int4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw),
noise_grad(hash_int4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw),
noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw),
noise_grad(hash_int4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f),
noise_grad(hash_int4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f),
noise_grad(hash_int4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f),
noise_grad(hash_int4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f),
noise_grad(hash_int4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f),
noise_grad(hash_int4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f),
noise_grad(hash_int4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f),
noise_grad(
hash_int4(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;
}
/* Remap the output of noise to a predictable range [-1, 1].
* The scale values were computed experimentally by the OSL developers.
*/
float noise_scale1(float result)
{
return 0.2500f * result;
}
float noise_scale2(float result)
{
return 0.6616f * result;
}
float noise_scale3(float result)
{
return 0.9820f * result;
}
float noise_scale4(float result)
{
return 0.8344f * result;
}
/* Safe Signed And Unsigned Noise */
float snoise(float p)
{
float precision_correction = 0.5f * float(abs(p) >= 1000000.0f);
/* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
* representation issues. */
p = compatible_mod(p, 100000.0f) + precision_correction;
return noise_scale1(noise_perlin(p));
}
float noise(float p)
{
return 0.5f * snoise(p) + 0.5f;
}
float snoise(float2 p)
{
float2 precision_correction = 0.5f * float2(float(abs(p.x) >= 1000000.0f),
float(abs(p.y) >= 1000000.0f));
/* Repeat Perlin noise texture every 100000.0 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 = compatible_mod(p, 100000.0f) + precision_correction;
return noise_scale2(noise_perlin(p));
}
float noise(float2 p)
{
return 0.5f * snoise(p) + 0.5f;
}
float snoise(float3 p)
{
float3 precision_correction = 0.5f * float3(float(abs(p.x) >= 1000000.0f),
float(abs(p.y) >= 1000000.0f),
float(abs(p.z) >= 1000000.0f));
/* Repeat Perlin noise texture every 100000.0 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 = compatible_mod(p, 100000.0f) + precision_correction;
return noise_scale3(noise_perlin(p));
}
float noise(float3 p)
{
return 0.5f * snoise(p) + 0.5f;
}
float snoise(float4 p)
{
float4 precision_correction = 0.5f * float4(float(abs(p.x) >= 1000000.0f),
float(abs(p.y) >= 1000000.0f),
float(abs(p.z) >= 1000000.0f),
float(abs(p.w) >= 1000000.0f));
/* Repeat Perlin noise texture every 100000.0 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 = compatible_mod(p, 100000.0f) + precision_correction;
return noise_scale4(noise_perlin(p));
}
float noise(float4 p)
{
return 0.5f * snoise(p) + 0.5f;
}

View File

@@ -0,0 +1,10 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void normal_new_shading(float3 nor, float3 dir, float3 &outnor, float &outdot)
{
outnor = dir;
outdot = dot(normalize(nor), dir);
}

View File

@@ -0,0 +1,63 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void input_normal_displaced(float3 &outnormal)
{
#ifdef MAT_DISPLACEMENT_BUMP
outnormal = g_data.N;
#else
outnormal = g_data.Ni;
#endif
}
[[node]]
void input_normal_original(float3 &outnormal)
{
outnormal = g_data.Ni;
}
[[node]]
void node_normal_map(
float4 tangent, float strength, float3 texnormal, float3 input_normal, float3 &outnormal)
{
if (all(equal(tangent, float4(0.0f, 0.0f, 0.0f, 1.0f)))) {
outnormal = input_normal;
return;
}
tangent *= (FrontFacing ? 1.0f : -1.0f);
float3 B = tangent.w * cross(input_normal, tangent.xyz);
B *= (object_infos_get().flag & OBJECT_NEGATIVE_SCALE) != 0 ? -1.0f : 1.0f;
/* Apply strength here instead of in node_normal_map_mix for tangent space. */
texnormal.xy *= strength;
texnormal.z = mix(1.0f, texnormal.z, saturate(strength));
outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * input_normal;
outnormal = normalize(outnormal);
}
[[node]]
void color_to_normal_new_shading(float3 color, float3 &normal)
{
normal = float3(2.0f) * color - float3(1.0f);
}
[[node]]
void color_to_blender_normal_new_shading(float3 color, float3 &normal)
{
normal = float3(2.0f, -2.0f, -2.0f) * color - float3(1.0f);
}
[[node]]
void color_invert_green_channel(float3 color, out float3 result)
{
result = float3(color.x, -color.y, color.z);
}
[[node]]
void node_normal_map_mix(float strength, float3 newnormal, float3 &outnormal)
{
outnormal = normalize(mix(g_data.N, newnormal, max(0.0f, strength)));
}

View File

@@ -0,0 +1,22 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_object_info(float mat_index,
float3 &location,
float4 &color,
float &alpha,
float &object_index,
float &material_index,
float &random)
{
location = object_matrices_get().model[3].xyz;
ObjectInfos info = object_infos_get();
color = info.ob_color;
alpha = info.ob_color.a;
object_index = info.index;
/* TODO(fclem): Put that inside the Material UBO. */
material_index = mat_index;
random = info.random;
}

View File

@@ -0,0 +1,20 @@
/* SPDX-FileCopyrightText: 2020-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_output_aov(float4 color, float value, float hash, Closure &dummy)
{
#ifdef GPU_FRAGMENT_SHADER
# ifdef OBINFO_LIB
output_aov(int2(gl_FragCoord.xy),
color,
value,
floatBitsToUint(hash),
g_holdout,
object_infos_get().flag);
# else
output_aov(int2(gl_FragCoord.xy), color, value, floatBitsToUint(hash), 0.0f, 0u);
# endif
#endif
}

View File

@@ -0,0 +1,40 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_transform_utils.glsl"
[[node]]
void node_output_material_surface(Closure surface, Closure &out_surface)
{
out_surface = surface;
}
[[node]]
void node_output_material_volume(Closure volume, Closure &out_volume)
{
out_volume = volume;
}
[[node]]
void node_output_material_displacement(float3 displacement, float3 &out_displacement)
{
out_displacement = displacement;
}
[[node]]
void node_output_material_thickness(float thickness, float &out_thickness)
{
const ObjectMatrices obj = object_matrices_get();
float3 ob_scale;
ob_scale.x = length(obj.model[0].xyz);
ob_scale.y = length(obj.model[1].xyz);
ob_scale.z = length(obj.model[2].xyz);
float3 thickness_vec = abs(max(thickness, 0.0f) * ob_scale);
/* Contrary to displacement we need to output a scalar quantity.
* We arbitrarily choose to output the axis with the minimum extent since it is the axis along
* which the object is usually viewed at. */
out_thickness = min(min(thickness_vec.x, thickness_vec.y), thickness_vec.z);
}

View File

@@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_output_world_surface(Closure surface, Closure &out_surface)
{
out_surface = surface;
}
[[node]]
void node_output_world_volume(Closure volume, Closure &out_volume)
{
out_volume = volume;
}

View File

@@ -0,0 +1,25 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void particle_info(float &index,
float &random,
float &age,
float &life_time,
float3 &location,
float &size,
float3 &velocity,
float3 &angular_velocity)
{
/* Unsupported for now. */
index = 0.0f;
random = 0.0f;
age = 0.0f;
life_time = 0.0f;
size = 0.0f;
location = float3(0.0f);
velocity = float3(0.0f);
angular_velocity = float3(0.0f);
}

View File

@@ -0,0 +1,25 @@
/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
[[node]]
void node_point_info(float3 &position, float &radius, float &random)
{
#ifdef MAT_GEOM_POINTCLOUD
/* EEVEE-Next case. */
position = pointcloud_interp.position;
radius = pointcloud_interp.radius;
random = wang_hash_noise(uint(pointcloud_interp_flat.id));
#elif defined(POINTCLOUD_SHADER)
/* EEVEE-Legacy case. */
position = pointPosition;
radius = pointRadius;
random = wang_hash_noise(uint(pointID));
#else
position = float3(0.0f, 0.0f, 0.0f);
radius = 0.0f;
random = 0.0f;
#endif
}

View File

@@ -0,0 +1,333 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_math.glsl"
#include "gpu_shader_math_fast_lib.glsl"
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
float3 tint_from_color(float3 color)
{
float lum = dot(color, float3(0.3f, 0.6f, 0.1f)); /* luminance approx. */
return (lum > 0.0f) ? color / lum : float3(1.0f); /* normalize lum. to isolate hue+sat */
}
float principled_sheen(float NV, float rough)
{
/* Empirical approximation (manual curve fitting) to the sheen_weight albedo. Can be refined. */
float den = 35.6694f * rough * rough - 24.4269f * rough * NV - 0.1405f * NV * NV +
6.1211f * rough + 0.28105f * NV - 0.1405f;
float num = 58.5299f * rough * rough - 85.0941f * rough * NV + 9.8955f * NV * NV +
1.9250f * rough + 74.2268f * NV - 0.2246f;
return saturate(den / num);
}
float ior_from_F0(float F0)
{
float f = sqrt(clamp(F0, 0.0f, 0.99f));
return (-f - 1.0f) / (f - 1.0f);
}
float thin_glass_transmission_roughness(float roughness, float ior)
{
return saturate(roughness *
sqrt(sqrt(3.4f * (ior - 1.0f) * square(ior - 0.5f) / (square(ior) * ior))));
}
/* Given the transmittance through a slab at normal incidence, compute the transmittance at a
* certain incident angle, based on Beer-Lambert law. */
float3 slab_transmittance_at_angle(float3 color, float cos_theta_i, float ior)
{
const float inv_cos_theta_t = ior * inversesqrt(square(ior) - (1.0f - square(cos_theta_i)));
return pow(color, float3(inv_cos_theta_t));
}
[[node]]
void node_bsdf_principled(float4 base_color,
float metallic,
float roughness,
float ior,
float alpha,
float thin_wall,
float3 N,
float weight,
float diffuse_roughness,
float subsurface_weight,
float3 subsurface_radius,
float subsurface_scale,
float subsurface_ior,
float subsurface_anisotropy,
float specular_ior_level,
float4 specular_tint,
float anisotropic,
float anisotropic_rotation,
float3 T,
float transmission_weight,
float coat_weight,
float coat_roughness,
float coat_ior,
float4 coat_tint,
float3 CN,
float sheen_weight,
float sheen_roughness,
float4 sheen_tint,
float4 emission,
float emission_strength,
float thin_film_thickness,
float thin_film_ior,
const float do_multiscatter,
const float subsurface_random_walk_radius_scale,
Closure &result)
{
/* Match cycles. */
metallic = saturate(metallic);
roughness = saturate(roughness);
ior = max(ior, 1e-5f);
alpha = saturate(alpha);
subsurface_weight = saturate(subsurface_weight);
/* Not used by EEVEE */
/* subsurface_anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f); */
/* subsurface_ior = clamp(subsurface_ior, 1.01f, 3.8f); */
specular_ior_level = max(specular_ior_level, 0.0f);
specular_tint = max(specular_tint, float4(0.0f));
/* Not used by EEVEE */
/* anisotropic = saturate(anisotropic); */
transmission_weight = saturate(transmission_weight);
coat_weight = max(coat_weight, 0.0f);
coat_roughness = saturate(coat_roughness);
coat_ior = max(coat_ior, 1.0f);
coat_tint = max(coat_tint, float4(0.0f));
sheen_weight = max(sheen_weight, 0.0f);
sheen_roughness = saturate(sheen_roughness);
sheen_tint = max(sheen_tint, float4(0.0f));
base_color = max(base_color, float4(0.0f));
float4 clamped_base_color = min(base_color, float4(1.0f));
N = normalize_fallback(N, g_data.N);
CN = normalize_fallback(CN, g_data.N);
float3 V = coordinate_incoming(g_data.P);
float NV = dot(N, V);
/* Transparency component. */
if (true) {
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = float3(1.0f - alpha);
transparency_data.holdout = 0.0f;
closure_eval(transparency_data);
weight *= alpha;
}
/* First layer: Sheen */
float3 sheen_data_color = float3(0.0f);
if (sheen_weight > 0.0f) {
float sheen_NV = NV;
#ifdef MAT_CLEARCOAT
if (coat_weight > 0.0f) {
float3 sheen_N = safe_normalize(mix(N, CN, saturate(coat_weight)));
sheen_NV = dot(sheen_N, V);
}
#endif
sheen_NV = saturate(sheen_NV);
/* TODO: Maybe sheen_weight should be specular. */
float3 sheen_color = sheen_weight * sheen_tint.rgb *
principled_sheen(sheen_NV, sheen_roughness);
sheen_data_color = weight * sheen_color;
/* Attenuate lower layers */
weight *= max((1.0f - math_reduce_max(sheen_color)), 0.0f);
}
#ifdef MAT_CLEARCOAT
/* Second layer: Coat */
if (coat_weight > 0.0f) {
float coat_NV = dot(CN, V);
float reflectance = bsdf_lut(coat_NV, coat_roughness, coat_ior, false).x;
ClosureReflection coat_data;
coat_data.N = CN;
coat_data.roughness = coat_roughness;
coat_data.color = float3(1.0f);
coat_data.weight = weight * coat_weight * reflectance;
closure_eval(coat_data);
/* Attenuate lower layers */
weight *= max((1.0f - reflectance * coat_weight), 0.0f);
if (!all(equal(coat_tint.rgb, float3(1.0f)))) {
/* Tint lower layers. */
const float3 tint = slab_transmittance_at_angle(coat_tint.rgb, NV, coat_ior);
coat_tint.rgb = mix(float3(1.0f), tint, saturate(coat_weight));
}
}
else {
coat_tint.rgb = float3(1.0f);
}
#else
coat_tint.rgb = float3(1.0f);
#endif
/* Emission component.
* Attenuated by sheen and coat.
*/
if (true) {
ClosureEmission emission_data;
emission_data.weight = weight;
emission_data.emission = coat_tint.rgb * emission.rgb * emission_strength;
closure_eval(emission_data);
}
/* Metallic component */
float3 reflection_tint = specular_tint.rgb;
float3 reflection_color = float3(0.0f);
if (metallic > 0.0f) {
float3 F0 = clamped_base_color.rgb;
float3 F82 = min(reflection_tint, float3(1.0f));
float3 metallic_brdf;
brdf_f82_tint_lut(F0, F82, NV, roughness, do_multiscatter != 0.0f, metallic_brdf);
reflection_color = weight * metallic * metallic_brdf;
/* Attenuate lower layers */
weight *= max((1.0f - metallic), 0.0f);
}
#ifdef MAT_REFRACTION
/* Transmission component */
if (transmission_weight > 0.0f) {
float3 F0 = float3(F0_from_ior(ior)) * reflection_tint;
float3 F90 = float3(1.0f);
float3 reflectance, transmittance;
if (thin_wall != 0.0f) {
bsdf_lut(F0, F90, float3(1.0f), NV, roughness, ior, true, reflectance, transmittance);
/* Adjust transmission tint based on relative path length. */
const float3 c = slab_transmittance_at_angle(clamped_base_color.rgb, NV, ior);
/* Account for internal reflections, t' = ctt + ct(rc)^2t + ct(rc)^4t + ... */
transmittance = safe_divide(c * square(transmittance), (1.0f - square(reflectance * c)));
/* r' = r + ctrct + ct(rc)^3t + ... */
reflectance *= (1.0f + transmittance * c);
/* Transmission. */
ClosureThinRefraction refraction_data;
refraction_data.color = transmittance * coat_tint.rgb;
refraction_data.weight = weight * transmission_weight;
refraction_data.N = N;
refraction_data.roughness = thin_glass_transmission_roughness(roughness, ior);
closure_eval(refraction_data);
}
else {
bsdf_lut(F0,
F90,
sqrt(clamped_base_color.rgb),
NV,
roughness,
ior,
do_multiscatter != 0.0f,
reflectance,
transmittance);
ClosureRefraction refraction_data;
refraction_data.N = N;
refraction_data.roughness = roughness;
refraction_data.ior = ior;
refraction_data.weight = weight * transmission_weight;
refraction_data.color = transmittance * coat_tint.rgb;
closure_eval(refraction_data);
}
reflection_color += weight * transmission_weight * reflectance;
/* Attenuate lower layers */
weight *= max((1.0f - transmission_weight), 0.0f);
}
#endif
/* Specular component */
if (true) {
float eta = ior;
float f0 = F0_from_ior(eta);
if (specular_ior_level != 0.5f) {
f0 *= 2.0f * specular_ior_level;
eta = ior_from_F0(f0);
if (ior < 1.0f) {
eta = 1.0f / eta;
}
}
float3 F0 = float3(f0) * reflection_tint;
F0 = clamp(F0, float3(0.0f), float3(1.0f));
float3 F90 = float3(1.0f);
float3 reflectance, unused;
bsdf_lut(
F0, F90, float3(0.0f), NV, roughness, eta, do_multiscatter != 0.0f, reflectance, unused);
ClosureReflection reflection_data;
reflection_data.N = N;
reflection_data.roughness = roughness;
reflection_data.color = (reflection_color + weight * reflectance) * coat_tint.rgb;
/* `weight` is already applied in `color`. */
reflection_data.weight = 1.0f;
closure_eval(reflection_data);
/* Attenuate lower layers */
weight *= max((1.0f - math_reduce_max(reflectance)), 0.0f);
}
float diffuse_weight = 0.0f;
/* Subsurface component */
if (subsurface_weight > 0.0f) {
if (thin_wall != 0.0f) {
/* Backward scattering is approximated by diffuse. */
diffuse_weight = subsurface_weight * weight *
saturate(0.5f * (1.0f - subsurface_anisotropy));
/* Forward scattering is approximated by translucent. */
ClosureTranslucent translucent_data;
translucent_data.weight = subsurface_weight * weight *
saturate(0.5f * (1.0f + subsurface_anisotropy));
translucent_data.color = base_color.rgb * coat_tint.rgb;
translucent_data.N = N;
closure_eval(translucent_data);
}
#ifdef MAT_SUBSURFACE
else {
ClosureSubsurface sss_data;
sss_data.N = N;
sss_data.sss_radius = max(subsurface_radius * subsurface_scale *
subsurface_random_walk_radius_scale,
float3(0.0f));
/* Subsurface Scattering materials behave unpredictably with values greater than 1.0 in
* Cycles. So it's clamped there and we clamp here for consistency with Cycles. */
sss_data.color = (subsurface_weight * weight) * clamped_base_color.rgb * coat_tint.rgb;
/* Add energy of the sheen layer until we have proper sheen BSDF. */
sss_data.color += sheen_data_color;
/* `weight` is already applied in `color`. */
sss_data.weight = 1.0f;
closure_eval(sss_data);
}
#endif
/* Attenuate lower layers */
weight *= max((1.0f - subsurface_weight), 0.0f);
}
#ifdef MAT_DIFFUSE
/* Diffuse component */
if (true) {
ClosureDiffuse diffuse_data;
diffuse_data.N = N;
diffuse_data.color = (diffuse_weight + weight) * base_color.rgb * coat_tint.rgb;
/* Add energy of the sheen layer until we have proper sheen BSDF. */
diffuse_data.color += sheen_data_color;
/* `weight` is already applied in `color`. */
diffuse_data.weight = 1.0f;
closure_eval(diffuse_data);
}
#endif
result = Closure(0);
}

View File

@@ -0,0 +1,17 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_compare_lib.glsl"
[[node]]
void quaternion_to_rotation(float w, float x, float y, float z, out float4 rotation)
{
const float4 quat = float4(w, x, y, z);
if (!is_zero(quat)) {
rotation = normalize(quat);
}
else {
rotation = float4(1.0f, 0.0f, 0.0f, 0.0f);
}
}

View File

@@ -0,0 +1,50 @@
/* SPDX-FileCopyrightText: 2024-2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_base_lib.glsl"
#include "gpu_shader_math_constants_lib.glsl"
/* Define macro flags for code adaption. */
/* No macro flags necessary, as code is adapted to GLSL by default. */
/* The rounded polygon calculation functions are defined in
* gpu_shader_material_radial_tiling_shared.glsl. */
#include "gpu_shader_material_radial_tiling_shared.glsl"
/* Undefine macro flags used for code adaption. */
/* No macro flags necessary, as code is adapted to GLSL by default. */
[[node]]
void node_radial_tiling(float2 coord,
float r_gon_sides,
float r_gon_roundness,
float normalize_r_gon_parameter,
float calculate_r_gon_parameter_field,
float calculate_segment_id,
float calculate_max_unit_parameter,
float calculate_x_axis_A_angle_bisector,
float3 &out_segment_coordinates,
float &out_segment_id,
float &out_max_unit_parameter,
float &out_x_axis_A_angle_bisector)
{
if (bool(calculate_r_gon_parameter_field) || bool(calculate_max_unit_parameter) ||
bool(calculate_x_axis_A_angle_bisector))
{
float4 out_variables = calculate_out_variables(bool(calculate_r_gon_parameter_field),
bool(calculate_max_unit_parameter),
bool(normalize_r_gon_parameter),
max(r_gon_sides, 2.0),
clamp(r_gon_roundness, 0.0, 1.0),
float2(coord.x, coord.y));
out_segment_coordinates = float3(out_variables.y, out_variables.x, 0.0);
out_max_unit_parameter = out_variables.z;
out_x_axis_A_angle_bisector = out_variables.w;
}
if (bool(calculate_segment_id)) {
out_segment_id = calculate_out_segment_id(max(r_gon_sides, 2.0), float2(coord.x, coord.y));
}
}

View File

@@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_bsdf_ray_portal(
float4 color, float3 position, float3 direction, float weight, Closure &result)
{
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = color.rgb;
transparency_data.holdout = 0.0f;
result = closure_eval(transparency_data);
}

View File

@@ -0,0 +1,39 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_raycast(float3 position,
float3 direction,
float length,
float &is_hit,
float &is_self_hit,
float &hit_distance,
float3 &hit_position,
float3 &hit_normal)
{
bool hit = false;
bool self_hit = false;
raycast_eval(
position, direction, length, false, hit, self_hit, hit_distance, hit_position, hit_normal);
is_hit = hit ? 1.0f : 0.0f;
is_self_hit = self_hit ? 1.0f : 0.0f;
}
[[node]]
void node_raycast_only_local(float3 position,
float3 direction,
float length,
float &is_hit,
float &is_self_hit,
float &hit_distance,
float3 &hit_position,
float3 &hit_normal)
{
bool hit = false;
bool self_hit = false;
raycast_eval(
position, direction, length, true, hit, self_hit, hit_distance, hit_position, hit_normal);
is_hit = hit ? 1.0f : 0.0f;
is_self_hit = self_hit ? 1.0f : 0.0f;
}

View File

@@ -0,0 +1,25 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
[[node]]
void node_bsdf_refraction(
float4 color, float roughness, float ior, float3 N, float weight, Closure &result)
{
color = max(color, float4(0.0f));
roughness = saturate(roughness);
ior = max(ior, 1e-5f);
N = safe_normalize(N);
ClosureRefraction refraction_data;
refraction_data.weight = weight;
refraction_data.color = color.rgb;
refraction_data.N = N;
refraction_data.roughness = roughness;
refraction_data.ior = ior;
result = closure_eval(refraction_data);
}

View File

@@ -0,0 +1,24 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifdef GPU_SHADER
# define REPEAT_BEGIN(count, var) \
for (int var##_i = 0; var##_i < count; var##_i++) { \
var = float(var##_i);
# define REPEAT_END() }
#else
/**
* Dummy functions for gpu_shader_dependency.
* Functions need parameters to be reflected, but we don't really rely on the reflection data.
*/
[[node]]
void REPEAT_BEGIN(float dummy) {};
[[node]]
void REPEAT_END(float dummy) {};
#endif

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void rgbtobw(float4 color, float3 luminance_coefficients, float &outval)
{
outval = dot(color.rgb, luminance_coefficients);
}

View File

@@ -0,0 +1,19 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_quaternion_lib.glsl"
[[node]]
void rotate_rotation_global(float4 rotation, float4 rotate_by, out float4 result)
{
result = math_quaternion_multiply(Quaternion{UNPACK4(rotate_by)}, Quaternion{UNPACK4(rotation)})
.as_float4();
}
[[node]]
void rotate_rotation_local(float4 rotation, float4 rotate_by, out float4 result)
{
result = math_quaternion_multiply(Quaternion{UNPACK4(rotation)}, Quaternion{UNPACK4(rotate_by)})
.as_float4();
}

View File

@@ -0,0 +1,11 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_quaternion_lib.glsl"
[[node]]
void rotate_vector(float3 vector, float4 rotation, out float3 result)
{
result = transform_point_by_quaternion(Quaternion{UNPACK4(rotation)}, vector);
}

View File

@@ -0,0 +1,13 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_rotation_conversion_lib.glsl"
[[node]]
void rotation_to_axis_angle(float4 rotation, out float3 axis, out float angle)
{
const AxisAngle aa = to_axis_angle(Quaternion{UNPACK4(rotation)});
axis = aa.axis;
angle = aa.angle;
}

View File

@@ -0,0 +1,13 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_matrix_construct_lib.glsl"
#include "gpu_shader_math_rotation_conversion_lib.glsl"
[[node]]
void rotation_to_euler(float4 rotation, out float3 euler)
{
Quaternion quat = Quaternion{UNPACK4(rotation)};
euler = to_euler(from_rotation(quat)).as_float3();
}

View File

@@ -0,0 +1,12 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void rotation_to_quaternion(float4 rotation, out float w, out float x, out float y, out float z)
{
w = rotation.x;
x = rotation.y;
y = rotation.z;
z = rotation.w;
}

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_scene_time(float &seconds, float &frame)
{
scene_time_uniforms(seconds, frame);
}

View File

@@ -0,0 +1,35 @@
/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_color_utils.glsl"
[[node]]
void separate_color_rgb(float4 col, float &r, float &g, float &b)
{
r = col.r;
g = col.g;
b = col.b;
}
[[node]]
void separate_color_hsv(float4 col, float &r, float &g, float &b)
{
float4 hsv;
rgb_to_hsv(col, hsv);
r = hsv[0];
g = hsv[1];
b = hsv[2];
}
[[node]]
void separate_color_hsl(float4 col, float &r, float &g, float &b)
{
float4 hsl;
rgb_to_hsl(col, hsl);
r = hsl[0];
g = hsl[1];
b = hsl[2];
}

View File

@@ -0,0 +1,11 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void separate_xyz(float3 vec, float &x, float &y, float &z)
{
x = vec.r;
y = vec.g;
z = vec.b;
}

View File

@@ -0,0 +1,57 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void set_value(float val, float &outval)
{
outval = val;
}
[[node]]
void set_rgb(float3 col, float3 &outcol)
{
outcol = col;
}
[[node]]
void set_rgba(float4 col, float4 &outcol)
{
outcol = col;
}
[[node]]
void set_value_zero(float &outval)
{
outval = 0.0f;
}
[[node]]
void set_value_one(float &outval)
{
outval = 1.0f;
}
[[node]]
void set_rgb_zero(float3 &outval)
{
outval = float3(0.0f);
}
[[node]]
void set_rgb_one(float3 &outval)
{
outval = float3(1.0f);
}
[[node]]
void set_rgba_zero(float4 &outval)
{
outval = float4(0.0f);
}
[[node]]
void set_rgba_one(float4 &outval)
{
outval = float4(1.0f);
}

View File

@@ -0,0 +1,14 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_shader_to_rgba(Closure cl, float4 &outcol, float &outalpha)
{
#ifdef GPU_VERTEX_SHADER
outcol = float4(0.0f);
#else
outcol = closure_to_rgba(cl);
#endif
outalpha = outcol.a;
}

View File

@@ -0,0 +1,22 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
#include "gpu_shader_utildefines_lib.glsl"
[[node]]
void node_bsdf_sheen(float4 color, float roughness, float3 N, float weight, Closure &result)
{
color = max(color, float4(0.0f));
roughness = saturate(roughness);
N = safe_normalize(N);
/* Fall back to diffuse. */
ClosureDiffuse diffuse_data;
diffuse_data.weight = weight;
diffuse_data.color = color.rgb;
diffuse_data.N = N;
result = closure_eval(diffuse_data);
}

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void squeeze(float val, float width, float center, float &outval)
{
outval = 1.0f / (1.0f + pow(2.71828183f, -((val - center) * width)));
}

View File

@@ -0,0 +1,31 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void node_subsurface_scattering(float4 color,
float scale,
float3 radius,
float ior,
float roughness,
float anisotropy,
float3 N,
float weight,
float random_walk_radius_scale,
Closure &result)
{
color = max(color, float4(0.0f));
ior = max(ior, 1e-5f);
/* roughness = saturate(roughness) */
N = safe_normalize(N);
ClosureSubsurface sss_data;
sss_data.weight = weight;
sss_data.color = color.rgb;
sss_data.N = N;
sss_data.sss_radius = max(radius * scale * random_walk_radius_scale, float3(0.0f));
result = closure_eval(sss_data);
}

View File

@@ -0,0 +1,36 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_transform_utils.glsl"
[[node]]
void tangent_orco_x(float3 orco_in, float3 &orco_out)
{
orco_out = orco_in.xzy * float3(0.0f, -0.5f, 0.5f) + float3(0.0f, 0.25f, -0.25f);
}
[[node]]
void tangent_orco_y(float3 orco_in, float3 &orco_out)
{
orco_out = orco_in.zyx * float3(-0.5f, 0.0f, 0.5f) + float3(0.25f, 0.0f, -0.25f);
}
[[node]]
void tangent_orco_z(float3 orco_in, float3 &orco_out)
{
orco_out = orco_in.yxz * float3(-0.5f, 0.5f, 0.0f) + float3(0.25f, -0.25f, 0.0f);
}
[[node]]
void node_tangentmap(float4 attr_tangent, float3 &tangent)
{
tangent = normalize(attr_tangent.xyz);
}
[[node]]
void node_tangent(float3 orco, float3 &T)
{
direction_transform_object_to_world(orco, T);
T = cross(g_data.N, normalize(cross(T, g_data.N)));
}

View File

@@ -0,0 +1,85 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
float2 calc_brick_texture(float3 p,
float mortar_size,
float mortar_smooth,
float bias,
float brick_width,
float row_height,
float offset_amount,
int offset_frequency,
float squash_amount,
int squash_frequency)
{
int bricknum, rownum;
float offset = 0.0f;
float x, y;
rownum = int(floor(p.y / row_height));
if (offset_frequency != 0 && squash_frequency != 0) {
brick_width *= (rownum % squash_frequency != 0) ? 1.0f : squash_amount; /* squash */
offset = (rownum % offset_frequency != 0) ? 0.0f : (brick_width * offset_amount); /* offset */
}
bricknum = int(floor((p.x + offset) / brick_width));
x = (p.x + offset) - brick_width * bricknum;
y = p.y - row_height * rownum;
float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0f, 1.0f);
float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
if (min_dist >= mortar_size) {
return float2(tint, 0.0f);
}
else if (mortar_smooth == 0.0f) {
return float2(tint, 1.0f);
}
else {
min_dist = 1.0f - min_dist / mortar_size;
return float2(tint, smoothstep(0.0f, mortar_smooth, min_dist));
}
}
[[node]]
void node_tex_brick(float3 co,
float4 color1,
float4 color2,
float4 mortar,
float scale,
float mortar_size,
float mortar_smooth,
float bias,
float brick_width,
float row_height,
float offset_amount,
float offset_frequency,
float squash_amount,
float squash_frequency,
float4 &color,
float &fac)
{
float2 f2 = calc_brick_texture(co * scale,
mortar_size,
mortar_smooth,
bias,
brick_width,
row_height,
offset_amount,
int(offset_frequency),
squash_amount,
int(squash_frequency));
float tint = f2.x;
float f = f2.y;
if (f != 1.0f) {
float facm = 1.0f - tint;
color1 = facm * color1 + tint * color2;
}
color = mix(color1, mortar, f);
fac = f;
}

View File

@@ -0,0 +1,22 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_tex_checker(
float3 co, float4 color1, float4 color2, float scale, float4 &color, float &fac)
{
float3 p = co * scale;
/* Prevent precision issues on unit coordinates. */
p = (p + 0.000001f) * 0.999999f;
int xi = int(abs(floor(p.x)));
int yi = int(abs(floor(p.y)));
int zi = int(abs(floor(p.z)));
bool check = ((mod(xi, 2) == mod(yi, 2)) == bool(mod(zi, 2)));
color = check ? color1 : color2;
fac = check ? 1.0f : 0.0f;
}

View File

@@ -0,0 +1,36 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_vector_math.glsl"
#include "gpu_shader_math_base_lib.glsl"
[[node]]
void node_tex_environment_equirectangular(float3 co, float3 &uv)
{
float3 nco = vector_math_safe_normalize(co);
if (nco.x == 0.0f || nco.y == 0.0f) {
uv = float3(0.0f);
return;
}
uv.x = -atan(nco.y, nco.x) / (2.0f * M_PI) + 0.5f;
uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5f;
}
[[node]]
void node_tex_environment_mirror_ball(float3 co, float3 &uv)
{
float3 nco = vector_math_safe_normalize(co);
nco.y -= 1.0f;
float div = 2.0f * sqrt(max(-0.5f * nco.y, 0.0f));
nco /= max(1e-8f, div);
uv = 0.5f * nco.xzz + 0.5f;
}
[[node]]
void node_tex_environment_empty(float3 co, float4 &color)
{
color = float4(1.0f, 0.0f, 1.0f, 1.0f);
}

View File

@@ -0,0 +1,329 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/* Implements Gabor noise based on the paper:
*
* Lagae, Ares, et al. "Procedural noise using sparse Gabor convolution." ACM Transactions on
* Graphics (TOG) 28.3f (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.4f
* (2019): 1-13.
*/
#include "gpu_shader_common_hash.glsl"
#include "gpu_shader_math_constants_lib.glsl"
#include "gpu_shader_math_vector_lib.glsl"
#define SHD_GABOR_TYPE_2D 0.0f
#define SHD_GABOR_TYPE_3D 1.0f
/* 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
/* 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. */
float2 compute_2d_gabor_kernel(float2 position, float frequency, float orientation)
{
float distance_squared = length_squared(position);
float hann_window = 0.5f + 0.5f * cos(M_PI * distance_squared);
float gaussian_envelop = exp(-M_PI * distance_squared);
float windowed_gaussian_envelope = gaussian_envelop * hann_window;
float2 frequency_vector = frequency * float2(cos(orientation), sin(orientation));
float angle = 2.0f * M_PI * dot(position, frequency_vector);
float2 phasor = float2(cos(angle), sin(angle));
return windowed_gaussian_envelope * phasor;
}
/* 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:
*
* \int_{-\infty}^{-\infty} (e^{- \pi (x^2 + y^2)} cos(2 \pi f_0 x))^2 dx
*
* Which gives:
*
* \frac{(e^{2 \pi f_0^2}-1) e^{-2 \pi y^2 - 2 pi f_0^2}}{2^\frac{3}{2}}
*
* Then we similarly integrate with respect to y to get:
*
* \frac{1 - e^{-2 \pi f_0^2}}{4}
*
* 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:
*
* \lim_{x \to \infty} \frac{1 - e^{-2 \pi f_0^2}}{4}
*
* To get an approximation of 0.25. */
float compute_2d_gabor_standard_deviation()
{
float integral_of_gabor_squared = 0.25f;
float second_moment = 0.5f;
return sqrt(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. */
float2 compute_2d_gabor_noise_cell(
float2 cell, float2 position, float frequency, float isotropy, float base_orientation)
{
float2 noise = float2(0.0f);
for (int i = 0; i < IMPULSES_COUNT; ++i) {
/* Compute unique seeds for each of the needed random variables. */
float3 seed_for_orientation = float3(cell, i * 3);
float3 seed_for_kernel_center = float3(cell, i * 3 + 1);
float3 seed_for_weight = float3(cell, 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. */
float random_orientation = (hash_vec3_to_float(seed_for_orientation) - 0.5f) * M_PI;
float orientation = base_orientation + random_orientation * isotropy;
float2 kernel_center = hash_vec3_to_vec2(seed_for_kernel_center);
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 (length_squared(position_in_kernel_space) >= 1.0f) {
continue;
}
/* We either add or subtract the Gabor kernel based on a Bernoulli distribution of equal
* probability. */
float weight = hash_vec3_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. */
float2 compute_2d_gabor_noise(float2 coordinates,
float frequency,
float isotropy,
float base_orientation)
{
float2 cell_position = floor(coordinates);
float2 local_position = coordinates - cell_position;
float2 sum = float2(0.0f);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
float2 cell_offset = float2(i, j);
float2 current_cell_position = cell_position + cell_offset;
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. */
float2 compute_3d_gabor_kernel(float3 position, float frequency, float3 orientation)
{
float distance_squared = length_squared(position);
float hann_window = 0.5f + 0.5f * cos(M_PI * distance_squared);
float gaussian_envelop = exp(-M_PI * distance_squared);
float windowed_gaussian_envelope = gaussian_envelop * hann_window;
float3 frequency_vector = frequency * orientation;
float angle = 2.0f * M_PI * dot(position, frequency_vector);
float2 phasor = float2(cos(angle), sin(angle));
return windowed_gaussian_envelope * phasor;
}
/* 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)). */
float compute_3d_gabor_standard_deviation()
{
float integral_of_gabor_squared = 1.0f / (4.0f * M_SQRT2);
float second_moment = 0.5f;
return sqrt(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. */
float3 compute_3d_orientation(float3 orientation, float isotropy, 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 = acos(orientation.z);
float azimuth = sign(orientation.y) * acos(orientation.x / length(orientation.xy));
/* 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. */
float2 random_angles = hash_vec4_to_vec2(seed) * M_PI;
inclination += random_angles.x * isotropy;
azimuth += random_angles.y * isotropy;
/* Convert back to Cartesian coordinates, */
return float3(
sin(inclination) * cos(azimuth), sin(inclination) * sin(azimuth), cos(inclination));
}
float2 compute_3d_gabor_noise_cell(
float3 cell, float3 position, float frequency, float isotropy, float3 base_orientation)
{
float2 noise = float2(0.0f);
for (int i = 0; i < IMPULSES_COUNT; ++i) {
/* Compute unique seeds for each of the needed random variables. */
float4 seed_for_orientation = float4(cell, i * 3);
float4 seed_for_kernel_center = float4(cell, i * 3 + 1);
float4 seed_for_weight = float4(cell, i * 3 + 2);
float3 orientation = compute_3d_orientation(base_orientation, isotropy, seed_for_orientation);
float3 kernel_center = hash_vec4_to_vec3(seed_for_kernel_center);
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 (length_squared(position_in_kernel_space) >= 1.0f) {
continue;
}
/* We either add or subtract the Gabor kernel based on a Bernoulli distribution of equal
* probability. */
float weight = hash_vec4_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. */
float2 compute_3d_gabor_noise(float3 coordinates,
float frequency,
float isotropy,
float3 base_orientation)
{
float3 cell_position = floor(coordinates);
float3 local_position = coordinates - cell_position;
float2 sum = float2(0.0f);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
float3 cell_offset = float3(i, j, k);
float3 current_cell_position = cell_position + cell_offset;
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;
}
[[node]]
void node_tex_gabor(float3 coordinates,
float scale,
float frequency,
float anisotropy,
float orientation_2d,
float3 orientation_3d,
float type,
float &output_value,
float &output_phase,
float &output_intensity)
{
float3 scaled_coordinates = coordinates * scale;
float isotropy = 1.0f - clamp(anisotropy, 0.0f, 1.0f);
frequency = max(0.001f, frequency);
float2 phasor = float2(0.0f);
float standard_deviation = 1.0f;
if (type == SHD_GABOR_TYPE_2D) {
phasor = compute_2d_gabor_noise(scaled_coordinates.xy, frequency, isotropy, orientation_2d);
standard_deviation = compute_2d_gabor_standard_deviation();
}
else if (type == SHD_GABOR_TYPE_3D) {
float3 orientation = normalize(orientation_3d);
phasor = compute_3d_gabor_noise(scaled_coordinates, frequency, isotropy, orientation);
standard_deviation = compute_3d_gabor_standard_deviation();
}
/* Normalize the noise by dividing by six times the standard deviation, which was determined
* empirically. */
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]. */
output_value = (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. */
output_phase = (atan2(phasor.y, phasor.x) + M_PI) / (2.0f * M_PI);
/* Compute the intensity based on equation (8) in Tricard's paper. */
output_intensity = length(phasor) / normalization_factor;
}

View File

@@ -0,0 +1,52 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
float calc_gradient(float3 p, int gradient_type)
{
float x, y, z;
x = p.x;
y = p.y;
z = p.z;
if (gradient_type == 0) { /* linear */
return x;
}
else if (gradient_type == 1) { /* quadratic */
float r = max(x, 0.0f);
return r * r;
}
else if (gradient_type == 2) { /* easing */
float r = min(max(x, 0.0f), 1.0f);
float t = r * r;
return (3.0f * t - 2.0f * t * r);
}
else if (gradient_type == 3) { /* diagonal */
return (x + y) * 0.5f;
}
else if (gradient_type == 4) { /* radial */
return atan(y, x) / (M_PI * 2) + 0.5f;
}
else {
/* 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. */
float r = max(0.999999f - sqrt(x * x + y * y + z * z), 0.0f);
if (gradient_type == 5) { /* quadratic sphere */
return r * r;
}
else if (gradient_type == 6) { /* sphere */
return r;
}
}
return 0.0f;
}
[[node]]
void node_tex_gradient(float3 co, float gradient_type, float4 &color, float &fac)
{
float f = calc_gradient(co, int(gradient_type));
f = clamp(f, 0.0f, 1.0f);
color = float4(f, f, f, 1.0f);
fac = f;
}

View File

@@ -0,0 +1,237 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_bicubic_sampler_lib.glsl"
#include "gpu_shader_tiled_image_lookup_lib.glsl"
[[node]]
void point_texco_remap_square(float3 vin, float3 &vout)
{
vout = vin * 2.0f - 1.0f;
}
[[node]]
void point_texco_clamp(float3 vin, sampler2D ima, float3 &vout)
{
float2 half_texel_size = 0.5f / float2(textureSize(ima, 0).xy);
vout = clamp(vin, half_texel_size.xyy, 1.0f - half_texel_size.xyy);
}
[[node]]
void point_map_to_sphere(float3 vin, float3 &vout)
{
float len = length(vin);
float v, u;
if (len > 0.0f) {
if (vin.x == 0.0f && vin.y == 0.0f) {
u = 0.0f;
}
else {
u = (1.0f - atan(vin.x, vin.y) / M_PI) / 2.0f;
}
v = 1.0f - acos(vin.z / len) / M_PI;
}
else {
v = u = 0.0f;
}
vout = float3(u, v, 0.0f);
}
[[node]]
void point_map_to_tube(float3 vin, float3 &vout)
{
float u, v;
v = (vin.z + 1.0f) * 0.5f;
float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
if (len > 0.0f) {
u = (1.0f - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5f;
}
else {
v = u = 0.0f;
}
vout = float3(u, v, 0.0f);
}
[[node]]
void node_tex_image_linear(float3 co, sampler2D ima, float4 &color, float &alpha)
{
#ifdef GPU_FRAGMENT_SHADER
float2 dx = gpu_dfdx(co.xy) * texture_lod_bias_get();
float2 dy = gpu_dfdy(co.xy) * texture_lod_bias_get();
color = textureGrad(ima, co.xy, dx, dy);
#else
color = texture(ima, co.xy);
#endif
alpha = color.a;
}
[[node]]
void node_tex_image_cubic(float3 co, sampler2D ima, float4 &color, float &alpha)
{
color = texture_bicubic(ima, co.xy);
alpha = color.a;
}
[[node]]
void tex_box_sample_linear(
float3 texco, float3 N, sampler2D ima, float4 &color1, float4 &color2, float4 &color3)
{
/* X projection */
float2 uv = texco.yz;
if (N.x < 0.0f) {
uv.x = 1.0f - uv.x;
}
color1 = texture(ima, uv);
/* Y projection */
uv = texco.xz;
if (N.y > 0.0f) {
uv.x = 1.0f - uv.x;
}
color2 = texture(ima, uv);
/* Z projection */
uv = texco.yx;
if (N.z > 0.0f) {
uv.x = 1.0f - uv.x;
}
color3 = texture(ima, uv);
}
[[node]]
void tex_box_sample_cubic(
float3 texco, float3 N, sampler2D ima, float4 &color1, float4 &color2, float4 &color3)
{
float alpha;
/* X projection */
float2 uv = texco.yz;
if (N.x < 0.0f) {
uv.x = 1.0f - uv.x;
}
node_tex_image_cubic(uv.xyy, ima, color1, alpha);
/* Y projection */
uv = texco.xz;
if (N.y > 0.0f) {
uv.x = 1.0f - uv.x;
}
node_tex_image_cubic(uv.xyy, ima, color2, alpha);
/* Z projection */
uv = texco.yx;
if (N.z > 0.0f) {
uv.x = 1.0f - uv.x;
}
node_tex_image_cubic(uv.xyy, ima, color3, alpha);
}
[[node]]
void tex_box_blend(float3 N,
float4 color1,
float4 color2,
float4 color3,
float blend,
float4 &color,
float &alpha)
{
/* project from direction vector to barycentric coordinates in triangles */
N = abs(N);
N /= dot(N, float3(1.0f));
/* 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
* EDIT: Now there is only 4 if's. */
float limit = 0.5f + 0.5f * blend;
float3 weight;
weight = N.xyz / (N.xyx + N.yzz);
weight = clamp((weight - 0.5f * (1.0f - blend)) / max(1e-8f, blend), 0.0f, 1.0f);
/* test for mixes between two textures */
if (N.z < (1.0f - limit) * (N.y + N.x)) {
weight.z = 0.0f;
weight.y = 1.0f - weight.x;
}
else if (N.x < (1.0f - limit) * (N.y + N.z)) {
weight.x = 0.0f;
weight.z = 1.0f - weight.y;
}
else if (N.y < (1.0f - limit) * (N.x + N.z)) {
weight.y = 0.0f;
weight.x = 1.0f - weight.z;
}
else {
/* last case, we have a mix between three */
weight = ((2.0f - limit) * N + (limit - 1.0f)) / max(1e-8f, blend);
}
color = weight.x * color1 + weight.y * color2 + weight.z * color3;
alpha = color.a;
}
[[node]]
void node_tex_image_empty(float3 co, float4 &color, float &alpha)
{
color = float4(0.0f);
alpha = 1.0f;
}
[[node]]
void node_tex_tile_linear(
float3 co, sampler2DArray ima, sampler1DArray map, float4 &color, float &alpha)
{
if (tiled_image_lookup(co, ima, map)) {
color = texture(ima, co);
}
else {
color = float4(1.0f, 0.0f, 1.0f, 1.0f);
}
alpha = color.a;
}
[[node]]
void node_tex_tile_cubic(
float3 co, sampler2DArray ima, sampler1DArray map, float4 &color, float &alpha)
{
if (tiled_image_lookup(co, ima, map)) {
float2 tex_size = float2(textureSize(ima, 0).xy);
co.xy *= tex_size;
/* texel center */
float2 tc = floor(co.xy - 0.5f) + 0.5f;
float2 w0, w1, w2, w3;
cubic_bspline_coefficients(co.xy - tc, w0, w1, w2, w3);
float2 s0 = w0 + w1;
float2 s1 = w2 + w3;
float2 f0 = w1 / (w0 + w1);
float2 f1 = w3 / (w2 + w3);
float4 final_co;
final_co.xy = tc - 1.0f + f0;
final_co.zw = tc + 1.0f + f1;
final_co /= tex_size.xyxy;
color = textureLod(ima, float3(final_co.xy, co.z), 0.0f) * s0.x * s0.y;
color += textureLod(ima, float3(final_co.zy, co.z), 0.0f) * s1.x * s0.y;
color += textureLod(ima, float3(final_co.xw, co.z), 0.0f) * s0.x * s1.y;
color += textureLod(ima, float3(final_co.zw, co.z), 0.0f) * s1.x * s1.y;
}
else {
color = float4(1.0f, 0.0f, 1.0f, 1.0f);
}
alpha = color.a;
}

View File

@@ -0,0 +1,67 @@
/* SPDX-FileCopyrightText: 2019-2021 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_tex_magic(
float3 co, float scale, float distortion, float depth, float4 &color, float &fac)
{
float3 p = mod(co * scale, 2.0f * M_PI);
float x = sin((p.x + p.y + p.z) * 5.0f);
float y = cos((-p.x + p.y - p.z) * 5.0f);
float z = -cos((-p.x - p.y + p.z) * 5.0f);
if (depth > 0) {
x *= distortion;
y *= distortion;
z *= distortion;
y = -cos(x - y + z);
y *= distortion;
if (depth > 1) {
x = cos(x - y - z);
x *= distortion;
if (depth > 2) {
z = sin(-x - y - z);
z *= distortion;
if (depth > 3) {
x = -cos(-x + y - z);
x *= distortion;
if (depth > 4) {
y = -sin(-x + y + z);
y *= distortion;
if (depth > 5) {
y = -cos(-x + y + z);
y *= distortion;
if (depth > 6) {
x = cos(x + y + z);
x *= distortion;
if (depth > 7) {
z = sin(x + y - z);
z *= distortion;
if (depth > 8) {
x = -cos(-x - y + z);
x *= distortion;
if (depth > 9) {
y = -sin(x - y + z);
y *= distortion;
}
}
}
}
}
}
}
}
}
}
if (distortion != 0.0f) {
distortion *= 2.0f;
x /= distortion;
y /= distortion;
z /= distortion;
}
color = float4(0.5f - x, 0.5f - y, 0.5f - z, 1.0f);
fac = (color.x + color.y + color.z) / 3.0f;
}

View File

@@ -0,0 +1,617 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/* 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.
*/
#include "gpu_shader_common_hash.glsl"
#include "gpu_shader_material_fractal_noise.glsl"
#include "gpu_shader_material_noise.glsl"
#define NOISE_FRACTAL_DISTORTED_1D(NOISE_TYPE) \
if (distortion != 0.0f) { \
p += snoise(p + random_float_offset(0.0f)) * distortion; \
} \
\
value = NOISE_TYPE(p, detail, roughness, lacunarity, offset, gain, normalize != 0.0f); \
if (compute_color != 0.0f) { \
color = float4(value, \
NOISE_TYPE(p + random_float_offset(1.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
NOISE_TYPE(p + random_float_offset(2.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
1.0f); \
}
#define NOISE_FRACTAL_DISTORTED_2D(NOISE_TYPE) \
if (distortion != 0.0f) { \
p += float2(snoise(p + random_vec2_offset(0.0f)) * distortion, \
snoise(p + random_vec2_offset(1.0f)) * distortion); \
} \
\
value = NOISE_TYPE(p, detail, roughness, lacunarity, offset, gain, normalize != 0.0f); \
if (compute_color != 0.0f) { \
color = float4(value, \
NOISE_TYPE(p + random_vec2_offset(2.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
NOISE_TYPE(p + random_vec2_offset(3.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
1.0f); \
}
#define NOISE_FRACTAL_DISTORTED_3D(NOISE_TYPE) \
if (distortion != 0.0f) { \
p += float3(snoise(p + random_vec3_offset(0.0f)) * distortion, \
snoise(p + random_vec3_offset(1.0f)) * distortion, \
snoise(p + random_vec3_offset(2.0f)) * distortion); \
} \
\
value = NOISE_TYPE(p, detail, roughness, lacunarity, offset, gain, normalize != 0.0f); \
if (compute_color != 0.0f) { \
color = float4(value, \
NOISE_TYPE(p + random_vec3_offset(3.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
NOISE_TYPE(p + random_vec3_offset(4.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
1.0f); \
}
#define NOISE_FRACTAL_DISTORTED_4D(NOISE_TYPE) \
if (distortion != 0.0f) { \
p += float4(snoise(p + random_vec4_offset(0.0f)) * distortion, \
snoise(p + random_vec4_offset(1.0f)) * distortion, \
snoise(p + random_vec4_offset(2.0f)) * distortion, \
snoise(p + random_vec4_offset(3.0f)) * distortion); \
} \
\
value = NOISE_TYPE(p, detail, roughness, lacunarity, offset, gain, normalize != 0.0f); \
if (compute_color != 0.0f) { \
color = float4(value, \
NOISE_TYPE(p + random_vec4_offset(4.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
NOISE_TYPE(p + random_vec4_offset(5.0f), \
detail, \
roughness, \
lacunarity, \
offset, \
gain, \
normalize != 0.0f), \
1.0f); \
}
float random_float_offset(float seed)
{
return 100.0f + hash_float_to_float(seed) * 100.0f;
}
float2 random_vec2_offset(float seed)
{
return float2(100.0f + hash_vec2_to_float(float2(seed, 0.0f)) * 100.0f,
100.0f + hash_vec2_to_float(float2(seed, 1.0f)) * 100.0f);
}
float3 random_vec3_offset(float seed)
{
return float3(100.0f + hash_vec2_to_float(float2(seed, 0.0f)) * 100.0f,
100.0f + hash_vec2_to_float(float2(seed, 1.0f)) * 100.0f,
100.0f + hash_vec2_to_float(float2(seed, 2.0f)) * 100.0f);
}
float4 random_vec4_offset(float seed)
{
return float4(100.0f + hash_vec2_to_float(float2(seed, 0.0f)) * 100.0f,
100.0f + hash_vec2_to_float(float2(seed, 1.0f)) * 100.0f,
100.0f + hash_vec2_to_float(float2(seed, 2.0f)) * 100.0f,
100.0f + hash_vec2_to_float(float2(seed, 3.0f)) * 100.0f);
}
/* Noise fBM */
[[node]]
void node_noise_tex_fbm_1d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float p = w * scale;
NOISE_FRACTAL_DISTORTED_1D(noise_fbm)
}
[[node]]
void node_noise_tex_fbm_2d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float2 p = co.xy * scale;
NOISE_FRACTAL_DISTORTED_2D(noise_fbm)
}
[[node]]
void node_noise_tex_fbm_3d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float3 p = co * scale;
NOISE_FRACTAL_DISTORTED_3D(noise_fbm)
}
[[node]]
void node_noise_tex_fbm_4d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float4 p = float4(co, w) * scale;
NOISE_FRACTAL_DISTORTED_4D(noise_fbm)
}
/* Noise Multi-fractal. */
[[node]]
void node_noise_tex_multi_fractal_1d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float p = w * scale;
NOISE_FRACTAL_DISTORTED_1D(noise_multi_fractal)
}
[[node]]
void node_noise_tex_multi_fractal_2d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float2 p = co.xy * scale;
NOISE_FRACTAL_DISTORTED_2D(noise_multi_fractal)
}
[[node]]
void node_noise_tex_multi_fractal_3d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float3 p = co * scale;
NOISE_FRACTAL_DISTORTED_3D(noise_multi_fractal)
}
[[node]]
void node_noise_tex_multi_fractal_4d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float4 p = float4(co, w) * scale;
NOISE_FRACTAL_DISTORTED_4D(noise_multi_fractal)
}
/* Noise Hetero Terrain */
[[node]]
void node_noise_tex_hetero_terrain_1d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float p = w * scale;
NOISE_FRACTAL_DISTORTED_1D(noise_hetero_terrain)
}
[[node]]
void node_noise_tex_hetero_terrain_2d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float2 p = co.xy * scale;
NOISE_FRACTAL_DISTORTED_2D(noise_hetero_terrain)
}
[[node]]
void node_noise_tex_hetero_terrain_3d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float3 p = co * scale;
NOISE_FRACTAL_DISTORTED_3D(noise_hetero_terrain)
}
[[node]]
void node_noise_tex_hetero_terrain_4d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float4 p = float4(co, w) * scale;
NOISE_FRACTAL_DISTORTED_4D(noise_hetero_terrain)
}
/* Noise Hybrid Multi-fractal. */
[[node]]
void node_noise_tex_hybrid_multi_fractal_1d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float p = w * scale;
NOISE_FRACTAL_DISTORTED_1D(noise_hybrid_multi_fractal)
}
[[node]]
void node_noise_tex_hybrid_multi_fractal_2d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float2 p = co.xy * scale;
NOISE_FRACTAL_DISTORTED_2D(noise_hybrid_multi_fractal)
}
[[node]]
void node_noise_tex_hybrid_multi_fractal_3d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float3 p = co * scale;
NOISE_FRACTAL_DISTORTED_3D(noise_hybrid_multi_fractal)
}
[[node]]
void node_noise_tex_hybrid_multi_fractal_4d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float4 p = float4(co, w) * scale;
NOISE_FRACTAL_DISTORTED_4D(noise_hybrid_multi_fractal)
}
/* Noise Ridged Multi-fractal. */
[[node]]
void node_noise_tex_ridged_multi_fractal_1d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float p = w * scale;
NOISE_FRACTAL_DISTORTED_1D(noise_ridged_multi_fractal)
}
[[node]]
void node_noise_tex_ridged_multi_fractal_2d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float2 p = co.xy * scale;
NOISE_FRACTAL_DISTORTED_2D(noise_ridged_multi_fractal)
}
[[node]]
void node_noise_tex_ridged_multi_fractal_3d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float3 p = co * scale;
NOISE_FRACTAL_DISTORTED_3D(noise_ridged_multi_fractal)
}
[[node]]
void node_noise_tex_ridged_multi_fractal_4d(float3 co,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
float distortion,
float normalize,
float compute_color,
float &value,
float4 &color)
{
detail = clamp(detail, 0.0f, 15.0f);
roughness = max(roughness, 0.0f);
float4 p = float4(co, w) * scale;
NOISE_FRACTAL_DISTORTED_4D(noise_ridged_multi_fractal)
}

View File

@@ -0,0 +1,178 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
float sky_angle_between(float thetav, float phiv, float theta, float phi)
{
float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta);
if (cospsi > 1.0f) {
return 0.0f;
}
if (cospsi < -1.0f) {
return M_PI;
}
return acos(cospsi);
}
float3 sky_spherical_coordinates(float3 dir)
{
return float3(M_PI_2 - atan(dir.z, length(dir.xy)), atan(dir.x, dir.y), 0.0f);
}
/* Preetham */
/* lam03+lam4: 5 floats passed as vec4+float */
float sky_perez_function(float4 lam03, float lam4, float theta, float gamma)
{
float ctheta = cos(theta);
float cgamma = cos(gamma);
return (1.0f + lam03[0] * exp(lam03[1] / ctheta)) *
(1.0f + lam03[2] * exp(lam03[3] * gamma) + lam4 * cgamma * cgamma);
}
float3 xyY_to_xyz(float x, float y, float Y)
{
float X, Z;
if (y != 0.0f) {
X = (x / y) * Y;
}
else {
X = 0.0f;
}
if (y != 0.0f && Y != 0.0f) {
Z = ((1.0f - x - y) / y) * Y;
}
else {
Z = 0.0f;
}
return float3(X, Y, Z);
}
[[node]]
void node_tex_sky_preetham(float3 co,
float4 config_Y03,
float config_Y4,
float4 config_x03,
float config_x4,
float4 config_y03,
float config_y4,
float2 sun_angles,
float3 radiance,
float3 xyz_to_r,
float3 xyz_to_g,
float3 xyz_to_b,
float4 &color)
{
/* convert vector to spherical coordinates */
float3 spherical = sky_spherical_coordinates(co);
float theta = spherical[0];
float phi = spherical[1];
float suntheta = sun_angles[0];
float sunphi = sun_angles[1];
/* angle between sun direction and dir */
float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
/* clamp theta to horizon */
theta = min(theta, M_PI_2 - 0.001f);
/* compute xyY color space values */
float Y = radiance[0] * sky_perez_function(config_Y03, config_Y4, theta, gamma);
float x = radiance[1] * sky_perez_function(config_x03, config_x4, theta, gamma);
float y = radiance[2] * sky_perez_function(config_y03, config_y4, theta, gamma);
/* convert to RGB */
float3 xyz = xyY_to_xyz(x, y, Y);
color = float4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1);
}
/* Hosek / Wilkie */
float sky_radiance_hosekwilkie(
float4 config03, float4 config47, float config8, float theta, float gamma)
{
float ctheta = cos(theta);
float cgamma = cos(gamma);
float expM = exp(config47[0] * gamma);
float rayM = cgamma * cgamma;
float mieM = (1.0f + rayM) / pow((1.0f + config8 * config8 - 2.0f * config8 * cgamma), 1.5f);
float zenith = sqrt(ctheta);
return (1.0f + config03[0] * exp(config03[1] / (ctheta + 0.01f))) *
(config03[2] + config03[3] * expM + config47[1] * rayM + config47[2] * mieM +
config47[3] * zenith);
}
[[node]]
void node_tex_sky_hosekwilkie(float3 co,
float4 config_x03,
float4 config_x47,
float4 config_y03,
float4 config_y47,
float4 config_z03,
float4 config_z47,
float3 config_xyz8,
float2 sun_angles,
float3 radiance,
float3 xyz_to_r,
float3 xyz_to_g,
float3 xyz_to_b,
float4 &color)
{
/* convert vector to spherical coordinates */
float3 spherical = sky_spherical_coordinates(co);
float theta = spherical[0];
float phi = spherical[1];
float suntheta = sun_angles[0];
float sunphi = sun_angles[1];
/* angle between sun direction and dir */
float gamma = sky_angle_between(theta, phi, suntheta, sunphi);
/* clamp theta to horizon */
theta = min(theta, M_PI_2 - 0.001f);
float3 xyz;
xyz.x = sky_radiance_hosekwilkie(config_x03, config_x47, config_xyz8[0], theta, gamma) *
radiance.x;
xyz.y = sky_radiance_hosekwilkie(config_y03, config_y47, config_xyz8[1], theta, gamma) *
radiance.y;
xyz.z = sky_radiance_hosekwilkie(config_z03, config_z47, config_xyz8[2], theta, gamma) *
radiance.z;
color = float4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1);
}
[[node]]
void node_tex_sky_nishita(float3 co,
float sky_type,
float sun_rotation,
float3 xyz_to_r,
float3 xyz_to_g,
float3 xyz_to_b,
sampler2DArray ima,
float layer,
float4 &color)
{
float3 spherical = sky_spherical_coordinates(co);
float3 xyz;
float dir_elevation = M_PI_2 - spherical.x;
float x = (spherical.y + M_PI + sun_rotation) / (2.0f * M_PI);
float fade = 1.0f;
float y;
/* Undo the non-linear transformation from the sky LUT. */
float dir_elevation_abs = (dir_elevation < 0.0f) ? -dir_elevation : dir_elevation;
y = sqrt(dir_elevation_abs / M_PI_2) * sign(dir_elevation) * 0.5f + 0.5f;
/* Look up color in the precomputed map and convert to RGB. */
xyz = fade * texture(ima, float3(x, y, layer)).rgb;
color = float4(dot(xyz_to_r, xyz), dot(xyz_to_g, xyz), dot(xyz_to_b, xyz), 1.0f);
}

View File

@@ -0,0 +1,656 @@
/* SPDX-FileCopyrightText: 2013 Inigo Quilez
* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: MIT AND GPL-2.0-or-later */
/*
* Smooth Voronoi:
*
* - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
*
* Distance To Edge based on:
*
* - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
* - https://www.shadertoy.com/view/ldl3W8
*
* With optimization to change -2..2 scan window to -1..1 for better performance,
* as explained in https://www.shadertoy.com/view/llG3zy.
*/
#include "gpu_shader_common_hash.glsl"
#include "gpu_shader_material_fractal_voronoi.glsl"
#include "gpu_shader_material_voronoi.glsl"
#include "gpu_shader_math_base_lib.glsl"
#define INITIALIZE_VORONOIPARAMS(FEATURE) \
params.feature = FEATURE; \
params.metric = int(metric); \
params.scale = scale; \
params.detail = clamp(detail, 0.0f, 15.0f); \
params.roughness = clamp(roughness, 0.0f, 1.0f); \
params.lacunarity = lacunarity; \
params.smoothness = clamp(smoothness / 2.0f, 0.0f, 0.5f); \
params.exponent = exponent; \
params.randomness = clamp(randomness, 0.0f, 1.0f); \
params.max_distance = 0.0f; \
params.normalize = bool(normalize);
/* **** 1D Voronoi **** */
[[node]]
void node_tex_voronoi_f1_1d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F1)
w *= scale;
params.max_distance = 0.5f + 0.5f * params.randomness;
VoronoiOutput Output = fractal_voronoi_x_fx(params, w);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outW = Output.Position.w;
}
[[node]]
void node_tex_voronoi_smooth_f1_1d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_SMOOTH_F1)
w *= scale;
params.max_distance = 0.5f + 0.5f * params.randomness;
VoronoiOutput Output = fractal_voronoi_x_fx(params, w);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outW = Output.Position.w;
}
[[node]]
void node_tex_voronoi_f2_1d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F2)
w *= scale;
params.max_distance = (0.5f + 0.5f * params.randomness) * 2.0f;
VoronoiOutput Output = fractal_voronoi_x_fx(params, w);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outW = Output.Position.w;
}
[[node]]
void node_tex_voronoi_distance_to_edge_1d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_DISTANCE_TO_EDGE)
w *= scale;
params.max_distance = 0.5f + 0.5f * params.randomness;
outDistance = fractal_voronoi_distance_to_edge(params, w);
}
[[node]]
void node_tex_voronoi_n_sphere_radius_1d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_N_SPHERE_RADIUS)
w *= scale;
outRadius = voronoi_n_sphere_radius(params, w);
}
/* **** 2D Voronoi **** */
[[node]]
void node_tex_voronoi_f1_2d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F1)
coord *= scale;
params.max_distance = voronoi_distance(
float2(0.0f), float2(0.5f + 0.5f * params.randomness), params);
VoronoiOutput Output = fractal_voronoi_x_fx(params, coord.xy);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
}
[[node]]
void node_tex_voronoi_smooth_f1_2d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_SMOOTH_F1)
coord *= scale;
params.max_distance = voronoi_distance(
float2(0.0f), float2(0.5f + 0.5f * params.randomness), params);
VoronoiOutput Output = fractal_voronoi_x_fx(params, coord.xy);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
}
[[node]]
void node_tex_voronoi_f2_2d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F2)
coord *= scale;
params.max_distance = voronoi_distance(
float2(0.0f), float2(0.5f + 0.5f * params.randomness), params) *
2.0f;
VoronoiOutput Output = fractal_voronoi_x_fx(params, coord.xy);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
}
[[node]]
void node_tex_voronoi_distance_to_edge_2d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_DISTANCE_TO_EDGE)
coord *= scale;
params.max_distance = 0.5f + 0.5f * params.randomness;
outDistance = fractal_voronoi_distance_to_edge(params, coord.xy);
}
[[node]]
void node_tex_voronoi_n_sphere_radius_2d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_N_SPHERE_RADIUS)
coord *= scale;
outRadius = voronoi_n_sphere_radius(params, coord.xy);
}
/* **** 3D Voronoi **** */
[[node]]
void node_tex_voronoi_f1_3d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F1)
coord *= scale;
params.max_distance = voronoi_distance(
float3(0.0f), float3(0.5f + 0.5f * params.randomness), params);
VoronoiOutput Output = fractal_voronoi_x_fx(params, coord);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
}
[[node]]
void node_tex_voronoi_smooth_f1_3d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_SMOOTH_F1)
coord *= scale;
params.max_distance = voronoi_distance(
float3(0.0f), float3(0.5f + 0.5f * params.randomness), params);
VoronoiOutput Output = fractal_voronoi_x_fx(params, coord);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
}
[[node]]
void node_tex_voronoi_f2_3d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F2)
coord *= scale;
params.max_distance = voronoi_distance(
float3(0.0f), float3(0.5f + 0.5f * params.randomness), params) *
2.0f;
VoronoiOutput Output = fractal_voronoi_x_fx(params, coord);
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
}
[[node]]
void node_tex_voronoi_distance_to_edge_3d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_DISTANCE_TO_EDGE)
coord *= scale;
params.max_distance = 0.5f + 0.5f * params.randomness;
outDistance = fractal_voronoi_distance_to_edge(params, coord);
}
[[node]]
void node_tex_voronoi_n_sphere_radius_3d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_N_SPHERE_RADIUS)
coord *= scale;
outRadius = voronoi_n_sphere_radius(params, coord);
}
/* **** 4D Voronoi **** */
[[node]]
void node_tex_voronoi_f1_4d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F1)
w *= scale;
coord *= scale;
params.max_distance = voronoi_distance(
float4(0.0f), float4(0.5f + 0.5f * params.randomness), params);
VoronoiOutput Output = fractal_voronoi_x_fx(params, float4(coord, w));
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
outW = Output.Position.w;
}
[[node]]
void node_tex_voronoi_smooth_f1_4d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_SMOOTH_F1)
w *= scale;
coord *= scale;
params.max_distance = voronoi_distance(
float4(0.0f), float4(0.5f + 0.5f * params.randomness), params);
VoronoiOutput Output = fractal_voronoi_x_fx(params, float4(coord, w));
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
outW = Output.Position.w;
}
[[node]]
void node_tex_voronoi_f2_4d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_F2)
w *= scale;
coord *= scale;
params.max_distance = voronoi_distance(
float4(0.0f), float4(0.5f + 0.5f * params.randomness), params) *
2.0f;
VoronoiOutput Output = fractal_voronoi_x_fx(params, float4(coord, w));
outDistance = Output.Distance;
outColor = float4(Output.Color, 1.0f);
outPosition = Output.Position.xyz;
outW = Output.Position.w;
}
[[node]]
void node_tex_voronoi_distance_to_edge_4d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_DISTANCE_TO_EDGE)
w *= scale;
coord *= scale;
params.max_distance = 0.5f + 0.5f * params.randomness;
outDistance = fractal_voronoi_distance_to_edge(params, float4(coord, w));
}
[[node]]
void node_tex_voronoi_n_sphere_radius_4d(float3 coord,
float w,
float scale,
float detail,
float roughness,
float lacunarity,
float smoothness,
float exponent,
float randomness,
float metric,
float normalize,
float &outDistance,
float4 &outColor,
float3 &outPosition,
float &outW,
float &outRadius)
{
VoronoiParams params;
INITIALIZE_VORONOIPARAMS(SHD_VORONOI_N_SPHERE_RADIUS)
w *= scale;
coord *= scale;
outRadius = voronoi_n_sphere_radius(params, float4(coord, w));
}

View File

@@ -0,0 +1,105 @@
/* SPDX-FileCopyrightText: 2019-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
#include "gpu_shader_material_fractal_noise.glsl"
#include "gpu_shader_material_noise.glsl"
float calc_wave(float3 p,
float distortion,
float detail,
float detail_scale,
float detail_roughness,
float phase,
int wave_type,
int bands_dir,
int rings_dir,
int wave_profile)
{
/* Prevent precision issues on unit coordinates. */
p = (p + 0.000001f) * 0.999999f;
float n;
if (wave_type == 0) { /* type bands */
if (bands_dir == 0) { /* X axis */
n = p.x * 20.0f;
}
else if (bands_dir == 1) { /* Y axis */
n = p.y * 20.0f;
}
else if (bands_dir == 2) { /* Z axis */
n = p.z * 20.0f;
}
else { /* Diagonal axis */
n = (p.x + p.y + p.z) * 10.0f;
}
}
else { /* type rings */
float3 rp = p;
if (rings_dir == 0) { /* X axis */
rp *= float3(0.0f, 1.0f, 1.0f);
}
else if (rings_dir == 1) { /* Y axis */
rp *= float3(1.0f, 0.0f, 1.0f);
}
else if (rings_dir == 2) { /* Z axis */
rp *= float3(1.0f, 1.0f, 0.0f);
}
/* else: Spherical */
n = length(rp) * 20.0f;
}
n += phase;
if (distortion != 0.0f) {
n += distortion *
(noise_fbm(p * detail_scale, detail, detail_roughness, 2.0f, 0.0f, 0.0f, true) * 2.0f -
1.0f);
}
if (wave_profile == 0) { /* profile sin */
return 0.5f + 0.5f * sin(n - M_PI_2);
}
else if (wave_profile == 1) { /* profile saw */
n /= 2.0f * M_PI;
return n - floor(n);
}
else { /* profile tri */
n /= 2.0f * M_PI;
return abs(n - floor(n + 0.5f)) * 2.0f;
}
}
[[node]]
void node_tex_wave(float3 co,
float scale,
float distortion,
float detail,
float detail_scale,
float detail_roughness,
float phase,
float wave_type,
float bands_dir,
float rings_dir,
float wave_profile,
float4 &color,
float &fac)
{
float f;
f = calc_wave(co * scale,
distortion,
detail,
detail_scale,
detail_roughness,
phase,
int(wave_type),
int(bands_dir),
int(rings_dir),
int(wave_profile));
color = float4(f, f, f, 1.0f);
fac = f;
}

View File

@@ -0,0 +1,35 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_hash.glsl"
/* White Noise */
[[node]]
void node_white_noise_1d(float3 vector, float w, float &value, float4 &color)
{
value = hash_float_to_float(w);
color = float4(hash_float_to_vec3(w), 1.0f);
}
[[node]]
void node_white_noise_2d(float3 vector, float w, float &value, float4 &color)
{
value = hash_vec2_to_float(vector.xy);
color = float4(hash_vec2_to_vec3(vector.xy), 1.0f);
}
[[node]]
void node_white_noise_3d(float3 vector, float w, float &value, float4 &color)
{
value = hash_vec3_to_float(vector);
color = float4(hash_vec3_to_vec3(vector), 1.0f);
}
[[node]]
void node_white_noise_4d(float3 vector, float w, float &value, float4 &color)
{
value = hash_vec4_to_float(float4(vector, w));
color = float4(hash_vec4_to_vec3(float4(vector, w)), 1.0f);
}

View File

@@ -0,0 +1,38 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_transform_utils.glsl"
[[node]]
void node_tex_coord_position(float3 &out_pos)
{
out_pos = g_data.P;
}
[[node]]
void node_tex_coord(float4x4 obmatinv,
float3 attr_orco,
float4 attr_uv,
float3 &generated,
float3 &normal,
float3 &uv,
float3 &object,
float3 &camera,
float3 &window,
float3 &reflection)
{
generated = attr_orco;
normal_transform_world_to_object(g_data.N, normal);
uv = attr_uv.xyz;
bool valid_mat = (obmatinv[3][3] != 0.0f);
if (valid_mat) {
object = (obmatinv * float4(g_data.P, 1.0f)).xyz;
}
else {
point_transform_world_to_object(g_data.P, object);
}
camera = coordinate_camera(g_data.P);
window = coordinate_screen(g_data.P);
reflection = coordinate_reflect(g_data.P, g_data.N);
}

View File

@@ -0,0 +1,21 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void node_bsdf_toon(
float4 color, float size, float tsmooth, float3 N, float weight, Closure &result)
{
color = max(color, float4(0.0f));
N = safe_normalize(N);
/* Fall back to diffuse. */
ClosureDiffuse diffuse_data;
diffuse_data.weight = weight;
diffuse_data.color = color.rgb;
diffuse_data.N = N;
result = closure_eval(diffuse_data);
}

View File

@@ -0,0 +1,143 @@
/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/* Requires all common matrices declared. */
[[node]]
void normal_transform_object_to_world(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
/* Expansion of NormalMatrix. */
vout = vin * to_float3x3(obj.model_inverse);
}
[[node]]
void normal_transform_world_to_object(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
/* Expansion of NormalMatrixInverse. */
vout = vin * to_float3x3(obj.model);
}
[[node]]
void normal_transform_object_to_view(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
const ViewMatrices view = view_matrices_get();
vout = vin * to_float3x3(obj.model_inverse);
vout = to_float3x3(view.viewmat) * vout;
}
[[node]]
void normal_transform_view_to_world(float3 vin, float3 &vout)
{
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(view.viewinv) * vin;
}
[[node]]
void normal_transform_view_to_object(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(view.viewinv) * vin;
vout = vout * to_float3x3(obj.model);
}
[[node]]
void normal_transform_world_to_view(float3 vin, float3 &vout)
{
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(view.viewmat) * vin;
}
[[node]]
void direction_transform_object_to_world(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
vout = to_float3x3(obj.model) * vin;
}
[[node]]
void direction_transform_object_to_view(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(obj.model) * vin;
vout = to_float3x3(view.viewmat) * vout;
}
[[node]]
void direction_transform_view_to_world(float3 vin, float3 &vout)
{
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(view.viewinv) * vin;
}
[[node]]
void direction_transform_view_to_object(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(view.viewinv) * vin;
vout = to_float3x3(obj.model_inverse) * vout;
}
[[node]]
void direction_transform_world_to_view(float3 vin, float3 &vout)
{
const ViewMatrices view = view_matrices_get();
vout = to_float3x3(view.viewmat) * vin;
}
[[node]]
void direction_transform_world_to_object(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
vout = to_float3x3(obj.model_inverse) * vin;
}
[[node]]
void point_transform_object_to_world(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
vout = (obj.model * float4(vin, 1.0f)).xyz;
}
[[node]]
void point_transform_object_to_view(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
const ViewMatrices view = view_matrices_get();
vout = (view.viewmat * (obj.model * float4(vin, 1.0f))).xyz;
}
[[node]]
void point_transform_view_to_world(float3 vin, float3 &vout)
{
const ViewMatrices view = view_matrices_get();
vout = (view.viewinv * float4(vin, 1.0f)).xyz;
}
[[node]]
void point_transform_view_to_object(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
const ViewMatrices view = view_matrices_get();
vout = (obj.model_inverse * (view.viewinv * float4(vin, 1.0f))).xyz;
}
[[node]]
void point_transform_world_to_view(float3 vin, float3 &vout)
{
const ViewMatrices view = view_matrices_get();
vout = (view.viewmat * float4(vin, 1.0f)).xyz;
}
[[node]]
void point_transform_world_to_object(float3 vin, float3 &vout)
{
const ObjectMatrices obj = object_matrices_get();
vout = (obj.model_inverse * float4(vin, 1.0f)).xyz;
}

View File

@@ -0,0 +1,19 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void node_bsdf_translucent(float4 color, float3 N, float weight, Closure &result)
{
color = max(color, float4(0.0f));
N = safe_normalize(N);
ClosureTranslucent translucent_data;
translucent_data.weight = weight;
translucent_data.color = color.rgb;
translucent_data.N = N;
result = closure_eval(translucent_data);
}

View File

@@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_bsdf_transparent(float4 color, float weight, Closure &result)
{
color = max(color, float4(0.0f));
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = color.rgb;
transparency_data.holdout = 0.0f;
result = closure_eval(transparency_data);
}

View File

@@ -0,0 +1,9 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_uvmap(float4 attr_uv, float3 &outvec)
{
outvec = attr_uv.xyz;
}

View File

@@ -0,0 +1,35 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_transform_utils.glsl"
#include "gpu_shader_math_vector_safe_lib.glsl"
[[node]]
void node_vector_displacement_tangent(
float4 vector, float midlevel, float scale, float4 T, float3 &result)
{
float3 oN, oT, oB;
normal_transform_world_to_object(g_data.N, oN);
normal_transform_world_to_object(T.xyz, oT);
oN = normalize(oN);
oT = normalize(oT);
oB = T.w * safe_normalize(cross(oN, oT));
float3 disp = (vector.xyz - midlevel) * scale;
disp = disp.x * oT + disp.y * oN + disp.z * oB;
direction_transform_object_to_world(disp, result);
}
[[node]]
void node_vector_displacement_object(float4 vector, float midlevel, float scale, float3 &result)
{
float3 disp = (vector.xyz - midlevel) * scale;
direction_transform_object_to_world(disp, result);
}
[[node]]
void node_vector_displacement_world(float4 vector, float midlevel, float scale, float3 &result)
{
result = (vector.xyz - midlevel) * scale;
}

View File

@@ -0,0 +1,226 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_vector_safe_lib.glsl"
float3 vector_math_safe_normalize(float3 a)
{
/* Match the safe normalize function in Cycles by defaulting to float3(0.0f) */
float length_sqr = dot(a, a);
return (length_sqr > 1e-35f) ? a * inversesqrt(length_sqr) : float3(0.0f);
}
[[node]]
void vector_math_add(float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = a + b;
}
[[node]]
void vector_math_subtract(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = a - b;
}
[[node]]
void vector_math_multiply(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = a * b;
}
[[node]]
void vector_math_divide(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = safe_divide(a, b);
}
[[node]]
void vector_math_cross(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = cross(a, b);
}
[[node]]
void vector_math_project(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
float lenSquared = dot(b, b);
outVector = (lenSquared != 0.0f) ? (dot(a, b) / lenSquared) * b : float3(0.0f);
}
[[node]]
void vector_math_reflect(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = reflect(a, vector_math_safe_normalize(b));
}
[[node]]
void vector_math_dot(float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outValue = dot(a, b);
}
[[node]]
void vector_math_distance(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outValue = distance(a, b);
}
[[node]]
void vector_math_length(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outValue = length(a);
}
[[node]]
void vector_math_scale(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = a * scale;
}
[[node]]
void vector_math_normalize(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = a;
/* Safe version of normalize(a). */
float lenSquared = dot(a, a);
if (lenSquared > 0.0f) {
outVector *= inversesqrt(lenSquared);
}
}
[[node]]
void vector_math_snap(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = floor(safe_divide(a, b)) * b;
}
[[node]]
void vector_math_floor(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = floor(a);
}
[[node]]
void vector_math_ceil(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = ceil(a);
}
[[node]]
void vector_math_modulo(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = compatible_mod(a, b);
}
[[node]]
void vector_math_wrap(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = wrap(a, b, c);
}
[[node]]
void vector_math_fraction(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = fract(a);
}
[[node]]
void vector_math_absolute(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = abs(a);
}
[[node]]
void vector_math_power(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = compatible_pow(a, b);
}
[[node]]
void vector_math_sign(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = sign(a);
}
[[node]]
void vector_math_round(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = floor(a + 0.5f);
}
[[node]]
void vector_math_minimum(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = min(a, b);
}
[[node]]
void vector_math_maximum(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = max(a, b);
}
[[node]]
void vector_math_sine(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = sin(a);
}
[[node]]
void vector_math_cosine(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = cos(a);
}
[[node]]
void vector_math_tangent(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = tan(a);
}
[[node]]
void vector_math_refract(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = refract(a, vector_math_safe_normalize(b), scale);
}
[[node]]
void vector_math_faceforward(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = faceforward(a, b, c);
}
[[node]]
void vector_math_multiply_add(
float3 a, float3 b, float3 c, float scale, float3 &outVector, float &outValue)
{
outVector = a * b + c;
}

View File

@@ -0,0 +1,91 @@
/* SPDX-FileCopyrightText: 2020-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_math_euler_lib.glsl"
#include "gpu_shader_math_matrix_construct_lib.glsl"
float3 rotate_around_axis(float3 p, float3 axis, float angle)
{
float costheta = cos(angle);
float sintheta = sin(angle);
float3 r;
r.x = ((costheta + (1.0f - costheta) * axis.x * axis.x) * p.x) +
(((1.0f - costheta) * axis.x * axis.y - axis.z * sintheta) * p.y) +
(((1.0f - costheta) * axis.x * axis.z + axis.y * sintheta) * p.z);
r.y = (((1.0f - costheta) * axis.x * axis.y + axis.z * sintheta) * p.x) +
((costheta + (1.0f - costheta) * axis.y * axis.y) * p.y) +
(((1.0f - costheta) * axis.y * axis.z - axis.x * sintheta) * p.z);
r.z = (((1.0f - costheta) * axis.x * axis.z - axis.y * sintheta) * p.x) +
(((1.0f - costheta) * axis.y * axis.z + axis.x * sintheta) * p.y) +
((costheta + (1.0f - costheta) * axis.z * axis.z) * p.z);
return r;
}
[[node]]
void node_vector_rotate_axis_angle(float3 vector_in,
float3 center,
float3 axis,
float angle,
float3 rotation,
float invert,
float3 &vec)
{
vec = (length(axis) != 0.0f) ?
rotate_around_axis(vector_in - center, normalize(axis), angle * invert) + center :
vector_in;
}
[[node]]
void node_vector_rotate_axis_x(float3 vector_in,
float3 center,
float3 axis,
float angle,
float3 rotation,
float invert,
float3 &vec)
{
vec = rotate_around_axis(vector_in - center, float3(1.0f, 0.0f, 0.0f), angle * invert) + center;
}
[[node]]
void node_vector_rotate_axis_y(float3 vector_in,
float3 center,
float3 axis,
float angle,
float3 rotation,
float invert,
float3 &vec)
{
vec = rotate_around_axis(vector_in - center, float3(0.0f, 1.0f, 0.0f), angle * invert) + center;
}
[[node]]
void node_vector_rotate_axis_z(float3 vector_in,
float3 center,
float3 axis,
float angle,
float3 rotation,
float invert,
float3 &vec)
{
vec = rotate_around_axis(vector_in - center, float3(0.0f, 0.0f, 1.0f), angle * invert) + center;
}
[[node]]
void node_vector_rotate_euler_xyz(float3 vector_in,
float3 center,
float3 axis,
float angle,
float3 rotation,
float invert,
float3 &vec)
{
float3x3 rmat = (invert < 0.0f) ? transpose(from_rotation(EulerXYZ::from_float3(rotation))) :
from_rotation(EulerXYZ::from_float3(rotation));
vec = rmat * (vector_in - center) + center;
}

View File

@@ -0,0 +1,10 @@
/* SPDX-FileCopyrightText: 2019 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_vertex_color(float4 vertexColor, float4 &outColor, float &outAlpha)
{
outColor = vertexColor;
outAlpha = vertexColor.a;
}

View File

@@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_volume_absorption(float4 color, float density, float weight, Closure &result)
{
color = max(color, float4(0.0f));
density = max(density, 0.0f);
ClosureVolumeAbsorption volume_absorption_data;
volume_absorption_data.weight = weight;
volume_absorption_data.absorption = (1.0f - color.rgb) * density;
result = closure_eval(volume_absorption_data);
}

View File

@@ -0,0 +1,33 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_blackbody.glsl"
[[node]]
void node_volume_coefficients(float weight,
float3 AbsorptionCoefficients,
float3 ScatterCoefficients,
float Anisotropy,
float IOR,
float Backscatter,
float Alpha,
float Diameter,
float3 EmissionCoefficients,
Closure &result)
{
ClosureVolumeScatter volume_scatter_data;
volume_scatter_data.weight = weight;
volume_scatter_data.scattering = ScatterCoefficients;
volume_scatter_data.anisotropy = Anisotropy;
ClosureVolumeAbsorption volume_absorption_data;
volume_absorption_data.weight = weight;
volume_absorption_data.absorption = AbsorptionCoefficients;
ClosureEmission emission_data;
emission_data.weight = weight;
emission_data.emission = EmissionCoefficients;
result = closure_eval(volume_scatter_data, volume_absorption_data, emission_data);
}

View File

@@ -0,0 +1,91 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_material_blackbody.glsl"
[[node]]
void node_volume_principled(float4 color,
float density,
float anisotropy,
float4 absorption_color,
float emission_strength,
float4 emission_color,
float blackbody_intensity,
float4 blackbody_tint,
float temperature,
float weight,
float4 density_attribute,
float4 color_attribute,
float4 temperature_attribute,
sampler1DArray spectrummap,
float layer,
Closure &result)
{
color = max(color, float4(0.0f));
density = max(density, 0.0f);
absorption_color = max(absorption_color, float4(0.0f));
emission_strength = max(emission_strength, 0.0f);
emission_color = max(emission_color, float4(0.0f));
blackbody_intensity = max(blackbody_intensity, 0.0f);
blackbody_tint = max(blackbody_tint, float4(0.0f));
temperature = max(temperature, 0.0f);
float3 absorption_coeff = float3(0.0f);
float3 scatter_coeff = float3(0.0f);
float3 emission_coeff = float3(0.0f);
/* Compute density. */
if (density > 1e-5f) {
density = max(density * density_attribute.x, 0.0f);
}
if (density > 1e-5f) {
/* Compute scattering and absorption coefficients. */
float3 scatter_color = color.rgb * color_attribute.rgb;
scatter_coeff = scatter_color * density;
absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0f));
absorption_coeff = max(1.0f - scatter_color, 0.0f) * max(1.0f - absorption_color.rgb, 0.0f) *
density;
}
/* Compute emission. */
emission_strength = max(emission_strength, 0.0f);
if (emission_strength > 1e-5f) {
emission_coeff += emission_strength * emission_color.rgb;
}
if (blackbody_intensity > 1e-3f) {
/* Add temperature from attribute. */
float T = max(temperature * max(temperature_attribute.x, 0.0f), 0.0f);
/* Stefan-Boltzmann law. */
float T2 = T * T;
float T4 = T2 * T2;
float sigma = 5.670373e-8f * 1e-6f / M_PI;
float intensity = sigma * mix(1.0f, T4, blackbody_intensity);
if (intensity > 1e-5f) {
float4 bb;
node_blackbody(T, spectrummap, layer, bb);
emission_coeff += bb.rgb * blackbody_tint.rgb * intensity;
}
}
ClosureVolumeScatter volume_scatter_data;
volume_scatter_data.weight = weight;
volume_scatter_data.scattering = scatter_coeff;
volume_scatter_data.anisotropy = anisotropy;
ClosureVolumeAbsorption volume_absorption_data;
volume_absorption_data.weight = weight;
volume_absorption_data.absorption = absorption_coeff;
ClosureEmission emission_data;
emission_data.weight = weight;
emission_data.emission = emission_coeff;
result = closure_eval(volume_scatter_data, volume_absorption_data, emission_data);
}

View File

@@ -0,0 +1,25 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
[[node]]
void node_volume_scatter(float4 color,
float density,
float anisotropy,
float IOR,
float Backscatter,
float alpha,
float diameter,
float weight,
Closure &result)
{
color = max(color, float4(0.0f));
density = max(density, 0.0f);
ClosureVolumeScatter volume_scatter_data;
volume_scatter_data.weight = weight;
volume_scatter_data.scattering = color.rgb * density;
volume_scatter_data.anisotropy = anisotropy;
result = closure_eval(volume_scatter_data);
}

Some files were not shown because too many files have changed in this diff Show More