EEVEE-Next: Add Translucent BSDF support

This adds support for Translucent BSDF.

This also fixes a bug to allow correct
shadowing.

The input normal had to be set back to
non-inverted in the node function to allow
for correct interpretation of the Normal
by Screen Space Reflections.

This add the necessary optimization
and code deduplication to hybrid deferred
and forward pipeline.

Pull Request: https://projects.blender.org/blender/blender/pulls/116070
This commit is contained in:
Clément Foucault
2023-12-13 02:19:19 +01:00
committed by Clément Foucault
parent 7ad2c71a0a
commit ac11ccd2bd
27 changed files with 351 additions and 326 deletions

View File

@@ -506,6 +506,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_film_cryptomatte_post_comp.glsl
engines/eevee_next/shaders/eevee_film_frag.glsl
engines/eevee_next/shaders/eevee_film_lib.glsl
engines/eevee_next/shaders/eevee_forward_lib.glsl
engines/eevee_next/shaders/eevee_gbuffer_lib.glsl
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl

View File

@@ -95,7 +95,7 @@ Closure closure_eval(ClosureTranslucent translucent)
/* Glue with the old system. */
CLOSURE_VARS_DECLARE_1(Translucent);
in_Translucent_0.N = translucent.N;
in_Translucent_0.N = -translucent.N;
CLOSURE_EVAL_FUNCTION_1(TranslucentBSDF, Translucent);

View File

@@ -125,6 +125,9 @@ static inline eClosureBits shader_closure_bits_from_flag(const GPUMaterial *gpum
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) {
closure_bits |= CLOSURE_TRANSPARENCY;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT)) {
closure_bits |= CLOSURE_TRANSLUCENT;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_EMISSION)) {
closure_bits |= CLOSURE_EMISSION;
}

View File

