Add Chromium-only Blender WebEngine parity work
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 ¶metric,
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user