2023-08-24 10:54:59 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2024-10-04 15:48:22 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2025-09-25 10:57:02 +02:00
|
|
|
#include "infos/eevee_common_infos.hh"
|
2024-12-02 21:26:15 +01:00
|
|
|
|
|
|
|
|
SHADER_LIBRARY_CREATE_INFO(eevee_global_ubo)
|
|
|
|
|
SHADER_LIBRARY_CREATE_INFO(eevee_utility_texture)
|
|
|
|
|
|
2024-10-04 15:48:22 +02:00
|
|
|
#include "draw_model_lib.glsl"
|
2025-03-06 11:06:26 +01:00
|
|
|
#include "draw_object_infos_lib.glsl"
|
2024-10-04 15:48:22 +02:00
|
|
|
#include "draw_view_lib.glsl"
|
|
|
|
|
#include "eevee_renderpass_lib.glsl"
|
2025-09-12 14:09:35 +02:00
|
|
|
#include "eevee_utility_tx_lib.glsl"
|
2024-10-04 15:48:22 +02:00
|
|
|
#include "gpu_shader_codegen_lib.glsl"
|
|
|
|
|
#include "gpu_shader_math_base_lib.glsl"
|
2025-09-15 12:07:26 +02:00
|
|
|
#include "gpu_shader_math_safe_lib.glsl"
|
2025-09-23 17:21:56 +02:00
|
|
|
#include "gpu_shader_math_vector_reduce_lib.glsl"
|
2024-10-04 15:48:22 +02:00
|
|
|
#include "gpu_shader_utildefines_lib.glsl"
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2024-11-12 12:58:58 +01:00
|
|
|
packed_float3 g_emission;
|
|
|
|
|
packed_float3 g_transmittance;
|
2022-05-02 09:22:14 +02:00
|
|
|
float g_holdout;
|
|
|
|
|
|
2024-11-12 12:58:58 +01:00
|
|
|
packed_float3 g_volume_scattering;
|
2023-12-14 13:00:15 +01:00
|
|
|
float g_volume_anisotropy;
|
2024-11-12 12:58:58 +01:00
|
|
|
packed_float3 g_volume_absorption;
|
2023-12-14 13:00:15 +01:00
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
/* The Closure type is never used. Use float as dummy type. */
|
|
|
|
|
#define Closure float
|
2025-04-11 18:28:45 +02:00
|
|
|
#define CLOSURE_DEFAULT 0.0f
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2024-02-24 00:00:11 +01:00
|
|
|
/* Maximum number of picked closure. */
|
|
|
|
|
#ifndef CLOSURE_BIN_COUNT
|
|
|
|
|
# define CLOSURE_BIN_COUNT 1
|
|
|
|
|
#endif
|
2022-05-02 09:22:14 +02:00
|
|
|
/* Sampled closure parameters. */
|
2024-02-24 00:00:11 +01:00
|
|
|
ClosureUndetermined g_closure_bins[CLOSURE_BIN_COUNT];
|
2022-05-02 09:22:14 +02:00
|
|
|
/* Random number per sampled closure type. */
|
2024-02-24 00:00:11 +01:00
|
|
|
float g_closure_rand[CLOSURE_BIN_COUNT];
|
|
|
|
|
|
2024-11-12 12:58:58 +01:00
|
|
|
ClosureUndetermined g_closure_get(uchar i)
|
2024-02-24 00:00:11 +01:00
|
|
|
{
|
|
|
|
|
switch (i) {
|
|
|
|
|
case 0:
|
|
|
|
|
return g_closure_bins[0];
|
|
|
|
|
#if CLOSURE_BIN_COUNT > 1
|
|
|
|
|
case 1:
|
|
|
|
|
return g_closure_bins[1];
|
|
|
|
|
#endif
|
|
|
|
|
#if CLOSURE_BIN_COUNT > 2
|
|
|
|
|
case 2:
|
|
|
|
|
return g_closure_bins[2];
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2025-09-10 12:17:21 +02:00
|
|
|
/* Unreachable. */
|
2025-09-10 12:20:59 +02:00
|
|
|
assert(false);
|
2025-09-10 12:17:21 +02:00
|
|
|
return g_closure_bins[0];
|
2024-02-24 00:00:11 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 12:58:58 +01:00
|
|
|
ClosureUndetermined g_closure_get_resolved(uchar i, float weight_fac)
|
2024-02-24 00:00:11 +01:00
|
|
|
{
|
|
|
|
|
ClosureUndetermined cl = g_closure_get(i);
|
|
|
|
|
cl.color *= cl.weight * weight_fac;
|
|
|
|
|
return cl;
|
|
|
|
|
}
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2023-12-23 05:58:52 +01:00
|
|
|
ClosureType closure_type_get(ClosureDiffuse cl)
|
|
|
|
|
{
|
|
|
|
|
return CLOSURE_BSDF_DIFFUSE_ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClosureType closure_type_get(ClosureTranslucent cl)
|
|
|
|
|
{
|
|
|
|
|
return CLOSURE_BSDF_TRANSLUCENT_ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClosureType closure_type_get(ClosureReflection cl)
|
|
|
|
|
{
|
|
|
|
|
return CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClosureType closure_type_get(ClosureRefraction cl)
|
|
|
|
|
{
|
|
|
|
|
return CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-09 16:27:30 +13:00
|
|
|
ClosureType closure_type_get(ClosureSubsurface cl)
|
|
|
|
|
{
|
|
|
|
|
return CLOSURE_BSSRDF_BURLEY_ID;
|
|
|
|
|
}
|
2023-12-23 05:58:52 +01:00
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
/**
|
|
|
|
|
* Returns true if the closure is to be selected based on the input weight.
|
|
|
|
|
*/
|
2023-12-23 05:58:52 +01:00
|
|
|
bool closure_select_check(float weight, inout float total_weight, inout float r)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-04-11 18:28:45 +02:00
|
|
|
if (weight < 1e-5f) {
|
2023-09-25 15:14:45 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-05-02 09:22:14 +02:00
|
|
|
total_weight += weight;
|
|
|
|
|
float x = weight / total_weight;
|
|
|
|
|
bool chosen = (r < x);
|
|
|
|
|
/* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
|
2023-03-18 20:54:20 +01:00
|
|
|
* that interval, so remapping to [0,1] again to explore this space of probability. */
|
2025-04-11 18:28:45 +02:00
|
|
|
r = (chosen) ? (r / x) : ((r - x) / (1.0f - x));
|
2022-05-02 09:22:14 +02:00
|
|
|
return chosen;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-23 05:58:52 +01:00
|
|
|
/**
|
|
|
|
|
* Assign `candidate` to `destination` based on a random value and the respective weights.
|
|
|
|
|
*/
|
|
|
|
|
void closure_select(inout ClosureUndetermined destination,
|
2024-02-24 00:00:11 +01:00
|
|
|
inout float random,
|
2023-12-23 05:58:52 +01:00
|
|
|
ClosureUndetermined candidate)
|
|
|
|
|
{
|
2024-07-16 19:08:08 +02:00
|
|
|
float candidate_color_weight = average(abs(candidate.color));
|
2024-07-15 17:00:51 +02:00
|
|
|
if (closure_select_check(candidate.weight * candidate_color_weight, destination.weight, random))
|
|
|
|
|
{
|
|
|
|
|
float total_weight = destination.weight;
|
2023-12-23 05:58:52 +01:00
|
|
|
destination = candidate;
|
2024-07-15 17:00:51 +02:00
|
|
|
destination.color /= candidate_color_weight;
|
|
|
|
|
destination.weight = total_weight;
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
2023-12-23 05:58:52 +01:00
|
|
|
}
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2024-02-24 00:00:11 +01:00
|
|
|
void closure_weights_reset(float closure_rand)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2024-02-24 00:00:11 +01:00
|
|
|
g_closure_rand[0] = closure_rand;
|
2025-04-11 18:28:45 +02:00
|
|
|
g_closure_bins[0].weight = 0.0f;
|
2024-02-24 00:00:11 +01:00
|
|
|
#if CLOSURE_BIN_COUNT > 1
|
|
|
|
|
g_closure_rand[1] = closure_rand;
|
2025-04-11 18:28:45 +02:00
|
|
|
g_closure_bins[1].weight = 0.0f;
|
2024-02-24 00:00:11 +01:00
|
|
|
#endif
|
|
|
|
|
#if CLOSURE_BIN_COUNT > 2
|
|
|
|
|
g_closure_rand[2] = closure_rand;
|
2025-04-11 18:28:45 +02:00
|
|
|
g_closure_bins[2].weight = 0.0f;
|
2024-02-24 00:00:11 +01:00
|
|
|
#endif
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
g_volume_scattering = float3(0.0f);
|
2025-04-11 18:28:45 +02:00
|
|
|
g_volume_anisotropy = 0.0f;
|
2025-04-14 13:46:41 +02:00
|
|
|
g_volume_absorption = float3(0.0f);
|
2023-08-04 16:47:16 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
g_emission = float3(0.0f);
|
|
|
|
|
g_transmittance = float3(0.0f);
|
|
|
|
|
g_volume_scattering = float3(0.0f);
|
|
|
|
|
g_volume_absorption = float3(0.0f);
|
2025-04-11 18:28:45 +02:00
|
|
|
g_holdout = 0.0f;
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-23 05:58:52 +01:00
|
|
|
#define closure_base_copy(cl, in_cl) \
|
|
|
|
|
cl.weight = in_cl.weight; \
|
|
|
|
|
cl.color = in_cl.color; \
|
|
|
|
|
cl.N = in_cl.N; \
|
|
|
|
|
cl.type = closure_type_get(in_cl);
|
|
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
/* Single BSDFs. */
|
|
|
|
|
Closure closure_eval(ClosureDiffuse diffuse)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
ClosureUndetermined cl;
|
|
|
|
|
closure_base_copy(cl, diffuse);
|
2024-04-12 22:06:25 +02:00
|
|
|
#if (CLOSURE_BIN_COUNT > 1) && defined(MAT_TRANSLUCENT) && !defined(MAT_CLEARCOAT)
|
|
|
|
|
/* Use second slot so we can have diffuse + translucent without noise. */
|
|
|
|
|
closure_select(g_closure_bins[1], g_closure_rand[1], cl);
|
|
|
|
|
#else
|
|
|
|
|
/* Either is single closure or use same bin as transmission bin. */
|
2024-02-24 00:00:11 +01:00
|
|
|
closure_select(g_closure_bins[0], g_closure_rand[0], cl);
|
2024-04-12 22:06:25 +02:00
|
|
|
#endif
|
2024-01-09 16:27:30 +13:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureSubsurface diffuse)
|
|
|
|
|
{
|
|
|
|
|
ClosureUndetermined cl;
|
|
|
|
|
closure_base_copy(cl, diffuse);
|
|
|
|
|
cl.data.rgb = diffuse.sss_radius;
|
2024-04-12 22:06:25 +02:00
|
|
|
/* Transmission Closures are always in first bin. */
|
2024-02-24 00:00:11 +01:00
|
|
|
closure_select(g_closure_bins[0], g_closure_rand[0], cl);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureTranslucent translucent)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
ClosureUndetermined cl;
|
|
|
|
|
closure_base_copy(cl, translucent);
|
2024-04-12 22:06:25 +02:00
|
|
|
/* Transmission Closures are always in first bin. */
|
2024-02-24 00:00:11 +01:00
|
|
|
closure_select(g_closure_bins[0], g_closure_rand[0], cl);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-24 00:00:11 +01:00
|
|
|
/* Alternate between two bins on a per closure basis.
|
|
|
|
|
* Allow clearcoat layer without noise.
|
|
|
|
|
* Choosing the bin with the least weight can choose a
|
|
|
|
|
* different bin for the same closure and
|
2024-02-26 10:23:12 +11:00
|
|
|
* produce issue with ray-tracing denoiser.
|
|
|
|
|
* Always start with the second bin, this one doesn't
|
2024-02-24 00:00:11 +01:00
|
|
|
* overlap with other closure. */
|
|
|
|
|
bool g_closure_reflection_bin = true;
|
|
|
|
|
#define CHOOSE_MIN_WEIGHT_CLOSURE_BIN(a, b) \
|
|
|
|
|
if (g_closure_reflection_bin) { \
|
|
|
|
|
closure_select(g_closure_bins[b], g_closure_rand[b], cl); \
|
|
|
|
|
} \
|
|
|
|
|
else { \
|
|
|
|
|
closure_select(g_closure_bins[a], g_closure_rand[a], cl); \
|
|
|
|
|
} \
|
|
|
|
|
g_closure_reflection_bin = !g_closure_reflection_bin;
|
|
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
Closure closure_eval(ClosureReflection reflection)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
ClosureUndetermined cl;
|
|
|
|
|
closure_base_copy(cl, reflection);
|
|
|
|
|
cl.data.r = reflection.roughness;
|
2024-02-24 00:00:11 +01:00
|
|
|
|
2024-04-12 22:06:25 +02:00
|
|
|
#ifdef MAT_CLEARCOAT
|
|
|
|
|
# if CLOSURE_BIN_COUNT == 2
|
|
|
|
|
/* Multiple reflection closures. */
|
2024-02-24 00:00:11 +01:00
|
|
|
CHOOSE_MIN_WEIGHT_CLOSURE_BIN(0, 1);
|
2024-04-12 22:06:25 +02:00
|
|
|
# elif CLOSURE_BIN_COUNT == 3
|
|
|
|
|
/* Multiple reflection closures and one other closure. */
|
2024-02-24 00:00:11 +01:00
|
|
|
CHOOSE_MIN_WEIGHT_CLOSURE_BIN(1, 2);
|
2024-04-12 22:06:25 +02:00
|
|
|
# else
|
|
|
|
|
# error Clearcoat should always have at least 2 bins
|
|
|
|
|
# endif
|
|
|
|
|
#else
|
|
|
|
|
# if CLOSURE_BIN_COUNT == 1
|
|
|
|
|
/* Only one reflection closure is present in the whole tree. */
|
|
|
|
|
closure_select(g_closure_bins[0], g_closure_rand[0], cl);
|
|
|
|
|
# elif CLOSURE_BIN_COUNT == 2
|
|
|
|
|
/* Only one reflection and one other closure. */
|
|
|
|
|
closure_select(g_closure_bins[1], g_closure_rand[1], cl);
|
|
|
|
|
# elif CLOSURE_BIN_COUNT == 3
|
|
|
|
|
/* Only one reflection and two other closures. */
|
|
|
|
|
closure_select(g_closure_bins[2], g_closure_rand[2], cl);
|
|
|
|
|
# endif
|
2024-02-24 00:00:11 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#undef CHOOSE_MIN_WEIGHT_CLOSURE_BIN
|
|
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureRefraction refraction)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
ClosureUndetermined cl;
|
|
|
|
|
closure_base_copy(cl, refraction);
|
|
|
|
|
cl.data.r = refraction.roughness;
|
|
|
|
|
cl.data.g = refraction.ior;
|
2024-04-12 22:06:25 +02:00
|
|
|
/* Transmission Closures are always in first bin. */
|
2024-02-24 00:00:11 +01:00
|
|
|
closure_select(g_closure_bins[0], g_closure_rand[0], cl);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureEmission emission)
|
|
|
|
|
{
|
|
|
|
|
g_emission += emission.emission * emission.weight;
|
|
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureTransparency transparency)
|
|
|
|
|
{
|
|
|
|
|
g_transmittance += transparency.transmittance * transparency.weight;
|
|
|
|
|
g_holdout += transparency.holdout * transparency.weight;
|
|
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureVolumeScatter volume_scatter)
|
|
|
|
|
{
|
2023-12-19 17:59:12 +01:00
|
|
|
g_volume_scattering += volume_scatter.scattering * volume_scatter.weight;
|
|
|
|
|
g_volume_anisotropy += volume_scatter.anisotropy * volume_scatter.weight;
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureVolumeAbsorption volume_absorption)
|
|
|
|
|
{
|
2023-12-19 17:59:12 +01:00
|
|
|
g_volume_absorption += volume_absorption.absorption * volume_absorption.weight;
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Closure closure_eval(ClosureHair hair)
|
|
|
|
|
{
|
|
|
|
|
/* TODO */
|
|
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Glass BSDF. */
|
|
|
|
|
Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
closure_eval(reflection);
|
|
|
|
|
closure_eval(refraction);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dielectric BSDF. */
|
|
|
|
|
Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
closure_eval(diffuse);
|
|
|
|
|
closure_eval(reflection);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Rework Principled BSDF Clearcoat
- Adds tint control, which simulates volumetric absorption inside the coating.
This results in angle-dependent saturation and affects all underlying layers
(diffuse, subsurface, metallic, transmission). It provides a physically-based
alternative to ad-hoc effects such as tinted specular highlights.
- Renames the component from "Clearcoat" to "Coat", since it's no longer
necessarily clear now. This matches naming in e.g. other renderers or OpenPBR.
- Adds an explicit Coat IOR input, in preparation for future smarter IOR logic
around the interaction between Coat and main IOR. This used to be hardcoded
to 1.5.
- Removes hardcoded 0.25 weight multiplier, and adds versioning code to update
existing files accordingly. OBJ import/export still applies the factor.
- Replaces the GTR1 microfacet component with regular GGX. This removes a corner
case in the Microfacet code, solves #53038, and makes us more consistent with
other standard surface shaders. The original Disney BSDF used GTR1, but it
doesn't appear that it caught on in the industry.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/110993
2023-09-13 00:03:11 +02:00
|
|
|
/* Coat BSDF. */
|
|
|
|
|
Closure closure_eval(ClosureReflection reflection, ClosureReflection coat)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
closure_eval(reflection);
|
|
|
|
|
closure_eval(coat);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Volume BSDF. */
|
|
|
|
|
Closure closure_eval(ClosureVolumeScatter volume_scatter,
|
|
|
|
|
ClosureVolumeAbsorption volume_absorption,
|
|
|
|
|
ClosureEmission emission)
|
|
|
|
|
{
|
2023-08-04 16:47:16 +02:00
|
|
|
closure_eval(volume_scatter);
|
|
|
|
|
closure_eval(volume_absorption);
|
|
|
|
|
closure_eval(emission);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Specular BSDF. */
|
Cycles: Rework Principled BSDF Clearcoat
- Adds tint control, which simulates volumetric absorption inside the coating.
This results in angle-dependent saturation and affects all underlying layers
(diffuse, subsurface, metallic, transmission). It provides a physically-based
alternative to ad-hoc effects such as tinted specular highlights.
- Renames the component from "Clearcoat" to "Coat", since it's no longer
necessarily clear now. This matches naming in e.g. other renderers or OpenPBR.
- Adds an explicit Coat IOR input, in preparation for future smarter IOR logic
around the interaction between Coat and main IOR. This used to be hardcoded
to 1.5.
- Removes hardcoded 0.25 weight multiplier, and adds versioning code to update
existing files accordingly. OBJ import/export still applies the factor.
- Replaces the GTR1 microfacet component with regular GGX. This removes a corner
case in the Microfacet code, solves #53038, and makes us more consistent with
other standard surface shaders. The original Disney BSDF used GTR1, but it
doesn't appear that it caught on in the industry.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/110993
2023-09-13 00:03:11 +02:00
|
|
|
Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, ClosureReflection coat)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
closure_eval(diffuse);
|
|
|
|
|
closure_eval(reflection);
|
|
|
|
|
closure_eval(coat);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Principled BSDF. */
|
|
|
|
|
Closure closure_eval(ClosureDiffuse diffuse,
|
|
|
|
|
ClosureReflection reflection,
|
Cycles: Rework Principled BSDF Clearcoat
- Adds tint control, which simulates volumetric absorption inside the coating.
This results in angle-dependent saturation and affects all underlying layers
(diffuse, subsurface, metallic, transmission). It provides a physically-based
alternative to ad-hoc effects such as tinted specular highlights.
- Renames the component from "Clearcoat" to "Coat", since it's no longer
necessarily clear now. This matches naming in e.g. other renderers or OpenPBR.
- Adds an explicit Coat IOR input, in preparation for future smarter IOR logic
around the interaction between Coat and main IOR. This used to be hardcoded
to 1.5.
- Removes hardcoded 0.25 weight multiplier, and adds versioning code to update
existing files accordingly. OBJ import/export still applies the factor.
- Replaces the GTR1 microfacet component with regular GGX. This removes a corner
case in the Microfacet code, solves #53038, and makes us more consistent with
other standard surface shaders. The original Disney BSDF used GTR1, but it
doesn't appear that it caught on in the industry.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/110993
2023-09-13 00:03:11 +02:00
|
|
|
ClosureReflection coat,
|
2022-05-02 09:22:14 +02:00
|
|
|
ClosureRefraction refraction)
|
|
|
|
|
{
|
2023-12-23 05:58:52 +01:00
|
|
|
closure_eval(diffuse);
|
|
|
|
|
closure_eval(reflection);
|
|
|
|
|
closure_eval(coat);
|
|
|
|
|
closure_eval(refraction);
|
2022-05-02 09:22:14 +02:00
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-05 10:49:20 +10:00
|
|
|
/* NOP since we are sampling closures. */
|
2022-05-02 09:22:14 +02:00
|
|
|
Closure closure_add(Closure cl1, Closure cl2)
|
|
|
|
|
{
|
|
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
Closure closure_mix(Closure cl1, Closure cl2, float fac)
|
|
|
|
|
{
|
|
|
|
|
return Closure(0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float ambient_occlusion_eval(float3 normal,
|
2023-06-30 19:37:30 +02:00
|
|
|
float max_distance,
|
2022-05-02 09:22:14 +02:00
|
|
|
const float inverted,
|
|
|
|
|
const float sample_count)
|
|
|
|
|
{
|
2023-08-25 08:56:58 +10:00
|
|
|
/* Avoid multi-line pre-processor conditionals.
|
2023-06-30 19:37:30 +02:00
|
|
|
* Some drivers don't handle them correctly. */
|
|
|
|
|
// clang-format off
|
|
|
|
|
#if defined(GPU_FRAGMENT_SHADER) && defined(MAT_AMBIENT_OCCLUSION) && !defined(MAT_DEPTH) && !defined(MAT_SHADOW)
|
|
|
|
|
// clang-format on
|
2023-12-11 14:45:48 +01:00
|
|
|
# if 0 /* TODO(fclem): Finish inverted horizon scan. */
|
|
|
|
|
/* TODO(fclem): Replace eevee_ambient_occlusion_lib by eevee_horizon_scan_eval_lib when this is
|
|
|
|
|
* finished. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 vP = drw_point_world_to_view(g_data.P);
|
|
|
|
|
float3 vN = drw_normal_world_to_view(normal);
|
2023-12-11 14:45:48 +01:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
int2 texel = int2(gl_FragCoord.xy);
|
|
|
|
|
float2 noise;
|
2025-09-10 12:47:49 +02:00
|
|
|
noise.x = interleaved_gradient_noise(float2(texel), 3.0f, 0.0f);
|
2025-04-14 13:46:41 +02:00
|
|
|
noise.y = utility_tx_fetch(utility_tx, float2(texel), UTIL_BLUE_NOISE_LAYER).r;
|
2023-12-11 14:45:48 +01:00
|
|
|
noise = fract(noise + sampling_rng_2D_get(SAMPLING_AO_U));
|
|
|
|
|
|
|
|
|
|
ClosureOcclusion occlusion;
|
2025-04-11 18:28:45 +02:00
|
|
|
occlusion.N = (inverted != 0.0f) ? -vN : vN;
|
2023-12-11 14:45:48 +01:00
|
|
|
|
|
|
|
|
HorizonScanContext ctx;
|
|
|
|
|
ctx.occlusion = occlusion;
|
|
|
|
|
|
|
|
|
|
horizon_scan_eval(vP,
|
|
|
|
|
ctx,
|
|
|
|
|
noise,
|
|
|
|
|
uniform_buf.ao.pixel_size,
|
|
|
|
|
max_distance,
|
2024-05-28 16:00:38 +02:00
|
|
|
uniform_buf.ao.thickness_near,
|
|
|
|
|
uniform_buf.ao.thickness_far,
|
2023-12-11 14:45:48 +01:00
|
|
|
uniform_buf.ao.angle_bias,
|
2024-05-26 20:23:42 +02:00
|
|
|
2,
|
2023-12-11 14:45:48 +01:00
|
|
|
10,
|
2025-04-11 18:28:45 +02:00
|
|
|
inverted != 0.0f,
|
2024-05-27 16:33:49 +02:00
|
|
|
true);
|
2023-12-11 14:45:48 +01:00
|
|
|
|
|
|
|
|
return saturate(ctx.occlusion_result.r);
|
|
|
|
|
# else
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 vP = drw_point_world_to_view(g_data.P);
|
|
|
|
|
int2 texel = int2(gl_FragCoord.xy);
|
2023-06-30 19:37:30 +02:00
|
|
|
OcclusionData data = ambient_occlusion_search(
|
|
|
|
|
vP, hiz_tx, texel, max_distance, inverted, sample_count);
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 V = drw_world_incident_vector(g_data.P);
|
|
|
|
|
float3 N = normal;
|
|
|
|
|
float3 Ng = g_data.Ng;
|
2023-06-30 19:37:30 +02:00
|
|
|
|
|
|
|
|
float unused_error, visibility;
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 unused;
|
2023-06-30 19:37:30 +02:00
|
|
|
ambient_occlusion_eval(data, texel, V, N, Ng, inverted, visibility, unused_error, unused);
|
|
|
|
|
return visibility;
|
2023-12-11 14:45:48 +01:00
|
|
|
# endif
|
2023-06-30 19:37:30 +02:00
|
|
|
#else
|
2025-04-11 18:28:45 +02:00
|
|
|
return 1.0f;
|
2023-06-30 19:37:30 +02:00
|
|
|
#endif
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef GPU_METAL
|
2024-02-24 00:00:11 +01:00
|
|
|
Closure nodetree_surface(float closure_rand);
|
2024-04-05 16:33:58 +02:00
|
|
|
Closure nodetree_volume();
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 nodetree_displacement();
|
2022-05-02 09:22:14 +02:00
|
|
|
float nodetree_thickness();
|
2025-04-14 13:46:41 +02:00
|
|
|
float4 closure_to_rgba(Closure cl);
|
2022-05-02 09:22:14 +02:00
|
|
|
#endif
|
|
|
|
|
|
2025-09-22 14:26:20 +02:00
|
|
|
/**
|
|
|
|
|
* Used for packing.
|
|
|
|
|
* This is the reflection coefficient also denoted r.
|
|
|
|
|
* https://en.wikipedia.org/wiki/Fresnel_equations#Complex_amplitude_reflection_and_transmission_coefficients
|
|
|
|
|
*/
|
|
|
|
|
float f0_from_ior(float eta)
|
|
|
|
|
{
|
|
|
|
|
return (eta - 1.0f) / (eta + 1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simplified form of F_eta(eta, 1.0).
|
|
|
|
|
* This is the power reflection coefficient also denoted R.
|
|
|
|
|
* https://en.wikipedia.org/wiki/Fresnel_equations#Complex_amplitude_reflection_and_transmission_coefficients
|
|
|
|
|
*/
|
2023-07-14 19:03:00 +02:00
|
|
|
float F0_from_ior(float eta)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-09-22 14:26:20 +02:00
|
|
|
return square(f0_from_ior(eta));
|
|
|
|
|
}
|
|
|
|
|
float F0_from_f0(float f0)
|
|
|
|
|
{
|
|
|
|
|
return square(f0);
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
2023-07-14 19:03:00 +02:00
|
|
|
|
2023-08-29 12:50:53 +02:00
|
|
|
/* Return the fresnel color from a precomputed LUT value (from brdf_lut). */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 F_brdf_single_scatter(float3 f0, float3 f90, float2 lut)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2023-08-29 12:50:53 +02:00
|
|
|
return f0 * lut.x + f90 * lut.y;
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
2023-07-14 19:03:00 +02:00
|
|
|
|
2023-08-29 12:50:53 +02:00
|
|
|
/* Multi-scattering brdf approximation from
|
|
|
|
|
* "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
|
|
|
|
|
* https://jcgt.org/published/0008/01/03/paper.pdf by Carmelo J. Fdez-Agüera. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 F_brdf_multi_scatter(float3 f0, float3 f90, float2 lut)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 FssEss = F_brdf_single_scatter(f0, f90, lut);
|
2023-07-14 19:03:00 +02:00
|
|
|
|
|
|
|
|
float Ess = lut.x + lut.y;
|
2025-04-11 18:28:45 +02:00
|
|
|
float Ems = 1.0f - Ess;
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 Favg = f0 + (f90 - f0) / 21.0f;
|
2023-08-29 12:50:53 +02:00
|
|
|
|
|
|
|
|
/* The original paper uses `FssEss * radiance + Fms*Ems * irradiance`, but
|
2023-10-03 11:22:43 +11:00
|
|
|
* "A Journey Through Implementing Multi-scattering BRDFs and Area Lights" by Steve McAuley
|
2023-09-03 21:35:03 +10:00
|
|
|
* suggests to use `FssEss * radiance + Fms*Ems * radiance` which results in comparable quality.
|
2023-08-29 12:50:53 +02:00
|
|
|
* We handle `radiance` outside of this function, so the result simplifies to:
|
|
|
|
|
* `FssEss + Fms*Ems = FssEss * (1 + Ems*Favg / (1 - Ems*Favg)) = FssEss / (1 - Ems*Favg)`.
|
|
|
|
|
* This is a simple albedo scaling very similar to the approach used by Cycles:
|
|
|
|
|
* "Practical multiple scattering compensation for microfacet model". */
|
2025-04-11 18:28:45 +02:00
|
|
|
return FssEss / (1.0f - Ems * Favg);
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
2023-07-14 19:03:00 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 brdf_lut(float cos_theta, float roughness)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-09-12 14:09:35 +02:00
|
|
|
auto &utility_tx = sampler_get(eevee_utility_texture, utility_tx);
|
2023-08-29 14:08:38 +02:00
|
|
|
return utility_tx_sample_lut(utility_tx, cos_theta, roughness, UTIL_BSDF_LAYER).rg;
|
2023-07-14 19:03:00 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
void brdf_f82_tint_lut(float3 F0,
|
|
|
|
|
float3 F82,
|
2023-09-26 10:16:39 +02:00
|
|
|
float cos_theta,
|
|
|
|
|
float roughness,
|
|
|
|
|
bool do_multiscatter,
|
2025-04-14 13:46:41 +02:00
|
|
|
out float3 reflectance)
|
2023-09-26 10:16:39 +02:00
|
|
|
{
|
2025-09-12 14:09:35 +02:00
|
|
|
auto &utility_tx = sampler_get(eevee_utility_texture, utility_tx);
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 split_sum = utility_tx_sample_lut(utility_tx, cos_theta, roughness, UTIL_BSDF_LAYER).rgb;
|
2023-09-26 10:16:39 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
reflectance = do_multiscatter ? F_brdf_multi_scatter(F0, float3(1.0f), split_sum.xy) :
|
|
|
|
|
F_brdf_single_scatter(F0, float3(1.0f), split_sum.xy);
|
2023-09-26 10:16:39 +02:00
|
|
|
|
|
|
|
|
/* Precompute the F82 term factor for the Fresnel model.
|
|
|
|
|
* In the classic F82 model, the F82 input directly determines the value of the Fresnel
|
|
|
|
|
* model at ~82°, similar to F0 and F90.
|
|
|
|
|
* With F82-Tint, on the other hand, the value at 82° is the value of the classic Schlick
|
|
|
|
|
* model multiplied by the tint input.
|
2023-09-26 19:50:04 +10:00
|
|
|
* Therefore, the factor follows by setting `F82Tint(cosI) = FSchlick(cosI) - b*cosI*(1-cosI)^6`
|
|
|
|
|
* and `F82Tint(acos(1/7)) = FSchlick(acos(1/7)) * f82_tint` and solving for `b`. */
|
2025-04-15 11:36:53 +02:00
|
|
|
constexpr float f = 6.0f / 7.0f;
|
|
|
|
|
constexpr float f5 = (f * f) * (f * f) * f;
|
|
|
|
|
constexpr float f6 = (f * f) * (f * f) * (f * f);
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 F_schlick = mix(F0, float3(1.0f), f5);
|
|
|
|
|
float3 b = F_schlick * (7.0f / f6) * (1.0f - F82);
|
2023-09-26 10:16:39 +02:00
|
|
|
reflectance -= b * split_sum.z;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-14 18:46:07 +02:00
|
|
|
/* Return texture coordinates to sample BSDF LUT. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 lut_coords_bsdf(float cos_theta, float roughness, float ior)
|
2023-09-14 18:46:07 +02:00
|
|
|
{
|
|
|
|
|
/* IOR is the sine of the critical angle. */
|
2025-04-11 18:28:45 +02:00
|
|
|
float critical_cos = sqrt(1.0f - ior * ior);
|
2023-09-14 18:46:07 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 coords;
|
2023-10-13 17:59:46 +02:00
|
|
|
coords.x = square(ior);
|
2023-09-14 18:46:07 +02:00
|
|
|
coords.y = cos_theta;
|
|
|
|
|
coords.y -= critical_cos;
|
2025-04-11 18:28:45 +02:00
|
|
|
coords.y /= (coords.y > 0.0f) ? (1.0f - critical_cos) : critical_cos;
|
|
|
|
|
coords.y = coords.y * 0.5f + 0.5f;
|
2023-09-14 18:46:07 +02:00
|
|
|
coords.z = roughness;
|
|
|
|
|
|
|
|
|
|
return saturate(coords);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-18 14:26:19 +02:00
|
|
|
/* Return texture coordinates to sample Surface LUT. */
|
2025-09-22 14:26:20 +02:00
|
|
|
float3 lut_coords_btdf(float cos_theta, float roughness, float f0)
|
2023-09-18 14:26:19 +02:00
|
|
|
{
|
2025-09-22 14:26:20 +02:00
|
|
|
return float3(sqrt(f0), sqrt(1.0f - cos_theta), roughness);
|
2023-09-18 14:26:19 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 16:56:44 +02:00
|
|
|
/* Computes the reflectance and transmittance based on the tint (`f0`, `f90`, `transmission_tint`)
|
|
|
|
|
* and the BSDF LUT. */
|
2025-04-14 13:46:41 +02:00
|
|
|
void bsdf_lut(float3 F0,
|
|
|
|
|
float3 F90,
|
|
|
|
|
float3 transmission_tint,
|
2023-09-22 16:56:44 +02:00
|
|
|
float cos_theta,
|
|
|
|
|
float roughness,
|
|
|
|
|
float ior,
|
2023-09-26 11:48:51 +02:00
|
|
|
bool do_multiscatter,
|
2025-04-14 13:46:41 +02:00
|
|
|
out float3 reflectance,
|
|
|
|
|
out float3 transmittance)
|
2023-07-14 19:03:00 +02:00
|
|
|
{
|
2025-09-12 14:09:35 +02:00
|
|
|
auto &utility_tx = sampler_get(eevee_utility_texture, utility_tx);
|
2025-04-11 18:28:45 +02:00
|
|
|
if (ior == 1.0f) {
|
2025-04-14 13:46:41 +02:00
|
|
|
reflectance = float3(0.0f);
|
2023-09-22 16:56:44 +02:00
|
|
|
transmittance = transmission_tint;
|
|
|
|
|
return;
|
2023-07-14 19:03:00 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 split_sum;
|
2023-09-18 14:26:19 +02:00
|
|
|
float transmission_factor;
|
|
|
|
|
|
2025-09-22 14:26:20 +02:00
|
|
|
const float f0 = f0_from_ior(ior);
|
|
|
|
|
|
2025-04-11 18:28:45 +02:00
|
|
|
if (ior > 1.0f) {
|
|
|
|
|
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0f, 1.33f], to avoid
|
|
|
|
|
* harsh transition at `IOR == 1`. */
|
2025-04-14 13:46:41 +02:00
|
|
|
if (all(equal(F90, float3(1.0f)))) {
|
2025-09-22 14:26:20 +02:00
|
|
|
F90 = float3(saturate(2.33f / 0.33f * f0));
|
2023-09-22 16:56:44 +02:00
|
|
|
}
|
2025-09-22 14:26:20 +02:00
|
|
|
const float3 coords = lut_coords_btdf(cos_theta, roughness, f0);
|
|
|
|
|
const float4 bsdf = utility_tx_sample_bsdf_lut(utility_tx, coords.xy, coords.z);
|
|
|
|
|
split_sum = brdf_lut(cos_theta, roughness);
|
|
|
|
|
transmission_factor = bsdf.a;
|
2023-09-18 14:26:19 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-09-22 14:26:20 +02:00
|
|
|
const float3 coords = lut_coords_bsdf(cos_theta, roughness, ior);
|
|
|
|
|
const float3 bsdf = utility_tx_sample_bsdf_lut(utility_tx, coords.xy, coords.z).rgb;
|
2023-09-18 14:26:19 +02:00
|
|
|
split_sum = bsdf.rg;
|
|
|
|
|
transmission_factor = bsdf.b;
|
2023-07-14 19:03:00 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 16:56:44 +02:00
|
|
|
reflectance = F_brdf_single_scatter(F0, F90, split_sum);
|
2025-04-14 13:46:41 +02:00
|
|
|
transmittance = (float3(1.0f) - F0) * transmission_factor * transmission_tint;
|
2023-09-18 14:26:19 +02:00
|
|
|
|
2023-09-26 11:48:51 +02:00
|
|
|
if (do_multiscatter) {
|
2025-09-22 14:26:20 +02:00
|
|
|
const float real_F0 = F0_from_f0(f0);
|
|
|
|
|
const float Ess = real_F0 * split_sum.x + split_sum.y + (1.0f - real_F0) * transmission_factor;
|
|
|
|
|
const float Ems = 1.0f - Ess;
|
2023-09-22 16:56:44 +02:00
|
|
|
/* Assume that the transmissive tint makes up most of the overall color if it's not zero. */
|
2025-09-22 14:26:20 +02:00
|
|
|
const float3 Favg = all(equal(transmission_tint, float3(0.0f))) ? F0 + (F90 - F0) / 21.0f :
|
|
|
|
|
transmission_tint;
|
2023-09-22 16:56:44 +02:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 scale = 1.0f / (1.0f - Ems * Favg);
|
2023-09-18 14:26:19 +02:00
|
|
|
reflectance *= scale;
|
|
|
|
|
transmittance *= scale;
|
2023-09-01 10:59:20 +02:00
|
|
|
}
|
2023-09-22 16:56:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Computes the reflectance and transmittance based on the BSDF LUT. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 bsdf_lut(float cos_theta, float roughness, float ior, bool do_multiscatter)
|
2023-09-22 16:56:44 +02:00
|
|
|
{
|
|
|
|
|
float F0 = F0_from_ior(ior);
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 color = float3(1.0f);
|
|
|
|
|
float3 reflectance, transmittance;
|
|
|
|
|
bsdf_lut(float3(F0),
|
2023-09-26 10:24:47 +02:00
|
|
|
color,
|
|
|
|
|
color,
|
|
|
|
|
cos_theta,
|
|
|
|
|
roughness,
|
|
|
|
|
ior,
|
|
|
|
|
do_multiscatter,
|
|
|
|
|
reflectance,
|
|
|
|
|
transmittance);
|
2025-04-14 13:46:41 +02:00
|
|
|
return float2(reflectance.r, transmittance.r);
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
2023-05-30 15:20:52 +02:00
|
|
|
|
2022-07-25 09:44:15 +02:00
|
|
|
#ifdef GPU_VERTEX_SHADER
|
2025-04-14 13:46:41 +02:00
|
|
|
# define closure_to_rgba(a) float4(0.0f)
|
2022-07-25 09:44:15 +02:00
|
|
|
#endif
|
|
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Fragment Displacement
|
|
|
|
|
*
|
|
|
|
|
* Displacement happening in the fragment shader.
|
|
|
|
|
* Can be used in conjunction with a per vertex displacement.
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-07-24 12:04:15 +02:00
|
|
|
#ifndef GPU_METAL
|
|
|
|
|
/* Prototype. */
|
|
|
|
|
float derivative_scale_get();
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-05-02 09:22:14 +02:00
|
|
|
#ifdef MAT_DISPLACEMENT_BUMP
|
|
|
|
|
/* Return new shading normal. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 displacement_bump()
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-05-05 09:59:00 +02:00
|
|
|
# if !defined(MAT_GEOM_CURVES)
|
2025-03-24 15:53:35 +01:00
|
|
|
/* This is the filter width for automatic displacement + bump mapping, which is fixed.
|
|
|
|
|
* NOTE: keep the same as default bump node filter width. */
|
2025-04-15 11:36:53 +02:00
|
|
|
constexpr float bump_filter_width = 0.1f;
|
2025-03-24 15:53:35 +01:00
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 dHd;
|
2025-03-24 15:53:35 +01:00
|
|
|
dF_branch(dot(nodetree_displacement(), g_data.N + dF_impl(g_data.N)), bump_filter_width, dHd);
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2025-07-24 12:04:15 +02:00
|
|
|
float3 dPdx = gpu_dfdx(g_data.P) * derivative_scale_get();
|
|
|
|
|
float3 dPdy = gpu_dfdy(g_data.P) * derivative_scale_get();
|
2022-05-02 09:22:14 +02:00
|
|
|
|
|
|
|
|
/* Get surface tangents from normal. */
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 Rx = cross(dPdy, g_data.N);
|
|
|
|
|
float3 Ry = cross(g_data.N, dPdx);
|
2022-05-02 09:22:14 +02:00
|
|
|
|
|
|
|
|
/* Compute surface gradient and determinant. */
|
|
|
|
|
float det = dot(dPdx, Rx);
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 surfgrad = dHd.x * Rx + dHd.y * Ry;
|
2022-05-02 09:22:14 +02:00
|
|
|
|
2025-04-11 18:28:45 +02:00
|
|
|
float facing = FrontFacing ? 1.0f : -1.0f;
|
2025-03-24 15:53:35 +01:00
|
|
|
return normalize(bump_filter_width * abs(det) * g_data.N - facing * sign(det) * surfgrad);
|
2022-05-02 09:22:14 +02:00
|
|
|
# else
|
|
|
|
|
return g_data.N;
|
|
|
|
|
# endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void fragment_displacement()
|
|
|
|
|
{
|
|
|
|
|
#ifdef MAT_DISPLACEMENT_BUMP
|
2024-05-24 15:12:41 +02:00
|
|
|
g_data.N = g_data.Ni = displacement_bump();
|
2022-05-02 09:22:14 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Coordinate implementations
|
|
|
|
|
*
|
|
|
|
|
* Callbacks for the texture coordinate node.
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 coordinate_camera(float3 P)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 vP;
|
2023-09-22 12:02:32 +10:00
|
|
|
if (false /* Probe. */) {
|
2022-05-02 09:22:14 +02:00
|
|
|
/* Unsupported. It would make the probe camera-dependent. */
|
|
|
|
|
vP = P;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2023-11-23 15:58:08 +01:00
|
|
|
#ifdef MAT_GEOM_WORLD
|
2023-10-13 17:59:46 +02:00
|
|
|
vP = drw_normal_world_to_view(P);
|
2022-05-02 09:22:14 +02:00
|
|
|
#else
|
2023-10-13 17:59:46 +02:00
|
|
|
vP = drw_point_world_to_view(P);
|
2022-05-02 09:22:14 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
vP.z = -vP.z;
|
|
|
|
|
return vP;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 coordinate_screen(float3 P)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 window = float3(0.0f);
|
2023-09-22 12:02:32 +10:00
|
|
|
if (false /* Probe. */) {
|
2022-05-02 09:22:14 +02:00
|
|
|
/* Unsupported. It would make the probe camera-dependent. */
|
2025-04-14 13:46:41 +02:00
|
|
|
window.xy = float2(0.5f);
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-11-23 15:58:08 +01:00
|
|
|
#ifdef MAT_GEOM_WORLD
|
|
|
|
|
window.xy = drw_point_view_to_screen(interp.P).xy;
|
|
|
|
|
#else
|
Cleanup: fix various typos
Found via codespell -q 3 -S ./intern,./extern -L ans,ba,bording,datas,eiter,fiter,hist,inout,lod,ot,parm,parms,pixelx,pres,te
Contributed by luzpaz.
Differential Revision: https://developer.blender.org/D15155
2022-06-13 13:17:32 +02:00
|
|
|
/* TODO(fclem): Actual camera transform. */
|
2023-10-13 17:59:46 +02:00
|
|
|
window.xy = drw_point_world_to_screen(P).xy;
|
2023-11-23 15:58:08 +01:00
|
|
|
#endif
|
2023-09-08 21:03:37 +02:00
|
|
|
window.xy = window.xy * uniform_buf.camera.uv_scale + uniform_buf.camera.uv_bias;
|
2022-05-02 09:22:14 +02:00
|
|
|
}
|
|
|
|
|
return window;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 coordinate_reflect(float3 P, float3 N)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2023-11-23 15:58:08 +01:00
|
|
|
#ifdef MAT_GEOM_WORLD
|
2022-05-02 09:22:14 +02:00
|
|
|
return N;
|
|
|
|
|
#else
|
2023-10-13 17:59:46 +02:00
|
|
|
return -reflect(drw_world_incident_vector(P), N);
|
2022-05-02 09:22:14 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 coordinate_incoming(float3 P)
|
2022-05-02 09:22:14 +02:00
|
|
|
{
|
2023-11-23 15:58:08 +01:00
|
|
|
#ifdef MAT_GEOM_WORLD
|
2022-05-02 09:22:14 +02:00
|
|
|
return -P;
|
|
|
|
|
#else
|
2023-10-13 17:59:46 +02:00
|
|
|
return drw_world_incident_vector(P);
|
2022-05-02 09:22:14 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
2022-07-25 09:44:15 +02:00
|
|
|
|
2024-03-13 12:00:24 +01:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Mixed render resolution
|
|
|
|
|
*
|
|
|
|
|
* Callbacks image texture sampling.
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2024-06-18 19:31:39 +02:00
|
|
|
float texture_lod_bias_get()
|
2024-03-13 12:00:24 +01:00
|
|
|
{
|
2024-06-18 19:31:39 +02:00
|
|
|
return uniform_buf.film.texture_lod_bias;
|
2024-03-13 12:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-24 12:04:15 +02:00
|
|
|
/**
|
|
|
|
|
* Scale hardware derivatives depending on render resolution.
|
|
|
|
|
* This is because the distance between pixels increases as we lower the resolution. The hardware
|
|
|
|
|
* uses neighboring pixels to compute derivatives and thus the value increases as we lower the
|
|
|
|
|
* resolution. So we compensate by scaling them back to the expected amplitude at full resolution.
|
|
|
|
|
*/
|
|
|
|
|
float derivative_scale_get()
|
|
|
|
|
{
|
|
|
|
|
return 1.0 / float(uniform_buf.film.scaling_factor);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-13 12:00:24 +01:00
|
|
|
/** \} */
|
|
|
|
|
|
2022-07-25 09:44:15 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Volume Attribute post
|
|
|
|
|
*
|
2025-02-28 17:26:07 +01:00
|
|
|
* TODO(@fclem): These implementation details should concern the DRWContext and not be a fix on
|
2022-07-25 09:44:15 +02:00
|
|
|
* the engine side. But as of now, the engines are responsible for loading the attributes.
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2024-04-05 16:33:58 +02:00
|
|
|
/* Point clouds and curves are not compatible with volume grids.
|
2025-06-02 17:13:56 -04:00
|
|
|
* They will fall back to their own attributes loading. */
|
2025-02-19 17:11:08 +01:00
|
|
|
#if defined(MAT_VOLUME) && !defined(MAT_GEOM_CURVES) && !defined(MAT_GEOM_POINTCLOUD)
|
2024-06-17 19:08:37 +02:00
|
|
|
# if defined(VOLUME_INFO_LIB) && !defined(MAT_GEOM_WORLD)
|
2024-04-05 16:33:58 +02:00
|
|
|
/* We could just check for GRID_ATTRIBUTES but this avoids for header dependency. */
|
|
|
|
|
# define GRID_ATTRIBUTES_LOAD_POST
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
2022-07-25 09:44:15 +02:00
|
|
|
|
|
|
|
|
float attr_load_temperature_post(float attr)
|
|
|
|
|
{
|
2024-04-05 16:33:58 +02:00
|
|
|
#ifdef GRID_ATTRIBUTES_LOAD_POST
|
2024-06-17 19:08:37 +02:00
|
|
|
/* Bring the value into standard range without having to modify the grid values */
|
2025-04-11 18:28:45 +02:00
|
|
|
attr = (attr > 0.01f) ? (attr * drw_volume.temperature_mul + drw_volume.temperature_bias) : 0.0f;
|
2024-04-05 16:33:58 +02:00
|
|
|
#endif
|
2022-07-25 09:44:15 +02:00
|
|
|
return attr;
|
|
|
|
|
}
|
2025-04-14 13:46:41 +02:00
|
|
|
float4 attr_load_color_post(float4 attr)
|
2022-07-25 09:44:15 +02:00
|
|
|
{
|
2024-04-05 16:33:58 +02:00
|
|
|
#ifdef GRID_ATTRIBUTES_LOAD_POST
|
2022-07-25 09:44:15 +02:00
|
|
|
/* Density is premultiplied for interpolation, divide it out here. */
|
|
|
|
|
attr.rgb *= safe_rcp(attr.a);
|
|
|
|
|
attr.rgb *= drw_volume.color_mul.rgb;
|
2025-04-11 18:28:45 +02:00
|
|
|
attr.a = 1.0f;
|
2024-04-05 16:33:58 +02:00
|
|
|
#endif
|
2022-07-25 09:44:15 +02:00
|
|
|
return attr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-05 16:33:58 +02:00
|
|
|
#undef GRID_ATTRIBUTES_LOAD_POST
|
2022-07-25 09:44:15 +02:00
|
|
|
|
|
|
|
|
/** \} */
|
2022-09-01 14:46:17 +02:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2022-09-02 20:56:55 +02:00
|
|
|
/** \name Uniform Attributes
|
2022-09-01 14:46:17 +02:00
|
|
|
*
|
2025-02-28 17:26:07 +01:00
|
|
|
* TODO(@fclem): These implementation details should concern the DRWContext and not be a fix on
|
2022-09-01 14:46:17 +02:00
|
|
|
* the engine side. But as of now, the engines are responsible for loading the attributes.
|
|
|
|
|
*
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float4 attr_load_uniform(float4 attr, const uint attr_hash)
|
2022-09-01 14:46:17 +02:00
|
|
|
{
|
2025-03-06 11:06:26 +01:00
|
|
|
return drw_object_attribute(attr_hash);
|
2022-09-01 14:46:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|