@@ -491,7 +491,8 @@ void DeferredLayer::begin_sync()
void DeferredLayer::end_sync()
{
eClosureBits evaluated_closures = CLOSURE_DIFFUSE | CLOSURE_REFLECTION | CLOSURE_REFRACTION;
eClosureBits evaluated_closures = CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT | CLOSURE_REFLECTION |
CLOSURE_REFRACTION;
if (closure_bits_ & evaluated_closures) {
/* Add the tile classification step at the end of the GBuffer pass. */
{
@@ -716,7 +717,8 @@ void DeferredLayer::render(View &main_view,
inst_.manager->submit(gbuffer_ps_, render_view);
int closure_count = count_bits_i(closure_bits_ & (CLOSURE_REFLECTION | CLOSURE_DIFFUSE));
int closure_count = count_bits_i(closure_bits_ &
(CLOSURE_REFLECTION | CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT));
for (int i = 0; i < ARRAY_SIZE(direct_radiance_txs_); i++) {
direct_radiance_txs_[i].acquire(
(closure_count > 1) ? extent : int2(1), GPU_R11F_G11F_B10F, usage_rw);

View File

@@ -188,15 +188,15 @@ struct DeferredLayerBase {
/* Return the amount of gbuffer layer needed. */
int closure_layer_count() const
{
return count_bits_i(closure_bits_ &
(CLOSURE_REFRACTION | CLOSURE_REFLECTION | CLOSURE_DIFFUSE | CLOSURE_SSS));
return count_bits_i(closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_REFLECTION |
CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT | CLOSURE_SSS));
}
/* Return the amount of gbuffer layer needed. */
int color_layer_count() const
{
return count_bits_i(closure_bits_ &
(CLOSURE_REFRACTION | CLOSURE_REFLECTION | CLOSURE_DIFFUSE));
return count_bits_i(closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_REFLECTION |
CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT));
}
};

View File

@@ -406,8 +406,56 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
info.additional_info("eevee_cryptomatte_out");
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE) && pipeline_type == MAT_PIPE_FORWARD) {
info.define("SSS_TRANSMITTANCE");
int lit_closure_count = 0;
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE)) {
info.define("MAT_DIFFUSE");
lit_closure_count++;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY)) {
info.define("MAT_REFLECTION");
lit_closure_count++;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT)) {
info.define("MAT_TRANSLUCENT");
lit_closure_count++;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE)) {
info.define("MAT_SUBSURFACE");
lit_closure_count++;
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT)) {
info.define("MAT_REFRACTION");
/* TODO(fclem): Support refracted lights. */
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT | GPU_MATFLAG_SUBSURFACE)) {
info.define("SHADOW_SUBSURFACE");
}
if ((pipeline_type == MAT_PIPE_FORWARD) ||
GPU_material_flag_get(gpumat, GPU_MATFLAG_SHADER_TO_RGBA))
{
switch (lit_closure_count) {
case 0:
/* Define nothing. This will in turn define SKIP_LIGHT_EVAL. */
break;
/* These need to be separated since the strings need to be static. */
case 1:
info.define("LIGHT_CLOSURE_EVAL_COUNT", "1");
break;
case 2:
info.define("LIGHT_CLOSURE_EVAL_COUNT", "2");
break;
case 3:
info.define("LIGHT_CLOSURE_EVAL_COUNT", "3");
break;
case 4:
info.define("LIGHT_CLOSURE_EVAL_COUNT", "4");
break;
default:
BLI_assert_unreachable();
break;
}
}
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC)) {

View File

@@ -1182,6 +1182,7 @@ enum eClosureBits : uint32_t {
CLOSURE_SSS = (1u << 1u),
CLOSURE_REFLECTION = (1u << 2u),
CLOSURE_REFRACTION = (1u << 3u),
CLOSURE_TRANSLUCENT = (1u << 4u),
CLOSURE_TRANSPARENCY = (1u << 8u),
CLOSURE_EMISSION = (1u << 9u),
CLOSURE_HOLDOUT = (1u << 10u),
@@ -1198,6 +1199,7 @@ enum GBufferMode : uint32_t {
GBUF_REFRACTION = 2u,
GBUF_DIFFUSE = 3u,
GBUF_SSS = 4u,
GBUF_TRANSLUCENT = 5u,
/** Special configurations. Packs multiple closures into 1 layer. */
GBUF_OPAQUE_DIELECTRIC = 14u,

View File

@@ -17,35 +17,42 @@ void main()
GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel);
vec3 diffuse_light = vec3(0.0);
vec3 reflect_light = vec3(0.0);
vec3 refract_light = vec3(0.0);
vec3 glossy_reflect_light = vec3(0.0);
vec3 glossy_refract_light = vec3(0.0);
vec3 diffuse_reflect_light = vec3(0.0);
vec3 diffuse_refract_light = vec3(0.0);
if (gbuf.has_diffuse) {
diffuse_light = imageLoad(direct_radiance_1_img, texel).rgb +
imageLoad(indirect_diffuse_img, texel).rgb;
diffuse_reflect_light = imageLoad(direct_radiance_1_img, texel).rgb +
imageLoad(indirect_diffuse_img, texel).rgb;
}
if (gbuf.has_reflection) {
reflect_light = imageLoad(direct_radiance_2_img, texel).rgb +
imageLoad(indirect_reflect_img, texel).rgb;
glossy_reflect_light = imageLoad(direct_radiance_2_img, texel).rgb +
imageLoad(indirect_reflect_img, texel).rgb;
}
if (gbuf.has_translucent) {
/* Indirect radiance not implemented yet. */
diffuse_refract_light = imageLoad(direct_radiance_3_img, texel).rgb;
}
if (gbuf.has_refraction) {
refract_light =
/* imageLoad(direct_radiance_3_img, texel).rgb + */ /* TODO: Not implemented. */
imageLoad(indirect_refract_img, texel).rgb;
/* Direct radiance not implemented yet. */
glossy_refract_light = imageLoad(indirect_refract_img, texel).rgb;
}
/* Light passes. */
vec3 specular_light = reflect_light + refract_light;
vec3 diffuse_light = diffuse_reflect_light + diffuse_refract_light;
vec3 specular_light = glossy_reflect_light + glossy_refract_light;
output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(diffuse_light, 1.0));
output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(specular_light, 1.0));
/* Combine. */
out_combined = vec4(0.0);
out_combined.xyz += diffuse_light * gbuf.diffuse.color;
out_combined.xyz += reflect_light * gbuf.reflection.color;
out_combined.xyz += refract_light * gbuf.refraction.color;
out_combined.xyz += diffuse_reflect_light * gbuf.diffuse.color;
out_combined.xyz += diffuse_refract_light * gbuf.translucent.color;
out_combined.xyz += glossy_reflect_light * gbuf.reflection.color;
out_combined.xyz += glossy_refract_light * gbuf.refraction.color;
if (any(isnan(out_combined))) {
out_combined = vec4(1.0, 0.0, 1.0, 0.0);

View File

@@ -31,43 +31,42 @@ void main()
vec3 V = drw_world_incident_vector(P);
float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
ClosureLightStack stack;
ClosureLight cl_diff;
cl_diff.N = gbuf.diffuse.N;
cl_diff.ltc_mat = LTC_LAMBERT_MAT;
cl_diff.type = LIGHT_DIFFUSE;
/* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the
* raytracing pipeline first. */
if (gbuf.has_diffuse) {
ClosureLight cl_diff;
cl_diff.N = gbuf.diffuse.N;
cl_diff.ltc_mat = LTC_LAMBERT_MAT;
cl_diff.type = LIGHT_DIFFUSE;
stack.cl[0] = cl_diff;
}
else {
ClosureLight cl_refl;
cl_refl.N = gbuf.reflection.N;
cl_refl.ltc_mat = LTC_GGX_MAT(dot(gbuf.reflection.N, V), gbuf.reflection.roughness);
cl_refl.type = LIGHT_SPECULAR;
stack.cl[0] = cl_refl;
}
#if LIGHT_CLOSURE_EVAL_COUNT > 1
ClosureLight cl_refl;
cl_refl.N = gbuf.reflection.N;
cl_refl.ltc_mat = LTC_GGX_MAT(dot(gbuf.reflection.N, V), gbuf.reflection.roughness);
cl_refl.type = LIGHT_SPECULAR;
stack.cl[1] = cl_refl;
#endif
#if LIGHT_CLOSURE_EVAL_COUNT > 2
ClosureLight cl_sss;
cl_sss.N = -gbuf.diffuse.N;
cl_sss.ltc_mat = LTC_LAMBERT_MAT;
cl_sss.type = LIGHT_DIFFUSE;
stack.cl[2] = cl_sss;
ClosureLight cl_translucent;
cl_translucent.N = -gbuf.translucent.N;
cl_translucent.ltc_mat = LTC_LAMBERT_MAT;
cl_translucent.type = LIGHT_DIFFUSE;
ClosureLightStack stack;
/* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the
* raytracing pipeline first. */
stack.cl[0] = (gbuf.has_diffuse) ? cl_diff : cl_refl;
#if LIGHT_CLOSURE_EVAL_COUNT > 1
stack.cl[1] = cl_refl;
#endif
float thickness = 0.0;
#ifdef SSS_TRANSMITTANCE
#if LIGHT_CLOSURE_EVAL_COUNT > 2
stack.cl[2] = (gbuf.has_translucent) ? cl_translucent : cl_sss;
#endif
float thickness = (gbuf.has_translucent) ? gbuf.thickness : 0.0;
#ifdef MAT_SUBSURFACE
if (gbuf.has_sss) {
float shadow_thickness = thickness_from_shadow(P, Ng, vPz);
thickness = (shadow_thickness != THICKNESS_NO_VALUE) ? max(shadow_thickness, gbuf.thickness) :
@@ -88,7 +87,7 @@ void main()
radiance_unshadowed += stack.cl[2].light_unshadowed;
#endif
#ifdef SSS_TRANSMITTANCE
#ifdef MAT_SUBSURFACE
if (gbuf.has_sss) {
vec3 sss_profile = subsurface_transmission(gbuf.diffuse.sss_radius, thickness);
stack.cl[2].light_shadowed *= sss_profile;
@@ -121,10 +120,8 @@ void main()
#endif
#if LIGHT_CLOSURE_EVAL_COUNT > 2
# if 0 /* Will work when we have fully flexible evaluation. */
if (gbuf.closure_count > 2) {
if (gbuf.closure_count > 2 || gbuf.has_translucent) {
imageStore(direct_radiance_3_img, texel, vec4(stack.cl[2].light_shadowed, 1.0));
}
# endif
#endif
}

View File

@@ -27,7 +27,11 @@ void main()
if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_REFRACTION))) {
imageStore(tile_mask_img, ivec3(tile_co, 2), uvec4(1u));
}
if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_SSS))) {
if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_TRANSLUCENT))) {
imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u));
}
/* TODO(fclem): For now, override SSS if we have translucency. */
else if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_SSS))) {
imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u));
}
}

View File

@@ -0,0 +1,121 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* Forward lighting evaluation: Lighting is evaluated during the geometry rasterization.
*
* This is used by alpha blended materials and materials using Shader to RGB nodes.
*/
#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmittance)
{
float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position());
vec3 V = drw_world_incident_vector(g_data.P);
ClosureLightStack stack;
ClosureLight cl_diffuse;
cl_diffuse.N = g_diffuse_data.N;
cl_diffuse.ltc_mat = LTC_LAMBERT_MAT;
cl_diffuse.type = LIGHT_DIFFUSE;
ClosureLight cl_subsurface;
cl_subsurface.N = -g_diffuse_data.N;
cl_subsurface.ltc_mat = LTC_LAMBERT_MAT;
cl_subsurface.type = LIGHT_DIFFUSE;
ClosureLight cl_translucent;
cl_translucent.N = -g_translucent_data.N;
cl_translucent.ltc_mat = LTC_LAMBERT_MAT;
cl_translucent.type = LIGHT_DIFFUSE;
ClosureLight cl_reflection;
cl_reflection.N = g_reflection_data.N;
cl_reflection.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness);
cl_reflection.type = LIGHT_SPECULAR;
int cl_layer = 0;
#ifdef MAT_DIFFUSE
const int cl_diffuse_id = cl_layer++;
stack.cl[cl_diffuse_id] = cl_diffuse;
#endif
#ifdef MAT_SUBSURFACE
const int cl_subsurface_id = cl_layer++;
stack.cl[cl_subsurface_id] = cl_subsurface;
#endif
#ifdef MAT_TRANSLUCENT
const int cl_translucent_id = cl_layer++;
stack.cl[cl_translucent_id] = cl_translucent;
#endif
#ifdef MAT_REFLECTION
const int cl_reflection_id = cl_layer++;
stack.cl[cl_reflection_id] = cl_reflection;
#endif
#ifndef SKIP_LIGHT_EVAL
light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness);
#endif
#ifdef MAT_SUBSURFACE
vec3 sss_profile = subsurface_transmission(g_diffuse_data.sss_radius, thickness);
stack.cl[cl_subsurface_id].light_shadowed *= sss_profile;
stack.cl[cl_subsurface_id].light_unshadowed *= sss_profile;
/* Fuse back the SSS transmittance with the diffuse lighting. */
stack.cl[cl_diffuse_id].light_shadowed += stack.cl[cl_subsurface_id].light_shadowed;
stack.cl[cl_diffuse_id].light_unshadowed += stack.cl[cl_subsurface_id].light_unshadowed;
#endif
vec3 diffuse_light = vec3(0.0);
vec3 translucent_light = vec3(0.0);
vec3 reflection_light = vec3(0.0);
vec3 refraction_light = vec3(0.0);
vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0));
LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V);
#ifdef MAT_DIFFUSE
diffuse_light = stack.cl[cl_diffuse_id].light_shadowed;
diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe);
#endif
#ifdef MAT_TRANSLUCENT
translucent_light = stack.cl[cl_translucent_id].light_shadowed;
translucent_light += lightprobe_eval(samp, g_translucent_data, g_data.P, V, noise_probe);
#endif
#ifdef MAT_REFLECTION
reflection_light = stack.cl[cl_reflection_id].light_shadowed;
reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe);
#endif
#ifdef MAT_REFRACTION
/* TODO(fclem): Refraction from lightprobe. */
// refraction_light += lightprobe_eval(samp, g_refraction_data, g_data.P, V, noise_probe);
#endif
/* Apply weight. */
g_diffuse_data.color *= g_diffuse_data.weight;
g_translucent_data.color *= g_translucent_data.weight;
g_reflection_data.color *= g_reflection_data.weight;
g_refraction_data.color *= g_refraction_data.weight;
/* Mask invalid lighting from undefined closure. */
diffuse_light = (g_diffuse_data.weight > 1e-5) ? diffuse_light : vec3(0.0);
translucent_light = (g_translucent_data.weight > 1e-5) ? translucent_light : vec3(0.0);
reflection_light = (g_reflection_data.weight > 1e-5) ? reflection_light : vec3(0.0);
refraction_light = (g_refraction_data.weight > 1e-5) ? refraction_light : vec3(0.0);
/* Combine all radiance. */
radiance = g_emission;
radiance += g_diffuse_data.color * diffuse_light;
radiance += g_reflection_data.color * reflection_light;
radiance += g_refraction_data.color * refraction_light;
radiance += g_translucent_data.color * translucent_light;
transmittance = g_transmittance;
}

View File

@@ -163,6 +163,13 @@ bool gbuffer_has_closure(uint header, eClosureBits closure)
return has_diffuse;
}
bool has_translucent = (gbuffer_header_unpack(header, layer) == GBUF_TRANSLUCENT);
layer += int(has_translucent);
if (closure == eClosureBits(CLOSURE_TRANSLUCENT)) {
return has_translucent;
}
bool has_sss = (gbuffer_header_unpack(header, layer) == GBUF_SSS);
layer += int(has_sss);
@@ -181,6 +188,7 @@ struct GBufferDataPacked {
};
GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse,
ClosureTranslucent translucent,
ClosureReflection reflection,
ClosureRefraction refraction,
vec3 default_N,
@@ -192,6 +200,7 @@ GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse,
bool has_refraction = refraction.weight > 1e-5;
bool has_reflection = reflection.weight > 1e-5;
bool has_diffuse = diffuse.weight > 1e-5;
bool has_translucent = translucent.weight > 1e-5;
bool has_sss = diffuse.sss_id > 0;
int layer = 0;
@@ -241,7 +250,16 @@ GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse,
layer += 1;
}
if (has_sss) {
if (has_translucent) {
gbuf.color[layer] = gbuffer_color_pack(translucent.color);
gbuf.closure[layer].xy = gbuffer_normal_pack(translucent.N);
gbuf.closure[layer].z = 0.0; /* Unused. */
gbuf.closure[layer].w = gbuffer_thickness_pack(thickness);
gbuf.header |= gbuffer_header_pack(GBUF_TRANSLUCENT, layer);
layer += 1;
}
/* TODO(fclem): For now, override SSS if we have translucency. */
else if (has_sss) {
gbuf.closure[layer].xyz = gbuffer_sss_radii_pack(diffuse.sss_radius);
gbuf.closure[layer].w = gbuffer_object_id_unorm16_pack(diffuse.sss_id);
gbuf.header |= gbuffer_header_pack(GBUF_SSS, layer);
@@ -264,12 +282,14 @@ GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse,
struct GBufferData {
/* Only valid (or null) if `has_diffuse`, `has_reflection` or `has_refraction` is true. */
ClosureDiffuse diffuse;
ClosureTranslucent translucent;
ClosureReflection reflection;
ClosureRefraction refraction;
/* First world normal stored in the gbuffer. Only valid if `has_any_surface` is true. */
vec3 surface_N;
float thickness;
bool has_diffuse;
bool has_translucent;
bool has_reflection;
bool has_refraction;
bool has_sss;
@@ -394,6 +414,24 @@ GBufferData gbuffer_read(usampler2D header_tx,
gbuf.thickness = 0.0;
}
gbuf.has_translucent = (gbuffer_header_unpack(gbuf.header, layer) == GBUF_TRANSLUCENT);
if (gbuf.has_translucent) {
vec4 closure_packed = texelFetch(closure_tx, ivec3(texel, layer), 0);
vec4 color_packed = texelFetch(color_tx, ivec3(texel, layer), 0);
gbuf.translucent.color = gbuffer_color_unpack(color_packed);
gbuf.translucent.N = gbuffer_normal_unpack(closure_packed.xy);
gbuf.thickness = gbuffer_thickness_unpack(closure_packed.w);
gbuf.closure_count += 1u;
layer += 1;
}
else {
/* Default values. */
gbuf.translucent.color = vec3(0.0);
gbuf.translucent.N = vec3(0.0, 0.0, 1.0);
}
gbuf.has_sss = (gbuffer_header_unpack(gbuf.header, layer) == GBUF_SSS);
if (gbuf.has_sss) {

View File

@@ -55,20 +55,7 @@ vec3 from_accumulation_space(vec3 color)
vec3 load_normal(ivec2 texel)
{
GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel);
/* TODO(fclem): Load preprocessed Normal. */
vec3 N = vec3(0.0);
if (gbuf.has_diffuse) {
N = gbuf.diffuse.N;
}
else if (gbuf.has_reflection) {
N = gbuf.reflection.N;
}
else if (gbuf.has_refraction) {
N = gbuf.refraction.N;
}
return N;
return gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel).surface_N;
}
void main()

View File

@@ -25,6 +25,7 @@
#if !defined(LIGHT_CLOSURE_EVAL_COUNT)
# define LIGHT_CLOSURE_EVAL_COUNT 1
# define SKIP_LIGHT_EVAL
#endif
uint shadow_pack(float visibility, uint bit_depth, uint shift)
@@ -192,7 +193,7 @@ void light_eval(inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V, float vP
light_eval(stack, P, Ng, V, vPz, thickness, 0u);
}
# if !defined(SSS_TRANSMITTANCE) && defined(LIGHT_ITER_FORCE_NO_CULLING)
# if !defined(SHADOW_SUBSURFACE) && defined(LIGHT_ITER_FORCE_NO_CULLING)
void light_eval(inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V)
{
light_eval(stack, P, Ng, V, 0.0, 0.0, 0u);

View File

@@ -233,35 +233,4 @@ float light_ltc(
}
}
#ifdef SSS_TRANSMITTANCE
float sample_transmittance_profile(float u)
{
return utility_tx_sample(utility_tx, vec2(u, 0.0), UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER).r;
}
vec3 light_translucent(const bool is_directional,
LightData light,
vec3 N,
LightVector lv,
vec3 sss_radius,
float delta)
{
/* TODO(fclem): We should compute the power at the entry point. */
/* NOTE(fclem): we compute the light attenuation using the light vector but the transmittance
* using the shadow depth delta. */
float power = light_point_light(light, is_directional, lv);
/* Do not add more energy on front faces. Also apply lambertian BSDF. */
power *= max(0.0, dot(-N, lv.L)) * M_1_PI;
sss_radius *= SSS_TRANSMIT_LUT_RADIUS;
vec3 channels_co = saturate(delta / sss_radius) * SSS_TRANSMIT_LUT_SCALE + SSS_TRANSMIT_LUT_BIAS;
vec3 translucency;
translucency.x = (sss_radius.x > 0.0) ? sample_transmittance_profile(channels_co.x) : 0.0;
translucency.y = (sss_radius.y > 0.0) ? sample_transmittance_profile(channels_co.y) : 0.0;
translucency.z = (sss_radius.z > 0.0) ? sample_transmittance_profile(channels_co.z) : 0.0;
return translucency * power;
}
#endif
/** \} */

View File

@@ -282,9 +282,15 @@ float lightprobe_roughness_to_lod(float roughness)
return sqrt(roughness) * 11.0;
}
vec3 lightprobe_eval(LightProbeSample samp, ClosureDiffuse diffuse, vec3 P, vec3 V, vec2 noise)
vec3 lightprobe_eval(LightProbeSample samp, ClosureDiffuse cl, vec3 P, vec3 V, vec2 noise)
{
vec3 radiance_sh = spherical_harmonics_evaluate_lambert(diffuse.N, samp.volume_irradiance);
vec3 radiance_sh = spherical_harmonics_evaluate_lambert(cl.N, samp.volume_irradiance);
return radiance_sh;
}
vec3 lightprobe_eval(LightProbeSample samp, ClosureTranslucent cl, vec3 P, vec3 V, vec2 noise)
{
vec3 radiance_sh = spherical_harmonics_evaluate_lambert(-cl.N, samp.volume_irradiance);
return radiance_sh;
}

View File

@@ -18,12 +18,14 @@ float g_holdout;
/* Sampled closure parameters. */
ClosureDiffuse g_diffuse_data;
ClosureTranslucent g_translucent_data;
ClosureReflection g_reflection_data;
ClosureRefraction g_refraction_data;
ClosureVolumeScatter g_volume_scatter_data;
ClosureVolumeAbsorption g_volume_absorption_data;
/* Random number per sampled closure type. */
float g_diffuse_rand;
float g_translucent_rand;
float g_reflection_rand;
float g_refraction_rand;
float g_volume_scatter_rand;
@@ -63,6 +65,10 @@ void closure_weights_reset()
g_diffuse_data.sss_radius = vec3(0.0);
g_diffuse_data.sss_id = uint(0);
g_translucent_data.weight = 0.0;
g_translucent_data.color = vec3(0.0);
g_translucent_data.N = vec3(0.0);
g_reflection_data.weight = 0.0;
g_reflection_data.color = vec3(0.0);
g_reflection_data.N = vec3(0.0);
@@ -82,10 +88,11 @@ void closure_weights_reset()
g_volume_absorption_data.absorption = vec3(0.0);
#if defined(GPU_FRAGMENT_SHADER)
g_diffuse_rand = g_reflection_rand = g_refraction_rand = g_closure_rand;
g_diffuse_rand = g_translucent_rand = g_reflection_rand = g_refraction_rand = g_closure_rand;
g_volume_scatter_rand = g_volume_absorption_rand = g_closure_rand;
#else
g_diffuse_rand = 0.0;
g_translucent_rand = 0.0;
g_reflection_rand = 0.0;
g_refraction_rand = 0.0;
g_volume_scatter_rand = 0.0;
@@ -106,7 +113,7 @@ Closure closure_eval(ClosureDiffuse diffuse)
Closure closure_eval(ClosureTranslucent translucent)
{
/* TODO */
SELECT_CLOSURE(g_translucent_data, g_translucent_rand, translucent);
return Closure(0);
}

View File

@@ -310,12 +310,10 @@ ShadowRayPunctual shadow_ray_generate_punctual(LightData light,
direction = point_on_light_shape - lP;
r_is_above_surface = dot(direction, lNg) > 0.0;
#ifdef SSS_TRANSMITTANCE
#ifdef SHADOW_SUBSURFACE
if (!r_is_above_surface) {
float dir_len;
vec3 L = normalize_and_get_length(direction, dir_len);
/* Skip the object volume. Do not push behind the light. */
float offset_len = saturate(thickness / dir_len);
float offset_len = saturate(thickness / length(direction));
lP += direction * offset_len;
direction *= 1.0 - offset_len;
}
@@ -341,12 +339,10 @@ ShadowRayPunctual shadow_ray_generate_punctual(LightData light,
direction = point_on_light_shape - lP;
r_is_above_surface = dot(direction, lNg) > 0.0;
#ifdef SSS_TRANSMITTANCE
#ifdef SHADOW_SUBSURFACE
if (!r_is_above_surface) {
float dir_len;
vec3 L = normalize_and_get_length(direction, dir_len);
/* Skip the object volume. Do not push behind the light. */
float offset_len = saturate(thickness / dir_len);
float offset_len = saturate(thickness / length(direction));
lP += direction * offset_len;
direction *= 1.0 - offset_len;
}
@@ -477,7 +473,7 @@ ShadowEvalResult shadow_eval(LightData light,
ShadowEvalResult result;
result.light_visibilty = saturate(1.0 - surface_hit * safe_rcp(surface_ray_count));
result.light_visibilty = min(result.light_visibilty,
saturate(1.0 - subsurface_hit * safe_rcp(surface_ray_count)));
saturate(1.0 - subsurface_hit * safe_rcp(subsurface_ray_count)));
result.occluder_distance = 0.0; /* Unused. Could reintroduced if needed. */
return result;
}

View File

@@ -25,7 +25,7 @@ void main(void)
GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel);
if (gbuf.has_diffuse && gbuf.diffuse.sss_id != 0u) {
if (gbuf.has_sss) {
vec3 radiance = imageLoad(direct_light_img, texel).rgb +
imageLoad(indirect_light_img, texel).rgb;

View File

@@ -82,8 +82,12 @@ void main()
/* ----- GBuffer output ----- */
GBufferDataPacked gbuf = gbuffer_pack(
g_diffuse_data, g_reflection_data, g_refraction_data, out_normal, thickness);
GBufferDataPacked gbuf = gbuffer_pack(g_diffuse_data,
g_translucent_data,
g_reflection_data,
g_refraction_data,
out_normal,
thickness);
/* Output header and first closure using frame-buffer attachment. */
out_gbuf_header = gbuf.header;

View File

@@ -9,63 +9,26 @@
*/
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_ambient_occlusion_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_volume_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_forward_lib.glsl)
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
vec4 closure_to_rgba(Closure cl)
/* Global thickness because it is needed for closure_to_rgba. */
float g_thickness;
vec4 closure_to_rgba(Closure cl_unused)
{
vec3 diffuse_light = vec3(0.0);
vec3 reflection_light = vec3(0.0);
vec3 refraction_light = vec3(0.0);
float shadow = 1.0;
float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position());
vec3 V = drw_world_incident_vector(g_data.P);
ClosureLightStack stack;
ClosureLight cl_diff;
cl_diff.N = g_diffuse_data.N;
cl_diff.ltc_mat = LTC_LAMBERT_MAT;
cl_diff.type = LIGHT_DIFFUSE;
stack.cl[0] = cl_diff;
ClosureLight cl_refl;
cl_refl.N = g_reflection_data.N;
cl_refl.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness);
cl_refl.type = LIGHT_SPECULAR;
stack.cl[1] = cl_refl;
float thickness = 0.01; /* TODO(fclem) thickness. */
light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness);
vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0));
LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V);
diffuse_light += stack.cl[0].light_shadowed;
diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe);
reflection_light += stack.cl[1].light_shadowed;
reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe);
vec4 out_color;
out_color.rgb = g_emission;
out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight * diffuse_light;
out_color.rgb += g_reflection_data.color * g_reflection_data.weight * reflection_light;
out_color.a = saturate(1.0 - average(g_transmittance));
vec3 radiance, transmittance;
forward_lighting_eval(g_thickness, radiance, transmittance);
/* Reset for the next closure tree. */
closure_weights_reset();
return out_color;
return vec4(radiance, saturate(1.0 - average(transmittance)));
}
void main()
@@ -80,124 +43,25 @@ void main()
fragment_displacement();
g_thickness = max(0.0, nodetree_thickness());
nodetree_surface();
g_holdout = saturate(g_holdout);
vec3 radiance, transmittance;
forward_lighting_eval(g_thickness, radiance, transmittance);
float thickness = nodetree_thickness();
float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position());
vec3 V = drw_world_incident_vector(g_data.P);
ClosureLightStack stack;
ClosureLight cl_diff;
cl_diff.N = g_diffuse_data.N;
cl_diff.ltc_mat = LTC_LAMBERT_MAT;
cl_diff.type = LIGHT_DIFFUSE;
stack.cl[0] = cl_diff;
ClosureLight cl_refl;
cl_refl.N = g_reflection_data.N;
cl_refl.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness);
cl_refl.type = LIGHT_SPECULAR;
stack.cl[1] = cl_refl;
#ifdef SSS_TRANSMITTANCE
ClosureLight cl_sss;
cl_sss.N = -g_diffuse_data.N;
cl_sss.ltc_mat = LTC_LAMBERT_MAT;
cl_sss.type = LIGHT_DIFFUSE;
stack.cl[2] = cl_sss;
#endif
light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness);
vec3 diffuse_light = stack.cl[0].light_shadowed;
vec3 reflection_light = stack.cl[1].light_shadowed;
vec3 refraction_light = vec3(0.0);
#ifdef SSS_TRANSMITTANCE
diffuse_light += stack.cl[2].light_shadowed;
#endif
vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0));
LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V);
diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe);
reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe);
g_diffuse_data.color *= g_diffuse_data.weight;
g_reflection_data.color *= g_reflection_data.weight;
g_refraction_data.color *= g_refraction_data.weight;
diffuse_light *= step(1e-5, g_diffuse_data.weight);
reflection_light *= step(1e-5, g_reflection_data.weight);
refraction_light *= step(1e-5, g_refraction_data.weight);
out_radiance.rgb = g_emission;
out_radiance.rgb += g_diffuse_data.color * diffuse_light;
out_radiance.rgb += g_reflection_data.color * reflection_light;
out_radiance.rgb += g_refraction_data.color * refraction_light;
out_radiance.a = 0.0;
vec3 specular_light = reflection_light + refraction_light;
vec3 specular_color = g_reflection_data.color + g_refraction_data.color;
/* TODO(fclem): This feels way too complex for what is it. */
bool has_any_bsdf_weight = g_diffuse_data.weight != 0.0 || g_reflection_data.weight != 0.0 ||
g_refraction_data.weight != 0.0;
vec3 out_normal = has_any_bsdf_weight ? vec3(0.0) : g_data.N;
out_normal += g_diffuse_data.N * g_diffuse_data.weight;
out_normal += g_reflection_data.N * g_reflection_data.weight;
out_normal += g_refraction_data.N * g_refraction_data.weight;
out_normal = safe_normalize(out_normal);
#ifdef MAT_RENDER_PASS_SUPPORT
ivec2 out_texel = ivec2(gl_FragCoord.xy);
if (imageSize(rp_cryptomatte_img).x > 1) {
vec4 cryptomatte_output = vec4(
cryptomatte_object_buf[resource_id], node_tree.crypto_hash, 0.0);
imageStore(rp_cryptomatte_img, out_texel, cryptomatte_output);
}
vec3 radiance_shadowed = stack.cl[0].light_shadowed;
vec3 radiance_unshadowed = stack.cl[0].light_unshadowed;
radiance_shadowed += stack.cl[1].light_shadowed;
radiance_unshadowed += stack.cl[1].light_unshadowed;
# ifdef SSS_TRANSMITTANCE
radiance_shadowed += stack.cl[2].light_shadowed;
radiance_unshadowed += stack.cl[2].light_unshadowed;
# endif
vec3 shadows = radiance_shadowed / safe_rcp(radiance_unshadowed);
output_renderpass_color(uniform_buf.render_pass.normal_id, vec4(out_normal, 1.0));
output_renderpass_color(uniform_buf.render_pass.position_id, vec4(g_data.P, 1.0));
output_renderpass_color(uniform_buf.render_pass.diffuse_color_id,
vec4(g_diffuse_data.color, 1.0));
output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(diffuse_light, 1.0));
output_renderpass_color(uniform_buf.render_pass.specular_color_id, vec4(specular_color, 1.0));
output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(specular_light, 1.0));
output_renderpass_color(uniform_buf.render_pass.emission_id, vec4(g_emission, 1.0));
output_renderpass_value(uniform_buf.render_pass.shadow_id, average(shadows));
/** NOTE: AO is done on its own pass. */
#endif
#ifdef MAT_TRANSPARENT
/* Volumetric resolve and compositing. */
vec2 uvs = gl_FragCoord.xy * uniform_buf.volumes.viewport_size_inv;
VolumeResolveSample vol = volume_resolve(
vec3(uvs, gl_FragCoord.z), volume_transmittance_tx, volume_scattering_tx);
/* Removes the part of the volume scattering that has
* already been added to the destination pixels by the opaque resolve.
* Since we do that using the blending pipeline we need to account for material transmittance. */
vol.scattering -= vol.scattering * g_transmittance;
radiance = radiance * vol.transmittance + vol.scattering;
out_radiance.rgb = out_radiance.rgb * vol.transmittance + vol.scattering;
#endif
radiance *= 1.0 - saturate(g_holdout);
out_radiance.rgb *= 1.0 - g_holdout;
out_transmittance.rgb = g_transmittance;
out_transmittance.a = saturate(average(g_transmittance));
out_radiance = vec4(radiance, 0.0);
out_transmittance = vec4(transmittance, saturate(average(transmittance)));
}

View File

@@ -14,58 +14,22 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_ambient_occlusion_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_forward_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
vec4 closure_to_rgba(Closure cl)
/* Global thickness because it is needed for closure_to_rgba. */
float g_thickness;
vec4 closure_to_rgba(Closure cl_unused)
{
vec3 diffuse_light = vec3(0.0);
vec3 reflection_light = vec3(0.0);
vec3 refraction_light = vec3(0.0);
float shadow = 1.0;
float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position());
vec3 V = drw_world_incident_vector(g_data.P);
ClosureLightStack stack;
ClosureLight cl_diff;
cl_diff.N = g_diffuse_data.N;
cl_diff.ltc_mat = LTC_LAMBERT_MAT;
cl_diff.type = LIGHT_DIFFUSE;
stack.cl[0] = cl_diff;
ClosureLight cl_refl;
cl_refl.N = g_reflection_data.N;
cl_refl.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness);
cl_refl.type = LIGHT_SPECULAR;
stack.cl[1] = cl_refl;
float thickness = 0.01; /* TODO(fclem) thickness. */
light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness);
vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0));
LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V);
diffuse_light += stack.cl[0].light_shadowed;
diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe);
reflection_light += stack.cl[1].light_shadowed;
reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe);
vec4 out_color;
out_color.rgb = g_emission;
out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight * diffuse_light;
out_color.rgb += g_reflection_data.color * g_reflection_data.weight * reflection_light;
out_color.a = saturate(1.0 - average(g_transmittance));
vec3 radiance, transmittance;
forward_lighting_eval(g_thickness, radiance, transmittance);
/* Reset for the next closure tree. */
closure_weights_reset();
return out_color;
return vec4(radiance, saturate(1.0 - average(transmittance)));
}
void main()
@@ -84,7 +48,7 @@ void main()
g_holdout = saturate(g_holdout);
float thickness = nodetree_thickness();
g_thickness = max(0.0, nodetree_thickness());
g_diffuse_data.color *= g_diffuse_data.weight;
g_reflection_data.color *= g_reflection_data.weight;
@@ -121,8 +85,12 @@ void main()
/* ----- GBuffer output ----- */
GBufferDataPacked gbuf = gbuffer_pack(
g_diffuse_data, g_reflection_data, g_refraction_data, out_normal, thickness);
GBufferDataPacked gbuf = gbuffer_pack(g_diffuse_data,
g_translucent_data,
g_reflection_data,
g_refraction_data,
out_normal,
g_thickness);
/* Output header and first closure using frame-buffer attachment. */
out_gbuf_header = gbuf.header;

View File

@@ -85,7 +85,8 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light_double)
GPU_SHADER_CREATE_INFO(eevee_deferred_light_triple)
.additional_info("eevee_deferred_light")
.define("SSS_TRANSMITTANCE")
.define("SHADOW_SUBSURFACE")
.define("MAT_SUBSURFACE")
.define("LIGHT_CLOSURE_EVAL_COUNT", "3")
.do_static_compilation(true);
@@ -112,7 +113,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_capture_eval)
.early_fragment_test(true)
/* Inputs. */
.fragment_out(0, Type::VEC4, "out_radiance")
.define("SSS_TRANSMITTANCE")
.define("SHADOW_SUBSURFACE")
.additional_info("eevee_shared",
"eevee_gbuffer_data",
"eevee_utility_texture",
@@ -132,7 +133,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_planar_eval)
/* Inputs. */
.fragment_out(0, Type::VEC4, "out_radiance")
.define("REFLECTION_PROBE")
.define("SSS_TRANSMITTANCE")
.define("SHADOW_SUBSURFACE")
.define("LIGHT_CLOSURE_EVAL_COUNT", "2")
.additional_info("eevee_shared",
"eevee_gbuffer_data",

View File

@@ -175,7 +175,6 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
GPU_SHADER_CREATE_INFO(eevee_surf_deferred_hybrid)
.fragment_source("eevee_surf_hybrid_frag.glsl")
.define("LIGHT_CLOSURE_EVAL_COUNT", "2")
.additional_info("eevee_surf_deferred_base",
"eevee_light_data",
"eevee_lightprobe_data",
@@ -189,7 +188,6 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward)
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
.fragment_source("eevee_surf_forward_frag.glsl")
.define("LIGHT_CLOSURE_EVAL_COUNT", "3")
.additional_info("eevee_global_ubo",
"eevee_light_data",
"eevee_lightprobe_data",

View File

@@ -79,12 +79,13 @@ typedef enum eGPUMaterialFlag {
GPU_MATFLAG_SHADER_TO_RGBA = (1 << 7),
GPU_MATFLAG_AO = (1 << 8),
GPU_MATFLAG_COAT = (1 << 9),
GPU_MATFLAG_TRANSLUCENT = (1 << 10),
GPU_MATFLAG_VOLUME_SCATTER = (1 << 10),
GPU_MATFLAG_VOLUME_ABSORPTION = (1 << 11),
GPU_MATFLAG_VOLUME_SCATTER = (1 << 16),
GPU_MATFLAG_VOLUME_ABSORPTION = (1 << 17),
GPU_MATFLAG_OBJECT_INFO = (1 << 12),
GPU_MATFLAG_AOV = (1 << 13),
GPU_MATFLAG_OBJECT_INFO = (1 << 18),
GPU_MATFLAG_AOV = (1 << 19),
GPU_MATFLAG_BARYCENTRIC = (1 << 20),

View File

@@ -10,7 +10,7 @@ void node_bsdf_translucent(vec4 color, vec3 N, float weight, out Closure result)
ClosureTranslucent translucent_data;
translucent_data.weight = weight;
translucent_data.color = color.rgb;
translucent_data.N = -N;
translucent_data.N = N;
result = closure_eval(translucent_data);
}

View File

@@ -24,7 +24,7 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[1].link);
}
GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
GPU_material_flag_set(mat, GPU_MATFLAG_TRANSLUCENT);
return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
}