Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-04-14 19:47:58 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-04-14 19:47:58 +0300
commit80859a6cb2726a39fb22cb49f06e0355dc9390a7 (patch)
treefd3f8ead5a247a79ea11e4aacc720843bbc5e2c2 /source
parent66dc4d4efb88ecf2d18bfa08ab9c43b024ebd2fb (diff)
GPU: Make nodetree GLSL Codegen render engine agnostic
This commit removes all EEVEE specific code from the `gpu_shader_material*.glsl` files. It defines a clear interface to evaluate the closure nodes leaving more flexibility to the render engine. Some of the long standing workaround are fixed: - bump mapping support is no longer duplicating a lot of node and is instead compiled into a function call. - bump rewiring to Normal socket is no longer needed as we now use a global `g_data.N` for that. Closure sampling with upstread weight eval is now supported if the engine needs it. This also makes all the material GLSL sources use `GPUSource` for better debugging experience. The `GPUFunction` parsing now happens in `GPUSource` creation. The whole `GPUCodegen` now uses the `ShaderCreateInfo` and is object type agnostic. Is has also been rewritten in C++. This patch changes a view behavior for EEVEE: - Mix shader node factor imput is now clamped. - Tangent Vector displacement behavior is now matching cycles. - The chosen BSDF used for SSR might change. - Hair shading may have very small changes on very large hairs when using hair polygon stripes. - ShaderToRGB node will remove any SSR and SSS form a shader. - SSS radius input now is no longer a scaling factor but defines an average radius. The SSS kernel "shape" (radii) are still defined by the socket default values. Appart from the listed changes no other regressions are expected.
Diffstat (limited to 'source')
-rw-r--r--source/blender/draw/CMakeLists.txt9
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c16
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h20
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c84
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders_extra.cc173
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c1
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl35
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl15
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl325
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl113
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl252
-rw-r--r--source/blender/draw/engines/eevee/shaders/eevee_empty.glsl7
-rw-r--r--source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl35
-rw-r--r--source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl21
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl92
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_frag.glsl141
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl166
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl108
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl111
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl28
-rw-r--r--source/blender/draw/engines/eevee/shaders/world_vert.glsl24
-rw-r--r--source/blender/draw/intern/DRW_render.h54
-rw-r--r--source/blender/draw/intern/draw_hair.c2
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c190
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h21
-rw-r--r--source/blender/draw/intern/shaders/common_attribute_lib.glsl21
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl54
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/gpu/GPU_material.h126
-rw-r--r--source/blender/gpu/GPU_uniform_buffer.h4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c1123
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc825
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h28
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c2
-rw-r--r--source/blender/gpu/intern/gpu_material.c339
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c904
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h27
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c117
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h54
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc5
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc5
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh9
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc325
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl173
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl18
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl26
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_background.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl38
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl31
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl101
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl7
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl53
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl64
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl39
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl46
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl26
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl69
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl14
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl12
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl36
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl18
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl248
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl37
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl30
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl16
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl3
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl84
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl20
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl17
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl32
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl19
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl24
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl22
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl23
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl24
-rw-r--r--source/blender/makesdna/DNA_node_types.h15
-rw-r--r--source/blender/nodes/NOD_shader.h5
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc735
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc15
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_background.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bevel.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc61
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.cc17
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.cc9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_emission.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.cc20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_holdout.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.cc9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.cc11
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_aov.cc14
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.cc44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.cc18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.cc13
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.cc9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.cc12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc29
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_transform.cc39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wireframe.cc14
165 files changed, 4622 insertions, 4335 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index aed527639c5..6d3c203b076 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -16,6 +16,7 @@ set(INC
../editors/space_view3d
../functions
../gpu
+ ../gpu/intern
../imbuf
../makesdna
../makesrna
@@ -123,6 +124,7 @@ set(SRC
engines/eevee/eevee_sampling.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_shaders.c
+ engines/eevee/eevee_shaders_extra.cc
engines/eevee/eevee_shadows.c
engines/eevee/eevee_shadows_cascade.c
engines/eevee/eevee_shadows_cube.c
@@ -266,9 +268,13 @@ set(GLSL_SRC
engines/eevee/shaders/closure_eval_lib.glsl
engines/eevee/shaders/closure_eval_diffuse_lib.glsl
engines/eevee/shaders/closure_eval_glossy_lib.glsl
+ engines/eevee/shaders/closure_eval_surface_lib.glsl
engines/eevee/shaders/closure_eval_refraction_lib.glsl
+ engines/eevee/shaders/closure_eval_volume_lib.glsl
engines/eevee/shaders/closure_eval_translucent_lib.glsl
engines/eevee/shaders/closure_type_lib.glsl
+ engines/eevee/shaders/eevee_empty.glsl
+ engines/eevee/shaders/eevee_empty_volume.glsl
engines/eevee/shaders/effect_bloom_frag.glsl
engines/eevee/shaders/effect_dof_bokeh_frag.glsl
engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl
@@ -302,7 +308,6 @@ set(GLSL_SRC
engines/eevee/shaders/object_motion_frag.glsl
engines/eevee/shaders/object_motion_vert.glsl
engines/eevee/shaders/prepass_frag.glsl
- engines/eevee/shaders/prepass_vert.glsl
engines/eevee/shaders/shadow_accum_frag.glsl
engines/eevee/shaders/shadow_frag.glsl
engines/eevee/shaders/shadow_vert.glsl
@@ -333,6 +338,7 @@ set(GLSL_SRC
engines/eevee/shaders/volumetric_resolve_frag.glsl
engines/eevee/shaders/volumetric_scatter_frag.glsl
engines/eevee/shaders/volumetric_integration_frag.glsl
+ engines/eevee/shaders/world_vert.glsl
engines/workbench/shaders/workbench_cavity_lib.glsl
engines/workbench/shaders/workbench_common_lib.glsl
@@ -364,6 +370,7 @@ set(GLSL_SRC
engines/workbench/workbench_shader_shared.h
+ intern/shaders/common_attribute_lib.glsl
intern/shaders/common_colormanagement_lib.glsl
intern/shaders/common_globals_lib.glsl
intern/shaders/common_gpencil_lib.glsl
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index c3f9a606dd0..c46e5dd75d6 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -73,7 +73,12 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE);
bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY);
bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT);
+ bool use_ao = GPU_material_flag_get(gpumat, GPU_MATFLAG_AO);
+#ifdef __APPLE__
+ /* NOTE: Some implementation do not optimize out the unused samplers. */
+ use_diffuse = use_glossy = use_refract = use_ao = true;
+#endif
LightCache *lcache = vedata->stl->g_data->light_cache;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
EEVEE_PrivateData *pd = vedata->stl->g_data;
@@ -91,6 +96,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
if (use_diffuse || use_glossy || use_refract) {
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
+ }
+ if (use_diffuse || use_glossy || use_refract || use_ao) {
DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer);
}
if ((use_diffuse || use_glossy) && !use_ssrefraction) {
@@ -374,6 +381,13 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &stl->g_data->renderpass_ubo);
+ DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &stl->g_data->light_cache->cube_tx.tex);
+ DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &stl->g_data->light_cache->grid_tx.tex);
+ DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &vedata->txl->maxzbuffer);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
@@ -578,7 +592,7 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT);
SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
- const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SSS);
+ const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE);
int ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? 1 : 0;
int option = (use_ssrefract ? 0 : (use_sss ? 1 : 2)) * 2 + do_cull;
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 722c03d7536..effae313acf 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -462,7 +462,7 @@ typedef struct EEVEE_RenderPassData {
int renderPassSSSColor;
int renderPassEnvironment;
int renderPassAOV;
- int renderPassAOVActive;
+ uint renderPassAOVActive;
int _pad[3];
} EEVEE_RenderPassData;
@@ -1050,7 +1050,7 @@ typedef struct EEVEE_PrivateData {
/* Renderpasses */
/* Bitmask containing the active render_passes */
eViewLayerEEVEEPassType render_passes;
- int aov_hash;
+ uint aov_hash;
int num_aovs_used;
struct CryptomatteSession *cryptomatte_session;
bool cryptomatte_accurate_mode;
@@ -1291,6 +1291,20 @@ struct GPUMaterial *EEVEE_material_get(
EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options);
void EEVEE_shaders_free(void);
+void eevee_shader_extra_init(void);
+void eevee_shader_extra_exit(void);
+void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
+ GPUCodegenOutput *codegen,
+ char *frag,
+ char *vert,
+ char *geom,
+ char *defines);
+GPUShader *eevee_shaders_sh_create_helper(const char *name,
+ const char *vert_name,
+ const char *frag_name,
+ const char *defines,
+ bool use_layered_rendering);
+
/* eevee_lightprobes.c */
bool EEVEE_lightprobes_obj_visibility_cb(bool vis_in, void *user_data);
@@ -1508,7 +1522,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata);
* Calculate the hash for an AOV. The least significant bit is used to store the AOV
* type the rest of the bits are used for the name hash.
*/
-int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
+uint EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
/* eevee_temporal_sampling.c */
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index 3814cf44fd6..237c830d547 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -60,9 +60,9 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata)
return (g_data->render_passes & ~EEVEE_RENDERPASSES_POST_PROCESS_ON_FIRST_SAMPLE) == 0;
}
-int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
+uint EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov)
{
- int hash = BLI_hash_string(aov->name) << 1;
+ uint hash = BLI_hash_string(aov->name) << 1u;
SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK);
return hash;
}
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index ae5e6e94f74..4e4a2a9eb8e 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -170,6 +170,7 @@ extern char datatoc_common_math_lib_glsl[];
extern char datatoc_common_math_geom_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_gpu_shader_codegen_lib_glsl[];
extern char datatoc_ambient_occlusion_lib_glsl[];
extern char datatoc_background_vert_glsl[];
@@ -178,6 +179,7 @@ extern char datatoc_bsdf_lut_frag_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_btdf_lut_frag_glsl[];
extern char datatoc_closure_type_lib_glsl[];
+extern char datatoc_closure_eval_volume_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_utiltex_lib_glsl[];
extern char datatoc_cryptomatte_frag_glsl[];
@@ -230,6 +232,7 @@ extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_lights_lib_glsl[];
extern char datatoc_closure_eval_lib_glsl[];
+extern char datatoc_closure_eval_surface_lib_glsl[];
extern char datatoc_closure_eval_diffuse_lib_glsl[];
extern char datatoc_closure_eval_glossy_lib_glsl[];
extern char datatoc_closure_eval_refraction_lib_glsl[];
@@ -239,7 +242,6 @@ extern char datatoc_object_motion_frag_glsl[];
extern char datatoc_object_motion_vert_glsl[];
extern char datatoc_octahedron_lib_glsl[];
extern char datatoc_prepass_frag_glsl[];
-extern char datatoc_prepass_vert_glsl[];
extern char datatoc_random_lib_glsl[];
extern char datatoc_raytrace_lib_glsl[];
extern char datatoc_renderpass_lib_glsl[];
@@ -261,6 +263,7 @@ extern char datatoc_volumetric_lib_glsl[];
extern char datatoc_volumetric_resolve_frag_glsl[];
extern char datatoc_volumetric_scatter_frag_glsl[];
extern char datatoc_volumetric_vert_glsl[];
+extern char datatoc_world_vert_glsl[];
/* *********** FUNCTIONS *********** */
@@ -275,6 +278,7 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
DRW_SHADER_LIB_ADD(e_data.lib, common_uniforms_lib);
DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_codegen_lib);
DRW_SHADER_LIB_ADD(e_data.lib, random_lib);
DRW_SHADER_LIB_ADD(e_data.lib, renderpass_lib);
DRW_SHADER_LIB_ADD(e_data.lib, bsdf_common_lib);
@@ -299,6 +303,8 @@ static void eevee_shader_library_ensure(void)
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib);
DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_surface_lib);
+ DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_volume_lib);
e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib,
datatoc_surface_frag_glsl);
@@ -313,6 +319,7 @@ static void eevee_shader_library_ensure(void)
void EEVEE_shaders_material_shaders_init(void)
{
+ eevee_shader_extra_init();
eevee_shader_library_ensure();
}
@@ -828,6 +835,7 @@ struct GPUShader *EEVEE_shaders_volumes_clear_sh_get()
datatoc_volumetric_frag_glsl,
e_data.lib,
SHADER_DEFINES
+ "#define STANDALONE\n"
"#define VOLUMETRICS\n"
"#define CLEAR\n");
}
@@ -842,6 +850,7 @@ struct GPUShader *EEVEE_shaders_volumes_scatter_sh_get()
datatoc_volumetric_scatter_frag_glsl,
e_data.lib,
SHADER_DEFINES
+ "#define STANDALONE\n"
"#define VOLUMETRICS\n"
"#define VOLUME_SHADOW\n");
}
@@ -857,6 +866,7 @@ struct GPUShader *EEVEE_shaders_volumes_scatter_with_lights_sh_get()
datatoc_volumetric_scatter_frag_glsl,
e_data.lib,
SHADER_DEFINES
+ "#define STANDALONE\n"
"#define VOLUMETRICS\n"
"#define VOLUME_LIGHTING\n"
"#define VOLUME_SHADOW\n");
@@ -872,7 +882,9 @@ struct GPUShader *EEVEE_shaders_volumes_integration_sh_get()
datatoc_volumetric_geom_glsl,
datatoc_volumetric_integration_frag_glsl,
e_data.lib,
- USE_VOLUME_OPTI ? "#define USE_VOLUME_OPTI\n" SHADER_DEFINES : SHADER_DEFINES);
+ USE_VOLUME_OPTI ? "#define USE_VOLUME_OPTI\n"
+ "#define STANDALONE\n" SHADER_DEFINES :
+ "#define STANDALONE\n" SHADER_DEFINES);
}
return e_data.volumetric_integration_sh;
}
@@ -1232,7 +1244,7 @@ Material *EEVEE_material_default_glossy_get(void)
Material *EEVEE_material_default_error_get(void)
{
if (!e_data.error_mat) {
- Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal");
+ Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default error");
bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
ma->nodetree = ntree;
@@ -1375,7 +1387,7 @@ static char *eevee_get_vert(int options)
str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_volumetric_vert_glsl);
}
else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) {
- str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_background_vert_glsl);
+ str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_world_vert_glsl);
}
else {
str = DRW_shader_library_create_shader_string(e_data.lib, datatoc_surface_vert_glsl);
@@ -1412,68 +1424,43 @@ static char *eevee_get_frag(int options)
return str;
}
-static void eevee_material_post_eval(GPUMaterial *mat,
- int options,
- const char **UNUSED(vert_code),
- const char **geom_code,
- const char **UNUSED(frag_lib),
- const char **UNUSED(defines))
+static void eevee_material_post_eval(void *UNUSED(thunk),
+ GPUMaterial *mat,
+ GPUCodegenOutput *codegen)
{
- const bool is_hair = (options & VAR_MAT_HAIR) != 0;
- const bool is_mesh = (options & VAR_MAT_MESH) != 0;
+ uint64_t options = GPU_material_uuid_get(mat);
- /* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used.
- * NOTE: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */
- if (!is_hair && is_mesh && GPU_material_flag_get(mat, GPU_MATFLAG_BARYCENTRIC) &&
- *geom_code == NULL) {
- *geom_code = e_data.surface_geom_barycentric;
- }
+ char *vert = eevee_get_vert(options);
+ char *geom = eevee_get_geom(options);
+ char *frag = eevee_get_frag(options);
+ char *defines = eevee_get_defines(options);
+
+ eevee_shader_material_create_info_amend(mat, codegen, frag, vert, geom, defines);
+
+ MEM_SAFE_FREE(defines);
+ MEM_SAFE_FREE(vert);
+ MEM_SAFE_FREE(geom);
+ MEM_SAFE_FREE(frag);
}
static struct GPUMaterial *eevee_material_get_ex(
- struct Scene *scene, Material *ma, World *wo, int options, bool deferred)
+ struct Scene *UNUSED(scene), Material *ma, World *wo, int options, bool deferred)
{
BLI_assert(ma || wo);
const bool is_volume = (options & VAR_MAT_VOLUME) != 0;
const bool is_default = (options & VAR_DEFAULT) != 0;
- const void *engine = &DRW_engine_viewport_eevee_type;
GPUMaterial *mat = NULL;
+ GPUCodegenCallbackFn cbfn = &eevee_material_post_eval;
if (ma) {
- mat = DRW_shader_find_from_material(ma, engine, options, deferred);
- }
- else {
- mat = DRW_shader_find_from_world(wo, engine, options, deferred);
- }
-
- if (mat) {
- return mat;
- }
-
- char *defines = eevee_get_defines(options);
- char *vert = eevee_get_vert(options);
- char *geom = eevee_get_geom(options);
- char *frag = eevee_get_frag(options);
-
- if (ma) {
- GPUMaterialEvalCallbackFn cbfn = &eevee_material_post_eval;
-
bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma);
- mat = DRW_shader_create_from_material(
- scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred, cbfn);
+ mat = DRW_shader_from_material(ma, ntree, options, is_volume, deferred, cbfn, NULL);
}
else {
bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo);
- mat = DRW_shader_create_from_world(
- scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred, NULL);
+ mat = DRW_shader_from_world(wo, ntree, options, is_volume, deferred, cbfn, NULL);
}
-
- MEM_SAFE_FREE(defines);
- MEM_SAFE_FREE(vert);
- MEM_SAFE_FREE(geom);
- MEM_SAFE_FREE(frag);
-
return mat;
}
@@ -1520,6 +1507,7 @@ struct GPUMaterial *EEVEE_material_get(
void EEVEE_shaders_free(void)
{
+ eevee_shader_extra_exit();
MEM_SAFE_FREE(e_data.surface_prepass_frag);
MEM_SAFE_FREE(e_data.surface_lit_frag);
MEM_SAFE_FREE(e_data.surface_geom_barycentric);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders_extra.cc b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
new file mode 100644
index 00000000000..1d3e07217b5
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_shaders_extra.cc
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. */
+
+/** \file
+ * \ingroup EEVEE
+ *
+ * This file is only there to handle ShaderCreateInfos.
+ */
+
+#include "GPU_shader.h"
+
+#include "BLI_string_ref.hh"
+
+#include "gpu_shader_create_info.hh"
+
+#include "eevee_private.h"
+
+using blender::gpu::shader::StageInterfaceInfo;
+
+static StageInterfaceInfo *stage_interface = nullptr;
+
+void eevee_shader_extra_init()
+{
+ if (stage_interface != nullptr) {
+ return;
+ }
+
+ using namespace blender::gpu::shader;
+ stage_interface = new StageInterfaceInfo("ShaderStageInterface", "");
+ stage_interface->smooth(Type::VEC3, "worldPosition");
+ stage_interface->smooth(Type::VEC3, "viewPosition");
+ stage_interface->smooth(Type::VEC3, "worldNormal");
+ stage_interface->smooth(Type::VEC3, "viewNormal");
+ stage_interface->flat(Type::INT, "resourceIDFrag");
+}
+
+void eevee_shader_extra_exit()
+{
+ delete stage_interface;
+}
+
+void eevee_shader_material_create_info_amend(GPUMaterial *gpumat,
+ GPUCodegenOutput *codegen_,
+ char *frag,
+ char *vert,
+ char *geom,
+ char *defines)
+{
+ using namespace blender::gpu::shader;
+
+ uint64_t options = GPU_material_uuid_get(gpumat);
+ const bool is_background = (options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0;
+ const bool is_volume = (options & (VAR_MAT_VOLUME)) != 0;
+ const bool is_hair = (options & (VAR_MAT_HAIR)) != 0;
+ const bool is_mesh = (options & (VAR_MAT_MESH)) != 0;
+ const bool is_point_cloud = (options & (VAR_MAT_POINTCLOUD)) != 0;
+
+ GPUCodegenOutput &codegen = *codegen_;
+ ShaderCreateInfo &info = *reinterpret_cast<ShaderCreateInfo *>(codegen.create_info);
+
+ info.legacy_resource_location(true);
+ info.auto_resource_location(true);
+
+ if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE)) {
+ info.define("USE_SSS");
+ }
+ if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) {
+ info.define("USE_SHADER_TO_RGBA");
+ }
+ if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC) && !is_volume && !is_hair &&
+ !is_point_cloud && !is_background) {
+ info.define("USE_BARYCENTRICS");
+ info.builtins(BuiltinBits::BARYCENTRIC_COORD);
+ }
+ if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC) && is_hair) {
+ info.define("USE_BARYCENTRICS");
+ }
+
+ std::stringstream attr_load;
+
+ const bool do_fragment_attrib_load = is_background || is_volume;
+
+ if (is_hair && !info.vertex_out_interfaces_.is_empty()) {
+ /** Hair attributes comme from sampler buffer. Transfer attributes to sampler. */
+ for (auto &input : info.vertex_inputs_) {
+ info.sampler(0, ImageType::FLOAT_BUFFER, input.name, Frequency::BATCH);
+ }
+ info.vertex_inputs_.clear();
+ }
+ else if (do_fragment_attrib_load && !info.vertex_out_interfaces_.is_empty()) {
+ /* Codegen outputs only one interface. */
+ const StageInterfaceInfo &iface = *info.vertex_out_interfaces_.first();
+ /* Globals the attrib_load() can write to when it is in the fragment shader. */
+ attr_load << "struct " << iface.name << " {\n";
+ for (auto &inout : iface.inouts) {
+ attr_load << " " << inout.type << " " << inout.name << ";\n";
+ }
+ attr_load << "};\n";
+ attr_load << iface.name << " " << iface.instance_name << ";\n";
+ /* Global vars just to make code valid. Only Orco is supported. */
+ for (const ShaderCreateInfo::VertIn &in : info.vertex_inputs_) {
+ attr_load << in.type << " " << in.name << ";\n";
+ }
+ info.vertex_out_interfaces_.clear();
+ }
+
+ if (!is_volume) {
+ info.define("EEVEE_GENERATED_INTERFACE");
+ info.vertex_out(*stage_interface);
+ }
+
+ attr_load << "void attrib_load()\n";
+ attr_load << "{\n";
+ attr_load << ((codegen.attr_load) ? codegen.attr_load : "");
+ attr_load << "}\n\n";
+
+ std::stringstream vert_gen, frag_gen, geom_gen;
+
+ if (do_fragment_attrib_load) {
+ frag_gen << attr_load.str();
+ }
+ else {
+ vert_gen << attr_load.str();
+ }
+
+ {
+ vert_gen << vert;
+ info.vertex_source_generated = vert_gen.str();
+ /* Everything is in generated source. */
+ info.vertex_source(is_volume ? "eevee_empty_volume.glsl" : "eevee_empty.glsl");
+ }
+
+ {
+ frag_gen << frag;
+ if (codegen.material_functions) {
+ frag_gen << codegen.material_functions;
+ }
+ frag_gen << "Closure nodetree_exec()\n";
+ frag_gen << "{\n";
+ if (GPU_material_is_volume_shader(gpumat)) {
+ frag_gen << ((codegen.volume) ? codegen.volume : "return CLOSURE_DEFAULT;\n");
+ }
+ else {
+ frag_gen << ((codegen.surface) ? codegen.surface : "return CLOSURE_DEFAULT;\n");
+ }
+ frag_gen << "}\n\n";
+
+ if (codegen.displacement && (is_hair || is_mesh)) {
+ info.define("EEVEE_DISPLACEMENT_BUMP");
+
+ frag_gen << "vec3 displacement_exec()\n";
+ frag_gen << "{\n";
+ frag_gen << codegen.displacement;
+ frag_gen << "}\n\n";
+ }
+
+ info.fragment_source_generated = frag_gen.str();
+ /* Everything is in generated source. */
+ info.fragment_source(is_volume ? "eevee_empty_volume.glsl" : "eevee_empty.glsl");
+ }
+
+ if (geom) {
+ geom_gen << geom;
+ info.geometry_source_generated = geom_gen.str();
+ info.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3);
+ /* Everything is in generated source. */
+ info.geometry_source("eevee_empty.glsl");
+ }
+
+ if (defines) {
+ info.typedef_source_generated += blender::StringRefNull(defines);
+ }
+}
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 7d210f15d8b..6a0c9fb36df 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -604,6 +604,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 4da30dd74ee..d8adf302e37 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -26,6 +26,10 @@
# endif
#endif
+#ifndef GPU_FRAGMENT_SHADER
+# define gl_FragCoord vec4(0.0)
+#endif
+
uniform sampler2D horizonBuffer;
/* aoSettings flags */
@@ -424,3 +428,34 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion)
return data;
}
+
+#ifndef GPU_FRAGMENT_SHADER
+# undef gl_FragCoord
+#endif
+
+float ambient_occlusion_eval(vec3 normal,
+ float max_distance,
+ const float inverted,
+ const float sample_count)
+{
+ /* Avoid multiline define causing compiler issues. */
+ /* clang-format off */
+#if defined(GPU_FRAGMENT_SHADER) && (defined(MESH_SHADER) || defined(HAIR_SHADER)) && !defined(DEPTH_SHADER) && !defined(VOLUMETRICS)
+ /* clang-format on */
+ vec3 bent_normal;
+ vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ OcclusionData data = occlusion_search(
+ viewPosition, maxzBuffer, max_distance, inverted, sample_count);
+
+ vec3 V = cameraVec(worldPosition);
+ vec3 N = normalize(normal);
+ vec3 Ng = safe_normalize(cross(dFdx(worldPosition), dFdy(worldPosition)));
+
+ float unused_error, visibility;
+ vec3 unused;
+ occlusion_eval(data, V, N, Ng, inverted, visibility, unused_error, unused);
+ return visibility;
+#else
+ return 1.0;
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl
index 5cd82d298d5..574b24b3650 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl
@@ -1,6 +1,8 @@
#pragma BLENDER_REQUIRE(lights_lib.glsl)
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
struct ClosureInputDiffuse {
vec3 N; /** Shading normal. */
@@ -88,6 +90,7 @@ void closure_Diffuse_eval_end(ClosureInputDiffuse cl_in,
ClosureEvalCommon cl_common,
inout ClosureOutputDiffuse cl_out)
{
+ cl_out.radiance = render_pass_diffuse_mask(cl_out.radiance);
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
cl_out.radiance = vec3(0.0);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
index 4271ac9105b..0deaf4054d2 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
@@ -4,6 +4,8 @@
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
struct ClosureInputGlossy {
vec3 N; /** Shading normal. */
@@ -143,6 +145,7 @@ void closure_Glossy_eval_end(ClosureInputGlossy cl_in,
ClosureEvalCommon cl_common,
inout ClosureOutputGlossy cl_out)
{
+ cl_out.radiance = render_pass_glossy_mask(cl_out.radiance);
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
cl_out.radiance = vec3(0.0);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
index a96d8ad3dac..3f07f80571a 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
@@ -1,8 +1,14 @@
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+// #pragma (gpu_shader_codegen_lib.glsl)
#pragma BLENDER_REQUIRE(lights_lib.glsl)
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#ifndef GPU_FRAGMENT_SHADER
+# define gl_FragCoord vec4(0.0)
+# define gl_FrontFacing true
+#endif
+
/**
* Extensive use of Macros to be able to change the maximum amount of evaluated closure easily.
* NOTE: GLSL does not support variadic macros.
@@ -240,7 +246,11 @@ ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal);
cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal);
cl_eval.vP = viewPosition;
+#ifdef GPU_FRAGMENT_SHADER
cl_eval.Ng = safe_normalize(cross(dFdx(cl_eval.P), dFdy(cl_eval.P)));
+#else
+ cl_eval.Ng = cl_eval.N;
+#endif
cl_eval.vNg = transform_direction(ViewMatrix, cl_eval.Ng);
cl_eval.occlusion_data = occlusion_load(cl_eval.vP, cl_in.occlusion);
@@ -337,3 +347,8 @@ ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common
}
/** \} */
+
+#ifndef GPU_FRAGMENT_SHADER
+# undef gl_FragCoord
+# undef gl_FrontFacing
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl
index 8129988920c..5c6769b185a 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl
@@ -4,6 +4,8 @@
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
#pragma BLENDER_REQUIRE(ssr_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
struct ClosureInputRefraction {
vec3 N; /** Shading normal. */
@@ -123,6 +125,7 @@ void closure_Refraction_eval_end(ClosureInputRefraction cl_in,
ClosureEvalCommon cl_common,
inout ClosureOutputRefraction cl_out)
{
+ cl_out.radiance = render_pass_glossy_mask(cl_out.radiance);
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
cl_out.radiance = vec3(0.0);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
new file mode 100644
index 00000000000..fa94b5ed272
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
@@ -0,0 +1,325 @@
+
+#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
+
+#ifdef USE_SHADER_TO_RGBA
+bool do_sss = false;
+bool do_ssr = false;
+#else
+bool do_sss = true;
+bool do_ssr = true;
+#endif
+
+vec3 out_sss_radiance;
+vec3 out_sss_color;
+float out_sss_radius;
+
+float out_ssr_roughness;
+vec3 out_ssr_color;
+vec3 out_ssr_N;
+
+bool aov_is_valid = false;
+vec3 out_aov;
+
+bool output_sss(ClosureDiffuse diffuse, ClosureOutputDiffuse diffuse_out)
+{
+ if (diffuse.sss_id == 0u || !do_sss || !sssToggle || outputSssId == 0) {
+ return false;
+ }
+ if (renderPassSSSColor) {
+ return false;
+ }
+ out_sss_radiance = diffuse_out.radiance;
+ out_sss_color = diffuse.color * diffuse.weight;
+ out_sss_radius = avg(diffuse.sss_radius);
+ do_sss = false;
+ return true;
+}
+
+bool output_ssr(ClosureReflection reflection)
+{
+ if (!do_ssr || !ssrToggle || outputSsrId == 0) {
+ return false;
+ }
+ out_ssr_roughness = reflection.roughness;
+ out_ssr_color = reflection.color * reflection.weight;
+ out_ssr_N = reflection.N;
+ do_ssr = false;
+ return true;
+}
+
+void output_aov(vec4 color, float value, uint hash)
+{
+ /* Keep in sync with `render_pass_aov_hash` and `EEVEE_renderpasses_aov_hash`. */
+ hash <<= 1u;
+
+ if (renderPassAOV && !aov_is_valid && hash == render_pass_aov_hash()) {
+ aov_is_valid = true;
+ if (render_pass_aov_is_color()) {
+ out_aov = color.rgb;
+ }
+ else {
+ out_aov = vec3(value);
+ }
+ }
+}
+
+/* Single BSDFs. */
+CLOSURE_EVAL_FUNCTION_DECLARE_1(DiffuseBSDF, Diffuse)
+Closure closure_eval(ClosureDiffuse diffuse)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_1(Diffuse);
+
+ in_Diffuse_0.N = diffuse.N;
+ in_Diffuse_0.albedo = diffuse.color;
+
+ CLOSURE_EVAL_FUNCTION_1(DiffuseBSDF, Diffuse);
+
+ Closure closure = CLOSURE_DEFAULT;
+ if (!output_sss(diffuse, out_Diffuse_0)) {
+ closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight;
+ }
+ return closure;
+}
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(TranslucentBSDF, Translucent)
+Closure closure_eval(ClosureTranslucent translucent)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_1(Translucent);
+
+ in_Translucent_0.N = translucent.N;
+
+ CLOSURE_EVAL_FUNCTION_1(TranslucentBSDF, Translucent);
+
+ Closure closure = CLOSURE_DEFAULT;
+ closure.radiance += out_Translucent_0.radiance * translucent.color * translucent.weight;
+ return closure;
+}
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(GlossyBSDF, Glossy)
+Closure closure_eval(ClosureReflection reflection)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_1(Glossy);
+
+ in_Glossy_0.N = reflection.N;
+ in_Glossy_0.roughness = reflection.roughness;
+
+ CLOSURE_EVAL_FUNCTION_1(GlossyBSDF, Glossy);
+
+ Closure closure = CLOSURE_DEFAULT;
+ if (!output_ssr(reflection)) {
+ closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight;
+ }
+ return closure;
+}
+
+CLOSURE_EVAL_FUNCTION_DECLARE_1(RefractionBSDF, Refraction)
+Closure closure_eval(ClosureRefraction refraction)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_1(Refraction);
+
+ in_Refraction_0.N = refraction.N;
+ in_Refraction_0.roughness = refraction.roughness;
+ in_Refraction_0.ior = refraction.ior;
+
+ CLOSURE_EVAL_FUNCTION_1(RefractionBSDF, Refraction);
+
+ Closure closure = CLOSURE_DEFAULT;
+ closure.radiance += out_Refraction_0.radiance * refraction.color * refraction.weight;
+ return closure;
+}
+
+Closure closure_eval(ClosureEmission emission)
+{
+ Closure closure = CLOSURE_DEFAULT;
+ closure.radiance += render_pass_emission_mask(emission.emission) * emission.weight;
+ return closure;
+}
+
+Closure closure_eval(ClosureTransparency transparency)
+{
+ Closure closure = CLOSURE_DEFAULT;
+ closure.transmittance += transparency.transmittance * transparency.weight;
+ closure.holdout += transparency.holdout * transparency.weight;
+ return closure;
+}
+
+/* Glass BSDF. */
+CLOSURE_EVAL_FUNCTION_DECLARE_2(GlassBSDF, Glossy, Refraction)
+Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
+
+ in_Glossy_0.N = reflection.N;
+ in_Glossy_0.roughness = reflection.roughness;
+ in_Refraction_1.N = refraction.N;
+ in_Refraction_1.roughness = refraction.roughness;
+ in_Refraction_1.ior = refraction.ior;
+
+ CLOSURE_EVAL_FUNCTION_2(GlassBSDF, Glossy, Refraction);
+
+ Closure closure = CLOSURE_DEFAULT;
+ closure.radiance += out_Refraction_1.radiance * refraction.color * refraction.weight;
+ if (!output_ssr(reflection)) {
+ closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight;
+ }
+ return closure;
+}
+
+/* Dielectric BSDF */
+CLOSURE_EVAL_FUNCTION_DECLARE_2(DielectricBSDF, Diffuse, Glossy)
+Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_2(Diffuse, Glossy);
+
+ in_Diffuse_0.N = diffuse.N;
+ in_Diffuse_0.albedo = diffuse.color;
+ in_Glossy_1.N = reflection.N;
+ in_Glossy_1.roughness = reflection.roughness;
+
+ CLOSURE_EVAL_FUNCTION_2(DielectricBSDF, Diffuse, Glossy);
+
+ Closure closure = CLOSURE_DEFAULT;
+ if (!output_sss(diffuse, out_Diffuse_0)) {
+ closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight;
+ }
+ if (!output_ssr(reflection)) {
+ closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight;
+ }
+ return closure;
+}
+
+/* Specular BSDF */
+CLOSURE_EVAL_FUNCTION_DECLARE_3(SpecularBSDF, Diffuse, Glossy, Glossy)
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
+
+ in_Diffuse_0.N = diffuse.N;
+ in_Diffuse_0.albedo = diffuse.color;
+ in_Glossy_1.N = reflection.N;
+ in_Glossy_1.roughness = reflection.roughness;
+ in_Glossy_2.N = clearcoat.N;
+ in_Glossy_2.roughness = clearcoat.roughness;
+
+ CLOSURE_EVAL_FUNCTION_3(SpecularBSDF, Diffuse, Glossy, Glossy);
+
+ Closure closure = CLOSURE_DEFAULT;
+ if (!output_sss(diffuse, out_Diffuse_0)) {
+ closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight;
+ }
+ closure.radiance += out_Glossy_2.radiance * clearcoat.color * clearcoat.weight;
+ if (!output_ssr(reflection)) {
+ closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight;
+ }
+ return closure;
+}
+
+/* Principled BSDF */
+CLOSURE_EVAL_FUNCTION_DECLARE_4(PrincipledBSDF, Diffuse, Glossy, Glossy, Refraction)
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat,
+ ClosureRefraction refraction)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
+
+ in_Diffuse_0.N = diffuse.N;
+ in_Diffuse_0.albedo = diffuse.color;
+ in_Glossy_1.N = reflection.N;
+ in_Glossy_1.roughness = reflection.roughness;
+ in_Glossy_2.N = clearcoat.N;
+ in_Glossy_2.roughness = clearcoat.roughness;
+ in_Refraction_3.N = refraction.N;
+ in_Refraction_3.roughness = refraction.roughness;
+ in_Refraction_3.ior = refraction.ior;
+
+ CLOSURE_EVAL_FUNCTION_4(PrincipledBSDF, Diffuse, Glossy, Glossy, Refraction);
+
+ Closure closure = CLOSURE_DEFAULT;
+ closure.radiance += out_Glossy_2.radiance * clearcoat.color * clearcoat.weight;
+ closure.radiance += out_Refraction_3.radiance * refraction.color * refraction.weight;
+ if (!output_sss(diffuse, out_Diffuse_0)) {
+ closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight;
+ }
+ if (!output_ssr(reflection)) {
+ closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight;
+ }
+ return closure;
+}
+
+CLOSURE_EVAL_FUNCTION_DECLARE_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy)
+Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat)
+{
+ /* Glue with the old system. */
+ CLOSURE_VARS_DECLARE_2(Glossy, Glossy);
+
+ in_Glossy_0.N = reflection.N;
+ in_Glossy_0.roughness = reflection.roughness;
+ in_Glossy_1.N = clearcoat.N;
+ in_Glossy_1.roughness = clearcoat.roughness;
+
+ CLOSURE_EVAL_FUNCTION_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy);
+
+ Closure closure = CLOSURE_DEFAULT;
+ closure.radiance += out_Glossy_1.radiance * clearcoat.color * clearcoat.weight;
+ if (!output_ssr(reflection)) {
+ closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight;
+ }
+ return closure;
+}
+
+/* Not supported for surface shaders. */
+Closure closure_eval(ClosureVolumeScatter volume_scatter)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureVolumeAbsorption volume_absorption)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureVolumeScatter volume_scatter,
+ ClosureVolumeAbsorption volume_absorption,
+ ClosureEmission emission)
+{
+ return CLOSURE_DEFAULT;
+}
+
+/* Not implemented yet. */
+Closure closure_eval(ClosureHair hair)
+{
+ return CLOSURE_DEFAULT;
+}
+
+vec4 closure_to_rgba(Closure closure)
+{
+ return vec4(closure.radiance, 1.0 - saturate(avg(closure.transmittance)));
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.radiance = cl1.radiance + cl2.radiance;
+ cl.transmittance = cl1.transmittance + cl2.transmittance;
+ cl.holdout = cl1.holdout + cl2.holdout;
+ return cl;
+}
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ /* Weights have already been applied. */
+ return closure_add(cl1, cl2);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl
index 706b75cb7f9..89a6f10e634 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl
@@ -3,6 +3,8 @@
#pragma BLENDER_REQUIRE(lights_lib.glsl)
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
struct ClosureInputTranslucent {
vec3 N; /** Shading normal. */
@@ -69,6 +71,7 @@ void closure_Translucent_eval_end(ClosureInputTranslucent cl_in,
ClosureEvalCommon cl_common,
inout ClosureOutputTranslucent cl_out)
{
+ cl_out.radiance = render_pass_diffuse_mask(cl_out.radiance);
#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
cl_out.radiance = vec3(0.0);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
new file mode 100644
index 00000000000..e450b8ad3c8
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl
@@ -0,0 +1,113 @@
+
+void output_aov(vec4 color, float value, uint hash)
+{
+ /* Unsupported. */
+}
+
+/* Surface BSDFs. */
+Closure closure_eval(ClosureDiffuse diffuse)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureTranslucent translucent)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureReflection reflection)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureRefraction refraction)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureEmission emission)
+{
+ Closure closure = CLOSURE_DEFAULT;
+ closure.emission = emission.emission;
+ return closure;
+}
+Closure closure_eval(ClosureTransparency transparency)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat,
+ ClosureRefraction refraction)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat)
+{
+ return CLOSURE_DEFAULT;
+}
+Closure closure_eval(ClosureHair hair)
+{
+ return CLOSURE_DEFAULT;
+}
+
+Closure closure_eval(ClosureVolumeScatter volume_scatter)
+{
+ Closure closure = CLOSURE_DEFAULT;
+ closure.scatter = volume_scatter.scattering;
+ closure.anisotropy = volume_scatter.anisotropy;
+ return closure;
+}
+Closure closure_eval(ClosureVolumeAbsorption volume_absorption)
+{
+ Closure closure = CLOSURE_DEFAULT;
+ closure.absorption = volume_absorption.absorption;
+ return closure;
+}
+Closure closure_eval(ClosureVolumeScatter volume_scatter,
+ ClosureVolumeAbsorption volume_absorption,
+ ClosureEmission emission)
+{
+ Closure closure = CLOSURE_DEFAULT;
+ closure.absorption = volume_absorption.absorption;
+ closure.scatter = volume_scatter.scattering;
+ closure.anisotropy = volume_scatter.anisotropy;
+ closure.emission = emission.emission;
+ return closure;
+}
+
+vec4 closure_to_rgba(Closure closure)
+{
+ /* Not supported */
+ return vec4(0.0);
+}
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+ Closure cl;
+ cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
+ cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
+ cl.emission = mix(cl1.emission, cl2.emission, fac);
+ cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
+ return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+ Closure cl;
+ cl.absorption = cl1.absorption + cl2.absorption;
+ cl.scatter = cl1.scatter + cl2.scatter;
+ cl.emission = cl1.emission + cl2.emission;
+ cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
+ return cl;
+}
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index 9022a9d3130..0096cd1747f 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -1,6 +1,8 @@
-#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
-#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
+/* #pragma (common_math_geom_lib.glsl) */
+/* #pragma (common_uniforms_lib.glsl) */
+/* #pragma (renderpass_lib.glsl) */
#ifndef VOLUMETRICS
@@ -20,15 +22,6 @@ struct Closure {
vec3 radiance;
vec3 transmittance;
float holdout;
- vec4 ssr_data;
- vec2 ssr_normal;
- int flag;
-# ifdef USE_SSS
- vec3 sss_irradiance;
- vec3 sss_albedo;
- float sss_radius;
-# endif
-
#endif
/* Metal Default Constructor - Requred for C++ constructor syntax. */
@@ -45,191 +38,76 @@ struct Closure {
}
# else
/* Explicit Closure constructors -- To support GLSL syntax */
- inline Closure(vec3 in_radiance,
- vec3 in_transmittance,
- float in_holdout,
- vec4 in_ssr_data,
- vec2 in_ssr_normal,
- int in_flag
-# ifdef USE_SSS
- ,
- vec3 in_sss_irradiance,
- vec3 in_sss_albedo,
- float in_sss_radius
-# endif /* USE_SSS */
- )
- : radiance(in_radiance),
- transmittance(in_transmittance),
- holdout(in_holdout),
- ssr_data(in_ssr_data),
- ssr_normal(in_ssr_normal),
- flag(in_flag)
-# ifdef USE_SSS
- ,
- sss_irradiance(in_sss_irradiance),
- sss_albedo(in_sss_albedo),
- sss_radius(in_sss_radius)
-# endif /* USE_SSS */
+ inline Closure(vec3 in_radiance, vec3 in_transmittance, float in_holdout)
+ : radiance(in_radiance), transmittance(in_transmittance), holdout(in_holdout)
{
}
-# endif /* VOLUMETRICS */
-#endif /* GPU_METAL */
+# endif /* VOLUMETRICS */
+#endif /* GPU_METAL */
};
#ifndef GPU_METAL
/* Prototype */
-Closure nodetree_exec(void);
+Closure nodetree_exec();
+vec4 closure_to_rgba(Closure);
+void output_aov(vec4 color, float value, uint hash);
+vec3 coordinate_camera(vec3 P);
+vec3 coordinate_screen(vec3 P);
+vec3 coordinate_reflect(vec3 P, vec3 N);
+vec3 coordinate_incoming(vec3 P);
+
+/* Single BSDFs. */
+Closure closure_eval(ClosureDiffuse diffuse);
+Closure closure_eval(ClosureTranslucent translucent);
+Closure closure_eval(ClosureReflection reflection);
+Closure closure_eval(ClosureRefraction refraction);
+Closure closure_eval(ClosureEmission emission);
+Closure closure_eval(ClosureTransparency transparency);
+Closure closure_eval(ClosureVolumeScatter volume_scatter);
+Closure closure_eval(ClosureVolumeAbsorption volume_absorption);
+Closure closure_eval(ClosureHair hair);
+
+/* Glass BSDF. */
+Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction);
+/* Dielectric BSDF. */
+Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection);
+/* ClearCoat BSDF. */
+Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat);
+/* Volume BSDF. */
+Closure closure_eval(ClosureVolumeScatter volume_scatter,
+ ClosureVolumeAbsorption volume_absorption,
+ ClosureEmission emission);
+/* Specular BSDF. */
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat);
+/* Principled BSDF. */
+Closure closure_eval(ClosureDiffuse diffuse,
+ ClosureReflection reflection,
+ ClosureReflection clearcoat,
+ ClosureRefraction refraction);
+
+Closure closure_add(Closure cl1, Closure cl2);
+Closure closure_mix(Closure cl1, Closure cl2, float fac);
+
+float ambient_occlusion_eval(vec3 normal,
+ float distance,
+ const float inverted,
+ const float sample_count);
+
+/* WORKAROUND: Included later with libs. This is because we are mixing include systems. */
+vec3 safe_normalize(vec3 N);
+float fast_sqrt(float a);
+vec3 cameraVec(vec3 P);
+vec2 btdf_lut(float a, float b, float c);
+vec2 brdf_lut(float a, float b);
+vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c);
+vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c);
+float F_eta(float a, float b);
#endif
-/* clang-format off */
-/* Avoid multi-line defines. */
#ifdef VOLUMETRICS
# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), vec3(0), 0.0)
-#elif !defined(USE_SSS)
-# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0, vec4(0), vec2(0), 0)
#else
-# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0, vec4(0), vec2(0), 0, vec3(0), vec3(0), 0.0)
-#endif
-/* clang-format on */
-
-#define FLAG_TEST(flag, val) (((flag) & (val)) != 0)
-
-#define CLOSURE_SSR_FLAG 1
-#define CLOSURE_SSS_FLAG 2
-#define CLOSURE_HOLDOUT_FLAG 4
-
-#ifdef VOLUMETRICS
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
-{
- Closure cl;
- cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
- cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
- cl.emission = mix(cl1.emission, cl2.emission, fac);
- cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
- return cl;
-}
-
-Closure closure_add(Closure cl1, Closure cl2)
-{
- Closure cl;
- cl.absorption = cl1.absorption + cl2.absorption;
- cl.scatter = cl1.scatter + cl2.scatter;
- cl.emission = cl1.emission + cl2.emission;
- cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
- return cl;
-}
-
-Closure closure_emission(vec3 rgb)
-{
- Closure cl = CLOSURE_DEFAULT;
- cl.emission = rgb;
- return cl;
-}
-
-#else /* SURFACE */
-
-Closure closure_mix(Closure cl1, Closure cl2, float fac)
-{
- Closure cl;
- cl.holdout = mix(cl1.holdout, cl2.holdout, fac);
-
- if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) {
- fac = 1.0;
- }
- else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) {
- fac = 0.0;
- }
-
- cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac);
- cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
- cl.flag = cl1.flag | cl2.flag;
- cl.ssr_data = mix(cl1.ssr_data, cl2.ssr_data, fac);
- bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
- /* When mixing SSR don't blend roughness and normals but only specular (ssr_data.xyz). */
- cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
- cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
-
-# ifdef USE_SSS
- cl.sss_albedo = mix(cl1.sss_albedo, cl2.sss_albedo, fac);
- bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or irradiance. */
- cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
- cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
-# endif
- return cl;
-}
-
-Closure closure_add(Closure cl1, Closure cl2)
-{
- Closure cl;
- cl.transmittance = cl1.transmittance + cl2.transmittance;
- cl.radiance = cl1.radiance + cl2.radiance;
- cl.holdout = cl1.holdout + cl2.holdout;
- cl.flag = cl1.flag | cl2.flag;
- cl.ssr_data = cl1.ssr_data + cl2.ssr_data;
- bool use_cl1_ssr = FLAG_TEST(cl1.flag, CLOSURE_SSR_FLAG);
- /* When mixing SSR don't blend roughness and normals. */
- cl.ssr_data.w = (use_cl1_ssr) ? cl1.ssr_data.w : cl2.ssr_data.w;
- cl.ssr_normal = (use_cl1_ssr) ? cl1.ssr_normal : cl2.ssr_normal;
-
-# ifdef USE_SSS
- cl.sss_albedo = cl1.sss_albedo + cl2.sss_albedo;
- bool use_cl1_sss = FLAG_TEST(cl1.flag, CLOSURE_SSS_FLAG);
- /* It also does not make sense to mix SSS radius or irradiance. */
- cl.sss_radius = (use_cl1_sss) ? cl1.sss_radius : cl2.sss_radius;
- cl.sss_irradiance = (use_cl1_sss) ? cl1.sss_irradiance : cl2.sss_irradiance;
-# endif
- return cl;
-}
-
-Closure closure_emission(vec3 rgb)
-{
- Closure cl = CLOSURE_DEFAULT;
- cl.radiance = rgb;
- return cl;
-}
-
-#endif
-
-#ifndef VOLUMETRICS
-
-/* Let radiance passthrough or replace it to get the BRDF and color
- * to applied to the SSR result. */
-vec3 closure_mask_ssr_radiance(vec3 radiance, float ssr_id)
-{
- return (ssrToggle && int(ssr_id) == outputSsrId) ? vec3(1.0) : radiance;
-}
-
-void closure_load_ssr_data(
- vec3 ssr_radiance, float roughness, vec3 N, float ssr_id, inout Closure cl)
-{
- /* Still encode to avoid artifacts in the SSR pass. */
- vec3 vN = normalize(mat3(ViewMatrix) * N);
- cl.ssr_normal = normal_encode(vN, viewCameraVec(viewPosition));
-
- if (ssrToggle && int(ssr_id) == outputSsrId) {
- cl.ssr_data = vec4(ssr_radiance, roughness);
- cl.flag |= CLOSURE_SSR_FLAG;
- }
- else {
- cl.radiance += ssr_radiance;
- }
-}
-
-void closure_load_sss_data(
- float radius, vec3 sss_irradiance, vec3 sss_albedo, int sss_id, inout Closure cl)
-{
-# ifdef USE_SSS
- if (sss_id == outputSssId) {
- cl.sss_irradiance = sss_irradiance;
- cl.sss_radius = radius;
- cl.sss_albedo = sss_albedo;
- cl.flag |= CLOSURE_SSS_FLAG;
- /* Irradiance will be convolved by SSSS pass. Do not add to radiance. */
- sss_irradiance = vec3(0);
- }
-# endif
- cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo;
-}
-
+# define CLOSURE_DEFAULT Closure(vec3(0), vec3(0), 0.0)
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/eevee_empty.glsl b/source/blender/draw/engines/eevee/shaders/eevee_empty.glsl
new file mode 100644
index 00000000000..e00bcc4e557
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/eevee_empty.glsl
@@ -0,0 +1,7 @@
+
+/* Empty GLSL source to satisfy the GPUShaderCreateInfo requirements. */
+/* Needed includes for shader nodes. */
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_attribute_lib.glsl)
diff --git a/source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl b/source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl
new file mode 100644
index 00000000000..a748c0092b6
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/eevee_empty_volume.glsl
@@ -0,0 +1,8 @@
+
+/* Empty GLSL source to satisfy the GPUShaderCreateInfo requirements. */
+/* Needed includes for shader nodes. */
+#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_attribute_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_volume_lib.glsl)
diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
index 1aff93e01f8..e86c5e06c99 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl
@@ -11,6 +11,7 @@ layout(std140) uniform sssProfile
{
vec4 sss_kernel[MAX_SSS_SAMPLES];
vec4 radii_max_radius;
+ float avg_inv_radius;
int sss_samples;
};
@@ -26,7 +27,7 @@ void main(void)
vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO: precompute. */
vec2 uvs = gl_FragCoord.xy * pixel_size;
vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb;
- float sss_radius = texture(sssRadius, uvs).r * radii_max_radius.w;
+ float sss_radius = texture(sssRadius, uvs).r * radii_max_radius.w * avg_inv_radius;
float depth = texture(depthBuffer, uvs).r;
float depth_view = get_view_z_from_depth(depth);
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
index 3cf21dc32d1..5e1725ace97 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl
@@ -23,12 +23,13 @@ layout(std140) uniform sssProfile
{
vec4 sss_kernel[MAX_SSS_SAMPLES];
vec4 radii_max_radius;
+ float avg_inv_radius;
int sss_samples;
};
vec3 sss_profile(float s)
{
- s /= radii_max_radius.w;
+ s /= radii_max_radius.w * avg_inv_radius;
return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index fd08dfda060..c8eea8d7860 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -2,15 +2,12 @@
/* Required by some nodes. */
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#ifdef USE_ALPHA_HASH
@@ -73,6 +70,7 @@ float hashed_alpha_threshold(vec3 co)
void main()
{
#if defined(USE_ALPHA_HASH)
+ g_data = init_globals();
Closure cl = nodetree_exec();
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
deleted file mode 100644
index f650e2eeb8c..00000000000
--- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl
+++ /dev/null
@@ -1,35 +0,0 @@
-
-#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
-#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-
-#ifndef HAIR_SHADER
-in vec3 pos;
-#endif
-
-void main()
-{
- GPU_INTEL_VERTEX_SHADER_WORKAROUND
-
-#ifdef HAIR_SHADER
- float time, thick_time, thickness;
- vec3 worldPosition, tan, binor;
- hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
- ModelMatrixInverse,
- ViewMatrixInverse[3].xyz,
- ViewMatrixInverse[2].xyz,
- worldPosition,
- tan,
- binor,
- time,
- thickness,
- thick_time);
-#else
- vec3 worldPosition = point_object_to_world(pos);
-#endif
-
- gl_Position = point_world_to_ndc(worldPosition);
-
-#ifdef CLIP_PLANES
- gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), clipPlanes[0]);
-#endif
-}
diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
index 3e0a5e76d00..f276e4f26ca 100644
--- a/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/renderpass_lib.glsl
@@ -1,4 +1,4 @@
-#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1
+#define EEVEE_AOV_HASH_COLOR_TYPE_MASK 1u
/* ---------------------------------------------------------------------- */
/** \name Resources
@@ -14,7 +14,7 @@ layout(std140) uniform renderpass_block
bool renderPassSSSColor;
bool renderPassEnvironment;
bool renderPassAOV;
- int renderPassAOVActive;
+ uint renderPassAOVActive;
};
/** \} */
@@ -23,19 +23,14 @@ layout(std140) uniform renderpass_block
/** \name Functions
* \{ */
-vec3 render_pass_diffuse_mask(vec3 diffuse_color, vec3 diffuse_light)
+vec3 render_pass_diffuse_mask(vec3 diffuse_light)
{
- return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : diffuse_color) : vec3(0.0);
+ return renderPassDiffuse ? (renderPassDiffuseLight ? diffuse_light : vec3(1.0)) : vec3(0.0);
}
-vec3 render_pass_sss_mask(vec3 sss_color)
+vec3 render_pass_glossy_mask(vec3 specular_light)
{
- return renderPassSSSColor ? sss_color : vec3(0.0);
-}
-
-vec3 render_pass_glossy_mask(vec3 specular_color, vec3 specular_light)
-{
- return renderPassGlossy ? (renderPassGlossyLight ? specular_light : specular_color) : vec3(0.0);
+ return renderPassGlossy ? (renderPassGlossyLight ? specular_light : vec3(1.0)) : vec3(0.0);
}
vec3 render_pass_emission_mask(vec3 emission_light)
@@ -45,10 +40,10 @@ vec3 render_pass_emission_mask(vec3 emission_light)
bool render_pass_aov_is_color()
{
- return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0;
+ return (renderPassAOVActive & EEVEE_AOV_HASH_COLOR_TYPE_MASK) != 0u;
}
-int render_pass_aov_hash()
+uint render_pass_aov_hash()
{
return renderPassAOVActive & ~EEVEE_AOV_HASH_COLOR_TYPE_MASK;
}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index cbfa9737a84..0e8e8dd9d01 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -1,5 +1,6 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
@@ -12,6 +13,7 @@ void main()
#ifdef HAIR_SHADER
hairStrandID = hair_get_strand_id();
+ hairBary = hair_get_barycentric();
vec3 pos, binor;
hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
ModelMatrixInverse,
@@ -52,3 +54,93 @@ void main()
# endif
#endif
}
+
+#ifdef HAIR_SHADER
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(samplerBuffer cd_buf)
+{
+ vec3 P = hair_get_strand_pos();
+ vec3 lP = transform_point(ModelMatrixInverse, P);
+ return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
+}
+# endif
+
+vec4 attr_load_tangent(samplerBuffer cd_buf)
+{
+ /* Not supported. */
+ return vec4(0.0, 0.0, 0.0, 1.0);
+}
+
+vec3 attr_load_uv(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgb;
+}
+
+vec4 attr_load_color(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgba;
+}
+
+vec4 attr_load_vec4(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgba;
+}
+
+vec3 attr_load_vec3(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgb;
+}
+
+vec2 attr_load_vec2(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rg;
+}
+
+float attr_load_float(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).r;
+}
+
+#else
+
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(samplerBuffer cd_buf)
+{
+ vec3 P = hair_get_strand_pos();
+ vec3 lP = transform_point(ModelMatrixInverse, P);
+ return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
+}
+# endif
+
+vec4 attr_load_tangent(vec4 tangent)
+{
+ tangent.xyz = safe_normalize(normal_object_to_world(tangent.xyz));
+ return tangent;
+}
+
+/* Simple passthrough. */
+vec4 attr_load_vec4(vec4 attr)
+{
+ return attr;
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return attr;
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return attr;
+}
+vec2 attr_load_float(vec2 attr)
+{
+ return attr;
+}
+vec4 attr_load_color(vec4 attr)
+{
+ return attr;
+}
+vec3 attr_load_uv(vec3 attr)
+{
+ return attr;
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
index 889bf439d5f..9ad7a4fdbc1 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
@@ -2,16 +2,14 @@
/* Required by some nodes. */
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
+#pragma BLENDER_REQUIRE(renderpass_lib.glsl)
#ifdef USE_ALPHA_BLEND
/* Use dual source blending to be able to make a whole range of effects. */
@@ -22,18 +20,74 @@ layout(location = 0, index = 1) out vec4 outTransmittance;
layout(location = 0) out vec4 outRadiance;
layout(location = 1) out vec2 ssrNormals;
layout(location = 2) out vec4 ssrData;
-# ifdef USE_SSS
layout(location = 3) out vec3 sssIrradiance;
layout(location = 4) out float sssRadius;
layout(location = 5) out vec3 sssAlbedo;
+
+#endif
+
+uniform float backgroundAlpha;
+
+#ifdef EEVEE_DISPLACEMENT_BUMP
+
+# ifndef GPU_METAL
+/* Prototype. */
+vec3 displacement_exec();
# endif
+/* Return new shading normal. */
+vec3 displacement_bump()
+{
+ vec2 dHd;
+ dF_branch(dot(displacement_exec(), g_data.N + dF_impl(g_data.N)), dHd);
+
+ vec3 dPdx = dFdx(g_data.P);
+ vec3 dPdy = dFdy(g_data.P);
+
+ /* Get surface tangents from normal. */
+ vec3 Rx = cross(dPdy, g_data.N);
+ vec3 Ry = cross(g_data.N, dPdx);
+
+ /* Compute surface gradient and determinant. */
+ float det = dot(dPdx, Rx);
+
+ vec3 surfgrad = dHd.x * Rx + dHd.y * Ry;
+
+ float facing = FrontFacing ? 1.0 : -1.0;
+ return normalize(abs(det) * g_data.N - facing * sign(det) * surfgrad);
+}
+
#endif
void main()
{
+ g_data = init_globals();
+
+#ifdef EEVEE_DISPLACEMENT_BUMP
+ g_data.N = displacement_bump();
+#endif
+
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ attrib_load();
+#endif
+
+ out_ssr_color = vec3(0.0);
+ out_ssr_roughness = 0.0;
+ out_ssr_N = g_data.N;
+
+ out_sss_radiance = vec3(0.0);
+ out_sss_radius = 0.0;
+ out_sss_color = vec3(0.0);
+
Closure cl = nodetree_exec();
+#ifdef WORLD_BACKGROUND
+ if (!renderPassEnvironment) {
+ cl.holdout += 1.0 - backgroundAlpha;
+ cl.radiance *= backgroundAlpha;
+ }
+#endif
+
float holdout = saturate(1.0 - cl.holdout);
float transmit = saturate(avg(cl.transmittance));
float alpha = 1.0 - transmit;
@@ -53,38 +107,40 @@ void main()
outTransmittance = vec4(cl.transmittance, transmit) * holdout;
#else
outRadiance = vec4(cl.radiance, holdout);
- ssrNormals = cl.ssr_normal;
- ssrData = cl.ssr_data;
-# ifdef USE_SSS
- sssIrradiance = cl.sss_irradiance;
- sssRadius = cl.sss_radius;
- sssAlbedo = cl.sss_albedo;
-# endif
+ ssrNormals = normal_encode(normalize(mat3(ViewMatrix) * out_ssr_N), vec3(0.0));
+ ssrData = vec4(out_ssr_color, out_ssr_roughness);
+ sssIrradiance = out_sss_radiance;
+ sssRadius = out_sss_radius;
+ sssAlbedo = out_sss_color;
#endif
- /* For Probe capture */
-#ifdef USE_SSS
- float fac = float(!sssToggle);
-
- /* TODO(fclem): we shouldn't need this.
- * Just disable USE_SSS when USE_REFRACTION is enabled. */
-# ifdef USE_REFRACTION
+#ifdef USE_REFRACTION
/* SSRefraction pass is done after the SSS pass.
* In order to not lose the diffuse light totally we
* need to merge the SSS radiance to the main radiance. */
- fac = 1.0;
-# endif
-
- outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
+ const bool use_refraction = true;
+#else
+ const bool use_refraction = false;
#endif
+ /* For Probe capture */
+ if (!sssToggle || use_refraction) {
+ outRadiance.rgb += out_sss_radiance * out_sss_color;
+ }
#ifndef USE_ALPHA_BLEND
float alpha_div = safe_rcp(alpha);
outRadiance.rgb *= alpha_div;
ssrData.rgb *= alpha_div;
-# ifdef USE_SSS
sssAlbedo.rgb *= alpha_div;
-# endif
+
+ if (renderPassAOV) {
+ if (aov_is_valid) {
+ outRadiance = vec4(out_aov, 1.0);
+ }
+ else {
+ outRadiance = vec4(0.0);
+ }
+ }
#endif
#ifdef LOOKDEV
@@ -92,3 +148,34 @@ void main()
gl_FragDepth = 0.0;
#endif
}
+
+/* Only supported attrib for world/background shaders. */
+vec3 attr_load_orco(vec4 orco)
+{
+ return g_data.P;
+}
+/* Unsupported. */
+vec4 attr_load_tangent(vec4 tangent)
+{
+ return vec4(0);
+}
+vec4 attr_load_vec4(vec4 attr)
+{
+ return vec4(0);
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return vec3(0);
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return vec2(0);
+}
+vec4 attr_load_color(vec4 attr)
+{
+ return vec4(0);
+}
+vec3 attr_load_uv(vec3 attr)
+{
+ return vec3(0);
+}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index d7fc5e0b52a..1f2f7cb65cc 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -1,12 +1,23 @@
/** This describe the entire interface of the shader. */
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
#define SURFACE_INTERFACE \
vec3 worldPosition; \
vec3 viewPosition; \
vec3 worldNormal; \
vec3 viewNormal;
-#if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE)
+#ifndef IN_OUT
+# if defined(GPU_VERTEX_SHADER)
+# define IN_OUT out
+# elif defined(GPU_FRAGMENT_SHADER)
+# define IN_OUT in
+# endif
+#endif
+
+#ifndef EEVEE_GENERATED_INTERFACE
+# if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE)
/* SSR will set these global variables itself.
* Also make false positive compiler warnings disappear by setting values. */
vec3 worldPosition = vec3(0);
@@ -14,22 +25,23 @@ vec3 viewPosition = vec3(0);
vec3 worldNormal = vec3(0);
vec3 viewNormal = vec3(0);
-#elif defined(GPU_GEOMETRY_SHADER)
+# elif defined(GPU_GEOMETRY_SHADER)
in ShaderStageInterface{SURFACE_INTERFACE} dataIn[];
out ShaderStageInterface{SURFACE_INTERFACE} dataOut;
-# define PASS_SURFACE_INTERFACE(vert) \
- dataOut.worldPosition = dataIn[vert].worldPosition; \
- dataOut.viewPosition = dataIn[vert].viewPosition; \
- dataOut.worldNormal = dataIn[vert].worldNormal; \
- dataOut.viewNormal = dataIn[vert].viewNormal;
+# define PASS_SURFACE_INTERFACE(vert) \
+ dataOut.worldPosition = dataIn[vert].worldPosition; \
+ dataOut.viewPosition = dataIn[vert].viewPosition; \
+ dataOut.worldNormal = dataIn[vert].worldNormal; \
+ dataOut.viewNormal = dataIn[vert].viewNormal;
-#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/
+# else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/
IN_OUT ShaderStageInterface{SURFACE_INTERFACE};
-#endif
+# endif
+#endif /* EEVEE_GENERATED_INTERFACE */
#ifdef HAIR_SHADER
IN_OUT ShaderHairInterface
@@ -40,6 +52,7 @@ IN_OUT ShaderHairInterface
float hairThickness;
float hairTime;
flat int hairStrandID;
+ vec2 hairBary;
};
#endif
@@ -52,3 +65,138 @@ IN_OUT ShaderPointCloudInterface
flat int pointID;
};
#endif
+
+#if defined(GPU_FRAGMENT_SHADER) && defined(CODEGEN_LIB)
+
+# if defined(USE_BARYCENTRICS) && !defined(HAIR_SHADER)
+vec3 barycentric_distances_get()
+{
+ /* NOTE: No need to undo perspective divide since it is not applied yet. */
+ vec3 pos0 = (ProjectionMatrixInverse * gpu_position_at_vertex(0)).xyz;
+ vec3 pos1 = (ProjectionMatrixInverse * gpu_position_at_vertex(1)).xyz;
+ vec3 pos2 = (ProjectionMatrixInverse * gpu_position_at_vertex(2)).xyz;
+ vec3 edge21 = pos2 - pos1;
+ vec3 edge10 = pos1 - pos0;
+ vec3 edge02 = pos0 - pos2;
+ vec3 d21 = safe_normalize(edge21);
+ vec3 d10 = safe_normalize(edge10);
+ vec3 d02 = safe_normalize(edge02);
+ vec3 dists;
+ float d = dot(d21, edge02);
+ dists.x = sqrt(dot(edge02, edge02) - d * d);
+ d = dot(d02, edge10);
+ dists.y = sqrt(dot(edge10, edge10) - d * d);
+ d = dot(d10, edge21);
+ dists.z = sqrt(dot(edge21, edge21) - d * d);
+ return dists.xyz;
+}
+# endif
+
+GlobalData init_globals(void)
+{
+ GlobalData surf;
+
+# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ surf.P = -cameraVec(worldPosition);
+ surf.N = surf.Ng = -surf.P;
+ surf.ray_length = 0.0;
+# else
+ surf.P = worldPosition;
+ surf.N = safe_normalize(worldNormal);
+ surf.Ng = safe_normalize(cross(dFdx(surf.P), dFdy(surf.P)));
+ surf.ray_length = distance(surf.P, cameraPos);
+# endif
+ surf.barycentric_coords = vec2(0.0);
+ surf.barycentric_dists = vec3(0.0);
+ if (!FrontFacing) {
+ surf.N = -surf.N;
+ }
+# ifdef HAIR_SHADER
+ /* Shade as a cylinder. */
+ vec3 B = normalize(cross(worldNormal, hairTangent));
+ float cos_theta;
+ if (hairThicknessRes == 1) {
+ /* Random cosine normal distribution on the hair surface. */
+ cos_theta = texelfetch_noise_tex(gl_FragCoord.xy).x * 2.0 - 1.0;
+ }
+ else {
+ /* Shade as a cylinder. */
+ cos_theta = hairThickTime / hairThickness;
+ }
+ float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
+ surf.N = safe_normalize(worldNormal * sin_theta + B * cos_theta);
+ surf.T = hairTangent;
+ surf.is_strand = true;
+ surf.hair_time = hairTime;
+ surf.hair_thickness = hairThickness;
+ surf.hair_strand_id = hairStrandID;
+# ifdef USE_BARYCENTRICS
+ surf.barycentric_coords = hair_resolve_barycentric(hairBary);
+# endif
+# else
+ surf.T = vec3(0.0);
+ surf.is_strand = false;
+ surf.hair_time = 0.0;
+ surf.hair_thickness = 0.0;
+ surf.hair_strand_id = 0;
+# ifdef USE_BARYCENTRICS
+ surf.barycentric_coords = gpu_BaryCoord.xy;
+ surf.barycentric_dists = barycentric_distances_get();
+# endif
+# endif
+ surf.ray_type = rayType;
+ surf.ray_depth = 0.0;
+ return surf;
+}
+#endif
+
+vec3 coordinate_camera(vec3 P)
+{
+ vec3 vP;
+#if defined(PROBE_CAPTURE)
+ /* Unsupported. It would make the probe camera-dependent. */
+ vP = P;
+#elif defined(WORLD_BACKGROUND)
+ vP = transform_direction(ViewMatrix, P);
+#else
+ vP = transform_point(ViewMatrix, P);
+#endif
+ vP.z = -vP.z;
+ return vP;
+}
+
+vec3 coordinate_screen(vec3 P)
+{
+ vec3 window = vec3(0.0);
+#if defined(PROBE_CAPTURE)
+ /* Unsupported. It would make the probe camera-dependent. */
+ window.xy = vec2(0.5);
+
+#elif defined(WORLD_BACKGROUND)
+ window.xy = project_point(ProjectionMatrix, viewPosition).xy * 0.5 + 0.5;
+ window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
+
+#else /* MESH */
+ window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
+ window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
+#endif
+ return window;
+}
+
+vec3 coordinate_reflect(vec3 P, vec3 N)
+{
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ return N;
+#else
+ return -reflect(cameraVec(P), N);
+#endif
+}
+
+vec3 coordinate_incoming(vec3 P)
+{
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+ return -P;
+#else
+ return cameraVec(P);
+#endif
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 51e9eda6cc2..6c6b810422b 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -1,6 +1,9 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl)
#pragma BLENDER_REQUIRE(surface_lib.glsl)
#ifndef HAIR_SHADER
@@ -18,6 +21,7 @@ void main()
#ifdef HAIR_SHADER
hairStrandID = hair_get_strand_id();
+ hairBary = hair_get_barycentric();
vec3 pos, binor;
hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0),
ModelMatrixInverse,
@@ -53,11 +57,103 @@ void main()
/* No need to normalize since this is just a rotation. */
viewNormal = normal_world_to_view(worldNormal);
-# ifdef USE_ATTR
-# ifdef HAIR_SHADER
- pos = hair_get_strand_pos();
-# endif
- pass_attr(pos, NormalMatrix, ModelMatrixInverse);
-# endif
+
+ attrib_load();
#endif
}
+
+#ifdef HAIR_SHADER
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(samplerBuffer cd_buf)
+{
+ vec3 P = hair_get_strand_pos();
+ vec3 lP = transform_point(ModelMatrixInverse, P);
+ return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
+}
+# endif
+
+vec4 attr_load_tangent(samplerBuffer cd_buf)
+{
+ return vec4(hairTangent, 1.0);
+}
+
+vec3 attr_load_uv(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgb;
+}
+
+vec4 attr_load_color(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgba;
+}
+
+vec4 attr_load_vec4(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgba;
+}
+
+vec3 attr_load_vec3(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rgb;
+}
+
+vec2 attr_load_vec2(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).rg;
+}
+
+float attr_load_float(samplerBuffer cd_buf)
+{
+ return texelFetch(cd_buf, hairStrandID).r;
+}
+
+#else
+
+# ifdef OBINFO_LIB
+vec3 attr_load_orco(vec4 orco)
+{
+ /* We know when there is no orco layer when orco.w is 1.0 because it uses the generic vertex
+ * attrib (which is [0,0,0,1]). */
+ if (orco.w == 0.0) {
+ return orco.xyz * 0.5 + 0.5;
+ }
+ else {
+ /* If the object does not have any deformation, the orco layer calculation is done on the fly
+ * using the orco_madd factors. */
+ return OrcoTexCoFactors[0].xyz + pos * OrcoTexCoFactors[1].xyz;
+ }
+}
+# endif
+
+vec4 attr_load_tangent(vec4 tangent)
+{
+ tangent.xyz = normal_object_to_world(tangent.xyz);
+ return tangent;
+}
+
+/* Simple passthrough. */
+vec4 attr_load_vec4(vec4 attr)
+{
+ return attr;
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return attr;
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return attr;
+}
+float attr_load_float(float attr)
+{
+ return attr;
+}
+vec4 attr_load_color(vec4 attr)
+{
+ return attr;
+}
+vec3 attr_load_uv(vec3 attr)
+{
+ return attr;
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index 4ff42892f7d..e0a79872928 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -1,6 +1,5 @@
#pragma BLENDER_REQUIRE(volumetric_lib.glsl)
-#pragma BLENDER_REQUIRE(closure_type_lib.glsl)
/* Based on Frosbite Unified Volumetric.
* https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */
@@ -18,9 +17,7 @@ flat in int slice;
vec3 worldPosition = vec3(0.0);
vec3 viewPosition = vec3(0.0);
vec3 viewNormal = vec3(0.0);
-#ifdef MESH_SHADER
-vec3 volumeObjectLocalCoord = vec3(0.0);
-#endif
+vec3 volumeOrco = vec3(0.0);
layout(location = 0) out vec4 volumeScattering;
layout(location = 1) out vec4 volumeExtinction;
@@ -29,6 +26,52 @@ layout(location = 3) out vec4 volumePhase;
/* Store volumetric properties into the froxel textures. */
+#ifdef MESH_SHADER
+GlobalData init_globals(void)
+{
+ GlobalData surf;
+ surf.P = worldPosition;
+ surf.N = vec3(0.0);
+ surf.Ng = vec3(0.0);
+ surf.is_strand = false;
+ surf.hair_time = 0.0;
+ surf.hair_thickness = 0.0;
+ surf.hair_strand_id = 0;
+ surf.barycentric_coords = vec2(0.0);
+ surf.barycentric_dists = vec3(0.0);
+ surf.ray_type = RAY_TYPE_CAMERA;
+ surf.ray_depth = 0.0;
+ surf.ray_length = distance(surf.P, cameraPos);
+ return surf;
+}
+
+vec3 coordinate_camera(vec3 P)
+{
+ vec3 vP;
+ vP = transform_point(ViewMatrix, P);
+ vP.z = -vP.z;
+ return vP;
+}
+
+vec3 coordinate_screen(vec3 P)
+{
+ vec3 window = vec3(0.0);
+ window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
+ window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
+ return window;
+}
+
+vec3 coordinate_reflect(vec3 P, vec3 N)
+{
+ return vec3(0.0);
+}
+
+vec3 coordinate_incoming(vec3 P)
+{
+ return cameraVec(P);
+}
+#endif
+
void main()
{
ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice);
@@ -37,14 +80,12 @@ void main()
viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
worldPosition = point_view_to_world(viewPosition);
#ifdef MESH_SHADER
- volumeObjectLocalCoord = point_world_to_object(worldPosition);
+ volumeOrco = point_world_to_object(worldPosition);
/* TODO: redundant transform */
- volumeObjectLocalCoord = (volumeObjectLocalCoord - volumeOrcoLoc + volumeOrcoSize) /
- (volumeOrcoSize * 2.0);
- volumeObjectLocalCoord = (volumeObjectToTexture * vec4(volumeObjectLocalCoord, 1.0)).xyz;
+ volumeOrco = (volumeOrco - volumeOrcoLoc + volumeOrcoSize) / (volumeOrcoSize * 2.0);
+ volumeOrco = (volumeObjectToTexture * vec4(volumeOrco, 1.0)).xyz;
- if (any(lessThan(volumeObjectLocalCoord, vec3(0.0))) ||
- any(greaterThan(volumeObjectLocalCoord, vec3(1.0)))) {
+ if (any(lessThan(volumeOrco, vec3(0.0))) || any(greaterThan(volumeOrco, vec3(1.0)))) {
/* Note: Discard is not an explicit return in Metal prior to versions 2.3.
* adding return after discard ensures consistent behaviour and avoids GPU
* side-effects where control flow continues with undefined values. */
@@ -54,21 +95,25 @@ void main()
#endif
#ifdef CLEAR
- Closure cl = CLOSURE_DEFAULT;
+ volumeScattering = vec4(0.0, 0.0, 0.0, 1.0);
+ volumeExtinction = vec4(0.0, 0.0, 0.0, 1.0);
+ volumeEmissive = vec4(0.0, 0.0, 0.0, 1.0);
+ volumePhase = vec4(0.0, 0.0, 0.0, 0.0);
#else
+# ifdef MESH_SHADER
+ g_data = init_globals();
+ attrib_load();
+# endif
Closure cl = nodetree_exec();
-#endif
-
-#ifdef MESH_SHADER
+# ifdef MESH_SHADER
cl.scatter *= volumeDensityScale;
cl.absorption *= volumeDensityScale;
cl.emission *= volumeDensityScale;
-#endif
+# endif
volumeScattering = vec4(cl.scatter, 1.0);
volumeExtinction = vec4(cl.absorption + cl.scatter, 1.0);
volumeEmissive = vec4(cl.emission, 1.0);
-
/* Do not add phase weight if no scattering. */
if (all(equal(cl.scatter, vec3(0.0)))) {
volumePhase = vec4(0.0);
@@ -76,4 +121,38 @@ void main()
else {
volumePhase = vec4(cl.anisotropy, vec3(1.0));
}
+#endif
+}
+
+vec3 attr_load_orco(vec4 orco)
+{
+ return volumeOrco;
+}
+vec4 attr_load_tangent(vec4 tangent)
+{
+ return vec4(0);
+}
+vec4 attr_load_vec4(vec4 attr)
+{
+ return vec4(0);
+}
+vec3 attr_load_vec3(vec3 attr)
+{
+ return vec3(0);
+}
+vec2 attr_load_vec2(vec2 attr)
+{
+ return vec2(0);
+}
+float attr_load_float(float attr)
+{
+ return 0.0;
+}
+vec4 attr_load_color(vec4 attr)
+{
+ return vec4(0);
+}
+vec3 attr_load_uv(vec3 attr)
+{
+ return vec3(0);
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
index 5226da57a06..1269761ffa4 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_geom.glsl
@@ -1,11 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#ifdef MESH_SHADER
-/* TODO: tight slices. */
-layout(triangles) in;
-layout(triangle_strip, max_vertices = 3) out;
-#else /* World */
+#ifdef STANDALONE
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index 527bbd18896..26b60c992e1 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -11,8 +11,10 @@ uniform sampler3D volumeScattering; /* Result of the scatter step */
uniform sampler3D volumeExtinction;
#ifdef USE_VOLUME_OPTI
-uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalScattering_img;
-uniform layout(r11f_g11f_b10f) writeonly restrict image3D finalTransmittance_img;
+uniform layout(r11f_g11f_b10f)
+writeonly restrict image3D finalScattering_img;
+uniform layout(r11f_g11f_b10f)
+writeonly restrict image3D finalTransmittance_img;
vec3 finalScattering;
vec3 finalTransmittance;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index b70747ecec3..b574e8cdb4c 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -30,8 +30,30 @@ void main()
vPos.w = 1.0;
PASS_RESOURCE_ID
+}
+
+/* Stubs */
+vec2 btdf_lut(float a, float b, float c)
+{
+ return vec2(0.0);
+}
+
+vec2 brdf_lut(float a, float b)
+{
+ return vec2(0.0);
+}
-#ifdef USE_ATTR
- pass_attr(vec3(0.0), mat3(1), mat4(1));
-#endif
+vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c)
+{
+ return vec3(0.0);
+}
+
+vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c)
+{
+ return vec3(0.0);
+}
+
+float F_eta(float a, float b)
+{
+ return 0.0;
}
diff --git a/source/blender/draw/engines/eevee/shaders/world_vert.glsl b/source/blender/draw/engines/eevee/shaders/world_vert.glsl
new file mode 100644
index 00000000000..29892a7ffb4
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/world_vert.glsl
@@ -0,0 +1,24 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+
+#pragma BLENDER_REQUIRE(closure_eval_surface_lib.glsl)
+
+in vec2 pos;
+
+RESOURCE_ID_VARYING
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ PASS_RESOURCE_ID
+
+ gl_Position = vec4(pos, 1.0, 1.0);
+ viewPosition = project_point(ProjectionMatrixInverse, vec3(pos, 0.0));
+ worldPosition = project_point(ViewProjectionMatrixInverse, vec3(pos, 0.0));
+ /* Not usable. */
+ viewNormal = vec3(0.0);
+ worldNormal = vec3(0.0);
+}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 1bf67a4f315..712118e8282 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -28,6 +28,7 @@
#include "DNA_world_types.h"
#include "GPU_framebuffer.h"
+#include "GPU_material.h"
#include "GPU_primitive.h"
#include "GPU_shader.h"
#include "GPU_storage_buffer.h"
@@ -197,13 +198,6 @@ void DRW_texture_free(struct GPUTexture *tex);
/* Shaders */
-typedef void (*GPUMaterialEvalCallbackFn)(struct GPUMaterial *mat,
- int options,
- const char **vert_code,
- const char **geom_code,
- const char **frag_lib,
- const char **defines);
-
struct GPUShader *DRW_shader_create_ex(
const char *vert, const char *geom, const char *frag, const char *defines, const char *name);
struct GPUShader *DRW_shader_create_with_lib_ex(const char *vert,
@@ -242,38 +236,20 @@ struct GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *fra
#define DRW_shader_create_fullscreen_with_shaderlib(frag, lib, defines) \
DRW_shader_create_fullscreen_with_shaderlib_ex(frag, lib, defines, __func__)
-struct GPUMaterial *DRW_shader_find_from_world(struct World *wo,
- const void *engine_type,
- int options,
- bool deferred);
-struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma,
- const void *engine_type,
- int options,
- bool deferred);
-struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
- struct World *wo,
- struct bNodeTree *ntree,
- const void *engine_type,
- int options,
- bool is_volume_shader,
- const char *vert,
- const char *geom,
- const char *frag_lib,
- const char *defines,
- bool deferred,
- GPUMaterialEvalCallbackFn callback);
-struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
- struct Material *ma,
- struct bNodeTree *ntree,
- const void *engine_type,
- int options,
- bool is_volume_shader,
- const char *vert,
- const char *geom,
- const char *frag_lib,
- const char *defines,
- bool deferred,
- GPUMaterialEvalCallbackFn callback);
+struct GPUMaterial *DRW_shader_from_world(struct World *wo,
+ struct bNodeTree *ntree,
+ const uint64_t shader_id,
+ const bool is_volume_shader,
+ bool deferred,
+ GPUCodegenCallbackFn callback,
+ void *thunk);
+struct GPUMaterial *DRW_shader_from_material(struct Material *ma,
+ struct bNodeTree *ntree,
+ const uint64_t shader_id,
+ const bool is_volume_shader,
+ bool deferred,
+ GPUCodegenCallbackFn callback,
+ void *thunk);
void DRW_shader_free(struct GPUShader *shader);
#define DRW_SHADER_FREE_SAFE(shader) \
do { \
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 0ac8bf91906..aac6f7e58c5 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -306,7 +306,7 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", hair_cache->final[subdiv].proc_tex);
if (hair_cache->length_tex) {
- DRW_shgroup_uniform_texture(shgrp, "hairLen", hair_cache->length_tex);
+ DRW_shgroup_uniform_texture(shgrp, "l", hair_cache->length_tex);
}
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 1936aa599ff..9f8a68f81f6 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -417,119 +417,81 @@ GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *frag,
return sh;
}
-GPUMaterial *DRW_shader_find_from_world(World *wo,
- const void *engine_type,
- const int options,
- bool deferred)
+GPUMaterial *DRW_shader_from_world(World *wo,
+ struct bNodeTree *ntree,
+ const uint64_t shader_id,
+ const bool is_volume_shader,
+ bool deferred,
+ GPUCodegenCallbackFn callback,
+ void *thunk)
{
- GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
- if (DRW_state_is_image_render() || !deferred) {
- if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
- /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
- * with the shader code and we will resume the compilation from there. */
- return NULL;
- }
- }
- return mat;
-}
-
-GPUMaterial *DRW_shader_find_from_material(Material *ma,
- const void *engine_type,
- const int options,
- bool deferred)
-{
- GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
- if (DRW_state_is_image_render() || !deferred) {
- if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) {
- /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX
- * with the shader code and we will resume the compilation from there. */
- return NULL;
- }
- }
- return mat;
-}
-
-GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
- World *wo,
- struct bNodeTree *ntree,
- const void *engine_type,
- const int options,
- const bool is_volume_shader,
- const char *vert,
- const char *geom,
- const char *frag_lib,
- const char *defines,
- bool deferred,
- GPUMaterialEvalCallbackFn callback)
-{
- GPUMaterial *mat = NULL;
- if (DRW_state_is_image_render() || !deferred) {
- mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
- }
-
- if (mat == NULL) {
- scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
- mat = GPU_material_from_nodetree(scene,
- NULL,
- ntree,
- &wo->gpumaterial,
- engine_type,
- options,
- is_volume_shader,
- vert,
- geom,
- frag_lib,
- defines,
- wo->id.name,
- callback);
+ Scene *scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
+ GPUMaterial *mat = GPU_material_from_nodetree(scene,
+ NULL,
+ ntree,
+ &wo->gpumaterial,
+ wo->id.name,
+ shader_id,
+ is_volume_shader,
+ false,
+ callback,
+ thunk);
+ if (!DRW_state_is_image_render() && deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* Shader has been already queued. */
+ return mat;
}
- if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ if (GPU_material_status(mat) == GPU_MAT_CREATED) {
+ GPU_material_status_set(mat, GPU_MAT_QUEUED);
drw_deferred_shader_add(mat, deferred);
}
+ if (!deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* Force compilation for shaders already queued. */
+ drw_deferred_shader_add(mat, false);
+ }
return mat;
}
-GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
- Material *ma,
- struct bNodeTree *ntree,
- const void *engine_type,
- const int options,
- const bool is_volume_shader,
- const char *vert,
- const char *geom,
- const char *frag_lib,
- const char *defines,
- bool deferred,
- GPUMaterialEvalCallbackFn callback)
+GPUMaterial *DRW_shader_from_material(Material *ma,
+ struct bNodeTree *ntree,
+ const uint64_t shader_id,
+ const bool is_volume_shader,
+ bool deferred,
+ GPUCodegenCallbackFn callback,
+ void *thunk)
{
- GPUMaterial *mat = NULL;
- if (DRW_state_is_image_render() || !deferred) {
- mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
+ Scene *scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
+ GPUMaterial *mat = GPU_material_from_nodetree(scene,
+ ma,
+ ntree,
+ &ma->gpumaterial,
+ ma->id.name,
+ shader_id,
+ is_volume_shader,
+ false,
+ callback,
+ thunk);
+
+ if (DRW_state_is_image_render()) {
+ /* Do not deferred if doing render. */
+ deferred = false;
}
- if (mat == NULL) {
- scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
- mat = GPU_material_from_nodetree(scene,
- ma,
- ntree,
- &ma->gpumaterial,
- engine_type,
- options,
- is_volume_shader,
- vert,
- geom,
- frag_lib,
- defines,
- ma->id.name,
- callback);
+ if (deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* Shader has been already queued. */
+ return mat;
}
- if (GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ if (GPU_material_status(mat) == GPU_MAT_CREATED) {
+ GPU_material_status_set(mat, GPU_MAT_QUEUED);
drw_deferred_shader_add(mat, deferred);
}
+ if (!deferred && GPU_material_status(mat) == GPU_MAT_QUEUED) {
+ /* Force compilation for shaders already queued. */
+ drw_deferred_shader_add(mat, false);
+ }
return mat;
}
@@ -552,15 +514,15 @@ void DRW_shader_free(GPUShader *shader)
* contains the needed libraries for this shader.
* \{ */
-/* 32 because we use a 32bit bitmap. */
-#define MAX_LIB 32
+/* 64 because we use a 64bit bitmap. */
+#define MAX_LIB 64
#define MAX_LIB_NAME 64
#define MAX_LIB_DEPS 8
struct DRWShaderLibrary {
const char *libs[MAX_LIB];
char libs_name[MAX_LIB][MAX_LIB_NAME];
- uint32_t libs_deps[MAX_LIB];
+ uint64_t libs_deps[MAX_LIB];
};
DRWShaderLibrary *DRW_shader_library_create(void)
@@ -589,23 +551,27 @@ static int drw_shader_library_search(const DRWShaderLibrary *lib, const char *na
}
/* Return bitmap of dependencies. */
-static uint32_t drw_shader_dependencies_get(const DRWShaderLibrary *lib, const char *lib_code)
+static uint64_t drw_shader_dependencies_get(const DRWShaderLibrary *lib,
+ const char *pragma_str,
+ const char *lib_code,
+ const char *UNUSED(lib_name))
{
/* Search dependencies. */
- uint32_t deps = 0;
+ uint pragma_len = strlen(pragma_str);
+ uint64_t deps = 0;
const char *haystack = lib_code;
- while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) {
- haystack += 16;
+ while ((haystack = strstr(haystack, pragma_str))) {
+ haystack += pragma_len;
int dep = drw_shader_library_search(lib, haystack);
if (dep == -1) {
- char dbg_name[33];
+ char dbg_name[MAX_NAME];
int i = 0;
while ((*haystack != ')') && (i < (sizeof(dbg_name) - 2))) {
dbg_name[i] = *haystack;
haystack++;
i++;
}
- dbg_name[i + 1] = '\0';
+ dbg_name[i] = '\0';
CLOG_INFO(&LOG,
0,
@@ -614,7 +580,7 @@ static uint32_t drw_shader_dependencies_get(const DRWShaderLibrary *lib, const c
dbg_name);
}
else {
- deps |= 1u << (uint32_t)dep;
+ deps |= 1llu << ((uint64_t)dep);
}
}
return deps;
@@ -633,7 +599,8 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, const char *lib_code, co
if (index > -1) {
lib->libs[index] = lib_code;
BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME);
- lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code);
+ lib->libs_deps[index] = drw_shader_dependencies_get(
+ lib, "BLENDER_REQUIRE(", lib_code, lib_name);
}
else {
printf("Error: Too many libraries. Cannot add %s.\n", lib_name);
@@ -643,21 +610,20 @@ void DRW_shader_library_add_file(DRWShaderLibrary *lib, const char *lib_code, co
char *DRW_shader_library_create_shader_string(const DRWShaderLibrary *lib, const char *shader_code)
{
- uint32_t deps = drw_shader_dependencies_get(lib, shader_code);
+ uint64_t deps = drw_shader_dependencies_get(lib, "BLENDER_REQUIRE(", shader_code, "shader code");
DynStr *ds = BLI_dynstr_new();
/* Add all dependencies recursively. */
for (int i = MAX_LIB - 1; i > -1; i--) {
- if (lib->libs[i] && (deps & (1u << (uint32_t)i))) {
+ if (lib->libs[i] && (deps & (1llu << (uint64_t)i))) {
deps |= lib->libs_deps[i];
}
}
/* Concatenate all needed libs into one string. */
- for (int i = 0; i < MAX_LIB; i++) {
- if (deps & 1u) {
+ for (int i = 0; i < MAX_LIB && deps != 0llu; i++, deps >>= 1llu) {
+ if (deps & 1llu) {
BLI_dynstr_append(ds, lib->libs[i]);
}
- deps = deps >> 1;
}
BLI_dynstr_append(ds, shader_code);
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index 5fc76bc25e6..58875c0496a 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -36,16 +36,19 @@ struct ViewInfos {
};
BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+/* Do not override old definitions if the shader uses this header but not shader info. */
+#ifdef USE_GPU_SHADER_CREATE_INFO
/* TODO(@fclem): Mass rename. */
-#define ViewProjectionMatrix drw_view.persmat
-#define ViewProjectionMatrixInverse drw_view.persinv
-#define ViewMatrix drw_view.viewmat
-#define ViewMatrixInverse drw_view.viewinv
-#define ProjectionMatrix drw_view.winmat
-#define ProjectionMatrixInverse drw_view.wininv
-#define clipPlanes drw_view.clip_planes
-#define ViewVecs drw_view.viewvecs
-#define CameraTexCoFactors drw_view.viewcamtexcofac
+# define ViewProjectionMatrix drw_view.persmat
+# define ViewProjectionMatrixInverse drw_view.persinv
+# define ViewMatrix drw_view.viewmat
+# define ViewMatrixInverse drw_view.viewinv
+# define ProjectionMatrix drw_view.winmat
+# define ProjectionMatrixInverse drw_view.wininv
+# define clipPlanes drw_view.clip_planes
+# define ViewVecs drw_view.viewvecs
+# define CameraTexCoFactors drw_view.viewcamtexcofac
+#endif
struct ObjectMatrices {
float4x4 drw_modelMatrix;
diff --git a/source/blender/draw/intern/shaders/common_attribute_lib.glsl b/source/blender/draw/intern/shaders/common_attribute_lib.glsl
new file mode 100644
index 00000000000..99db2929a13
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_attribute_lib.glsl
@@ -0,0 +1,21 @@
+
+/* Prototype of functions to implement to load attributes data.
+ * Implementation changes based on object data type. */
+
+vec3 attr_load_orco(vec4 orco);
+vec4 attr_load_tangent(vec4 tangent);
+vec3 attr_load_uv(vec3 uv);
+vec4 attr_load_color(vec4 color);
+vec4 attr_load_vec4(vec4 attr);
+vec3 attr_load_vec3(vec3 attr);
+vec2 attr_load_vec2(vec2 attr);
+float attr_load_float(float attr);
+
+vec3 attr_load_orco(samplerBuffer orco);
+vec4 attr_load_tangent(samplerBuffer tangent);
+vec3 attr_load_uv(samplerBuffer uv);
+vec4 attr_load_color(samplerBuffer color);
+vec4 attr_load_vec4(samplerBuffer attr);
+vec3 attr_load_vec3(samplerBuffer attr);
+vec2 attr_load_vec2(samplerBuffer attr);
+float attr_load_float(samplerBuffer attr);
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index 4d0ffaeb40f..1ac26c91b93 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -1,4 +1,8 @@
+/* WORKAROUND: to guard against double include in EEVEE. */
+#ifndef COMMON_MATH_LIB_GLSL
+#define COMMON_MATH_LIB_GLSL
+
/* ---------------------------------------------------------------------- */
/** \name Common Math Utilities
* \{ */
@@ -276,3 +280,5 @@ vec3 hue_gradient(float t)
vec3 p = abs(fract(t + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0);
return (clamp(p - 1.0, 0.0, 1.0));
}
+
+#endif /* COMMON_MATH_LIB_GLSL */
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index a2b8cb4bbd6..4086162a530 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -1,5 +1,10 @@
+
+/* WORKAROUND: to guard against double include in EEVEE. */
+#ifndef COMMON_VIEW_LIB_GLSL
+#define COMMON_VIEW_LIB_GLSL
+
/* Temporary until we fully make the switch. */
-#ifndef USE_GPU_SHADER_CREATE_INFO
+#if !defined(USE_GPU_SHADER_CREATE_INFO)
# define DRW_RESOURCE_CHUNK_LEN 512
@@ -37,7 +42,10 @@ layout(std140) uniform viewBlock
#define cameraForward ViewMatrixInverse[2].xyz
#define cameraPos ViewMatrixInverse[3].xyz
-#define cameraVec(P) ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - P) : cameraForward)
+vec3 cameraVec(vec3 P)
+{
+ return ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - P) : cameraForward);
+}
#define viewCameraVec(vP) ((ProjectionMatrix[3][3] == 0.0) ? normalize(-vP) : vec3(0.0, 0.0, 1.0))
#ifdef world_clip_planes_calc_clip_distance
@@ -92,14 +100,14 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos)
}
/* Temporary until we fully make the switch. */
-#ifndef DRW_SHADER_SHARED_H
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform int drw_resourceChunk;
-#endif /* DRW_SHADER_SHARED_H */
+#endif /* USE_GPU_SHADER_CREATE_INFO */
#ifdef GPU_VERTEX_SHADER
/* Temporary until we fully make the switch. */
-# ifndef DRW_SHADER_SHARED_H
+# ifndef USE_GPU_SHADER_CREATE_INFO
/* clang-format off */
# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR) || defined(DRW_LEGACY_MODEL_MATRIX) || defined(GPU_DEPRECATED_AMD_DRIVER)
@@ -121,7 +129,10 @@ uniform int drw_ResourceID;
/* Use this to declare and pass the value if
* the fragment shader uses the resource_id. */
-# ifdef USE_GEOMETRY_SHADER
+# if defined(EEVEE_GENERATED_INTERFACE)
+# define RESOURCE_ID_VARYING
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# elif defined(USE_GEOMETRY_SHADER)
# define RESOURCE_ID_VARYING flat out int resourceIDGeom;
# define PASS_RESOURCE_ID resourceIDGeom = resource_id;
# else
@@ -129,12 +140,12 @@ uniform int drw_ResourceID;
# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
# endif
-# endif /* DRW_SHADER_SHARED_H */
+# endif /* USE_GPU_SHADER_CREATE_INFO */
#endif /* GPU_VERTEX_SHADER */
/* Temporary until we fully make the switch. */
-#ifdef DRW_SHADER_SHARED_H
+#ifdef USE_GPU_SHADER_CREATE_INFO
/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */
# if defined(UNIFORM_RESOURCE_ID)
# define resource_id drw_ResourceID
@@ -159,16 +170,23 @@ uniform int drw_ResourceID;
/* If used in a fragment / geometry shader, we pass
* resource_id as varying. */
# ifdef GPU_GEOMETRY_SHADER
-# define RESOURCE_ID_VARYING \
- flat out int resourceIDFrag; \
- flat in int resourceIDGeom[];
+/* TODO(fclem): Remove. This is getting ridiculous. */
+# if !defined(EEVEE_GENERATED_INTERFACE)
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
+# else
+# define RESOURCE_ID_VARYING
+# endif
# define resource_id resourceIDGeom
# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
# endif
-# ifdef GPU_FRAGMENT_SHADER
+# if defined(GPU_FRAGMENT_SHADER)
+# if !defined(EEVEE_GENERATED_INTERFACE)
flat in int resourceIDFrag;
+# endif
# define resource_id resourceIDFrag
# endif
#endif
@@ -185,7 +203,9 @@ struct ObjectMatrices {
mat4 drw_modelMatrix;
mat4 drw_modelMatrixInverse;
};
+# endif /* DRW_SHADER_SHARED_H */
+# ifndef USE_GPU_SHADER_CREATE_INFO
layout(std140) uniform modelBlock
{
ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
@@ -193,24 +213,24 @@ layout(std140) uniform modelBlock
# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
-# endif /* DRW_SHADER_SHARED_H */
+# endif /* USE_GPU_SHADER_CREATE_INFO */
#else /* GPU_INTEL */
/* Temporary until we fully make the switch. */
-# ifndef DRW_SHADER_SHARED_H
+# ifndef USE_GPU_SHADER_CREATE_INFO
/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
* So for now we just force using the legacy path. */
/* Note that this is also a workaround of a problem on osx (amd or nvidia)
* and older amd driver on windows. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
-# endif /* DRW_SHADER_SHARED_H */
+# endif /* USE_GPU_SHADER_CREATE_INFO */
#endif
/* Temporary until we fully make the switch. */
-#ifndef DRW_SHADER_SHARED_H
+#ifndef USE_GPU_SHADER_CREATE_INFO
# define resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
#endif
@@ -337,3 +357,5 @@ vec3 get_view_vector_from_screen_uv(vec2 uv)
return vec3(0.0, 0.0, 1.0);
}
}
+
+#endif /* COMMON_VIEW_LIB_GLSL */
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 3e12426acdc..98d15a1024c 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -46,7 +46,7 @@ set(SRC
intern/gpu_batch_utils.c
intern/gpu_buffers.c
intern/gpu_capabilities.cc
- intern/gpu_codegen.c
+ intern/gpu_codegen.cc
intern/gpu_compute.cc
intern/gpu_context.cc
intern/gpu_debug.cc
@@ -57,7 +57,6 @@ set(SRC
intern/gpu_index_buffer.cc
intern/gpu_init_exit.c
intern/gpu_material.c
- intern/gpu_material_library.c
intern/gpu_matrix.cc
intern/gpu_node_graph.c
intern/gpu_platform.cc
@@ -312,6 +311,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_glass.glsl
shaders/material/gpu_shader_material_glossy.glsl
shaders/material/gpu_shader_material_hair_info.glsl
+ shaders/material/gpu_shader_material_hair.glsl
shaders/material/gpu_shader_material_hash.glsl
shaders/material/gpu_shader_material_holdout.glsl
shaders/material/gpu_shader_material_hue_sat_val.glsl
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 9b63d0feb1e..f38b9681ad7 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -13,6 +13,7 @@
#include "BLI_sys_types.h" /* for bool */
+#include "GPU_shader.h" /* for GPUShaderCreateInfo */
#include "GPU_texture.h" /* for eGPUSamplerState */
#ifdef __cplusplus
@@ -58,8 +59,6 @@ typedef enum eGPUType {
GPU_TEX2D = 1002,
GPU_TEX2D_ARRAY = 1003,
GPU_TEX3D = 1004,
- GPU_SHADOW2D = 1005,
- GPU_TEXCUBE = 1006,
/* GLSL Struct types */
GPU_CLOSURE = 1007,
@@ -68,35 +67,30 @@ typedef enum eGPUType {
GPU_ATTR = 3001,
} eGPUType;
-typedef enum eGPUBuiltin {
- GPU_VIEW_MATRIX = (1 << 0),
- GPU_OBJECT_MATRIX = (1 << 1),
- GPU_INVERSE_VIEW_MATRIX = (1 << 2),
- GPU_INVERSE_OBJECT_MATRIX = (1 << 3),
- GPU_VIEW_POSITION = (1 << 4),
- GPU_VIEW_NORMAL = (1 << 5),
- GPU_OBJECT_COLOR = (1 << 6),
- GPU_AUTO_BUMPSCALE = (1 << 7),
- GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
- GPU_PARTICLE_SCALAR_PROPS = (1 << 9),
- GPU_PARTICLE_LOCATION = (1 << 10),
- GPU_PARTICLE_VELOCITY = (1 << 11),
- GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
- GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
- GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
- GPU_OBJECT_INFO = (1 << 15),
- GPU_BARYCENTRIC_TEXCO = (1 << 16),
- GPU_BARYCENTRIC_DIST = (1 << 17),
- GPU_WORLD_NORMAL = (1 << 18),
-} eGPUBuiltin;
-
-typedef enum eGPUMatFlag {
+typedef enum eGPUMaterialFlag {
GPU_MATFLAG_DIFFUSE = (1 << 0),
- GPU_MATFLAG_GLOSSY = (1 << 1),
- GPU_MATFLAG_REFRACT = (1 << 2),
- GPU_MATFLAG_SSS = (1 << 3),
- GPU_MATFLAG_BARYCENTRIC = (1 << 4),
-} eGPUMatFlag;
+ GPU_MATFLAG_SUBSURFACE = (1 << 1),
+ GPU_MATFLAG_GLOSSY = (1 << 2),
+ GPU_MATFLAG_REFRACT = (1 << 3),
+ GPU_MATFLAG_EMISSION = (1 << 4),
+ GPU_MATFLAG_TRANSPARENT = (1 << 5),
+ GPU_MATFLAG_HOLDOUT = (1 << 6),
+ GPU_MATFLAG_SHADER_TO_RGBA = (1 << 7),
+ GPU_MATFLAG_AO = (1 << 8),
+
+ GPU_MATFLAG_OBJECT_INFO = (1 << 10),
+ GPU_MATFLAG_AOV = (1 << 11),
+
+ GPU_MATFLAG_BARYCENTRIC = (1 << 20),
+
+ /* Tells the render engine the material was just compiled or updated. */
+ GPU_MATFLAG_UPDATED = (1 << 29),
+
+ /* HACK(fclem) Tells the environment texture node to not bail out if empty. */
+ GPU_MATFLAG_LOOKDEV_HACK = (1 << 30),
+} eGPUMaterialFlag;
+
+ENUM_OPERATORS(eGPUMaterialFlag, GPU_MATFLAG_LOOKDEV_HACK);
typedef struct GPUNodeStack {
eGPUType type;
@@ -110,6 +104,7 @@ typedef struct GPUNodeStack {
typedef enum eGPUMaterialStatus {
GPU_MAT_FAILED = 0,
+ GPU_MAT_CREATED,
GPU_MAT_QUEUED,
GPU_MAT_SUCCESS,
} eGPUMaterialStatus;
@@ -119,12 +114,19 @@ typedef enum eGPUVolumeDefaultValue {
GPU_VOLUME_DEFAULT_1,
} eGPUVolumeDefaultValue;
-typedef void (*GPUMaterialEvalCallbackFn)(GPUMaterial *mat,
- int options,
- const char **vert_code,
- const char **geom_code,
- const char **frag_lib,
- const char **defines);
+typedef struct GPUCodegenOutput {
+ char *attr_load;
+ /* Nodetree functions calls. */
+ char *displacement;
+ char *surface;
+ char *volume;
+ char *thickness;
+ char *material_functions;
+
+ GPUShaderCreateInfo *create_info;
+} GPUCodegenOutput;
+
+typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOutput *codegen);
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
@@ -143,7 +145,12 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro
GPUNodeLink *GPU_volume_grid(GPUMaterial *mat,
const char *name,
eGPUVolumeDefaultValue default_value);
-GPUNodeLink *GPU_builtin(eGPUBuiltin builtin);
+/**
+ * Create an implementation defined differential calculation of a float function.
+ * The given function should return a float.
+ * The result will be a vec2 containing dFdx and dFdy result of that function.
+ */
+GPUNodeLink *GPU_differentiate_float_function(const char *function_name);
bool GPU_link(GPUMaterial *mat, const char *name, ...);
bool GPU_stack_link(GPUMaterial *mat,
@@ -157,10 +164,26 @@ GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat,
struct GPUNodeStack *stack,
int index);
-void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link);
+void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link);
+
void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash);
-void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]);
+/**
+ * Wrap a part of the material graph into a function. You need then need to call the function by
+ * using something like #GPU_differentiate_float_function.
+ * \note This replace the link by a constant to break the link with the main graph.
+ * \param return_type: sub function return type. Output is cast to this type.
+ * \param link: link to use as the sub function output.
+ * \return the name of the generated function.
+ */
+char *GPU_material_split_sub_function(GPUMaterial *material,
+ eGPUType return_type,
+ GPUNodeLink **link);
+
+bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3]);
struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
int sample_len,
struct GPUTexture **tex_profile);
@@ -180,15 +203,13 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
struct ListBase *gpumaterials,
- const void *engine_type,
- int options,
- bool is_volume_shader,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines,
const char *name,
- GPUMaterialEvalCallbackFn callback);
+ uint64_t shader_uuid,
+ bool is_volume_shader,
+ bool is_lookdev,
+ GPUCodegenCallbackFn callback,
+ void *thunk);
+
void GPU_material_compile(GPUMaterial *mat);
void GPU_material_free(struct ListBase *gpumaterial);
@@ -205,6 +226,7 @@ struct Material *GPU_material_get_material(GPUMaterial *material);
* Return true if the material compilation has not yet begin or begin.
*/
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
+void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status);
struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
/**
@@ -215,13 +237,15 @@ struct GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material);
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs);
struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void);
+bool GPU_material_is_volume_shader(GPUMaterial *mat);
bool GPU_material_has_surface_output(GPUMaterial *mat);
bool GPU_material_has_volume_output(GPUMaterial *mat);
-bool GPU_material_is_volume_shader(GPUMaterial *mat);
-
-void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag);
-bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag);
+void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag);
+bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag);
+eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat);
+bool GPU_material_recalc_flag_get(GPUMaterial *mat);
+uint64_t GPU_material_uuid_get(GPUMaterial *mat);
void GPU_pass_cache_init(void);
void GPU_pass_cache_garbage_collect(void);
diff --git a/source/blender/gpu/GPU_uniform_buffer.h b/source/blender/gpu/GPU_uniform_buffer.h
index c47be05a646..f78719d1963 100644
--- a/source/blender/gpu/GPU_uniform_buffer.h
+++ b/source/blender/gpu/GPU_uniform_buffer.h
@@ -42,8 +42,8 @@ void GPU_uniformbuf_bind(GPUUniformBuf *ubo, int slot);
void GPU_uniformbuf_unbind(GPUUniformBuf *ubo);
void GPU_uniformbuf_unbind_all(void);
-#define GPU_UBO_BLOCK_NAME "nodeTree"
-#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "uniformAttrs"
+#define GPU_UBO_BLOCK_NAME "node_tree"
+#define GPU_ATTRIBUTE_UBO_BLOCK_NAME "unf_attrs"
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
deleted file mode 100644
index e462308d3ee..00000000000
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2005 Blender Foundation. All rights reserved. */
-
-/** \file
- * \ingroup gpu
- *
- * Convert material node-trees to GLSL.
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_customdata_types.h"
-#include "DNA_image_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_ghash.h"
-#include "BLI_hash_mm2a.h"
-#include "BLI_link_utils.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
-#include "PIL_time.h"
-
-#include "BKE_material.h"
-
-#include "GPU_capabilities.h"
-#include "GPU_material.h"
-#include "GPU_shader.h"
-#include "GPU_uniform_buffer.h"
-#include "GPU_vertex_format.h"
-
-#include "BLI_sys_types.h" /* for intptr_t support */
-
-#include "gpu_codegen.h"
-#include "gpu_material_library.h"
-#include "gpu_node_graph.h"
-
-#include <stdarg.h>
-#include <string.h>
-
-extern char datatoc_gpu_shader_codegen_lib_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
-
-/* -------------------- GPUPass Cache ------------------ */
-/**
- * Internal shader cache: This prevent the shader recompilation / stall when
- * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
- * same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
- */
-
-/* Only use one linked-list that contains the GPUPasses grouped by hash. */
-static GPUPass *pass_cache = NULL;
-static SpinLock pass_cache_spin;
-
-static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, ListBase *attributes)
-{
- BLI_HashMurmur2A hm2a;
- BLI_hash_mm2a_init(&hm2a, 0);
- BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen));
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attributes) {
- BLI_hash_mm2a_add(&hm2a, (uchar *)attr->name, strlen(attr->name));
- }
- if (defs) {
- BLI_hash_mm2a_add(&hm2a, (uchar *)defs, strlen(defs));
- }
-
- return BLI_hash_mm2a_end(&hm2a);
-}
-
-/* Search by hash only. Return first pass with the same hash.
- * There is hash collision if (pass->next && pass->next->hash == hash) */
-static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
-{
- BLI_spin_lock(&pass_cache_spin);
- /* Could be optimized with a Lookup table. */
- for (GPUPass *pass = pass_cache; pass; pass = pass->next) {
- if (pass->hash == hash) {
- BLI_spin_unlock(&pass_cache_spin);
- return pass;
- }
- }
- BLI_spin_unlock(&pass_cache_spin);
- return NULL;
-}
-
-/* Check all possible passes with the same hash. */
-static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass,
- const char *vert,
- const char *geom,
- const char *frag,
- const char *defs,
- uint32_t hash)
-{
- BLI_spin_lock(&pass_cache_spin);
- /* Collision, need to `strcmp` the whole shader. */
- for (; pass && (pass->hash == hash); pass = pass->next) {
- if ((defs != NULL) && (!STREQ(pass->defines, defs))) { /* Pass */
- }
- else if ((geom != NULL) && (!STREQ(pass->geometrycode, geom))) { /* Pass */
- }
- else if ((!STREQ(pass->fragmentcode, frag) == 0) && (STREQ(pass->vertexcode, vert))) {
- BLI_spin_unlock(&pass_cache_spin);
- return pass;
- }
- }
- BLI_spin_unlock(&pass_cache_spin);
- return NULL;
-}
-
-/* GLSL code generation */
-
-static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *tmp, int id)
-{
- char name[1024];
-
- BLI_snprintf(name, sizeof(name), "%s%d", tmp, id);
-
- if (from == to) {
- BLI_dynstr_append(ds, name);
- }
- else if (to == GPU_FLOAT) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.2126, 0.7152, 0.0722))", name);
- }
- else if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "%s.r", name);
- }
- }
- else if (to == GPU_VEC2) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name);
- }
- else if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name);
- }
- }
- else if (to == GPU_VEC3) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "%s.rgb", name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name);
- }
- }
- else if (to == GPU_VEC4) {
- if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
- }
- }
- else if (to == GPU_CLOSURE) {
- if (from == GPU_VEC4) {
- BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
- }
- else if (from == GPU_VEC3) {
- BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
- }
- else if (from == GPU_VEC2) {
- BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name);
- }
- else if (from == GPU_FLOAT) {
- BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name);
- }
- }
- else {
- BLI_dynstr_append(ds, name);
- }
-}
-
-static void codegen_print_datatype(DynStr *ds, const eGPUType type, float *data)
-{
- int i;
-
- BLI_dynstr_appendf(ds, "%s(", gpu_data_type_to_string(type));
-
- for (i = 0; i < type; i++) {
- BLI_dynstr_appendf(ds, "%.12f", data[i]);
- if (i == type - 1) {
- BLI_dynstr_append(ds, ")");
- }
- else {
- BLI_dynstr_append(ds, ", ");
- }
- }
-}
-
-static const char *gpu_builtin_name(eGPUBuiltin builtin)
-{
- if (builtin == GPU_VIEW_MATRIX) {
- return "unfviewmat";
- }
- if (builtin == GPU_OBJECT_MATRIX) {
- return "unfobmat";
- }
- if (builtin == GPU_INVERSE_VIEW_MATRIX) {
- return "unfinvviewmat";
- }
- if (builtin == GPU_INVERSE_OBJECT_MATRIX) {
- return "unfinvobmat";
- }
- if (builtin == GPU_LOC_TO_VIEW_MATRIX) {
- return "unflocaltoviewmat";
- }
- if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- return "unfinvlocaltoviewmat";
- }
- if (builtin == GPU_VIEW_POSITION) {
- return "varposition";
- }
- if (builtin == GPU_WORLD_NORMAL) {
- return "varwnormal";
- }
- if (builtin == GPU_VIEW_NORMAL) {
- return "varnormal";
- }
- if (builtin == GPU_OBJECT_COLOR) {
- return "unfobjectcolor";
- }
- if (builtin == GPU_AUTO_BUMPSCALE) {
- return "unfobautobumpscale";
- }
- if (builtin == GPU_CAMERA_TEXCO_FACTORS) {
- return "unfcameratexfactors";
- }
- if (builtin == GPU_PARTICLE_SCALAR_PROPS) {
- return "unfparticlescalarprops";
- }
- if (builtin == GPU_PARTICLE_LOCATION) {
- return "unfparticleco";
- }
- if (builtin == GPU_PARTICLE_VELOCITY) {
- return "unfparticlevel";
- }
- if (builtin == GPU_PARTICLE_ANG_VELOCITY) {
- return "unfparticleangvel";
- }
- if (builtin == GPU_OBJECT_INFO) {
- return "unfobjectinfo";
- }
- if (builtin == GPU_BARYCENTRIC_TEXCO) {
- return "unfbarycentrictex";
- }
- if (builtin == GPU_BARYCENTRIC_DIST) {
- return "unfbarycentricdist";
- }
- return "";
-}
-
-static void codegen_set_unique_ids(GPUNodeGraph *graph)
-{
- int id = 1;
-
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- /* set id for unique names of uniform variables */
- input->id = id++;
- }
-
- LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
- /* set id for unique names of tmp variables storing output */
- output->id = id++;
- }
- }
-}
-
-/**
- * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO.
- */
-static int codegen_process_uniforms_functions(GPUMaterial *material,
- DynStr *ds,
- GPUNodeGraph *graph)
-{
- const char *name;
- int builtins = 0;
- ListBase ubo_inputs = {NULL, NULL};
-
- /* Textures */
- LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph->textures) {
- if (tex->colorband) {
- BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->sampler_name);
- }
- else if (tex->tiled_mapping_name[0]) {
- BLI_dynstr_appendf(ds, "uniform sampler2DArray %s;\n", tex->sampler_name);
- BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->tiled_mapping_name);
- }
- else {
- BLI_dynstr_appendf(ds, "uniform sampler2D %s;\n", tex->sampler_name);
- }
- }
-
- /* Volume Grids */
- LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
- BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name);
- BLI_dynstr_appendf(ds, "uniform mat4 %s = mat4(0.0);\n", grid->transform_name);
- }
-
- /* Print other uniforms */
-
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- if (input->source == GPU_SOURCE_BUILTIN) {
- /* only define each builtin uniform/varying once */
- if (!(builtins & input->builtin)) {
- builtins |= input->builtin;
- name = gpu_builtin_name(input->builtin);
-
- if (BLI_str_startswith(name, "unf")) {
- BLI_dynstr_appendf(ds, "uniform %s %s;\n", gpu_data_type_to_string(input->type), name);
- }
- else {
- BLI_dynstr_appendf(ds, "in %s %s;\n", gpu_data_type_to_string(input->type), name);
- }
- }
- }
- else if (input->source == GPU_SOURCE_STRUCT) {
- /* Add other struct here if needed. */
- BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id);
- }
- else if (input->source == GPU_SOURCE_UNIFORM) {
- if (!input->link) {
- /* We handle the UBOuniforms separately. */
- BLI_addtail(&ubo_inputs, BLI_genericNodeN(input));
- }
- }
- else if (input->source == GPU_SOURCE_CONSTANT) {
- BLI_dynstr_appendf(
- ds, "const %s cons%d = ", gpu_data_type_to_string(input->type), input->id);
- codegen_print_datatype(ds, input->type, input->vec);
- BLI_dynstr_append(ds, ";\n");
- }
- }
- }
-
- /* Handle the UBO block separately. */
- if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) {
- GPU_material_uniform_buffer_create(material, &ubo_inputs);
-
- /* Inputs are sorted */
- BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME);
-
- LISTBASE_FOREACH (LinkData *, link, &ubo_inputs) {
- GPUInput *input = (GPUInput *)(link->data);
- BLI_dynstr_appendf(ds, " %s unf%d;\n", gpu_data_type_to_string(input->type), input->id);
- }
- BLI_dynstr_append(ds, "};\n");
- BLI_freelistN(&ubo_inputs);
- }
-
- /* Generate the uniform attribute UBO if necessary. */
- if (!BLI_listbase_is_empty(&graph->uniform_attrs.list)) {
- BLI_dynstr_append(ds, "\nstruct UniformAttributes {\n");
- LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph->uniform_attrs.list) {
- BLI_dynstr_appendf(ds, " vec4 attr%d;\n", attr->id);
- }
- BLI_dynstr_append(ds, "};\n");
- BLI_dynstr_appendf(ds, "layout (std140) uniform %s {\n", GPU_ATTRIBUTE_UBO_BLOCK_NAME);
- BLI_dynstr_append(ds, " UniformAttributes uniform_attrs[DRW_RESOURCE_CHUNK_LEN];\n");
- BLI_dynstr_append(ds, "};\n");
- BLI_dynstr_append(ds, "#define GET_UNIFORM_ATTR(name) (uniform_attrs[resource_id].name)\n");
- }
-
- BLI_dynstr_append(ds, "\n");
-
- return builtins;
-}
-
-static void codegen_declare_tmps(DynStr *ds, GPUNodeGraph *graph)
-{
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- /* declare temporary variables for node output storage */
- LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
- if (output->type == GPU_CLOSURE) {
- BLI_dynstr_appendf(ds, " Closure tmp%d;\n", output->id);
- }
- else {
- BLI_dynstr_appendf(ds, " %s tmp%d;\n", gpu_data_type_to_string(output->type), output->id);
- }
- }
- }
- BLI_dynstr_append(ds, "\n");
-}
-
-static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph)
-{
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- BLI_dynstr_appendf(ds, " %s(", node->name);
-
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- if (input->source == GPU_SOURCE_TEX) {
- BLI_dynstr_append(ds, input->texture->sampler_name);
- }
- else if (input->source == GPU_SOURCE_TEX_TILED_MAPPING) {
- BLI_dynstr_append(ds, input->texture->tiled_mapping_name);
- }
- else if (input->source == GPU_SOURCE_VOLUME_GRID) {
- BLI_dynstr_append(ds, input->volume_grid->sampler_name);
- }
- else if (input->source == GPU_SOURCE_VOLUME_GRID_TRANSFORM) {
- BLI_dynstr_append(ds, input->volume_grid->transform_name);
- }
- else if (input->source == GPU_SOURCE_OUTPUT) {
- codegen_convert_datatype(
- ds, input->link->output->type, input->type, "tmp", input->link->output->id);
- }
- else if (input->source == GPU_SOURCE_BUILTIN) {
- /* TODO(fclem): get rid of that. */
- if (input->builtin == GPU_INVERSE_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "viewinv");
- }
- else if (input->builtin == GPU_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "viewmat");
- }
- else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) {
- BLI_dynstr_append(ds, "camtexfac");
- }
- else if (input->builtin == GPU_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "localtoviewmat");
- }
- else if (input->builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, "invlocaltoviewmat");
- }
- else if (input->builtin == GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "barycentricDist");
- }
- else if (input->builtin == GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "barytexco");
- }
- else if (input->builtin == GPU_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, "objmat");
- }
- else if (input->builtin == GPU_OBJECT_INFO) {
- BLI_dynstr_append(ds, "ObjectInfo");
- }
- else if (input->builtin == GPU_OBJECT_COLOR) {
- BLI_dynstr_append(ds, "ObjectColor");
- }
- else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, "objinv");
- }
- else if (input->builtin == GPU_VIEW_POSITION) {
- BLI_dynstr_append(ds, "viewposition");
- }
- else if (input->builtin == GPU_VIEW_NORMAL) {
- BLI_dynstr_append(ds, "facingnormal");
- }
- else if (input->builtin == GPU_WORLD_NORMAL) {
- BLI_dynstr_append(ds, "facingwnormal");
- }
- else {
- BLI_dynstr_append(ds, gpu_builtin_name(input->builtin));
- }
- }
- else if (input->source == GPU_SOURCE_STRUCT) {
- BLI_dynstr_appendf(ds, "strct%d", input->id);
- }
- else if (input->source == GPU_SOURCE_UNIFORM) {
- BLI_dynstr_appendf(ds, "unf%d", input->id);
- }
- else if (input->source == GPU_SOURCE_CONSTANT) {
- BLI_dynstr_appendf(ds, "cons%d", input->id);
- }
- else if (input->source == GPU_SOURCE_ATTR) {
- codegen_convert_datatype(ds, input->attr->gputype, input->type, "var", input->attr->id);
- }
- else if (input->source == GPU_SOURCE_UNIFORM_ATTR) {
- BLI_dynstr_appendf(ds, "GET_UNIFORM_ATTR(attr%d)", input->uniform_attr->id);
- }
-
- BLI_dynstr_append(ds, ", ");
- }
-
- LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
- BLI_dynstr_appendf(ds, "tmp%d", output->id);
- if (output->next) {
- BLI_dynstr_append(ds, ", ");
- }
- }
-
- BLI_dynstr_append(ds, ");\n");
- }
-}
-
-static void codegen_final_output(DynStr *ds, GPUOutput *finaloutput)
-{
- BLI_dynstr_appendf(ds, "return tmp%d;\n", finaloutput->id);
-}
-
-static char *code_generate_fragment(GPUMaterial *material,
- GPUNodeGraph *graph,
- const char *interface_str)
-{
- DynStr *ds = BLI_dynstr_new();
- char *code;
- int builtins;
-
- codegen_set_unique_ids(graph);
-
- /* Attributes, Shader stage interface. */
- if (interface_str) {
- BLI_dynstr_appendf(ds, "in codegenInterface {%s};\n\n", interface_str);
- }
-
- builtins = codegen_process_uniforms_functions(material, ds, graph);
-
- if (builtins & (GPU_OBJECT_INFO | GPU_OBJECT_COLOR)) {
- BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
- }
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
- }
-
- BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n");
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, " vec2 barytexco = barycentric_resolve(barycentricTexCo);\n");
- }
- /* TODO(fclem): get rid of that. */
- if (builtins & GPU_VIEW_MATRIX) {
- BLI_dynstr_append(ds, " #define viewmat ViewMatrix\n");
- }
- if (builtins & GPU_CAMERA_TEXCO_FACTORS) {
- BLI_dynstr_append(ds, " #define camtexfac CameraTexCoFactors\n");
- }
- if (builtins & GPU_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, " #define objmat ModelMatrix\n");
- }
- if (builtins & GPU_INVERSE_OBJECT_MATRIX) {
- BLI_dynstr_append(ds, " #define objinv ModelMatrixInverse\n");
- }
- if (builtins & GPU_INVERSE_VIEW_MATRIX) {
- BLI_dynstr_append(ds, " #define viewinv ViewMatrixInverse\n");
- }
- if (builtins & GPU_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds, " #define localtoviewmat (ViewMatrix * ModelMatrix)\n");
- }
- if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
- BLI_dynstr_append(ds,
- " #define invlocaltoviewmat (ModelMatrixInverse * ViewMatrixInverse)\n");
- }
- if (builtins & GPU_VIEW_NORMAL) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, " vec3 n;\n");
- BLI_dynstr_append(ds, " world_normals_get(n);\n");
- BLI_dynstr_append(ds, " vec3 facingnormal = transform_direction(ViewMatrix, n);\n");
- BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, " vec3 facingnormal = gl_FrontFacing ? viewNormal: -viewNormal;\n");
- BLI_dynstr_append(ds, "#endif\n");
- }
- if (builtins & GPU_WORLD_NORMAL) {
- BLI_dynstr_append(ds, " vec3 facingwnormal;\n");
- if (builtins & GPU_VIEW_NORMAL) {
- BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n");
- BLI_dynstr_append(ds, " facingwnormal = n;\n");
- BLI_dynstr_append(ds, "#else\n");
- BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n");
- BLI_dynstr_append(ds, "#endif\n");
- }
- else {
- BLI_dynstr_append(ds, " world_normals_get(facingwnormal);\n");
- }
- }
- if (builtins & GPU_VIEW_POSITION) {
- BLI_dynstr_append(ds, " #define viewposition viewPosition\n");
- }
-
- codegen_declare_tmps(ds, graph);
- codegen_call_functions(ds, graph);
-
- BLI_dynstr_append(ds, " #ifndef VOLUMETRICS\n");
- BLI_dynstr_append(ds, " if (renderPassAOV) {\n");
- BLI_dynstr_append(ds, " switch (render_pass_aov_hash()) {\n");
- GSet *aovhashes_added = BLI_gset_int_new(__func__);
- LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
- void *aov_key = POINTER_FROM_INT(aovlink->hash);
- if (BLI_gset_haskey(aovhashes_added, aov_key)) {
- continue;
- }
- BLI_dynstr_appendf(ds, " case %d: {\n ", aovlink->hash);
- codegen_final_output(ds, aovlink->outlink->output);
- BLI_dynstr_append(ds, " }\n");
- BLI_gset_add(aovhashes_added, aov_key);
- }
- BLI_gset_free(aovhashes_added, NULL);
- BLI_dynstr_append(ds, " default: {\n");
- BLI_dynstr_append(ds, " Closure no_aov = CLOSURE_DEFAULT;\n");
- BLI_dynstr_append(ds, " no_aov.holdout = 1.0;\n");
- BLI_dynstr_append(ds, " return no_aov;\n");
- BLI_dynstr_append(ds, " }\n");
- BLI_dynstr_append(ds, " }\n");
- BLI_dynstr_append(ds, " } else {\n");
- BLI_dynstr_append(ds, " #else /* VOLUMETRICS */\n");
- BLI_dynstr_append(ds, " {\n");
- BLI_dynstr_append(ds, " #endif /* VOLUMETRICS */\n ");
- codegen_final_output(ds, graph->outlink->output);
- BLI_dynstr_append(ds, " }\n");
-
- BLI_dynstr_append(ds, "}\n");
-
- /* create shader */
- code = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
-#if 0
- if (G.debug & G_DEBUG) {
- printf("%s\n", code);
- }
-#endif
-
- return code;
-}
-
-static const char *attr_prefix_get(CustomDataType type)
-{
- switch (type) {
- case CD_ORCO:
- return "orco";
- case CD_MTFACE:
- return "u";
- case CD_TANGENT:
- return "t";
- case CD_MCOL:
- case CD_MLOOPCOL:
- return "c";
- case CD_PROP_COLOR:
- return "c";
- case CD_AUTO_FROM_NAME:
- return "a";
- case CD_HAIRLENGTH:
- return "hl";
- default:
- BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
- return "";
- }
-}
-
-/* We talk about shader stage interface, not to be mistaken with GPUShaderInterface. */
-static char *code_generate_interface(GPUNodeGraph *graph, int builtins)
-{
- if (BLI_listbase_is_empty(&graph->attributes) &&
- (builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0) {
- return NULL;
- }
-
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, "\n");
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- if (attr->type == CD_HAIRLENGTH) {
- BLI_dynstr_appendf(ds, "float var%d;\n", attr->id);
- }
- else {
- BLI_dynstr_appendf(ds, "%s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
- }
- }
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "vec2 barycentricTexCo;\n");
- }
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_append(ds, "vec3 barycentricDist;\n");
- }
-
- char *code = BLI_dynstr_get_cstring(ds);
-
- BLI_dynstr_free(ds);
-
- return code;
-}
-
-static char *code_generate_vertex(GPUNodeGraph *graph,
- const char *interface_str,
- const char *vert_code,
- int builtins)
-{
- DynStr *ds = BLI_dynstr_new();
-
- BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
-
- /* Inputs */
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- const char *type_str = gpu_data_type_to_string(attr->gputype);
- const char *prefix = attr_prefix_get(attr->type);
- /* XXX FIXME: see notes in mesh_render_data_create() */
- /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
- if (attr->type == CD_ORCO) {
- /* OPTI: orco is computed from local positions, but only if no modifier is present. */
- BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
- BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
- }
- else if (attr->type == CD_HAIRLENGTH) {
- BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
- BLI_dynstr_append(ds, "DEFINE_ATTR(float, hairLen);\n");
- }
- else if (attr->name[0] == '\0') {
- BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s);\n", type_str, prefix);
- BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, prefix);
- }
- else {
- char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
- GPU_vertformat_safe_attr_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
- BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s%s);\n", type_str, prefix, attr_safe_name);
- BLI_dynstr_appendf(ds, "#define att%d %s%s\n", attr->id, prefix, attr_safe_name);
- }
- }
-
- /* Outputs interface */
- if (interface_str) {
- BLI_dynstr_appendf(ds, "out codegenInterface {%s};\n\n", interface_str);
- }
-
- /* Prototype. Needed for hair functions. */
- BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv);\n");
- BLI_dynstr_append(ds, "#define USE_ATTR\n\n");
-
- BLI_dynstr_append(ds, vert_code);
- BLI_dynstr_append(ds, "\n\n");
-
- BLI_dynstr_append(ds, "void pass_attr(vec3 position, mat3 normalmat, mat4 modelmatinv) {\n");
-
- /* GPU_BARYCENTRIC_TEXCO cannot be computed based on gl_VertexID
- * for MESH_SHADER because of indexed drawing. In this case a
- * geometry shader is needed. */
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_appendf(ds, " barycentricTexCo = barycentric_get();\n");
- }
- if (builtins & GPU_BARYCENTRIC_DIST) {
- BLI_dynstr_appendf(ds, " barycentricDist = vec3(0);\n");
- }
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- if (attr->type == CD_TANGENT) { /* silly exception */
- BLI_dynstr_appendf(ds, " var%d = tangent_get(att%d, normalmat);\n", attr->id, attr->id);
- }
- else if (attr->type == CD_ORCO) {
- BLI_dynstr_appendf(
- ds, " var%d = orco_get(position, modelmatinv, OrcoTexCoFactors, orco);\n", attr->id);
- }
- else if (attr->type == CD_HAIRLENGTH) {
- BLI_dynstr_appendf(ds, " var%d = hair_len_get(hair_get_strand_id(), hairLen);\n", attr->id);
- }
- else {
- const char *type_str = gpu_data_type_to_string(attr->gputype);
- BLI_dynstr_appendf(ds, " var%d = GET_ATTR(%s, att%d);\n", attr->id, type_str, attr->id);
- }
- }
-
- BLI_dynstr_append(ds, "}\n");
-
- char *code = BLI_dynstr_get_cstring(ds);
-
- BLI_dynstr_free(ds);
-
-#if 0
- if (G.debug & G_DEBUG) {
- printf("%s\n", code);
- }
-#endif
-
- return code;
-}
-
-static char *code_generate_geometry(GPUNodeGraph *graph,
- const char *interface_str,
- const char *geom_code,
- int builtins)
-{
- if (!geom_code) {
- return NULL;
- }
-
- DynStr *ds = BLI_dynstr_new();
-
- /* Attributes, Shader interface; */
- if (interface_str) {
- BLI_dynstr_appendf(ds, "in codegenInterface {%s} dataAttrIn[];\n\n", interface_str);
- BLI_dynstr_appendf(ds, "out codegenInterface {%s} dataAttrOut;\n\n", interface_str);
- }
-
- BLI_dynstr_append(ds, datatoc_gpu_shader_codegen_lib_glsl);
-
- if (builtins & GPU_BARYCENTRIC_DIST) {
- /* geom_code should do something with this, but may not. */
- BLI_dynstr_append(ds, "#define DO_BARYCENTRIC_DISTANCES\n");
- }
-
- /* Generate varying assignments. */
- BLI_dynstr_append(ds, "#define USE_ATTR\n");
- /* This needs to be a define. Some drivers don't like variable vert index inside dataAttrIn. */
- BLI_dynstr_append(ds, "#define pass_attr(vert) {\\\n");
-
- if (builtins & GPU_BARYCENTRIC_TEXCO) {
- BLI_dynstr_append(ds, "dataAttrOut.barycentricTexCo = calc_barycentric_co(vert);\\\n");
- }
-
- LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- /* TODO: let shader choose what to do depending on what the attribute is. */
- BLI_dynstr_appendf(ds, "dataAttrOut.var%d = dataAttrIn[vert].var%d;\\\n", attr->id, attr->id);
- }
- BLI_dynstr_append(ds, "}\n\n");
-
- BLI_dynstr_append(ds, geom_code);
-
- char *code = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- return code;
-}
-
-GPUShader *GPU_pass_shader_get(GPUPass *pass)
-{
- return pass->shader;
-}
-
-/* Pass create/free */
-
-static bool gpu_pass_is_valid(GPUPass *pass)
-{
- /* Shader is not null if compilation is successful. */
- return (pass->compiled == false || pass->shader != NULL);
-}
-
-GPUPass *GPU_generate_pass(GPUMaterial *material,
- GPUNodeGraph *graph,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines)
-{
- /* Prune the unused nodes and extract attributes before compiling so the
- * generated VBOs are ready to accept the future shader. */
- gpu_node_graph_prune_unused(graph);
- gpu_node_graph_finalize_uniform_attrs(graph);
-
- int builtins = 0;
- LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
- if (input->source == GPU_SOURCE_BUILTIN) {
- builtins |= input->builtin;
- }
- }
- }
- /* generate code */
- char *interface_str = code_generate_interface(graph, builtins);
- char *fragmentgen = code_generate_fragment(material, graph, interface_str);
-
- /* Cache lookup: Reuse shaders already compiled */
- uint32_t hash = gpu_pass_hash(fragmentgen, defines, &graph->attributes);
- GPUPass *pass_hash = gpu_pass_cache_lookup(hash);
-
- if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) {
- /* No collision, just return the pass. */
- MEM_SAFE_FREE(interface_str);
- MEM_freeN(fragmentgen);
- if (!gpu_pass_is_valid(pass_hash)) {
- /* Shader has already been created but failed to compile. */
- return NULL;
- }
- pass_hash->refcount += 1;
- return pass_hash;
- }
-
- /* Either the shader is not compiled or there is a hash collision...
- * continue generating the shader strings. */
- GSet *used_libraries = gpu_material_used_libraries(material);
- char *tmp = gpu_material_library_generate_code(used_libraries, frag_lib);
-
- char *geometrycode = code_generate_geometry(graph, interface_str, geom_code, builtins);
- char *vertexcode = code_generate_vertex(graph, interface_str, vert_code, builtins);
- char *fragmentcode = BLI_strdupcat(tmp, fragmentgen);
-
- MEM_SAFE_FREE(interface_str);
- MEM_freeN(fragmentgen);
- MEM_freeN(tmp);
-
- GPUPass *pass = NULL;
- if (pass_hash) {
- /* Cache lookup: Reuse shaders already compiled */
- pass = gpu_pass_cache_resolve_collision(
- pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash);
- }
-
- if (pass) {
- MEM_SAFE_FREE(vertexcode);
- MEM_SAFE_FREE(fragmentcode);
- MEM_SAFE_FREE(geometrycode);
-
- /* Cache hit. Reuse the same GPUPass and GPUShader. */
- if (!gpu_pass_is_valid(pass)) {
- /* Shader has already been created but failed to compile. */
- return NULL;
- }
-
- pass->refcount += 1;
- }
- else {
- /* We still create a pass even if shader compilation
- * fails to avoid trying to compile again and again. */
- pass = MEM_callocN(sizeof(GPUPass), "GPUPass");
- pass->shader = NULL;
- pass->refcount = 1;
- pass->hash = hash;
- pass->vertexcode = vertexcode;
- pass->fragmentcode = fragmentcode;
- pass->geometrycode = geometrycode;
- pass->defines = (defines) ? BLI_strdup(defines) : NULL;
- pass->compiled = false;
-
- BLI_spin_lock(&pass_cache_spin);
- if (pass_hash != NULL) {
- /* Add after the first pass having the same hash. */
- pass->next = pass_hash->next;
- pass_hash->next = pass;
- }
- else {
- /* No other pass have same hash, just prepend to the list. */
- BLI_LINKS_PREPEND(pass_cache, pass);
- }
- BLI_spin_unlock(&pass_cache_spin);
- }
-
- return pass;
-}
-
-static int count_active_texture_sampler(GPUShader *shader, const char *source)
-{
- const char *code = source;
-
- /* Remember this is per stage. */
- GSet *sampler_ids = BLI_gset_int_new(__func__);
- int num_samplers = 0;
-
- while ((code = strstr(code, "uniform "))) {
- /* Move past "uniform". */
- code += 7;
- /* Skip following spaces. */
- while (*code == ' ') {
- code++;
- }
- /* Skip "i" from potential isamplers. */
- if (*code == 'i') {
- code++;
- }
- /* Skip following spaces. */
- if (BLI_str_startswith(code, "sampler")) {
- /* Move past "uniform". */
- code += 7;
- /* Skip sampler type suffix. */
- while (!ELEM(*code, ' ', '\0')) {
- code++;
- }
- /* Skip following spaces. */
- while (*code == ' ') {
- code++;
- }
-
- if (*code != '\0') {
- char sampler_name[64];
- code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name));
- int id = GPU_shader_get_uniform(shader, sampler_name);
-
- if (id == -1) {
- continue;
- }
- /* Catch duplicates. */
- if (BLI_gset_add(sampler_ids, POINTER_FROM_INT(id))) {
- num_samplers++;
- }
- }
- }
- }
-
- BLI_gset_free(sampler_ids, NULL);
-
- return num_samplers;
-}
-
-static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader)
-{
- if (shader == NULL) {
- return false;
- }
-
- /* NOTE: The only drawback of this method is that it will count a sampler
- * used in the fragment shader and only declared (but not used) in the vertex
- * shader as used by both. But this corner case is not happening for now. */
- int vert_samplers_len = count_active_texture_sampler(shader, pass->vertexcode);
- int frag_samplers_len = count_active_texture_sampler(shader, pass->fragmentcode);
-
- int total_samplers_len = vert_samplers_len + frag_samplers_len;
-
- /* Validate against opengl limit. */
- if ((frag_samplers_len > GPU_max_textures_frag()) ||
- (vert_samplers_len > GPU_max_textures_vert())) {
- return false;
- }
-
- if (pass->geometrycode) {
- int geom_samplers_len = count_active_texture_sampler(shader, pass->geometrycode);
- total_samplers_len += geom_samplers_len;
- if (geom_samplers_len > GPU_max_textures_geom()) {
- return false;
- }
- }
-
- return (total_samplers_len <= GPU_max_textures());
-}
-
-bool GPU_pass_compile(GPUPass *pass, const char *shname)
-{
- bool success = true;
- if (!pass->compiled) {
- GPUShader *shader = GPU_shader_create(
- pass->vertexcode, pass->fragmentcode, pass->geometrycode, NULL, pass->defines, shname);
-
- /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit.
- * We need to make sure to count active samplers to avoid undefined behavior. */
- if (!gpu_pass_shader_validate(pass, shader)) {
- success = false;
- if (shader != NULL) {
- fprintf(stderr, "GPUShader: error: too many samplers in shader.\n");
- GPU_shader_free(shader);
- shader = NULL;
- }
- }
- pass->shader = shader;
- pass->compiled = true;
- }
-
- return success;
-}
-
-void GPU_pass_release(GPUPass *pass)
-{
- BLI_assert(pass->refcount > 0);
- pass->refcount--;
-}
-
-static void gpu_pass_free(GPUPass *pass)
-{
- BLI_assert(pass->refcount == 0);
- if (pass->shader) {
- GPU_shader_free(pass->shader);
- }
- MEM_SAFE_FREE(pass->fragmentcode);
- MEM_SAFE_FREE(pass->geometrycode);
- MEM_SAFE_FREE(pass->vertexcode);
- MEM_SAFE_FREE(pass->defines);
- MEM_freeN(pass);
-}
-
-void GPU_pass_cache_garbage_collect(void)
-{
- static int lasttime = 0;
- const int shadercollectrate = 60; /* hardcoded for now. */
- int ctime = (int)PIL_check_seconds_timer();
-
- if (ctime < shadercollectrate + lasttime) {
- return;
- }
-
- lasttime = ctime;
-
- BLI_spin_lock(&pass_cache_spin);
- GPUPass *next, **prev_pass = &pass_cache;
- for (GPUPass *pass = pass_cache; pass; pass = next) {
- next = pass->next;
- if (pass->refcount == 0) {
- /* Remove from list */
- *prev_pass = next;
- gpu_pass_free(pass);
- }
- else {
- prev_pass = &pass->next;
- }
- }
- BLI_spin_unlock(&pass_cache_spin);
-}
-
-void GPU_pass_cache_init(void)
-{
- BLI_spin_init(&pass_cache_spin);
-}
-
-void GPU_pass_cache_free(void)
-{
- BLI_spin_lock(&pass_cache_spin);
- while (pass_cache) {
- GPUPass *next = pass_cache->next;
- gpu_pass_free(pass_cache);
- pass_cache = next;
- }
- BLI_spin_unlock(&pass_cache_spin);
-
- BLI_spin_end(&pass_cache_spin);
-}
-
-/* Module */
-
-void gpu_codegen_init(void)
-{
-}
-
-void gpu_codegen_exit(void)
-{
- BKE_material_defaults_free_gpu();
- GPU_shader_free_builtin_shaders();
-}
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
new file mode 100644
index 00000000000..8963fa45c96
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -0,0 +1,825 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2005 Blender Foundation. */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Convert material node-trees to GLSL.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_image_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_hash_mm2a.h"
+#include "BLI_link_utils.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "PIL_time.h"
+
+#include "BKE_material.h"
+#include "BKE_world.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_uniform_buffer.h"
+#include "GPU_vertex_format.h"
+
+#include "BLI_sys_types.h" /* for intptr_t support */
+
+#include "gpu_codegen.h"
+#include "gpu_material_library.h"
+#include "gpu_node_graph.h"
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_dependency_private.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <sstream>
+#include <string>
+
+using namespace blender::gpu::shader;
+
+struct GPUCodegenCreateInfo : ShaderCreateInfo {
+ struct NameBuffer {
+ char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
+ char var_names[16][8];
+ };
+
+ /** Optional generated interface. */
+ StageInterfaceInfo *interface_generated = nullptr;
+ /** Optional name buffer containing names referenced by StringRefNull. */
+ NameBuffer *name_buffer = nullptr;
+
+ GPUCodegenCreateInfo(const char *name) : ShaderCreateInfo(name){};
+ ~GPUCodegenCreateInfo()
+ {
+ delete interface_generated;
+ MEM_delete(name_buffer);
+ };
+};
+
+struct GPUPass {
+ struct GPUPass *next;
+
+ GPUShader *shader;
+ GPUCodegenCreateInfo *create_info = nullptr;
+ /** Orphaned GPUPasses gets freed by the garbage collector. */
+ uint refcount;
+ /** Identity hash generated from all GLSL code. */
+ uint32_t hash;
+ /** Did we already tried to compile the attached GPUShader. */
+ bool compiled;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name GPUPass Cache
+ *
+ * Internal shader cache: This prevent the shader recompilation / stall when
+ * using undo/redo AND also allows for GPUPass reuse if the Shader code is the
+ * same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
+ */
+
+/* Only use one linklist that contains the GPUPasses grouped by hash. */
+static GPUPass *pass_cache = nullptr;
+static SpinLock pass_cache_spin;
+
+/* Search by hash only. Return first pass with the same hash.
+ * There is hash collision if (pass->next && pass->next->hash == hash) */
+static GPUPass *gpu_pass_cache_lookup(uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ /* Could be optimized with a Lookup table. */
+ for (GPUPass *pass = pass_cache; pass; pass = pass->next) {
+ if (pass->hash == hash) {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ return nullptr;
+}
+
+static void gpu_pass_cache_insert_after(GPUPass *node, GPUPass *pass)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ if (node != nullptr) {
+ /* Add after the first pass having the same hash. */
+ pass->next = node->next;
+ node->next = pass;
+ }
+ else {
+ /* No other pass have same hash, just prepend to the list. */
+ BLI_LINKS_PREPEND(pass_cache, pass);
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+}
+
+/* Check all possible passes with the same hash. */
+static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass,
+ GPUShaderCreateInfo *info,
+ uint32_t hash)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ for (; pass && (pass->hash == hash); pass = pass->next) {
+ if (*reinterpret_cast<ShaderCreateInfo *>(info) ==
+ *reinterpret_cast<ShaderCreateInfo *>(pass->create_info)) {
+ BLI_spin_unlock(&pass_cache_spin);
+ return pass;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+ return nullptr;
+}
+
+static bool gpu_pass_is_valid(GPUPass *pass)
+{
+ /* Shader is not null if compilation is successful. */
+ return (pass->compiled == false || pass->shader != nullptr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Type > string conversion
+ * \{ */
+
+static std::ostream &operator<<(std::ostream &stream, const GPUInput *input)
+{
+ switch (input->source) {
+ case GPU_SOURCE_FUNCTION_CALL:
+ case GPU_SOURCE_OUTPUT:
+ return stream << "tmp" << input->id;
+ case GPU_SOURCE_CONSTANT:
+ return stream << "cons" << input->id;
+ case GPU_SOURCE_UNIFORM:
+ return stream << "node_tree.u" << input->id;
+ case GPU_SOURCE_ATTR:
+ return stream << "var_attrs.v" << input->attr->id;
+ case GPU_SOURCE_UNIFORM_ATTR:
+ return stream << "unf_attrs[resource_id].attr" << input->uniform_attr->id;
+ case GPU_SOURCE_STRUCT:
+ return stream << "strct" << input->id;
+ case GPU_SOURCE_TEX:
+ return stream << input->texture->sampler_name;
+ case GPU_SOURCE_TEX_TILED_MAPPING:
+ return stream << input->texture->tiled_mapping_name;
+ case GPU_SOURCE_VOLUME_GRID:
+ return stream << input->volume_grid->sampler_name;
+ case GPU_SOURCE_VOLUME_GRID_TRANSFORM:
+ return stream << input->volume_grid->transform_name;
+ default:
+ BLI_assert(0);
+ return stream;
+ }
+}
+
+static std::ostream &operator<<(std::ostream &stream, const GPUOutput *output)
+{
+ return stream << "tmp" << output->id;
+}
+
+/* Trick type to change overload and keep a somewhat nice syntax. */
+struct GPUConstant : public GPUInput {
+};
+
+/* Print data constructor (i.e: vec2(1.0f, 1.0f)). */
+static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input)
+{
+ stream << input->type << "(";
+ for (int i = 0; i < input->type; i++) {
+ char formated_float[32];
+ /* Print with the maximum precision for single precision float using scientific notation.
+ * See https://stackoverflow.com/questions/16839658/#answer-21162120 */
+ SNPRINTF(formated_float, "%.9g", input->vec[i]);
+ stream << formated_float;
+ if (i < input->type - 1) {
+ stream << ", ";
+ }
+ }
+ stream << ")";
+ return stream;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GLSL code generation
+ * \{ */
+
+class GPUCodegen {
+ public:
+ GPUMaterial &mat;
+ GPUNodeGraph &graph;
+ GPUCodegenOutput output = {};
+ GPUCodegenCreateInfo *create_info = nullptr;
+
+ private:
+ uint32_t hash_ = 0;
+ BLI_HashMurmur2A hm2a_;
+ ListBase ubo_inputs_ = {nullptr, nullptr};
+
+ public:
+ GPUCodegen(GPUMaterial *mat_, GPUNodeGraph *graph_) : mat(*mat_), graph(*graph_)
+ {
+ BLI_hash_mm2a_init(&hm2a_, GPU_material_uuid_get(&mat));
+ BLI_hash_mm2a_add_int(&hm2a_, GPU_material_flag(&mat));
+ create_info = new GPUCodegenCreateInfo("codegen");
+ output.create_info = reinterpret_cast<GPUShaderCreateInfo *>(
+ static_cast<ShaderCreateInfo *>(create_info));
+
+ if (GPU_material_flag_get(mat_, GPU_MATFLAG_OBJECT_INFO)) {
+ create_info->additional_info("draw_object_infos");
+ }
+ }
+
+ ~GPUCodegen()
+ {
+ MEM_SAFE_FREE(output.attr_load);
+ MEM_SAFE_FREE(output.surface);
+ MEM_SAFE_FREE(output.volume);
+ MEM_SAFE_FREE(output.thickness);
+ MEM_SAFE_FREE(output.displacement);
+ MEM_SAFE_FREE(output.material_functions);
+ delete create_info;
+ BLI_freelistN(&ubo_inputs_);
+ };
+
+ void generate_graphs();
+ void generate_uniform_buffer();
+ void generate_attribs();
+ void generate_resources();
+ void generate_library();
+
+ uint32_t hash_get() const
+ {
+ return hash_;
+ }
+
+ private:
+ void set_unique_ids();
+
+ void node_serialize(std::stringstream &eval_ss, const GPUNode *node);
+ char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link);
+
+ static char *extract_c_str(std::stringstream &stream)
+ {
+ auto string = stream.str();
+ return BLI_strdup(string.c_str());
+ }
+};
+
+static char attr_prefix_get(CustomDataType type)
+{
+ switch (type) {
+ case CD_MTFACE:
+ return 'u';
+ case CD_TANGENT:
+ return 't';
+ case CD_MCOL:
+ case CD_MLOOPCOL:
+ return 'c';
+ case CD_PROP_COLOR:
+ return 'c';
+ case CD_AUTO_FROM_NAME:
+ return 'a';
+ case CD_HAIRLENGTH:
+ return 'l';
+ default:
+ BLI_assert_msg(0, "GPUVertAttr Prefix type not found : This should not happen!");
+ return '\0';
+ }
+}
+
+void GPUCodegen::generate_attribs()
+{
+ if (BLI_listbase_is_empty(&graph.attributes)) {
+ output.attr_load = nullptr;
+ return;
+ }
+
+ GPUCodegenCreateInfo &info = *create_info;
+
+ info.name_buffer = MEM_new<GPUCodegenCreateInfo::NameBuffer>("info.name_buffer");
+ info.interface_generated = new StageInterfaceInfo("codegen_iface", "var_attrs");
+ StageInterfaceInfo &iface = *info.interface_generated;
+ info.vertex_out(iface);
+
+ /* Input declaration, loading / assignment to interface and geometry shader passthrough. */
+ std::stringstream decl_ss, iface_ss, load_ss;
+
+ int slot = 15;
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
+
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ if (attr->type == CD_ORCO) {
+ /* OPTI: orco is computed from local positions, but only if no modifier is present. */
+ STRNCPY(info.name_buffer->attr_names[slot], "orco");
+ }
+ else {
+ char *name = info.name_buffer->attr_names[slot];
+ name[0] = attr_prefix_get(static_cast<CustomDataType>(attr->type));
+ name[1] = '\0';
+ if (attr->name[0] != '\0') {
+ /* XXX FIXME: see notes in mesh_render_data_create() */
+ GPU_vertformat_safe_attr_name(attr->name, &name[1], GPU_MAX_SAFE_ATTR_NAME);
+ }
+ }
+ SNPRINTF(info.name_buffer->var_names[slot], "v%d", attr->id);
+
+ blender::StringRefNull attr_name = info.name_buffer->attr_names[slot];
+ blender::StringRefNull var_name = info.name_buffer->var_names[slot];
+
+ eGPUType input_type, iface_type;
+
+ load_ss << "var_attrs." << var_name;
+ switch (attr->type) {
+ case CD_ORCO:
+ /* Need vec4 to detect usage of default attribute. */
+ input_type = GPU_VEC4;
+ iface_type = GPU_VEC3;
+ load_ss << " = attr_load_orco(" << attr_name << ");\n";
+ break;
+ case CD_HAIRLENGTH:
+ iface_type = input_type = GPU_FLOAT;
+ load_ss << " = attr_load_" << input_type << "(" << attr_name << ");\n";
+ break;
+ case CD_TANGENT:
+ iface_type = input_type = GPU_VEC4;
+ load_ss << " = attr_load_tangent(" << attr_name << ");\n";
+ break;
+ case CD_MTFACE:
+ iface_type = input_type = GPU_VEC3;
+ load_ss << " = attr_load_uv(" << attr_name << ");\n";
+ break;
+ case CD_MCOL:
+ iface_type = input_type = GPU_VEC4;
+ load_ss << " = attr_load_color(" << attr_name << ");\n";
+ break;
+ default:
+ iface_type = input_type = GPU_VEC4;
+ load_ss << " = attr_load_" << input_type << "(" << attr_name << ");\n";
+ break;
+ }
+
+ info.vertex_in(slot--, to_type(input_type), attr_name);
+ iface.smooth(to_type(iface_type), var_name);
+ }
+
+ output.attr_load = extract_c_str(load_ss);
+}
+
+void GPUCodegen::generate_resources()
+{
+ GPUCodegenCreateInfo &info = *create_info;
+
+ std::stringstream ss;
+
+ /* Textures. */
+ LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) {
+ if (tex->colorband) {
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ }
+ else if (tex->tiled_mapping_name[0] != '\0') {
+ info.sampler(0, ImageType::FLOAT_2D_ARRAY, tex->sampler_name, Frequency::BATCH);
+ info.sampler(0, ImageType::FLOAT_1D_ARRAY, tex->tiled_mapping_name, Frequency::BATCH);
+ }
+ else {
+ info.sampler(0, ImageType::FLOAT_2D, tex->sampler_name, Frequency::BATCH);
+ }
+ }
+ /* Volume Grids. */
+ LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph.volume_grids) {
+ info.sampler(0, ImageType::FLOAT_3D, grid->sampler_name, Frequency::BATCH);
+ /* TODO(@fclem): Global uniform. To put in an UBO. */
+ info.push_constant(Type::MAT4, grid->transform_name);
+ }
+
+ if (!BLI_listbase_is_empty(&ubo_inputs_)) {
+ /* NOTE: generate_uniform_buffer() should have sorted the inputs before this. */
+ ss << "struct NodeTree {\n";
+ LISTBASE_FOREACH (LinkData *, link, &ubo_inputs_) {
+ GPUInput *input = (GPUInput *)(link->data);
+ ss << input->type << " u" << input->id << ";\n";
+ }
+ ss << "};\n\n";
+
+ info.uniform_buf(0, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH);
+ }
+
+ if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) {
+ ss << "struct UniformAttrs {\n";
+ LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph.uniform_attrs.list) {
+ ss << "vec4 attr" << attr->id << ";\n";
+ }
+ ss << "};\n\n";
+
+ /* TODO(fclem): Use the macro for length. Currently not working for EEVEE. */
+ /* DRW_RESOURCE_CHUNK_LEN = 512 */
+ info.uniform_buf(0, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH);
+ }
+
+ info.typedef_source_generated = ss.str();
+}
+
+void GPUCodegen::generate_library()
+{
+ GPUCodegenCreateInfo &info = *create_info;
+
+ void *value;
+ GSetIterState pop_state = {};
+ while (BLI_gset_pop(graph.used_libraries, &pop_state, &value)) {
+ auto deps = gpu_shader_dependency_get_resolved_source((const char *)value);
+ info.dependencies_generated.extend_non_duplicates(deps);
+ }
+}
+
+void GPUCodegen::node_serialize(std::stringstream &eval_ss, const GPUNode *node)
+{
+ /* Declare constants. */
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ switch (input->source) {
+ case GPU_SOURCE_FUNCTION_CALL:
+ eval_ss << input->type << " " << input << "; " << input->function_call << input << ");\n";
+ break;
+ case GPU_SOURCE_STRUCT:
+ eval_ss << input->type << " " << input << " = CLOSURE_DEFAULT;\n";
+ break;
+ case GPU_SOURCE_CONSTANT:
+ eval_ss << input->type << " " << input << " = " << (GPUConstant *)input << ";\n";
+ break;
+ default:
+ break;
+ }
+ }
+ /* Declare temporary variables for node output storage. */
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
+ eval_ss << output->type << " " << output << ";\n";
+ }
+
+ /* Function call. */
+ eval_ss << node->name << "(";
+ /* Input arguments. */
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ switch (input->source) {
+ case GPU_SOURCE_OUTPUT:
+ case GPU_SOURCE_ATTR: {
+ /* These inputs can have non matching types. Do conversion. */
+ eGPUType to = input->type;
+ eGPUType from = (input->source == GPU_SOURCE_ATTR) ? input->attr->gputype :
+ input->link->output->type;
+ if (from != to) {
+ /* Use defines declared inside codegen_lib (i.e: vec4_from_float). */
+ eval_ss << to << "_from_" << from << "(";
+ }
+
+ if (input->source == GPU_SOURCE_ATTR) {
+ eval_ss << input;
+ }
+ else {
+ eval_ss << input->link->output;
+ }
+
+ if (from != to) {
+ eval_ss << ")";
+ }
+ break;
+ }
+ default:
+ eval_ss << input;
+ break;
+ }
+ eval_ss << ", ";
+ }
+ /* Output arguments. */
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
+ eval_ss << output;
+ if (output->next) {
+ eval_ss << ", ";
+ }
+ }
+ eval_ss << ");\n\n";
+}
+
+char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link)
+{
+ if (output_link == nullptr) {
+ return nullptr;
+ }
+
+ std::stringstream eval_ss;
+ /* NOTE: The node order is already top to bottom (or left to right in node editor)
+ * because of the evaluation order inside ntreeExecGPUNodes(). */
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ if ((node->tag & tree_tag) == 0) {
+ continue;
+ }
+ node_serialize(eval_ss, node);
+ }
+ eval_ss << "return " << output_link->output << ";\n";
+
+ char *eval_c_str = extract_c_str(eval_ss);
+ BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size());
+ return eval_c_str;
+}
+
+void GPUCodegen::generate_uniform_buffer()
+{
+ /* Extract uniform inputs. */
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ if (input->source == GPU_SOURCE_UNIFORM && !input->link) {
+ /* We handle the UBO uniforms separately. */
+ BLI_addtail(&ubo_inputs_, BLI_genericNodeN(input));
+ }
+ }
+ }
+ if (!BLI_listbase_is_empty(&ubo_inputs_)) {
+ /* This sorts the inputs based on size. */
+ GPU_material_uniform_buffer_create(&mat, &ubo_inputs_);
+ }
+}
+
+/* Sets id for unique names for all inputs, resources and temp variables. */
+void GPUCodegen::set_unique_ids()
+{
+ int id = 1;
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
+ input->id = id++;
+ }
+ LISTBASE_FOREACH (GPUOutput *, output, &node->outputs) {
+ output->id = id++;
+ }
+ }
+}
+
+void GPUCodegen::generate_graphs()
+{
+ set_unique_ids();
+
+ output.surface = graph_serialize(GPU_NODE_TAG_SURFACE | GPU_NODE_TAG_AOV, graph.outlink_surface);
+ output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume);
+ output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement);
+ output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness);
+
+ if (!BLI_listbase_is_empty(&graph.material_functions)) {
+ std::stringstream eval_ss;
+ eval_ss << "\n/* Generated Functions */\n\n";
+ LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, func_link, &graph.material_functions) {
+ char *fn = graph_serialize(GPU_NODE_TAG_FUNCTION, func_link->outlink);
+ eval_ss << "float " << func_link->name << "() {\n" << fn << "}\n\n";
+ MEM_SAFE_FREE(fn);
+ }
+ output.material_functions = extract_c_str(eval_ss);
+ }
+
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
+ BLI_hash_mm2a_add(&hm2a_, (uchar *)attr->name, strlen(attr->name));
+ }
+
+ hash_ = BLI_hash_mm2a_end(&hm2a_);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GPUPass
+ * \{ */
+
+GPUPass *GPU_generate_pass(GPUMaterial *material,
+ GPUNodeGraph *graph,
+ GPUCodegenCallbackFn finalize_source_cb,
+ void *thunk)
+{
+ /* Prune the unused nodes and extract attributes before compiling so the
+ * generated VBOs are ready to accept the future shader. */
+ gpu_node_graph_prune_unused(graph);
+ gpu_node_graph_finalize_uniform_attrs(graph);
+
+ GPUCodegen codegen(material, graph);
+ codegen.generate_graphs();
+ codegen.generate_uniform_buffer();
+
+ /* Cache lookup: Reuse shaders already compiled. */
+ GPUPass *pass_hash = gpu_pass_cache_lookup(codegen.hash_get());
+
+ /* FIXME(fclem): This is broken. Since we only check for the hash and not the full source
+ * there is no way to have a collision currently. Some advocated to only use a bigger hash. */
+ if (pass_hash && (pass_hash->next == nullptr || pass_hash->next->hash != codegen.hash_get())) {
+ if (!gpu_pass_is_valid(pass_hash)) {
+ /* Shader has already been created but failed to compile. */
+ return nullptr;
+ }
+ /* No collision, just return the pass. */
+ pass_hash->refcount += 1;
+ return pass_hash;
+ }
+
+ /* Either the shader is not compiled or there is a hash collision...
+ * continue generating the shader strings. */
+ codegen.generate_attribs();
+ codegen.generate_resources();
+ codegen.generate_library();
+
+ /* Make engine add its own code and implement the generated functions. */
+ finalize_source_cb(thunk, material, &codegen.output);
+
+ GPUPass *pass = nullptr;
+ if (pass_hash) {
+ /* Cache lookup: Reuse shaders already compiled. */
+ pass = gpu_pass_cache_resolve_collision(
+ pass_hash, codegen.output.create_info, codegen.hash_get());
+ }
+
+ if (pass) {
+ /* Cache hit. Reuse the same GPUPass and GPUShader. */
+ if (!gpu_pass_is_valid(pass)) {
+ /* Shader has already been created but failed to compile. */
+ return nullptr;
+ }
+ pass->refcount += 1;
+ }
+ else {
+ /* We still create a pass even if shader compilation
+ * fails to avoid trying to compile again and again. */
+ pass = (GPUPass *)MEM_callocN(sizeof(GPUPass), "GPUPass");
+ pass->shader = nullptr;
+ pass->refcount = 1;
+ pass->create_info = codegen.create_info;
+ pass->hash = codegen.hash_get();
+ pass->compiled = false;
+
+ codegen.create_info = nullptr;
+
+ gpu_pass_cache_insert_after(pass_hash, pass);
+ }
+ return pass;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Compilation
+ * \{ */
+
+static int count_active_texture_sampler(GPUPass *pass, GPUShader *shader)
+{
+ int num_samplers = 0;
+
+ for (const ShaderCreateInfo::Resource &res : pass->create_info->pass_resources_) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
+ if (GPU_shader_get_uniform(shader, res.sampler.name.c_str()) != -1) {
+ num_samplers += 1;
+ }
+ }
+ }
+
+ return num_samplers;
+}
+
+static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader)
+{
+ if (shader == nullptr) {
+ return false;
+ }
+
+ /* NOTE: The only drawback of this method is that it will count a sampler
+ * used in the fragment shader and only declared (but not used) in the vertex
+ * shader as used by both. But this corner case is not happening for now. */
+ int active_samplers_len = count_active_texture_sampler(pass, shader);
+
+ /* Validate against opengl limit. */
+ if ((active_samplers_len > GPU_max_textures_frag()) ||
+ (active_samplers_len > GPU_max_textures_vert())) {
+ return false;
+ }
+
+ if (pass->create_info->geometry_source_.is_empty() == false) {
+ if (active_samplers_len > GPU_max_textures_geom()) {
+ return false;
+ }
+ }
+
+ return (active_samplers_len * 3 <= GPU_max_textures());
+}
+
+bool GPU_pass_compile(GPUPass *pass, const char *shname)
+{
+ bool success = true;
+ if (!pass->compiled) {
+ GPUShaderCreateInfo *info = reinterpret_cast<GPUShaderCreateInfo *>(
+ static_cast<ShaderCreateInfo *>(pass->create_info));
+
+ pass->create_info->name_ = shname;
+
+ GPUShader *shader = GPU_shader_create_from_info(info);
+
+ /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit.
+ * We need to make sure to count active samplers to avoid undefined behavior. */
+ if (!gpu_pass_shader_validate(pass, shader)) {
+ success = false;
+ if (shader != nullptr) {
+ fprintf(stderr, "GPUShader: error: too many samplers in shader.\n");
+ GPU_shader_free(shader);
+ shader = nullptr;
+ }
+ }
+ pass->shader = shader;
+ pass->compiled = true;
+ }
+ return success;
+}
+
+GPUShader *GPU_pass_shader_get(GPUPass *pass)
+{
+ return pass->shader;
+}
+
+void GPU_pass_release(GPUPass *pass)
+{
+ BLI_assert(pass->refcount > 0);
+ pass->refcount--;
+}
+
+static void gpu_pass_free(GPUPass *pass)
+{
+ BLI_assert(pass->refcount == 0);
+ if (pass->shader) {
+ GPU_shader_free(pass->shader);
+ }
+ delete pass->create_info;
+ MEM_freeN(pass);
+}
+
+void GPU_pass_cache_garbage_collect(void)
+{
+ static int lasttime = 0;
+ const int shadercollectrate = 60; /* hardcoded for now. */
+ int ctime = (int)PIL_check_seconds_timer();
+
+ if (ctime < shadercollectrate + lasttime) {
+ return;
+ }
+
+ lasttime = ctime;
+
+ BLI_spin_lock(&pass_cache_spin);
+ GPUPass *next, **prev_pass = &pass_cache;
+ for (GPUPass *pass = pass_cache; pass; pass = next) {
+ next = pass->next;
+ if (pass->refcount == 0) {
+ /* Remove from list */
+ *prev_pass = next;
+ gpu_pass_free(pass);
+ }
+ else {
+ prev_pass = &pass->next;
+ }
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+}
+
+void GPU_pass_cache_init(void)
+{
+ BLI_spin_init(&pass_cache_spin);
+}
+
+void GPU_pass_cache_free(void)
+{
+ BLI_spin_lock(&pass_cache_spin);
+ while (pass_cache) {
+ GPUPass *next = pass_cache->next;
+ gpu_pass_free(pass_cache);
+ pass_cache = next;
+ }
+ BLI_spin_unlock(&pass_cache_spin);
+
+ BLI_spin_end(&pass_cache_spin);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Module
+ * \{ */
+
+void gpu_codegen_init(void)
+{
+}
+
+void gpu_codegen_exit(void)
+{
+ // BKE_world_defaults_free_gpu();
+ BKE_material_defaults_free_gpu();
+ GPU_shader_free_builtin_shaders();
+}
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 0e99476d3ea..95a672c0400 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -9,36 +9,24 @@
#pragma once
+#include "GPU_material.h"
+#include "GPU_shader.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-struct GPUMaterial;
struct GPUNodeGraph;
-struct GPUShader;
-
-typedef struct GPUPass {
- struct GPUPass *next;
- struct GPUShader *shader;
- char *fragmentcode;
- char *geometrycode;
- char *vertexcode;
- char *defines;
- uint refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */
- uint32_t hash; /* Identity hash generated from all GLSL code. */
- bool compiled; /* Did we already tried to compile the attached GPUShader. */
-} GPUPass;
+typedef struct GPUPass GPUPass;
/* Pass */
-GPUPass *GPU_generate_pass(struct GPUMaterial *material,
+GPUPass *GPU_generate_pass(GPUMaterial *material,
struct GPUNodeGraph *graph,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines);
-struct GPUShader *GPU_pass_shader_get(GPUPass *pass);
+ GPUCodegenCallbackFn finalize_source_cb,
+ void *thunk);
+GPUShader *GPU_pass_shader_get(GPUPass *pass);
bool GPU_pass_compile(GPUPass *pass, const char *shname);
void GPU_pass_release(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 7ccb0f89dc3..e97c9e9c829 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -39,7 +39,6 @@ void GPU_init(void)
gpu_shader_create_info_init();
gpu_codegen_init();
- gpu_material_library_init();
gpu_batch_init();
@@ -56,7 +55,6 @@ void GPU_exit(void)
gpu_batch_exit();
- gpu_material_library_exit();
gpu_codegen_exit();
gpu_shader_dependency_exit();
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 49732240125..711a3943a25 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -16,7 +16,6 @@
#include "DNA_scene_types.h"
#include "DNA_world_types.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -27,6 +26,7 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_scene.h"
+#include "BKE_world.h"
#include "NOD_shader.h"
@@ -49,56 +49,50 @@ typedef struct GPUColorBandBuilder {
} GPUColorBandBuilder;
struct GPUMaterial {
- Scene *scene; /* DEPRECATED was only useful for lights. */
- Material *ma;
-
+ /* Contains GPUShader and source code for deferred compilation.
+ * Can be shared between similar material (i.e: sharing same nodetree topology). */
+ GPUPass *pass;
+ /** UBOs for this material parameters. */
+ GPUUniformBuf *ubo;
+ /** Compilation status. Do not use if shader is not GPU_MAT_SUCCESS. */
eGPUMaterialStatus status;
-
- const void *engine_type; /* attached engine type */
- int options; /* to identify shader variations (shadow, probe, world background...) */
- bool is_volume_shader; /* is volumetric shader */
-
- /* Nodes */
+ /** Some flags about the nodetree & the needed resources. */
+ eGPUMaterialFlag flag;
+ /* Identify shader variations (shadow, probe, world background...).
+ * Should be unique even across render engines. */
+ uint64_t uuid;
+ /* Number of generated function. */
+ int generated_function_len;
+ /** Object type for attribute fetching. */
+ bool is_volume_shader;
+
+ /** DEPRECATED Currently only used for deferred compilation. */
+ Scene *scene;
+ /** Source material, might be null. */
+ Material *ma;
+ /** 1D Texture array containing all color bands. */
+ GPUTexture *coba_tex;
+ /** Builder for coba_tex. */
+ GPUColorBandBuilder *coba_builder;
+ /* Low level node graph(s). Also contains resources needed by the material. */
GPUNodeGraph graph;
- /* for binding the material */
- GPUPass *pass;
-
- /* XXX: Should be in Material. But it depends on the output node
- * used and since the output selection is different for GPUMaterial...
- */
- bool has_volume_output;
+ /** DEPRECATED: To remove. */
bool has_surface_output;
-
- /* Only used by Eevee to know which BSDF are used. */
- eGPUMatFlag flag;
-
- /* Used by 2.8 pipeline */
- GPUUniformBuf *ubo; /* UBOs for shader uniforms. */
-
- /* Eevee SSS */
+ bool has_volume_output;
+ /** DEPRECATED: To remove. */
GPUUniformBuf *sss_profile; /* UBO containing SSS profile. */
GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
- float sss_enabled;
+ bool sss_enabled;
float sss_radii[3];
int sss_samples;
bool sss_dirty;
- GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
- GPUColorBandBuilder *coba_builder;
-
- GSet *used_libraries;
-
#ifndef NDEBUG
char name[64];
#endif
};
-enum {
- GPU_USE_SURFACE_OUTPUT = (1 << 0),
- GPU_USE_VOLUME_OUTPUT = (1 << 1),
-};
-
/* Functions */
GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
@@ -159,17 +153,15 @@ static void gpu_material_free_single(GPUMaterial *material)
if (material->ubo != NULL) {
GPU_uniformbuf_free(material->ubo);
}
- if (material->sss_tex_profile != NULL) {
- GPU_texture_free(material->sss_tex_profile);
+ if (material->coba_tex != NULL) {
+ GPU_texture_free(material->coba_tex);
}
if (material->sss_profile != NULL) {
GPU_uniformbuf_free(material->sss_profile);
}
- if (material->coba_tex != NULL) {
- GPU_texture_free(material->coba_tex);
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
}
-
- BLI_gset_free(material->used_libraries, NULL);
}
void GPU_material_free(ListBase *gpumaterial)
@@ -217,17 +209,40 @@ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
material->ubo = GPU_uniformbuf_create_from_list(inputs, name);
}
+ListBase GPU_material_attributes(GPUMaterial *material)
+{
+ return material->graph.attributes;
+}
+
+ListBase GPU_material_textures(GPUMaterial *material)
+{
+ return material->graph.textures;
+}
+
+ListBase GPU_material_volume_grids(GPUMaterial *material)
+{
+ return material->graph.volume_grids;
+}
+
+GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
+{
+ GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
+ return attrs->count > 0 ? attrs : NULL;
+}
+
+#if 1 /* End of life code. */
/* Eevee Subsurface scattering. */
/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
-#define SSS_SAMPLES 65
-#define SSS_EXPONENT 2.0f /* Importance sampling exponent */
+# define SSS_SAMPLES 65
+# define SSS_EXPONENT 2.0f /* Importance sampling exponent */
typedef struct GPUSssKernelData {
float kernel[SSS_SAMPLES][4];
float param[3], max_radius;
+ float avg_inv_radius;
int samples;
- int pad[3];
+ int pad[2];
} GPUSssKernelData;
BLI_STATIC_ASSERT_ALIGN(GPUSssKernelData, 16)
@@ -243,8 +258,8 @@ static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponen
}
}
-#define BURLEY_TRUNCATE 16.0f
-#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
+# define BURLEY_TRUNCATE 16.0f
+# define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
static float burley_profile(float r, float d)
{
float exp_r_3_d = expf(-r / (3.0f * d));
@@ -259,7 +274,7 @@ static float eval_profile(float r, float param)
}
/* Resolution for each sample of the precomputed kernel profile */
-#define INTEGRAL_RESOLUTION 32
+# define INTEGRAL_RESOLUTION 32
static float eval_integral(float x0, float x1, float param)
{
const float range = x1 - x0;
@@ -274,7 +289,7 @@ static float eval_integral(float x0, float x1, float param)
return integral;
}
-#undef INTEGRAL_RESOLUTION
+# undef INTEGRAL_RESOLUTION
static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int sample_len)
{
@@ -284,6 +299,8 @@ static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int s
rad[1] = MAX2(radii[1], 1e-15f);
rad[2] = MAX2(radii[2], 1e-15f);
+ kd->avg_inv_radius = 3.0f / (rad[0] + rad[1] + rad[2]);
+
/* Christensen-Burley fitting */
float l[3], d[3];
@@ -358,7 +375,7 @@ static void compute_sss_kernel(GPUSssKernelData *kd, const float radii[3], int s
kd->samples = sample_len;
}
-#define INTEGRAL_RESOLUTION 512
+# define INTEGRAL_RESOLUTION 512
static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
int resolution,
float **output)
@@ -417,10 +434,14 @@ static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
mul_v3_fl(texels[resolution - 3], 0.5f);
mul_v3_fl(texels[resolution - 4], 0.75f);
}
-#undef INTEGRAL_RESOLUTION
+# undef INTEGRAL_RESOLUTION
-void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3])
+bool GPU_material_sss_profile_create(GPUMaterial *material, float radii[3])
{
+ /* Enable only once. */
+ if (material->sss_enabled) {
+ return false;
+ }
copy_v3_v3(material->sss_radii, radii);
material->sss_dirty = true;
material->sss_enabled = true;
@@ -429,6 +450,7 @@ void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3])
if (material->sss_profile == NULL) {
material->sss_profile = GPU_uniformbuf_create(sizeof(GPUSssKernelData));
}
+ return true;
}
struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material,
@@ -475,34 +497,37 @@ struct GPUUniformBuf *GPU_material_create_sss_profile_ubo(void)
return GPU_uniformbuf_create(sizeof(GPUSssKernelData));
}
-#undef SSS_EXPONENT
-#undef SSS_SAMPLES
-
-ListBase GPU_material_attributes(GPUMaterial *material)
-{
- return material->graph.attributes;
-}
+# undef SSS_EXPONENT
+# undef SSS_SAMPLES
+#endif
-ListBase GPU_material_textures(GPUMaterial *material)
+void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link)
{
- return material->graph.textures;
+ if (!material->graph.outlink_surface) {
+ material->graph.outlink_surface = link;
+ material->has_surface_output = true;
+ }
}
-ListBase GPU_material_volume_grids(GPUMaterial *material)
+void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link)
{
- return material->graph.volume_grids;
+ if (!material->graph.outlink_volume) {
+ material->graph.outlink_volume = link;
+ material->has_volume_output = true;
+ }
}
-GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
+void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link)
{
- GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
- return attrs->count > 0 ? attrs : NULL;
+ if (!material->graph.outlink_displacement) {
+ material->graph.outlink_displacement = link;
+ }
}
-void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
+void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link)
{
- if (!material->graph.outlink) {
- material->graph.outlink = link;
+ if (!material->graph.outlink_thickness) {
+ material->graph.outlink_thickness = link;
}
}
@@ -514,23 +539,71 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link,
BLI_addtail(&material->graph.outlink_aovs, aov_link);
}
+char *GPU_material_split_sub_function(GPUMaterial *material,
+ eGPUType return_type,
+ GPUNodeLink **link)
+{
+ /* Force cast to return type. */
+ switch (return_type) {
+ case GPU_FLOAT:
+ GPU_link(material, "set_value", *link, link);
+ break;
+ case GPU_VEC3:
+ GPU_link(material, "set_rgb", *link, link);
+ break;
+ case GPU_VEC4:
+ GPU_link(material, "set_rgba", *link, link);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ GPUNodeGraphFunctionLink *func_link = MEM_callocN(sizeof(GPUNodeGraphFunctionLink), __func__);
+ func_link->outlink = *link;
+ SNPRINTF(func_link->name, "ntree_fn%d", material->generated_function_len++);
+ BLI_addtail(&material->graph.material_functions, func_link);
+
+ /* Set value to break the link with the main graph. */
+ switch (return_type) {
+ case GPU_FLOAT:
+ GPU_link(material, "set_value_one", link);
+ break;
+ case GPU_VEC3:
+ GPU_link(material, "set_rgb_one", link);
+ break;
+ case GPU_VEC4:
+ GPU_link(material, "set_rgba_one", link);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ return func_link->name;
+}
+
GPUNodeGraph *gpu_material_node_graph(GPUMaterial *material)
{
return &material->graph;
}
-GSet *gpu_material_used_libraries(GPUMaterial *material)
+eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
- return material->used_libraries;
+ return mat->status;
}
-eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
+void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus status)
{
- return mat->status;
+ mat->status = status;
}
/* Code generation */
+bool GPU_material_is_volume_shader(GPUMaterial *mat)
+{
+ return mat->is_volume_shader;
+}
+
bool GPU_material_has_surface_output(GPUMaterial *mat)
{
return mat->has_surface_output;
@@ -541,100 +614,79 @@ bool GPU_material_has_volume_output(GPUMaterial *mat)
return mat->has_volume_output;
}
-bool GPU_material_is_volume_shader(GPUMaterial *mat)
+void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag)
{
- return mat->is_volume_shader;
+ mat->flag |= flag;
}
-void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag)
+bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
{
- mat->flag |= flag;
+ return (mat->flag & flag) != 0;
}
-bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag)
+eGPUMaterialFlag GPU_material_flag(const GPUMaterial *mat)
{
- return (mat->flag & flag) != 0;
+ return mat->flag;
}
-GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
- const void *engine_type,
- int options)
+/* Note: Consumes the flags. */
+bool GPU_material_recalc_flag_get(GPUMaterial *mat)
{
- LISTBASE_FOREACH (LinkData *, link, gpumaterials) {
- GPUMaterial *current_material = (GPUMaterial *)link->data;
- if (current_material->engine_type == engine_type && current_material->options == options) {
- return current_material;
- }
- }
+ bool updated = (mat->flag & GPU_MATFLAG_UPDATED) != 0;
+ mat->flag &= ~GPU_MATFLAG_UPDATED;
+ return updated;
+}
- return NULL;
+uint64_t GPU_material_uuid_get(GPUMaterial *mat)
+{
+ return mat->uuid;
}
GPUMaterial *GPU_material_from_nodetree(Scene *scene,
- struct Material *ma,
- struct bNodeTree *ntree,
+ Material *ma,
+ bNodeTree *ntree,
ListBase *gpumaterials,
- const void *engine_type,
- const int options,
- const bool is_volume_shader,
- const char *vert_code,
- const char *geom_code,
- const char *frag_lib,
- const char *defines,
const char *name,
- GPUMaterialEvalCallbackFn callback)
+ uint64_t shader_uuid,
+ bool is_volume_shader,
+ bool is_lookdev,
+ GPUCodegenCallbackFn callback,
+ void *thunk)
{
- LinkData *link;
- bool has_volume_output, has_surface_output;
-
- /* Caller must re-use materials. */
- BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
-
- /* HACK: Eevee assume this to create #GHash keys. */
- BLI_assert(sizeof(GPUPass) > 16);
+ /* Search if this material is not already compiled. */
+ LISTBASE_FOREACH (LinkData *, link, gpumaterials) {
+ GPUMaterial *mat = (GPUMaterial *)link->data;
+ if (mat->uuid == shader_uuid) {
+ return mat;
+ }
+ }
- /* allocate material */
GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
mat->ma = ma;
mat->scene = scene;
- mat->engine_type = engine_type;
- mat->options = options;
+ mat->uuid = shader_uuid;
+ mat->flag = GPU_MATFLAG_UPDATED;
mat->is_volume_shader = is_volume_shader;
+ mat->graph.used_libraries = BLI_gset_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
#ifndef NDEBUG
BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
#else
UNUSED_VARS(name);
#endif
+ if (is_lookdev) {
+ mat->flag |= GPU_MATFLAG_LOOKDEV_HACK;
+ }
- mat->used_libraries = BLI_gset_new(
- BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUMaterial.used_libraries");
-
- /* localize tree to create links for reroute and mute */
+ /* Localize tree to create links for reroute and mute. */
bNodeTree *localtree = ntreeLocalize(ntree);
- ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
+ ntreeGPUMaterialNodes(localtree, mat);
gpu_material_ramp_texture_build(mat);
- mat->has_surface_output = has_surface_output;
- mat->has_volume_output = has_volume_output;
-
- if (mat->graph.outlink) {
- if (callback) {
- callback(mat, options, &vert_code, &geom_code, &frag_lib, &defines);
- }
- /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */
- if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
- defines = BLI_string_joinN(defines,
- "#ifndef USE_ALPHA_BLEND\n"
- "# define USE_SSS\n"
- "#endif\n");
- }
+ {
/* Create source code and search pass cache for an already compiled version. */
- mat->pass = GPU_generate_pass(mat, &mat->graph, vert_code, geom_code, frag_lib, defines);
-
- if (GPU_material_flag_get(mat, GPU_MATFLAG_SSS)) {
- MEM_freeN((char *)defines);
- }
+ mat->pass = GPU_generate_pass(mat, &mat->graph, callback, thunk);
if (mat->pass == NULL) {
/* We had a cache hit and the shader has already failed to compile. */
@@ -649,26 +701,20 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
gpu_node_graph_free_nodes(&mat->graph);
}
else {
- mat->status = GPU_MAT_QUEUED;
+ mat->status = GPU_MAT_CREATED;
}
}
}
- else {
- mat->status = GPU_MAT_FAILED;
- gpu_node_graph_free(&mat->graph);
- }
- /* Only free after GPU_pass_shader_get where GPUUniformBuf
- * read data from the local tree. */
+ /* Only free after GPU_pass_shader_get where GPUUniformBuf read data from the local tree. */
ntreeFreeLocalTree(localtree);
BLI_assert(!localtree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
MEM_freeN(localtree);
- /* note that even if building the shader fails in some way, we still keep
+ /* Note that even if building the shader fails in some way, we still keep
* it to avoid trying to compile again and again, and simply do not use
- * the actual shader on drawing */
-
- link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
+ * the actual shader on drawing. */
+ LinkData *link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
link->data = mat;
BLI_addtail(gpumaterials, link);
@@ -690,6 +736,8 @@ void GPU_material_compile(GPUMaterial *mat)
success = GPU_pass_compile(mat->pass, __func__);
#endif
+ mat->flag |= GPU_MATFLAG_UPDATED;
+
if (success) {
GPUShader *sh = GPU_pass_shader_get(mat->pass);
if (sh != NULL) {
@@ -715,5 +763,6 @@ void GPU_materials_free(Main *bmain)
GPU_material_free(&wo->gpumaterial);
}
+ // BKE_world_defaults_free_gpu();
BKE_material_defaults_free_gpu();
}
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
deleted file mode 100644
index ca5c3d4bb45..00000000000
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2005 Blender Foundation. All rights reserved. */
-
-/** \file
- * \ingroup gpu
- *
- * GPU material library parsing and code generation.
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_ghash.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-
-#include "gpu_material_library.h"
-
-/* List of all gpu_shader_material_*.glsl files used by GLSL materials. These
- * will be parsed to make all functions in them available to use for GPU_link().
- *
- * If a file uses functions from another file, it must be added to the list of
- * dependencies, and be placed after that file in the list. */
-
-extern char datatoc_gpu_shader_material_add_shader_glsl[];
-extern char datatoc_gpu_shader_material_ambient_occlusion_glsl[];
-extern char datatoc_gpu_shader_material_anisotropic_glsl[];
-extern char datatoc_gpu_shader_material_attribute_glsl[];
-extern char datatoc_gpu_shader_material_background_glsl[];
-extern char datatoc_gpu_shader_material_bevel_glsl[];
-extern char datatoc_gpu_shader_material_wavelength_glsl[];
-extern char datatoc_gpu_shader_material_blackbody_glsl[];
-extern char datatoc_gpu_shader_material_bright_contrast_glsl[];
-extern char datatoc_gpu_shader_material_bump_glsl[];
-extern char datatoc_gpu_shader_material_camera_glsl[];
-extern char datatoc_gpu_shader_material_clamp_glsl[];
-extern char datatoc_gpu_shader_material_color_ramp_glsl[];
-extern char datatoc_gpu_shader_material_color_util_glsl[];
-extern char datatoc_gpu_shader_material_combine_hsv_glsl[];
-extern char datatoc_gpu_shader_material_combine_rgb_glsl[];
-extern char datatoc_gpu_shader_material_combine_xyz_glsl[];
-extern char datatoc_gpu_shader_material_diffuse_glsl[];
-extern char datatoc_gpu_shader_material_displacement_glsl[];
-extern char datatoc_gpu_shader_material_eevee_specular_glsl[];
-extern char datatoc_gpu_shader_material_emission_glsl[];
-extern char datatoc_gpu_shader_material_float_curve_glsl[];
-extern char datatoc_gpu_shader_material_fractal_noise_glsl[];
-extern char datatoc_gpu_shader_material_fresnel_glsl[];
-extern char datatoc_gpu_shader_material_gamma_glsl[];
-extern char datatoc_gpu_shader_material_geometry_glsl[];
-extern char datatoc_gpu_shader_material_glass_glsl[];
-extern char datatoc_gpu_shader_material_glossy_glsl[];
-extern char datatoc_gpu_shader_material_hair_info_glsl[];
-extern char datatoc_gpu_shader_material_hash_glsl[];
-extern char datatoc_gpu_shader_material_holdout_glsl[];
-extern char datatoc_gpu_shader_material_hue_sat_val_glsl[];
-extern char datatoc_gpu_shader_material_invert_glsl[];
-extern char datatoc_gpu_shader_material_layer_weight_glsl[];
-extern char datatoc_gpu_shader_material_light_falloff_glsl[];
-extern char datatoc_gpu_shader_material_light_path_glsl[];
-extern char datatoc_gpu_shader_material_mapping_glsl[];
-extern char datatoc_gpu_shader_material_map_range_glsl[];
-extern char datatoc_gpu_shader_material_math_glsl[];
-extern char datatoc_gpu_shader_material_math_util_glsl[];
-extern char datatoc_gpu_shader_material_mix_rgb_glsl[];
-extern char datatoc_gpu_shader_material_mix_shader_glsl[];
-extern char datatoc_gpu_shader_material_noise_glsl[];
-extern char datatoc_gpu_shader_material_normal_glsl[];
-extern char datatoc_gpu_shader_material_normal_map_glsl[];
-extern char datatoc_gpu_shader_material_object_info_glsl[];
-extern char datatoc_gpu_shader_material_output_aov_glsl[];
-extern char datatoc_gpu_shader_material_output_material_glsl[];
-extern char datatoc_gpu_shader_material_output_world_glsl[];
-extern char datatoc_gpu_shader_material_particle_info_glsl[];
-extern char datatoc_gpu_shader_material_point_info_glsl[];
-extern char datatoc_gpu_shader_material_principled_glsl[];
-extern char datatoc_gpu_shader_material_refraction_glsl[];
-extern char datatoc_gpu_shader_material_rgb_curves_glsl[];
-extern char datatoc_gpu_shader_material_rgb_to_bw_glsl[];
-extern char datatoc_gpu_shader_material_separate_hsv_glsl[];
-extern char datatoc_gpu_shader_material_separate_rgb_glsl[];
-extern char datatoc_gpu_shader_material_separate_xyz_glsl[];
-extern char datatoc_gpu_shader_material_set_glsl[];
-extern char datatoc_gpu_shader_material_shader_to_rgba_glsl[];
-extern char datatoc_gpu_shader_material_squeeze_glsl[];
-extern char datatoc_gpu_shader_material_subsurface_scattering_glsl[];
-extern char datatoc_gpu_shader_material_tangent_glsl[];
-extern char datatoc_gpu_shader_material_tex_brick_glsl[];
-extern char datatoc_gpu_shader_material_tex_checker_glsl[];
-extern char datatoc_gpu_shader_material_tex_environment_glsl[];
-extern char datatoc_gpu_shader_material_tex_gradient_glsl[];
-extern char datatoc_gpu_shader_material_tex_image_glsl[];
-extern char datatoc_gpu_shader_material_tex_magic_glsl[];
-extern char datatoc_gpu_shader_material_tex_musgrave_glsl[];
-extern char datatoc_gpu_shader_material_tex_noise_glsl[];
-extern char datatoc_gpu_shader_material_tex_sky_glsl[];
-extern char datatoc_gpu_shader_material_texture_coordinates_glsl[];
-extern char datatoc_gpu_shader_material_tex_voronoi_glsl[];
-extern char datatoc_gpu_shader_material_tex_wave_glsl[];
-extern char datatoc_gpu_shader_material_tex_white_noise_glsl[];
-extern char datatoc_gpu_shader_material_toon_glsl[];
-extern char datatoc_gpu_shader_material_translucent_glsl[];
-extern char datatoc_gpu_shader_material_transparent_glsl[];
-extern char datatoc_gpu_shader_material_uv_map_glsl[];
-extern char datatoc_gpu_shader_material_vector_curves_glsl[];
-extern char datatoc_gpu_shader_material_vector_displacement_glsl[];
-extern char datatoc_gpu_shader_material_vector_math_glsl[];
-extern char datatoc_gpu_shader_material_vector_rotate_glsl[];
-extern char datatoc_gpu_shader_material_velvet_glsl[];
-extern char datatoc_gpu_shader_material_vertex_color_glsl[];
-extern char datatoc_gpu_shader_material_volume_absorption_glsl[];
-extern char datatoc_gpu_shader_material_volume_info_glsl[];
-extern char datatoc_gpu_shader_material_volume_principled_glsl[];
-extern char datatoc_gpu_shader_material_volume_scatter_glsl[];
-extern char datatoc_gpu_shader_material_wireframe_glsl[];
-extern char datatoc_gpu_shader_material_world_normals_glsl[];
-
-static GPUMaterialLibrary gpu_shader_material_math_util_library = {
- .code = datatoc_gpu_shader_material_math_util_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_color_util_library = {
- .code = datatoc_gpu_shader_material_color_util_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_hash_library = {
- .code = datatoc_gpu_shader_material_hash_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_noise_library = {
- .code = datatoc_gpu_shader_material_noise_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_fractal_noise_library = {
- .code = datatoc_gpu_shader_material_fractal_noise_glsl,
- .dependencies = {&gpu_shader_material_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_add_shader_library = {
- .code = datatoc_gpu_shader_material_add_shader_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_ambient_occlusion_library = {
- .code = datatoc_gpu_shader_material_ambient_occlusion_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_glossy_library = {
- .code = datatoc_gpu_shader_material_glossy_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_anisotropic_library = {
- .code = datatoc_gpu_shader_material_anisotropic_glsl,
- .dependencies = {&gpu_shader_material_glossy_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_attribute_library = {
- .code = datatoc_gpu_shader_material_attribute_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_background_library = {
- .code = datatoc_gpu_shader_material_background_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_bevel_library = {
- .code = datatoc_gpu_shader_material_bevel_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_wavelength_library = {
- .code = datatoc_gpu_shader_material_wavelength_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_blackbody_library = {
- .code = datatoc_gpu_shader_material_blackbody_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_bright_contrast_library = {
- .code = datatoc_gpu_shader_material_bright_contrast_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_bump_library = {
- .code = datatoc_gpu_shader_material_bump_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_camera_library = {
- .code = datatoc_gpu_shader_material_camera_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_clamp_library = {
- .code = datatoc_gpu_shader_material_clamp_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_color_ramp_library = {
- .code = datatoc_gpu_shader_material_color_ramp_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_combine_hsv_library = {
- .code = datatoc_gpu_shader_material_combine_hsv_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_combine_rgb_library = {
- .code = datatoc_gpu_shader_material_combine_rgb_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_combine_xyz_library = {
- .code = datatoc_gpu_shader_material_combine_xyz_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_diffuse_library = {
- .code = datatoc_gpu_shader_material_diffuse_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_displacement_library = {
- .code = datatoc_gpu_shader_material_displacement_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_eevee_specular_library = {
- .code = datatoc_gpu_shader_material_eevee_specular_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_emission_library = {
- .code = datatoc_gpu_shader_material_emission_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_float_curve_library = {
- .code = datatoc_gpu_shader_material_float_curve_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_fresnel_library = {
- .code = datatoc_gpu_shader_material_fresnel_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_gamma_library = {
- .code = datatoc_gpu_shader_material_gamma_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tangent_library = {
- .code = datatoc_gpu_shader_material_tangent_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_geometry_library = {
- .code = datatoc_gpu_shader_material_geometry_glsl,
- .dependencies = {&gpu_shader_material_tangent_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_glass_library = {
- .code = datatoc_gpu_shader_material_glass_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_hair_info_library = {
- .code = datatoc_gpu_shader_material_hair_info_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_holdout_library = {
- .code = datatoc_gpu_shader_material_holdout_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_hue_sat_val_library = {
- .code = datatoc_gpu_shader_material_hue_sat_val_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_invert_library = {
- .code = datatoc_gpu_shader_material_invert_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_layer_weight_library = {
- .code = datatoc_gpu_shader_material_layer_weight_glsl,
- .dependencies = {&gpu_shader_material_fresnel_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_light_falloff_library = {
- .code = datatoc_gpu_shader_material_light_falloff_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_light_path_library = {
- .code = datatoc_gpu_shader_material_light_path_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_mapping_library = {
- .code = datatoc_gpu_shader_material_mapping_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_map_range_library = {
- .code = datatoc_gpu_shader_material_map_range_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_math_library = {
- .code = datatoc_gpu_shader_material_math_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_mix_rgb_library = {
- .code = datatoc_gpu_shader_material_mix_rgb_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_mix_shader_library = {
- .code = datatoc_gpu_shader_material_mix_shader_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_normal_library = {
- .code = datatoc_gpu_shader_material_normal_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_normal_map_library = {
- .code = datatoc_gpu_shader_material_normal_map_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_object_info_library = {
- .code = datatoc_gpu_shader_material_object_info_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_output_aov_library = {
- .code = datatoc_gpu_shader_material_output_aov_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_output_material_library = {
- .code = datatoc_gpu_shader_material_output_material_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_output_world_library = {
- .code = datatoc_gpu_shader_material_output_world_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_particle_info_library = {
- .code = datatoc_gpu_shader_material_particle_info_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_point_info_library = {
- .code = datatoc_gpu_shader_material_point_info_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_principled_library = {
- .code = datatoc_gpu_shader_material_principled_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_refraction_library = {
- .code = datatoc_gpu_shader_material_refraction_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_rgb_curves_library = {
- .code = datatoc_gpu_shader_material_rgb_curves_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_rgb_to_bw_library = {
- .code = datatoc_gpu_shader_material_rgb_to_bw_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_separate_hsv_library = {
- .code = datatoc_gpu_shader_material_separate_hsv_glsl,
- .dependencies = {&gpu_shader_material_color_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_separate_rgb_library = {
- .code = datatoc_gpu_shader_material_separate_rgb_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_separate_xyz_library = {
- .code = datatoc_gpu_shader_material_separate_xyz_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_set_library = {
- .code = datatoc_gpu_shader_material_set_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_shader_to_rgba_library = {
- .code = datatoc_gpu_shader_material_shader_to_rgba_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_squeeze_library = {
- .code = datatoc_gpu_shader_material_squeeze_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_subsurface_scattering_library = {
- .code = datatoc_gpu_shader_material_subsurface_scattering_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_brick_library = {
- .code = datatoc_gpu_shader_material_tex_brick_glsl,
- .dependencies = {&gpu_shader_material_math_util_library,
- &gpu_shader_material_hash_library,
- NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_checker_library = {
- .code = datatoc_gpu_shader_material_tex_checker_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_environment_library = {
- .code = datatoc_gpu_shader_material_tex_environment_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_gradient_library = {
- .code = datatoc_gpu_shader_material_tex_gradient_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_image_library = {
- .code = datatoc_gpu_shader_material_tex_image_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_magic_library = {
- .code = datatoc_gpu_shader_material_tex_magic_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_musgrave_library = {
- .code = datatoc_gpu_shader_material_tex_musgrave_glsl,
- .dependencies = {&gpu_shader_material_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_noise_library = {
- .code = datatoc_gpu_shader_material_tex_noise_glsl,
- .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_sky_library = {
- .code = datatoc_gpu_shader_material_tex_sky_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_texture_coordinates_library = {
- .code = datatoc_gpu_shader_material_texture_coordinates_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_voronoi_library = {
- .code = datatoc_gpu_shader_material_tex_voronoi_glsl,
- .dependencies = {&gpu_shader_material_math_util_library,
- &gpu_shader_material_hash_library,
- NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_wave_library = {
- .code = datatoc_gpu_shader_material_tex_wave_glsl,
- .dependencies = {&gpu_shader_material_fractal_noise_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_tex_white_noise_library = {
- .code = datatoc_gpu_shader_material_tex_white_noise_glsl,
- .dependencies = {&gpu_shader_material_hash_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_toon_library = {
- .code = datatoc_gpu_shader_material_toon_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_translucent_library = {
- .code = datatoc_gpu_shader_material_translucent_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_transparent_library = {
- .code = datatoc_gpu_shader_material_transparent_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_uv_map_library = {
- .code = datatoc_gpu_shader_material_uv_map_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_curves_library = {
- .code = datatoc_gpu_shader_material_vector_curves_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_displacement_library = {
- .code = datatoc_gpu_shader_material_vector_displacement_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_math_library = {
- .code = datatoc_gpu_shader_material_vector_math_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vector_rotate_library = {
- .code = datatoc_gpu_shader_material_vector_rotate_glsl,
- .dependencies = {&gpu_shader_material_math_util_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_velvet_library = {
- .code = datatoc_gpu_shader_material_velvet_glsl,
- .dependencies = {&gpu_shader_material_diffuse_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_vertex_color_library = {
- .code = datatoc_gpu_shader_material_vertex_color_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_absorption_library = {
- .code = datatoc_gpu_shader_material_volume_absorption_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_info_library = {
- .code = datatoc_gpu_shader_material_volume_info_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_principled_library = {
- .code = datatoc_gpu_shader_material_volume_principled_glsl,
- .dependencies = {&gpu_shader_material_blackbody_library, NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_volume_scatter_library = {
- .code = datatoc_gpu_shader_material_volume_scatter_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_wireframe_library = {
- .code = datatoc_gpu_shader_material_wireframe_glsl,
- .dependencies = {NULL},
-};
-
-static GPUMaterialLibrary gpu_shader_material_world_normals_library = {
- .code = datatoc_gpu_shader_material_world_normals_glsl,
- .dependencies = {&gpu_shader_material_texture_coordinates_library, NULL},
-};
-
-static GPUMaterialLibrary *gpu_material_libraries[] = {
- &gpu_shader_material_math_util_library,
- &gpu_shader_material_color_util_library,
- &gpu_shader_material_hash_library,
- &gpu_shader_material_noise_library,
- &gpu_shader_material_float_curve_library,
- &gpu_shader_material_fractal_noise_library,
- &gpu_shader_material_add_shader_library,
- &gpu_shader_material_ambient_occlusion_library,
- &gpu_shader_material_glossy_library,
- &gpu_shader_material_anisotropic_library,
- &gpu_shader_material_attribute_library,
- &gpu_shader_material_background_library,
- &gpu_shader_material_bevel_library,
- &gpu_shader_material_wavelength_library,
- &gpu_shader_material_blackbody_library,
- &gpu_shader_material_bright_contrast_library,
- &gpu_shader_material_bump_library,
- &gpu_shader_material_camera_library,
- &gpu_shader_material_clamp_library,
- &gpu_shader_material_color_ramp_library,
- &gpu_shader_material_combine_hsv_library,
- &gpu_shader_material_combine_rgb_library,
- &gpu_shader_material_combine_xyz_library,
- &gpu_shader_material_diffuse_library,
- &gpu_shader_material_displacement_library,
- &gpu_shader_material_eevee_specular_library,
- &gpu_shader_material_emission_library,
- &gpu_shader_material_fresnel_library,
- &gpu_shader_material_gamma_library,
- &gpu_shader_material_tangent_library,
- &gpu_shader_material_geometry_library,
- &gpu_shader_material_glass_library,
- &gpu_shader_material_hair_info_library,
- &gpu_shader_material_holdout_library,
- &gpu_shader_material_hue_sat_val_library,
- &gpu_shader_material_invert_library,
- &gpu_shader_material_layer_weight_library,
- &gpu_shader_material_light_falloff_library,
- &gpu_shader_material_light_path_library,
- &gpu_shader_material_mapping_library,
- &gpu_shader_material_map_range_library,
- &gpu_shader_material_math_library,
- &gpu_shader_material_mix_rgb_library,
- &gpu_shader_material_mix_shader_library,
- &gpu_shader_material_normal_library,
- &gpu_shader_material_normal_map_library,
- &gpu_shader_material_object_info_library,
- &gpu_shader_material_output_aov_library,
- &gpu_shader_material_output_material_library,
- &gpu_shader_material_output_world_library,
- &gpu_shader_material_particle_info_library,
- &gpu_shader_material_point_info_library,
- &gpu_shader_material_principled_library,
- &gpu_shader_material_refraction_library,
- &gpu_shader_material_rgb_curves_library,
- &gpu_shader_material_rgb_to_bw_library,
- &gpu_shader_material_separate_hsv_library,
- &gpu_shader_material_separate_rgb_library,
- &gpu_shader_material_separate_xyz_library,
- &gpu_shader_material_set_library,
- &gpu_shader_material_shader_to_rgba_library,
- &gpu_shader_material_squeeze_library,
- &gpu_shader_material_subsurface_scattering_library,
- &gpu_shader_material_tex_brick_library,
- &gpu_shader_material_tex_checker_library,
- &gpu_shader_material_tex_environment_library,
- &gpu_shader_material_tex_gradient_library,
- &gpu_shader_material_tex_image_library,
- &gpu_shader_material_tex_magic_library,
- &gpu_shader_material_tex_musgrave_library,
- &gpu_shader_material_tex_noise_library,
- &gpu_shader_material_tex_sky_library,
- &gpu_shader_material_texture_coordinates_library,
- &gpu_shader_material_tex_voronoi_library,
- &gpu_shader_material_tex_wave_library,
- &gpu_shader_material_tex_white_noise_library,
- &gpu_shader_material_toon_library,
- &gpu_shader_material_translucent_library,
- &gpu_shader_material_transparent_library,
- &gpu_shader_material_uv_map_library,
- &gpu_shader_material_vector_curves_library,
- &gpu_shader_material_vector_displacement_library,
- &gpu_shader_material_vector_math_library,
- &gpu_shader_material_vector_rotate_library,
- &gpu_shader_material_velvet_library,
- &gpu_shader_material_vertex_color_library,
- &gpu_shader_material_volume_absorption_library,
- &gpu_shader_material_volume_info_library,
- &gpu_shader_material_volume_principled_library,
- &gpu_shader_material_volume_scatter_library,
- &gpu_shader_material_wireframe_library,
- &gpu_shader_material_world_normals_library,
- NULL};
-
-/* GLSL code parsing for finding function definitions.
- * These are stored in a hash for lookup when creating a material. */
-
-static GHash *FUNCTION_HASH = NULL;
-
-const char *gpu_str_skip_token(const char *str, char *token, int max)
-{
- int len = 0;
-
- /* skip a variable/function name */
- while (*str) {
- if (ELEM(*str, ' ', '(', ')', ',', ';', '\t', '\n', '\r')) {
- break;
- }
-
- if (token && len < max - 1) {
- *token = *str;
- token++;
- len++;
- }
- str++;
- }
-
- if (token) {
- *token = '\0';
- }
-
- /* skip the next special characters:
- * note the missing ')' */
- while (*str) {
- if (ELEM(*str, ' ', '(', ',', ';', '\t', '\n', '\r')) {
- str++;
- }
- else {
- break;
- }
- }
-
- return str;
-}
-
-/* Indices match the eGPUType enum */
-static const char *GPU_DATATYPE_STR[17] = {
- "",
- "float",
- "vec2",
- "vec3",
- "vec4",
- NULL,
- NULL,
- NULL,
- NULL,
- "mat3",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "mat4",
-};
-
-const char *gpu_data_type_to_string(const eGPUType type)
-{
- return GPU_DATATYPE_STR[type];
-}
-
-static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
-{
- GPUFunction *function;
- eGPUType type;
- GPUFunctionQual qual;
- int i;
- const char *code = library->code;
-
- while ((code = strstr(code, "void "))) {
- function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
- function->library = library;
-
- code = gpu_str_skip_token(code, NULL, 0);
- code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME);
-
- /* get parameters */
- while (*code && *code != ')') {
- if (BLI_str_startswith(code, "const ")) {
- code = gpu_str_skip_token(code, NULL, 0);
- }
-
- /* test if it's an input or output */
- qual = FUNCTION_QUAL_IN;
- if (BLI_str_startswith(code, "out ")) {
- qual = FUNCTION_QUAL_OUT;
- }
- if (BLI_str_startswith(code, "inout ")) {
- qual = FUNCTION_QUAL_INOUT;
- }
- if ((qual != FUNCTION_QUAL_IN) || BLI_str_startswith(code, "in ")) {
- code = gpu_str_skip_token(code, NULL, 0);
- }
-
- /* test for type */
- type = GPU_NONE;
- for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) {
- if (GPU_DATATYPE_STR[i] && BLI_str_startswith(code, GPU_DATATYPE_STR[i])) {
- type = i;
- break;
- }
- }
-
- if (!type && BLI_str_startswith(code, "samplerCube")) {
- type = GPU_TEXCUBE;
- }
- if (!type && BLI_str_startswith(code, "sampler2DShadow")) {
- type = GPU_SHADOW2D;
- }
- if (!type && BLI_str_startswith(code, "sampler1DArray")) {
- type = GPU_TEX1D_ARRAY;
- }
- if (!type && BLI_str_startswith(code, "sampler2DArray")) {
- type = GPU_TEX2D_ARRAY;
- }
- if (!type && BLI_str_startswith(code, "sampler2D")) {
- type = GPU_TEX2D;
- }
- if (!type && BLI_str_startswith(code, "sampler3D")) {
- type = GPU_TEX3D;
- }
-
- if (!type && BLI_str_startswith(code, "Closure")) {
- type = GPU_CLOSURE;
- }
-
- if (type) {
- /* add parameter */
- code = gpu_str_skip_token(code, NULL, 0);
- code = gpu_str_skip_token(code, NULL, 0);
- function->paramqual[function->totparam] = qual;
- function->paramtype[function->totparam] = type;
- function->totparam++;
- }
- else {
- fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name);
- break;
- }
- }
-
- if (function->name[0] == '\0' || function->totparam == 0) {
- fprintf(stderr, "GPU functions parse error.\n");
- MEM_freeN(function);
- break;
- }
-
- BLI_ghash_insert(hash, function->name, function);
- }
-}
-
-/* Module */
-
-void gpu_material_library_init(void)
-{
- /* Only parse GLSL shader files once. */
- if (FUNCTION_HASH) {
- return;
- }
-
- FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
- for (int i = 0; gpu_material_libraries[i]; i++) {
- gpu_parse_material_library(FUNCTION_HASH, gpu_material_libraries[i]);
- }
-}
-
-void gpu_material_library_exit(void)
-{
- if (FUNCTION_HASH) {
- BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN);
- FUNCTION_HASH = NULL;
- }
-}
-
-/* Code Generation */
-
-static void gpu_material_use_library_with_dependencies(GSet *used_libraries,
- GPUMaterialLibrary *library)
-{
- if (BLI_gset_add(used_libraries, library->code)) {
- for (int i = 0; library->dependencies[i]; i++) {
- gpu_material_use_library_with_dependencies(used_libraries, library->dependencies[i]);
- }
- }
-}
-
-GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name)
-{
- GPUFunction *function = BLI_ghash_lookup(FUNCTION_HASH, (const void *)name);
- if (function) {
- gpu_material_use_library_with_dependencies(used_libraries, function->library);
- }
- return function;
-}
-
-char *gpu_material_library_generate_code(GSet *used_libraries, const char *frag_lib)
-{
- DynStr *ds = BLI_dynstr_new();
-
- if (frag_lib) {
- BLI_dynstr_append(ds, frag_lib);
- }
-
- /* Always include those because they may be needed by the execution function. */
- gpu_material_use_library_with_dependencies(used_libraries,
- &gpu_shader_material_world_normals_library);
-
- /* Add library code in order, for dependencies. */
- for (int i = 0; gpu_material_libraries[i]; i++) {
- GPUMaterialLibrary *library = gpu_material_libraries[i];
- if (BLI_gset_haskey(used_libraries, library->code)) {
- BLI_dynstr_append(ds, library->code);
- }
- }
-
- char *result = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- return result;
-}
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index 96e1a265c72..ffc2228a49b 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -10,16 +10,15 @@
#include "GPU_material.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MAX_FUNCTION_NAME 64
#define MAX_PARAMETER 36
struct GSet;
-typedef struct GPUMaterialLibrary {
- char *code;
- struct GPUMaterialLibrary *dependencies[8];
-} GPUMaterialLibrary;
-
typedef enum {
FUNCTION_QUAL_IN,
FUNCTION_QUAL_OUT,
@@ -31,20 +30,12 @@ typedef struct GPUFunction {
eGPUType paramtype[MAX_PARAMETER];
GPUFunctionQual paramqual[MAX_PARAMETER];
int totparam;
- GPUMaterialLibrary *library;
+ /* TOOD(@fclem): Clean that void pointer. */
+ void *source; /* GPUSource */
} GPUFunction;
-/* Module */
-
-void gpu_material_library_init(void);
-void gpu_material_library_exit(void);
-
-/* Code Generation */
-
GPUFunction *gpu_material_library_use_function(struct GSet *used_libraries, const char *name);
-char *gpu_material_library_generate_code(struct GSet *used_libraries, const char *frag_lib);
-
-/* Code Parsing */
-const char *gpu_str_skip_token(const char *str, char *token, int max);
-const char *gpu_data_type_to_string(eGPUType type);
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 57e415a8183..d9143a12d5b 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -87,10 +87,6 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
input->type = type;
switch (link->link_type) {
- case GPU_NODE_LINK_BUILTIN:
- input->source = GPU_SOURCE_BUILTIN;
- input->builtin = link->builtin;
- break;
case GPU_NODE_LINK_OUTPUT:
input->source = GPU_SOURCE_OUTPUT;
input->link = link;
@@ -132,6 +128,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
case GPU_NODE_LINK_UNIFORM:
input->source = GPU_SOURCE_UNIFORM;
break;
+ case GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN:
+ input->source = GPU_SOURCE_FUNCTION_CALL;
+ /* NOTE(@fclem): End of function call is the return variable set during codegen. */
+ SNPRINTF(input->function_call, "dF_branch(%s(), ", link->function_name);
+ break;
default:
break;
}
@@ -478,6 +479,11 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name);
+ if (type == CD_ORCO) {
+ /* OPTI: orco might be computed from local positions and needs object infos. */
+ GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO);
+ }
+
/* Dummy fallback if out of slots. */
if (attr == NULL) {
static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
@@ -523,6 +529,14 @@ GPUNodeLink *GPU_uniform(const float *num)
return link;
}
+GPUNodeLink *GPU_differentiate_float_function(const char *function_name)
+{
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN;
+ link->function_name = function_name;
+ return link;
+}
+
GPUNodeLink *GPU_image(GPUMaterial *mat,
Image *ima,
ImageUser *iuser,
@@ -588,41 +602,35 @@ GPUNodeLink *GPU_volume_grid(GPUMaterial *mat,
transform_link->volume_grid = link->volume_grid;
transform_link->volume_grid->users++;
+ GPUNodeLink *cos_link = GPU_attribute(mat, CD_ORCO, "");
+
/* Two special cases, where we adjust the output values of smoke grids to
* bring the into standard range without having to modify the grid values. */
if (STREQ(name, "color")) {
- GPU_link(mat, "node_attribute_volume_color", link, transform_link, &link);
+ GPU_link(mat, "node_attribute_volume_color", link, transform_link, cos_link, &link);
}
else if (STREQ(name, "temperature")) {
- GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, &link);
+ GPU_link(mat, "node_attribute_volume_temperature", link, transform_link, cos_link, &link);
}
else {
- GPU_link(mat, "node_attribute_volume", link, transform_link, &link);
+ GPU_link(mat, "node_attribute_volume", link, transform_link, cos_link, &link);
}
return link;
}
-GPUNodeLink *GPU_builtin(eGPUBuiltin builtin)
-{
- GPUNodeLink *link = gpu_node_link_create();
- link->link_type = GPU_NODE_LINK_BUILTIN;
- link->builtin = builtin;
- return link;
-}
-
/* Creating Nodes */
bool GPU_link(GPUMaterial *mat, const char *name, ...)
{
- GSet *used_libraries = gpu_material_used_libraries(mat);
+ GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNode *node;
GPUFunction *function;
GPUNodeLink *link, **linkptr;
va_list params;
int i;
- function = gpu_material_library_use_function(used_libraries, name);
+ function = gpu_material_library_use_function(graph->used_libraries, name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return false;
@@ -643,27 +651,25 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
}
va_end(params);
- GPUNodeGraph *graph = gpu_material_node_graph(mat);
BLI_addtail(&graph->nodes, node);
return true;
}
-bool GPU_stack_link(GPUMaterial *material,
- bNode *bnode,
- const char *name,
- GPUNodeStack *in,
- GPUNodeStack *out,
- ...)
+static bool gpu_stack_link_v(GPUMaterial *material,
+ bNode *bnode,
+ const char *name,
+ GPUNodeStack *in,
+ GPUNodeStack *out,
+ va_list params)
{
- GSet *used_libraries = gpu_material_used_libraries(material);
+ GPUNodeGraph *graph = gpu_material_node_graph(material);
GPUNode *node;
GPUFunction *function;
GPUNodeLink *link, **linkptr;
- va_list params;
int i, totin, totout;
- function = gpu_material_library_use_function(used_libraries, name);
+ function = gpu_material_library_use_function(graph->used_libraries, name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return false;
@@ -691,7 +697,6 @@ bool GPU_stack_link(GPUMaterial *material,
}
}
- va_start(params, out);
for (i = 0; i < function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
@@ -717,14 +722,27 @@ bool GPU_stack_link(GPUMaterial *material,
}
}
}
- va_end(params);
- GPUNodeGraph *graph = gpu_material_node_graph(material);
BLI_addtail(&graph->nodes, node);
return true;
}
+bool GPU_stack_link(GPUMaterial *material,
+ bNode *bnode,
+ const char *name,
+ GPUNodeStack *in,
+ GPUNodeStack *out,
+ ...)
+{
+ va_list params;
+ va_start(params, out);
+ bool valid = gpu_stack_link_v(material, bnode, name, in, out, params);
+ va_end(params);
+
+ return valid;
+}
+
GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat,
bNode *node,
GPUNodeStack *stack,
@@ -786,12 +804,16 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph)
gpu_node_free(node);
}
- graph->outlink = NULL;
+ graph->outlink_surface = NULL;
+ graph->outlink_volume = NULL;
+ graph->outlink_displacement = NULL;
+ graph->outlink_thickness = NULL;
}
void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
+ BLI_freelistN(&graph->material_functions);
gpu_node_graph_free_nodes(graph);
LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
@@ -801,28 +823,32 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
BLI_freelistN(&graph->textures);
BLI_freelistN(&graph->attributes);
GPU_uniform_attr_list_free(&graph->uniform_attrs);
+
+ if (graph->used_libraries) {
+ BLI_gset_free(graph->used_libraries, NULL);
+ graph->used_libraries = NULL;
+ }
}
/* Prune Unused Nodes */
-static void gpu_nodes_tag(GPUNodeLink *link)
+static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag)
{
GPUNode *node;
- GPUInput *input;
- if (!link->output) {
+ if (!link || !link->output) {
return;
}
node = link->output->node;
- if (node->tag) {
+ if (node->tag & tag) {
return;
}
- node->tag = true;
- for (input = node->inputs.first; input; input = input->next) {
+ node->tag |= tag;
+ LISTBASE_FOREACH (GPUInput *, input, &node->inputs) {
if (input->link) {
- gpu_nodes_tag(input->link);
+ gpu_nodes_tag(input->link, tag);
}
}
}
@@ -830,18 +856,25 @@ static void gpu_nodes_tag(GPUNodeLink *link)
void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
{
LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
- node->tag = false;
+ node->tag = GPU_NODE_TAG_NONE;
}
- gpu_nodes_tag(graph->outlink);
+ gpu_nodes_tag(graph->outlink_surface, GPU_NODE_TAG_SURFACE);
+ gpu_nodes_tag(graph->outlink_volume, GPU_NODE_TAG_VOLUME);
+ gpu_nodes_tag(graph->outlink_displacement, GPU_NODE_TAG_DISPLACEMENT);
+ gpu_nodes_tag(graph->outlink_thickness, GPU_NODE_TAG_THICKNESS);
+
LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) {
- gpu_nodes_tag(aovlink->outlink);
+ gpu_nodes_tag(aovlink->outlink, GPU_NODE_TAG_AOV);
+ }
+ LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) {
+ gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION);
}
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
next = node->next;
- if (!node->tag) {
+ if (node->tag == GPU_NODE_TAG_NONE) {
BLI_remlink(&graph->nodes, node);
gpu_node_free(node);
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index 5856001d548..024119e1c24 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -12,9 +12,15 @@
#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
+#include "BLI_ghash.h"
+
#include "GPU_material.h"
#include "GPU_shader.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct GPUNode;
struct GPUOutput;
struct ListBase;
@@ -25,19 +31,18 @@ typedef enum eGPUDataSource {
GPU_SOURCE_UNIFORM,
GPU_SOURCE_ATTR,
GPU_SOURCE_UNIFORM_ATTR,
- GPU_SOURCE_BUILTIN,
GPU_SOURCE_STRUCT,
GPU_SOURCE_TEX,
GPU_SOURCE_TEX_TILED_MAPPING,
GPU_SOURCE_VOLUME_GRID,
GPU_SOURCE_VOLUME_GRID_TRANSFORM,
+ GPU_SOURCE_FUNCTION_CALL,
} eGPUDataSource;
typedef enum {
GPU_NODE_LINK_NONE = 0,
GPU_NODE_LINK_ATTR,
GPU_NODE_LINK_UNIFORM_ATTR,
- GPU_NODE_LINK_BUILTIN,
GPU_NODE_LINK_COLORBAND,
GPU_NODE_LINK_CONSTANT,
GPU_NODE_LINK_IMAGE,
@@ -47,15 +52,28 @@ typedef enum {
GPU_NODE_LINK_VOLUME_GRID_TRANSFORM,
GPU_NODE_LINK_OUTPUT,
GPU_NODE_LINK_UNIFORM,
+ GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN,
} GPUNodeLinkType;
+typedef enum {
+ GPU_NODE_TAG_NONE = 0,
+ GPU_NODE_TAG_SURFACE = (1 << 0),
+ GPU_NODE_TAG_VOLUME = (1 << 1),
+ GPU_NODE_TAG_DISPLACEMENT = (1 << 2),
+ GPU_NODE_TAG_THICKNESS = (1 << 3),
+ GPU_NODE_TAG_AOV = (1 << 4),
+ GPU_NODE_TAG_FUNCTION = (1 << 5),
+} eGPUNodeTag;
+
+ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION)
+
struct GPUNode {
struct GPUNode *next, *prev;
const char *name;
/* Internal flag to mark nodes during pruning */
- bool tag;
+ eGPUNodeTag tag;
ListBase inputs;
ListBase outputs;
@@ -70,8 +88,6 @@ struct GPUNodeLink {
union {
/* GPU_NODE_LINK_CONSTANT | GPU_NODE_LINK_UNIFORM */
const float *data;
- /* GPU_NODE_LINK_BUILTIN */
- eGPUBuiltin builtin;
/* GPU_NODE_LINK_COLORBAND */
struct GPUTexture **colorband;
/* GPU_NODE_LINK_VOLUME_GRID */
@@ -84,6 +100,8 @@ struct GPUNodeLink {
struct GPUUniformAttr *uniform_attr;
/* GPU_NODE_LINK_IMAGE_BLENDER */
struct GPUMaterialTexture *texture;
+ /* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */
+ const char *function_name;
};
};
@@ -110,8 +128,6 @@ typedef struct GPUInput {
union {
/* GPU_SOURCE_CONSTANT | GPU_SOURCE_UNIFORM */
float vec[16]; /* vector data */
- /* GPU_SOURCE_BUILTIN */
- eGPUBuiltin builtin; /* builtin uniform */
/* GPU_SOURCE_TEX | GPU_SOURCE_TEX_TILED_MAPPING */
struct GPUMaterialTexture *texture;
/* GPU_SOURCE_ATTR */
@@ -120,6 +136,8 @@ typedef struct GPUInput {
struct GPUUniformAttr *uniform_attr;
/* GPU_SOURCE_VOLUME_GRID | GPU_SOURCE_VOLUME_GRID_TRANSFORM */
struct GPUMaterialVolumeGrid *volume_grid;
+ /* GPU_SOURCE_FUNCTION_CALL */
+ char function_call[64];
};
} GPUInput;
@@ -129,14 +147,25 @@ typedef struct GPUNodeGraphOutputLink {
GPUNodeLink *outlink;
} GPUNodeGraphOutputLink;
+typedef struct GPUNodeGraphFunctionLink {
+ struct GPUNodeGraphFunctionLink *next, *prev;
+ char name[16];
+ GPUNodeLink *outlink;
+} GPUNodeGraphFunctionLink;
+
typedef struct GPUNodeGraph {
/* Nodes */
ListBase nodes;
- /* Main Output. */
- GPUNodeLink *outlink;
+ /* Main Outputs. */
+ GPUNodeLink *outlink_surface;
+ GPUNodeLink *outlink_volume;
+ GPUNodeLink *outlink_displacement;
+ GPUNodeLink *outlink_thickness;
/* List of GPUNodeGraphOutputLink */
ListBase outlink_aovs;
+ /* List of GPUNodeGraphFunctionLink */
+ ListBase material_functions;
/* Requested attributes and textures. */
ListBase attributes;
@@ -145,6 +174,9 @@ typedef struct GPUNodeGraph {
/* The list of uniform attributes. */
GPUUniformAttrList uniform_attrs;
+
+ /** Set of all the GLSL lib code blocks . */
+ GSet *used_libraries;
} GPUNodeGraph;
/* Node Graph */
@@ -171,4 +203,6 @@ struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat,
float *pixels,
float *row);
-struct GSet *gpu_material_used_libraries(struct GPUMaterial *material);
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 76b3402435a..fe9aacb95f9 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -294,7 +294,9 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
std::string defines = shader->defines_declare(info);
std::string resources = shader->resources_declare(info);
- defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
+ if (info.legacy_resource_location_ == false) {
+ defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
+ }
Vector<const char *> typedefs;
if (!info.typedef_sources_.is_empty() || !info.typedef_source_generated.empty()) {
@@ -362,6 +364,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
sources.append(resources.c_str());
sources.append(layout.c_str());
sources.append(interface.c_str());
+ sources.append(info.geometry_source_generated.c_str());
sources.extend(code);
shader->geometry_shader_from_glsl(sources);
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
index 95f9b031fe8..515f65adb73 100644
--- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -202,10 +202,7 @@ int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *UNUSED(subdiv_ccg),
/* -------------------------------------------------------------------- */
/** \name Stubs of BKE_node.h
* \{ */
-void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree),
- struct GPUMaterial *UNUSED(mat),
- bool *UNUSED(has_surface_output),
- bool *UNUSED(has_volume_output))
+void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree), struct GPUMaterial *UNUSED(mat))
{
BLI_assert_unreachable();
}
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index dfd73219d1b..3ab96d0d84a 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -284,6 +284,8 @@ struct ShaderCreateInfo {
bool auto_resource_location_ = false;
/** If true, force depth and stencil tests to always happen before fragment shader invocation. */
bool early_fragment_test_ = false;
+ /** If true, force the use of the GL shader introspection for resource location. */
+ bool legacy_resource_location_ = false;
/** Allow optimization when fragment shader writes to `gl_FragDepth`. */
DepthWrite depth_write_ = DepthWrite::ANY;
/**
@@ -296,6 +298,7 @@ struct ShaderCreateInfo {
/** Manually set generated code. */
std::string vertex_source_generated = "";
std::string fragment_source_generated = "";
+ std::string geometry_source_generated = "";
std::string typedef_source_generated = "";
/** Manually set generated dependencies. */
Vector<const char *, 0> dependencies_generated;
@@ -721,6 +724,12 @@ struct ShaderCreateInfo {
return *(Self *)this;
}
+ Self &legacy_resource_location(bool value)
+ {
+ legacy_resource_location_ = value;
+ return *(Self *)this;
+ }
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 2c6845334d3..7ee64d7e80f 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -10,11 +10,14 @@
#include <iomanip>
#include <iostream>
+#include <sstream>
+#include "BLI_ghash.h"
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
+#include "gpu_material_library.h"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
@@ -31,6 +34,7 @@ extern "C" {
namespace blender::gpu {
using GPUSourceDictionnary = Map<StringRef, struct GPUSource *>;
+using GPUFunctionDictionnary = Map<StringRef, struct GPUFunction *>;
struct GPUSource {
StringRefNull fullpath;
@@ -41,7 +45,10 @@ struct GPUSource {
shader::BuiltinBits builtins = (shader::BuiltinBits)0;
std::string processed_source;
- GPUSource(const char *path, const char *file, const char *datatoc)
+ GPUSource(const char *path,
+ const char *file,
+ const char *datatoc,
+ GPUFunctionDictionnary *g_functions)
: fullpath(path), filename(file), source(datatoc)
{
/* Scan for builtins. */
@@ -92,16 +99,20 @@ struct GPUSource {
if (filename.endswith(".h") || filename.endswith(".hh")) {
enum_preprocess();
}
+
+ if (is_from_material_library()) {
+ material_functions_parse(g_functions);
+ }
};
- bool is_in_comment(const StringRef &input, int64_t offset)
+ static bool is_in_comment(const StringRef &input, int64_t offset)
{
return (input.rfind("/*", offset) > input.rfind("*/", offset)) ||
(input.rfind("//", offset) > input.rfind("\n", offset));
}
template<bool check_whole_word = true, bool reversed = false, typename T>
- int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
+ static int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
{
while (true) {
if constexpr (reversed) {
@@ -114,7 +125,7 @@ struct GPUSource {
if constexpr (check_whole_word) {
/* Fix false positive if something has "enum" as suffix. */
char previous_char = input[offset - 1];
- if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) {
+ if (!(ELEM(previous_char, '\n', '\t', ' ', ':', '(', ','))) {
offset += (reversed) ? -1 : 1;
continue;
}
@@ -129,9 +140,13 @@ struct GPUSource {
}
}
+#define find_keyword find_str<true, false>
+#define rfind_keyword find_str<true, true>
+#define find_token find_str<false, false>
+#define rfind_token find_str<false, true>
+
void print_error(const StringRef &input, int64_t offset, const StringRef message)
{
- std::cout << " error: " << message << "\n";
StringRef sub = input.substr(0, offset);
int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1;
int64_t line_end = input.find("\n", offset);
@@ -152,6 +167,12 @@ struct GPUSource {
std::cout << "^\n";
}
+#define CHECK(test_value, str, ofs, msg) \
+ if ((test_value) == -1) { \
+ print_error(str, ofs, msg); \
+ continue; \
+ }
+
/**
* Transform C,C++ enum declaration into GLSL compatible defines and constants:
*
@@ -193,16 +214,6 @@ struct GPUSource {
int64_t last_pos = 0;
const bool is_cpp = filename.endswith(".hh");
-#define find_keyword find_str<true, false>
-#define find_token find_str<false, false>
-#define rfind_token find_str<false, true>
-#define CHECK(test_value, str, ofs, msg) \
- if ((test_value) == -1) { \
- print_error(str, ofs, msg); \
- cursor++; \
- continue; \
- }
-
while (true) {
cursor = find_keyword(input, "enum ", cursor + 1);
if (cursor == -1) {
@@ -268,10 +279,6 @@ struct GPUSource {
return;
}
-#undef find_keyword
-#undef find_token
-#undef rfind_token
-
if (last_pos != 0) {
output += input.substr(last_pos);
}
@@ -279,37 +286,241 @@ struct GPUSource {
source = processed_source.c_str();
};
+ void material_functions_parse(GPUFunctionDictionnary *g_functions)
+ {
+ const StringRefNull input = source;
+
+ const char whitespace_chars[] = " \n\t";
+
+ auto function_parse = [&](const StringRef &input,
+ int64_t &cursor,
+ StringRef &out_return_type,
+ StringRef &out_name,
+ StringRef &out_args) -> bool {
+ cursor = find_keyword(input, "void ", cursor + 1);
+ if (cursor == -1) {
+ return false;
+ }
+ int64_t arg_start = find_token(input, '(', cursor);
+ if (arg_start == -1) {
+ return false;
+ }
+ int64_t arg_end = find_token(input, ')', arg_start);
+ if (arg_end == -1) {
+ return false;
+ }
+ int64_t body_start = find_token(input, '{', arg_end);
+ int64_t next_semicolon = find_token(input, ';', arg_end);
+ if (body_start != -1 && next_semicolon != -1 && body_start > next_semicolon) {
+ /* Assert no prototypes but could also just skip them. */
+ BLI_assert_msg(false, "No prototypes allowed in node GLSL libraries.");
+ }
+ int64_t name_start = input.find_first_not_of(whitespace_chars, input.find(' ', cursor));
+ if (name_start == -1) {
+ return false;
+ }
+ int64_t name_end = input.find_last_not_of(whitespace_chars, arg_start);
+ if (name_end == -1) {
+ return false;
+ }
+ /* Only support void type for now. */
+ out_return_type = "void";
+ out_name = input.substr(name_start, name_end - name_start);
+ out_args = input.substr(arg_start + 1, arg_end - (arg_start + 1));
+ return true;
+ };
+
+ auto keyword_parse = [&](const StringRef &str, int64_t &cursor) -> const StringRef {
+ int64_t keyword_start = str.find_first_not_of(whitespace_chars, cursor);
+ if (keyword_start == -1) {
+ /* No keyword found. */
+ return str.substr(0, 0);
+ }
+ int64_t keyword_end = str.find_first_of(whitespace_chars, keyword_start);
+ if (keyword_end == -1) {
+ /* Last keyword. */
+ keyword_end = str.size();
+ }
+ cursor = keyword_end + 1;
+ return str.substr(keyword_start, keyword_end - keyword_start);
+ };
+
+ auto arg_parse = [&](const StringRef &str,
+ int64_t &cursor,
+ StringRef &out_qualifier,
+ StringRef &out_type,
+ StringRef &out_name) -> bool {
+ int64_t arg_start = cursor + 1;
+ if (arg_start >= str.size()) {
+ return false;
+ }
+ cursor = find_token(str, ',', arg_start);
+ if (cursor == -1) {
+ /* Last argument. */
+ cursor = str.size();
+ }
+ const StringRef arg = str.substr(arg_start, cursor - arg_start);
+
+ int64_t keyword_cursor = 0;
+ out_qualifier = keyword_parse(arg, keyword_cursor);
+ out_type = keyword_parse(arg, keyword_cursor);
+ out_name = keyword_parse(arg, keyword_cursor);
+ if (out_name.is_empty()) {
+ /* No qualifier case. */
+ out_name = out_type;
+ out_type = out_qualifier;
+ out_qualifier = arg.substr(0, 0);
+ }
+ return true;
+ };
+
+ int64_t cursor = -1;
+ StringRef func_return_type, func_name, func_args;
+ while (function_parse(input, cursor, func_return_type, func_name, func_args)) {
+ GPUFunction *func = MEM_new<GPUFunction>(__func__);
+ func_name.copy(func->name, sizeof(func->name));
+ func->source = reinterpret_cast<void *>(this);
+
+ bool insert = g_functions->add(func->name, func);
+
+ /* NOTE: We allow overloading non void function, but only if the function comes from the
+ * same file. Otherwise the dependency system breaks. */
+ if (!insert) {
+ GPUSource *other_source = reinterpret_cast<GPUSource *>(
+ g_functions->lookup(func_name)->source);
+ if (other_source != this) {
+ print_error(input,
+ source.find(func_name),
+ "Function redefinition or overload in two different files ...");
+ print_error(
+ input, other_source->source.find(func_name), "... previous definition was here");
+ }
+ else {
+ /* Non-void function overload. */
+ MEM_delete(func);
+ }
+ continue;
+ }
+
+ if (func_return_type != "void") {
+ continue;
+ }
+
+ func->totparam = 0;
+ int64_t args_cursor = -1;
+ StringRef arg_qualifier, arg_type, arg_name;
+ while (arg_parse(func_args, args_cursor, arg_qualifier, arg_type, arg_name)) {
+
+ if (func->totparam >= ARRAY_SIZE(func->paramtype)) {
+ print_error(input, source.find(func_name), "Too much parameter in function");
+ break;
+ }
+
+ auto parse_qualifier = [](StringRef &qualifier) -> GPUFunctionQual {
+ if (qualifier == "out") {
+ return FUNCTION_QUAL_OUT;
+ }
+ else if (qualifier == "inout") {
+ return FUNCTION_QUAL_INOUT;
+ }
+ else {
+ return FUNCTION_QUAL_IN;
+ }
+ };
+
+ auto parse_type = [](StringRef &type) -> eGPUType {
+ if (type == "float") {
+ return GPU_FLOAT;
+ }
+ else if (type == "vec2") {
+ return GPU_VEC2;
+ }
+ else if (type == "vec3") {
+ return GPU_VEC3;
+ }
+ else if (type == "vec4") {
+ return GPU_VEC4;
+ }
+ else if (type == "mat3") {
+ return GPU_MAT3;
+ }
+ else if (type == "mat4") {
+ return GPU_MAT4;
+ }
+ else if (type == "sampler1DArray") {
+ return GPU_TEX1D_ARRAY;
+ }
+ else if (type == "sampler2DArray") {
+ return GPU_TEX2D_ARRAY;
+ }
+ else if (type == "sampler2D") {
+ return GPU_TEX2D;
+ }
+ else if (type == "sampler3D") {
+ return GPU_TEX3D;
+ }
+ else if (type == "Closure") {
+ return GPU_CLOSURE;
+ }
+ else {
+ return GPU_NONE;
+ }
+ };
+
+ func->paramqual[func->totparam] = parse_qualifier(arg_qualifier);
+ func->paramtype[func->totparam] = parse_type(arg_type);
+
+ if (func->paramtype[func->totparam] == GPU_NONE) {
+ std::string err = "Unknown parameter type \"" + arg_type + "\"";
+ int64_t err_ofs = source.find(func_name);
+ err_ofs = find_keyword(source, arg_name, err_ofs);
+ err_ofs = rfind_keyword(source, arg_type, err_ofs);
+ print_error(input, err_ofs, err);
+ }
+
+ func->totparam++;
+ }
+ }
+ }
+
+#undef find_keyword
+#undef rfind_keyword
+#undef find_token
+#undef rfind_token
+
/* Return 1 one error. */
- int init_dependencies(const GPUSourceDictionnary &dict)
+ int init_dependencies(const GPUSourceDictionnary &dict,
+ const GPUFunctionDictionnary &g_functions)
{
- if (dependencies_init) {
+ if (this->dependencies_init) {
return 0;
}
- dependencies_init = true;
- int64_t pos = 0;
+ this->dependencies_init = true;
+ int64_t pos = -1;
+
while (true) {
- pos = source.find("pragma BLENDER_REQUIRE(", pos);
- if (pos == -1) {
- return 0;
- }
- int64_t start = source.find('(', pos) + 1;
- int64_t end = source.find(')', pos);
- if (end == -1) {
- /* TODO Use clog. */
- std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"."
- << std::endl;
- return 1;
- }
- StringRef dependency_name = source.substr(start, end - start);
- GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr);
- if (dependency_source == nullptr) {
- /* TODO Use clog. */
- std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name
- << "\"." << std::endl;
- return 1;
+ GPUSource *dependency_source = nullptr;
+
+ {
+ pos = source.find("pragma BLENDER_REQUIRE(", pos + 1);
+ if (pos == -1) {
+ return 0;
+ }
+ int64_t start = source.find('(', pos) + 1;
+ int64_t end = source.find(')', pos);
+ if (end == -1) {
+ print_error(source, start, "Malformed BLENDER_REQUIRE: Missing \")\" token");
+ return 1;
+ }
+ StringRef dependency_name = source.substr(start, end - start);
+ dependency_source = dict.lookup_default(dependency_name, nullptr);
+ if (dependency_source == nullptr) {
+ print_error(source, start, "Dependency not found");
+ return 1;
+ }
}
/* Recursive. */
- int result = dependency_source->init_dependencies(dict);
+ int result = dependency_source->init_dependencies(dict, g_functions);
if (result != 0) {
return 1;
}
@@ -318,8 +529,8 @@ struct GPUSource {
dependencies.append_non_duplicates(dep);
}
dependencies.append_non_duplicates(dependency_source);
- pos++;
- };
+ }
+ return 0;
}
/* Returns the final string with all includes done. */
@@ -339,6 +550,11 @@ struct GPUSource {
}
return out_builtins;
}
+
+ bool is_from_material_library() const
+ {
+ return filename.startswith("gpu_shader_material_") && filename.endswith(".glsl");
+ }
};
} // namespace blender::gpu
@@ -346,13 +562,15 @@ struct GPUSource {
using namespace blender::gpu;
static GPUSourceDictionnary *g_sources = nullptr;
+static GPUFunctionDictionnary *g_functions = nullptr;
void gpu_shader_dependency_init()
{
g_sources = new GPUSourceDictionnary();
+ g_functions = new GPUFunctionDictionnary();
#define SHADER_SOURCE(datatoc, filename, filepath) \
- g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc));
+ g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc, g_functions));
#include "glsl_draw_source_list.h"
#include "glsl_gpu_source_list.h"
#ifdef WITH_OCIO
@@ -362,7 +580,7 @@ void gpu_shader_dependency_init()
int errors = 0;
for (auto *value : g_sources->values()) {
- errors += value->init_dependencies(*g_sources);
+ errors += value->init_dependencies(*g_sources, *g_functions);
}
BLI_assert_msg(errors == 0, "Dependency errors detected: Aborting");
UNUSED_VARS_NDEBUG(errors);
@@ -373,7 +591,20 @@ void gpu_shader_dependency_exit()
for (auto *value : g_sources->values()) {
delete value;
}
+ for (auto *value : g_functions->values()) {
+ MEM_delete(value);
+ }
delete g_sources;
+ delete g_functions;
+}
+
+GPUFunction *gpu_material_library_use_function(GSet *used_libraries, const char *name)
+{
+ GPUFunction *function = g_functions->lookup_default(name, nullptr);
+ BLI_assert_msg(function != nullptr, "Requested function not in the function library");
+ GPUSource *source = reinterpret_cast<GPUSource *>(function->source);
+ BLI_gset_add(used_libraries, const_cast<char *>(source->filename.c_str()));
+ return function;
}
namespace blender::gpu::shader {
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 5938444ce49..9768318f3b6 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -572,10 +572,13 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
}
if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
if (!GLContext::native_barycentric_support) {
+ ss << "flat in vec4 gpu_pos[3];\n";
ss << "smooth in vec3 gpu_BaryCoord;\n";
ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n";
+ ss << "#define gpu_position_at_vertex(v) gpu_pos[v]\n";
}
else if (GLEW_AMD_shader_explicit_vertex_parameter) {
+ std::cout << "native" << std::endl;
/* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry
* shader workaround if this extension/feature is detected. */
ss << "\n/* Stable Barycentric Coordinates. */\n";
@@ -591,6 +594,12 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n";
ss << " return bary.xyz;\n";
ss << "}\n";
+ ss << "\n";
+ ss << "vec4 gpu_position_at_vertex(int v) {\n";
+ ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { v = (v + 2) % 3; }\n";
+ ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { v = (v + 1) % 3; }\n";
+ ss << " return interpolateAtVertexAMD(gpu_pos, v);\n";
+ ss << "}\n";
pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n";
pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n";
@@ -730,6 +739,7 @@ std::string GLShader::workaround_geometry_shader_source_create(
ss << "in int gpu_Layer[];\n";
}
if (do_barycentric_workaround) {
+ ss << "flat out vec4 gpu_pos[3];\n";
ss << "smooth out vec3 gpu_BaryCoord;\n";
ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\n";
}
@@ -740,6 +750,11 @@ std::string GLShader::workaround_geometry_shader_source_create(
if (do_layer_workaround) {
ss << " gl_Layer = gpu_Layer[0];\n";
}
+ if (do_barycentric_workaround) {
+ ss << " gpu_pos[0] = gl_in[0].gl_Position;\n";
+ ss << " gpu_pos[1] = gl_in[1].gl_Position;\n";
+ ss << " gpu_pos[2] = gl_in[2].gl_Position;\n";
+ }
for (auto i : IndexRange(3)) {
for (StageInterfaceInfo *iface : info_modified.vertex_out_interfaces_) {
for (auto &inout : iface->inouts) {
@@ -977,7 +992,7 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info)
return false;
}
- if (info != nullptr) {
+ if (info != nullptr && info->legacy_resource_location_ == false) {
interface = new GLShaderInterface(shader_program_, *info);
}
else {
diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
index 193a4190cbf..5c97eada77d 100644
--- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl
@@ -95,3 +95,176 @@ vec4 tangent_get(vec4 attr, mat3 normalmat)
}
#endif
+
+/* Assumes GPU_VEC4 is color data. So converting to luminance like cycles. */
+#define float_from_vec4(v) dot(v.rgb, vec3(0.2126, 0.7152, 0.0722))
+#define float_from_vec3(v) avg(v.rgb)
+#define float_from_vec2(v) v.r
+
+#define vec2_from_vec4(v) vec2(avg(v.rgb), v.a)
+#define vec2_from_vec3(v) vec2(avg(v.rgb), 1.0)
+#define vec2_from_float(v) vec2(v)
+
+#define vec3_from_vec4(v) v.rgb
+#define vec3_from_vec2(v) v.rrr
+#define vec3_from_float(v) vec3(v)
+
+#define vec4_from_vec3(v) vec4(v, 1.0)
+#define vec4_from_vec2(v) v.rrrg
+#define vec4_from_float(v) vec4(vec3(v), 1.0)
+
+/* TODO: Move to shader_shared. */
+#define RAY_TYPE_CAMERA 0
+#define RAY_TYPE_SHADOW 1
+#define RAY_TYPE_DIFFUSE 2
+#define RAY_TYPE_GLOSSY 3
+
+#ifdef GPU_FRAGMENT_SHADER
+# define FrontFacing gl_FrontFacing
+#else
+# define FrontFacing true
+#endif
+
+struct ClosureDiffuse {
+ float weight;
+ vec3 color;
+ vec3 N;
+ vec3 sss_radius;
+ uint sss_id;
+};
+
+struct ClosureTranslucent {
+ float weight;
+ vec3 color;
+ vec3 N;
+};
+
+struct ClosureReflection {
+ float weight;
+ vec3 color;
+ vec3 N;
+ float roughness;
+};
+
+struct ClosureRefraction {
+ float weight;
+ vec3 color;
+ vec3 N;
+ float roughness;
+ float ior;
+};
+
+struct ClosureHair {
+ float weight;
+ vec3 color;
+ float offset;
+ vec2 roughness;
+ vec3 T;
+};
+
+struct ClosureVolumeScatter {
+ float weight;
+ vec3 scattering;
+ float anisotropy;
+};
+
+struct ClosureVolumeAbsorption {
+ float weight;
+ vec3 absorption;
+};
+
+struct ClosureEmission {
+ float weight;
+ vec3 emission;
+};
+
+struct ClosureTransparency {
+ float weight;
+ vec3 transmittance;
+ float holdout;
+};
+
+struct GlobalData {
+ /** World position. */
+ vec3 P;
+ /** Surface Normal. */
+ vec3 N;
+ /** Geometric Normal. */
+ vec3 Ng;
+ /** Surface default Tangent. */
+ vec3 T;
+ /** Barycentric coordinates. */
+ vec2 barycentric_coords;
+ vec3 barycentric_dists;
+ /** Ray properties (approximation). */
+ int ray_type;
+ float ray_depth;
+ float ray_length;
+ /** Hair time along hair length. 0 at base 1 at tip. */
+ float hair_time;
+ /** Hair time along width of the hair. */
+ float hair_time_width;
+ /** Hair thickness in world space. */
+ float hair_thickness;
+ /** Index of the strand for per strand effects. */
+ int hair_strand_id;
+ /** Is hair. */
+ bool is_strand;
+};
+
+GlobalData g_data;
+
+#ifndef GPU_FRAGMENT_SHADER
+/* Stubs. */
+vec3 dF_impl(vec3 v)
+{
+ return vec3(0.0);
+}
+
+void dF_branch(float fn, out vec2 result)
+{
+ result = vec2(0.0);
+}
+
+#elif 0 /* TODO(@fclem): User Option? */
+/* Fast derivatives */
+vec3 dF_impl(vec3 v)
+{
+ return vec3(0.0);
+}
+
+void dF_branch(float fn, out vec2 result)
+{
+ result.x = DFDX_SIGN * dFdx(fn);
+ result.y = DFDY_SIGN * dFdy(fn);
+}
+
+#else
+/* Precise derivatives */
+int g_derivative_flag = 0;
+
+vec3 dF_impl(vec3 v)
+{
+ if (g_derivative_flag > 0) {
+ return DFDX_SIGN * dFdx(v);
+ }
+ else if (g_derivative_flag < 0) {
+ return DFDY_SIGN * dFdy(v);
+ }
+ return vec3(0.0);
+}
+
+# define dF_branch(fn, result) \
+ if (true) { \
+ g_derivative_flag = 1; \
+ result.x = (fn); \
+ g_derivative_flag = -1; \
+ result.y = (fn); \
+ g_derivative_flag = 0; \
+ result -= vec2((fn)); \
+ }
+
+#endif
+
+/* TODO(fclem): Remove. */
+#define CODEGEN_LIB
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
index 12921a31b23..4ba1f6f7368 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl
@@ -1,4 +1,4 @@
-#ifndef VOLUMETRICS
+
void node_ambient_occlusion(vec4 color,
float dist,
vec3 normal,
@@ -7,20 +7,6 @@ void node_ambient_occlusion(vec4 color,
out vec4 result_color,
out float result_ao)
{
- vec3 bent_normal;
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count);
-
- vec3 V = cameraVec(worldPosition);
- vec3 N = normalize(normal);
- vec3 Ng = safe_normalize(cross(dFdx(worldPosition), dFdy(worldPosition)));
-
- float unused_error;
- vec3 unused;
- occlusion_eval(data, V, N, Ng, inverted, result_ao, unused_error, unused);
+ result_ao = ambient_occlusion_eval(normal, dist, inverted, sample_count);
result_color = result_ao * color;
}
-#else
-/* Stub ambient occlusion because it is not compatible with volumetrics. */
-# define node_ambient_occlusion(a, b, c, d, e, f) (e = vec4(0); f = 0.0)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
index ec49cc86761..77de9e096a6 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl
@@ -1,17 +1,27 @@
-#ifndef VOLUMETRICS
+
void node_bsdf_anisotropic(vec4 color,
float roughness,
float anisotropy,
float rotation,
vec3 N,
vec3 T,
- const float use_multiscatter,
- const float ssr_id,
+ float weight,
+ const float do_multiscatter,
out Closure result)
{
- node_bsdf_glossy(color, roughness, N, use_multiscatter, ssr_id, result);
+ N = safe_normalize(N);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
+
+ vec2 split_sum = brdf_lut(NV, roughness);
+
+ ClosureReflection reflection_data;
+ reflection_data.weight = weight;
+ reflection_data.color = (do_multiscatter != 0.0) ?
+ F_brdf_multi_scatter(color.rgb, color.rgb, split_sum) :
+ F_brdf_single_scatter(color.rgb, color.rgb, split_sum);
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
+
+ result = closure_eval(reflection_data);
}
-#else
-/* Stub anisotropic because it is not compatible with volumetrics. */
-# define node_bsdf_anisotropic(a, b, c, d, e, f, g, h, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
index 69ef4dcb7c7..2460bd63b38 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_background.glsl
@@ -1,11 +1,9 @@
-void node_background(vec4 color, float strength, out Closure result)
+
+void node_background(vec4 color, float strength, float weight, out Closure result)
{
-#ifndef VOLUMETRICS
- color *= strength;
- result = CLOSURE_DEFAULT;
- result.radiance = color.rgb;
- result.transmittance = vec3(0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = color.rgb * strength;
+
+ result = closure_eval(emission_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
index 9f73f654217..e0931128485 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl
@@ -1,28 +1,19 @@
-void dfdx_v3(vec3 v, out vec3 dy)
-{
- dy = v + DFDX_SIGN * dFdx(v);
-}
-void dfdy_v3(vec3 v, out vec3 dy)
+void differentiate_texco(vec3 v, out vec3 df)
{
- dy = v + DFDY_SIGN * dFdy(v);
+ /* Implementation defined. */
+ df = v + dF_impl(v);
}
-void node_bump(float strength,
- float dist,
- float height,
- float height_dx,
- float height_dy,
- vec3 N,
- vec3 surf_pos,
- float invert,
- out vec3 result)
+void node_bump(
+ float strength, float dist, float height, vec3 N, vec2 dHd, float invert, out vec3 result)
{
- N = mat3(ViewMatrix) * normalize(N);
- dist *= gl_FrontFacing ? invert : -invert;
+ N = normalize(N);
+ dist *= FrontFacing ? invert : -invert;
- vec3 dPdx = dFdx(surf_pos);
- vec3 dPdy = dFdy(surf_pos);
+#ifdef GPU_FRAGMENT_SHADER
+ vec3 dPdx = dFdx(g_data.P);
+ vec3 dPdy = dFdy(g_data.P);
/* Get surface tangents from normal. */
vec3 Rx = cross(dPdy, N);
@@ -31,14 +22,13 @@ void node_bump(float strength,
/* Compute surface gradient and determinant. */
float det = dot(dPdx, Rx);
- float dHdx = height_dx - height;
- float dHdy = height_dy - height;
- vec3 surfgrad = dHdx * Rx + dHdy * Ry;
+ vec3 surfgrad = dHd.x * Rx + dHd.y * Ry;
strength = max(strength, 0.0);
result = normalize(abs(det) * N - dist * sign(det) * surfgrad);
result = normalize(mix(N, result, strength));
-
- result = mat3(ViewMatrixInverse) * result;
+#else
+ result = N;
+#endif
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
index 03e61e9f472..ff84a0a334c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -1,6 +1,6 @@
-void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
+void camera(out vec3 outview, out float outdepth, out float outdist)
{
- outdepth = abs(co.z);
- outdist = length(co);
- outview = normalize(co);
+ outdepth = abs(transform_point(ViewMatrix, g_data.P).z);
+ outdist = distance(g_data.P, cameraPos);
+ outview = normalize(g_data.P - cameraPos);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
index 2ce061da3cb..e8f444080b9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_combine_hsv.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void combine_hsv(float h, float s, float v, out vec4 col)
{
hsv_to_rgb(vec4(h, s, v, 1.0), col);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
index ab6024b073d..bbdd86bd664 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
@@ -1,28 +1,11 @@
-#ifndef VOLUMETRICS
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse)
-
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, float weight, out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Diffuse);
-
- in_Diffuse_0.N = N; /* Normalized during eval. */
- in_Diffuse_0.albedo = color.rgb;
-
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse);
-
- result = CLOSURE_DEFAULT;
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
- out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance);
- out_Diffuse_0.radiance *= color.rgb;
-
- result.radiance = out_Diffuse_0.radiance;
-
- /* TODO(@fclem): Try to not use this. */
- closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
+ result = closure_eval(diffuse_data);
}
-
-#else
-/* Stub diffuse because it is not compatible with volumetrics. */
-# define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
index 0838b5c8b71..cdcdbe50917 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_displacement.glsl
@@ -1,9 +1,9 @@
-void node_displacement_object(
- float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result)
+void node_displacement_object(float height, float midlevel, float scale, vec3 N, out vec3 result)
{
- N = (vec4(N, 0.0) * obmat).xyz;
+ N = transform_direction(ModelMatrix, N);
result = (height - midlevel) * scale * normalize(N);
- result = (obmat * vec4(result, 0.0)).xyz;
+ /* Apply object scale and orientation. */
+ result = transform_direction(ModelMatrix, result);
}
void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index 0941482df45..c81880184e3 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -1,80 +1,69 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy)
void node_eevee_specular(vec4 diffuse,
vec4 specular,
float roughness,
vec4 emissive,
float transp,
- vec3 normal,
+ vec3 N,
float clearcoat,
float clearcoat_roughness,
- vec3 clearcoat_normal,
+ vec3 CN,
float occlusion,
- float ssr_id,
+ float weight,
+ const float use_clearcoat,
out Closure result)
{
- CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
-
- in_common.occlusion = occlusion;
-
- in_Diffuse_0.N = normal; /* Normalized during eval. */
- in_Diffuse_0.albedo = diffuse.rgb;
+ N = safe_normalize(N);
+ CN = safe_normalize(CN);
+ vec3 V = cameraVec(g_data.P);
- in_Glossy_1.N = normal; /* Normalized during eval. */
- in_Glossy_1.roughness = roughness;
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = emissive.rgb;
- in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
- in_Glossy_2.roughness = clearcoat_roughness;
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = vec3(transp);
+ transparency_data.holdout = 0.0;
- CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
+ float alpha = (1.0 - transp) * weight;
- result = CLOSURE_DEFAULT;
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = alpha;
+ diffuse_data.color = diffuse.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
- vec3 V = cameraVec(worldPosition);
-
- {
- /* Diffuse. */
- out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance);
- out_Diffuse_0.radiance *= in_Diffuse_0.albedo;
- result.radiance += out_Diffuse_0.radiance;
- }
- {
- /* Glossy. */
- float NV = dot(in_Glossy_1.N, V);
- vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness);
+ ClosureReflection reflection_data;
+ reflection_data.weight = alpha;
+ if (true) {
+ float NV = dot(N, V);
+ vec2 split_sum = brdf_lut(NV, roughness);
vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
- out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
- out_Glossy_1.radiance *= brdf;
- out_Glossy_1.radiance = render_pass_glossy_mask(specular.rgb, out_Glossy_1.radiance);
- closure_load_ssr_data(
- out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
+ reflection_data.color = specular.rgb * brdf;
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
}
- {
- /* Clearcoat. */
- float NV = dot(in_Glossy_2.N, V);
- vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
+
+ ClosureReflection clearcoat_data;
+ clearcoat_data.weight = alpha * clearcoat * 0.25;
+ if (true) {
+ float NV = dot(CN, V);
+ vec2 split_sum = brdf_lut(NV, clearcoat_roughness);
vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
- out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
- out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
- result.radiance += out_Glossy_2.radiance;
- }
- {
- /* Emission. */
- vec3 out_emission_radiance = render_pass_emission_mask(emissive.rgb);
- result.radiance += out_emission_radiance;
+ clearcoat_data.color = brdf;
+ clearcoat_data.N = CN;
+ clearcoat_data.roughness = clearcoat_roughness;
}
- float alpha = 1.0 - transp;
- result.transmittance = vec3(transp);
- result.radiance *= alpha;
- result.ssr_data.rgb *= alpha;
+ if (use_clearcoat != 0.0f) {
+ result = closure_eval(diffuse_data, reflection_data, clearcoat_data);
+ }
+ else {
+ result = closure_eval(diffuse_data, reflection_data);
+ }
+ result = closure_add(result, closure_eval(emission_data));
+ result = closure_add(result, closure_eval(transparency_data));
}
-
-#else
-/* Stub specular because it is not compatible with volumetrics. */
-# define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
index f2de7c2da39..32484491abd 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_emission.glsl
@@ -1,10 +1,9 @@
-void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
+
+void node_emission(vec4 color, float strength, float weight, out Closure result)
{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.radiance = render_pass_emission_mask(color.rgb) * strength;
- result.ssr_normal = normal_encode(vN, viewCameraVec(viewPosition));
-#else
- result.emission = color.rgb * strength;
-#endif
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = color.rgb * strength;
+
+ result = closure_eval(emission_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
index 95f2be4bd44..7f502f74c0c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+
/* The fractal_noise functions are all exactly the same except for the input type. */
float fractal_noise(float p, float octaves, float roughness)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
index 7a4d28f2dd6..9fb98d598ab 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fresnel.glsl
@@ -26,12 +26,11 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
}
-void node_fresnel(float ior, vec3 N, vec3 I, out float result)
+void node_fresnel(float ior, vec3 N, out float result)
{
N = normalize(N);
- /* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 V = cameraVec(g_data.P);
float eta = max(ior, 0.00001);
- result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
+ result = fresnel_dielectric(V, N, (FrontFacing) ? eta : 1.0 / eta);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
index 5733992f8dd..29fb09ceebd 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_gamma.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void node_gamma(vec4 col, float gamma, out vec4 outcol)
{
outcol = col;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index a14ff5021bf..5e86a4577ee 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -1,9 +1,6 @@
-void node_geometry(vec3 I,
- vec3 N,
- vec3 orco,
- mat4 objmat,
- mat4 toworld,
- vec2 barycentric,
+#pragma BLENDER_REQUIRE(gpu_shader_material_tangent.glsl)
+
+void node_geometry(vec3 orco,
out vec3 position,
out vec3 normal,
out vec3 tangent,
@@ -15,39 +12,21 @@ void node_geometry(vec3 I,
out float random_per_island)
{
/* handle perspective/orthographic */
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
- incoming = -(toworld * vec4(I_view, 0.0)).xyz;
-
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- position = -incoming;
- true_normal = normal = incoming;
- tangent = parametric = vec3(0.0);
- vec3(0.0);
- backfacing = 0.0;
- pointiness = 0.0;
-#else
-
- position = worldPosition;
-# ifndef VOLUMETRICS
- normal = normalize(N);
- vec3 B = dFdx(worldPosition);
- vec3 T = dFdy(worldPosition);
- true_normal = normalize(cross(B, T));
-# else
- normal = (toworld * vec4(N, 0.0)).xyz;
- true_normal = normal;
-# endif
+ incoming = coordinate_incoming(g_data.P);
+ position = g_data.P;
+ normal = g_data.N;
+ true_normal = g_data.Ng;
-# ifdef HAIR_SHADER
- tangent = -hairTangent;
-# else
- tangent_orco_z(orco, orco);
- node_tangent(N, orco, objmat, tangent);
-# endif
+ if (g_data.is_strand) {
+ tangent = g_data.T;
+ }
+ else {
+ tangent_orco_z(orco, orco);
+ node_tangent(orco, tangent);
+ }
- parametric = vec3(barycentric, 0.0);
- backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
+ parametric = vec3(g_data.barycentric_coords, 0.0);
+ backfacing = (FrontFacing) ? 0.0 : 1.0;
pointiness = 0.5;
random_per_island = 0.0;
-#endif
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
index aa0a8873596..36c71c27837 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl
@@ -1,57 +1,33 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction)
void node_bsdf_glass(vec4 color,
float roughness,
float ior,
vec3 N,
- const float do_multiscatter,
- const float ssr_id,
+ float weight,
+ float do_multiscatter,
out Closure result)
{
- CLOSURE_VARS_DECLARE_2(Glossy, Refraction);
-
- in_Glossy_0.N = N; /* Normalized during eval. */
- in_Glossy_0.roughness = roughness;
-
- in_Refraction_1.N = N; /* Normalized during eval. */
- in_Refraction_1.roughness = roughness;
- in_Refraction_1.ior = ior;
+ N = safe_normalize(N);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
- CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction);
+ vec2 split_sum = btdf_lut(NV, roughness, ior);
- result = CLOSURE_DEFAULT;
+ float fresnel = (do_multiscatter != 0.0) ? split_sum.y : F_eta(ior, NV);
+ float btdf = (do_multiscatter != 0.0) ? 1.0 : split_sum.x;
- float NV = dot(in_Refraction_1.N, cameraVec(worldPosition));
+ ClosureReflection reflection_data;
+ reflection_data.weight = fresnel * weight;
+ reflection_data.color = color.rgb;
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
- float fresnel = (do_multiscatter != 0.0) ?
- btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).y :
- F_eta(in_Refraction_1.ior, NV);
+ ClosureRefraction refraction_data;
+ refraction_data.weight = (1.0 - fresnel) * weight;
+ refraction_data.color = color.rgb * btdf;
+ refraction_data.N = N;
+ refraction_data.roughness = roughness;
+ refraction_data.ior = ior;
- vec2 split_sum = brdf_lut(NV, in_Glossy_0.roughness);
- vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
- F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
-
- out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
- out_Glossy_0.radiance *= brdf;
- out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
- out_Glossy_0.radiance *= color.rgb * fresnel;
- closure_load_ssr_data(
- out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
-
- float btdf = (do_multiscatter != 0.0) ?
- 1.0 :
- btdf_lut(NV, in_Refraction_1.roughness, in_Refraction_1.ior).x;
- out_Refraction_1.radiance *= btdf;
- out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance);
- out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel);
- /* Simulate 2nd absorption event. */
- out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
- result.radiance += out_Refraction_1.radiance;
+ result = closure_eval(reflection_data, refraction_data);
}
-
-#else
-/* Stub glass because it is not compatible with volumetrics. */
-# define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
index fa83bfb6c7a..2e48ddd1c5e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl
@@ -1,33 +1,20 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy)
void node_bsdf_glossy(
- vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result)
+ vec4 color, float roughness, vec3 N, float weight, float do_multiscatter, out Closure result)
{
- bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId);
-
- CLOSURE_VARS_DECLARE_1(Glossy);
+ N = safe_normalize(N);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
- in_Glossy_0.N = N; /* Normalized during eval. */
- in_Glossy_0.roughness = roughness;
+ vec2 split_sum = brdf_lut(NV, roughness);
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
+ ClosureReflection reflection_data;
+ reflection_data.weight = weight;
+ reflection_data.color = (do_multiscatter != 0.0) ?
+ F_brdf_multi_scatter(color.rgb, color.rgb, split_sum) :
+ F_brdf_single_scatter(color.rgb, color.rgb, split_sum);
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
- result = CLOSURE_DEFAULT;
-
- vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec(worldPosition)), in_Glossy_0.roughness);
- vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) :
- F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum);
- out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id);
- out_Glossy_0.radiance *= brdf;
- out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance);
- out_Glossy_0.radiance *= color.rgb;
- closure_load_ssr_data(
- out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result);
+ result = closure_eval(reflection_data);
}
-
-#else
-/* Stub glossy because it is not compatible with volumetrics. */
-# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
new file mode 100644
index 00000000000..7bf8795495a
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
@@ -0,0 +1,46 @@
+
+void node_bsdf_hair(vec4 color,
+ float offset,
+ float roughness_u,
+ float roughness_v,
+ vec3 T,
+ float weight,
+ out Closure result)
+{
+ ClosureHair hair_data;
+ hair_data.weight = weight;
+ hair_data.color = color.rgb;
+ hair_data.offset = offset;
+ hair_data.roughness = vec2(roughness_u, roughness_v);
+ hair_data.T = T;
+
+ result = closure_eval(hair_data);
+}
+
+void node_bsdf_hair_principled(vec4 color,
+ float melanin,
+ float melanin_redness,
+ vec4 tint,
+ vec3 absorption_coefficient,
+ float roughness,
+ float radial_roughness,
+ float coat,
+ float ior,
+ float offset,
+ float random_color,
+ float random_roughness,
+ float random,
+ float weight,
+ out Closure result)
+{
+ /* Placeholder closure.
+ * Some computation will have to happen here just like the Principled BSDF. */
+ ClosureHair hair_data;
+ hair_data.weight = weight;
+ hair_data.color = color.rgb;
+ hair_data.offset = offset;
+ hair_data.roughness = vec2(0.0);
+ hair_data.T = g_data.T;
+
+ result = closure_eval(hair_data);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 59f0377869b..2885bf4e082 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -1,25 +1,19 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
void node_hair_info(float hair_length,
out float is_strand,
out float intercept,
- out float length,
+ out float out_length,
out float thickness,
out vec3 tangent,
out float random)
{
- length = hair_length;
-#ifdef HAIR_SHADER
- is_strand = 1.0;
- intercept = hairTime;
- thickness = hairThickness;
- tangent = normalize(worldNormal);
- random = wang_hash_noise(
- uint(hairStrandID)); /* TODO: could be precomputed per strand instead. */
-#else
- is_strand = 0.0;
- intercept = 0.0;
- thickness = 0.0;
- tangent = vec3(1.0);
- random = 0.0;
-#endif
+ is_strand = float(g_data.is_strand);
+ intercept = g_data.hair_time;
+ thickness = g_data.hair_thickness;
+ out_length = hair_length;
+ tangent = g_data.T;
+ /* TODO: could be precomputed per strand instead. */
+ random = wang_hash_noise(uint(g_data.hair_strand_id));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
index 50ce2bf2ab8..d022c1ced59 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_holdout.glsl
@@ -1,8 +1,10 @@
-void node_holdout(out Closure result)
+
+void node_holdout(float weight, out Closure result)
{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- result.holdout = 1.0;
- result.flag = CLOSURE_HOLDOUT_FLAG;
-#endif
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = vec3(0.0);
+ transparency_data.holdout = 1.0;
+
+ result = closure_eval(transparency_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
index 64ac73ecdf3..30b808508e9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hue_sat_val.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
{
vec4 hsv;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
index 588d295bcc4..2b61343a200 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_layer_weight.glsl
@@ -1,15 +1,17 @@
-void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float facing)
+#pragma BLENDER_REQUIRE(gpu_shader_material_fresnel.glsl)
+
+void node_layer_weight(float blend, vec3 N, out float fresnel, out float facing)
{
N = normalize(N);
/* fresnel */
float eta = max(1.0 - blend, 0.00001);
- vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+ vec3 V = cameraVec(g_data.P);
- fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
+ fresnel = fresnel_dielectric(V, N, (FrontFacing) ? 1.0 / eta : eta);
/* facing */
- facing = abs(dot(I_view, N));
+ facing = abs(dot(V, N));
if (blend != 0.5) {
blend = clamp(blend, 0.0, 0.99999);
blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
index 50c87e3f105..628a3d5e0e5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
@@ -13,19 +13,19 @@ void node_light_path(out float is_camera_ray,
out float transmission_depth)
{
/* Supported. */
- is_camera_ray = (rayType == EEVEE_RAY_CAMERA) ? 1.0 : 0.0;
- is_shadow_ray = (rayType == EEVEE_RAY_SHADOW) ? 1.0 : 0.0;
- is_diffuse_ray = (rayType == EEVEE_RAY_DIFFUSE) ? 1.0 : 0.0;
- is_glossy_ray = (rayType == EEVEE_RAY_GLOSSY) ? 1.0 : 0.0;
+ 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 = rayDepth;
- diffuse_depth = (is_diffuse_ray == 1.0) ? rayDepth : 0.0;
- glossy_depth = (is_glossy_ray == 1.0) ? rayDepth : 0.0;
+ ray_depth = g_data.ray_depth;
+ diffuse_depth = (is_diffuse_ray == 1.0) ? g_data.ray_depth : 0.0;
+ glossy_depth = (is_glossy_ray == 1.0) ? g_data.ray_depth : 0.0;
transmission_depth = (is_transmission_ray == 1.0) ? glossy_depth : 0.0;
+ ray_length = g_data.ray_length;
/* Not supported. */
- ray_length = 1.0;
transparent_depth = 0.0;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
index 1def3abec26..119ee3c0eaa 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
float smootherstep(float edge0, float edge1, float x)
{
x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
index 07f152439fe..312c57231c5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void mapping_mat4(
vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
index f200d666e28..0948ce2c9fa 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void math_add(float a, float b, float c, out float result)
{
result = a + b;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
index 2a98d9fadd0..91a8996939a 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -140,17 +140,74 @@ mat3 euler_to_mat3(vec3 euler)
return mat;
}
-void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+void normal_transform_object_to_world(vec3 vin, out vec3 vout)
{
- vout = (mat * vec4(vin, 0.0)).xyz;
+ vout = normal_object_to_world(vin);
}
-void normal_transform_transposed_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+void normal_transform_world_to_object(vec3 vin, out vec3 vout)
{
- vout = transpose(mat3(mat)) * vin;
+ vout = normal_world_to_object(vin);
}
-void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+void direction_transform_object_to_world(vec3 vin, out vec3 vout)
{
- vout = (mat * vec4(vin, 1.0)).xyz;
+ vout = transform_direction(ModelMatrix, vin);
+}
+
+void direction_transform_object_to_view(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrix, vin);
+ vout = transform_direction(ViewMatrix, vout);
+}
+
+void direction_transform_view_to_world(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrixInverse, vin);
+}
+
+void direction_transform_view_to_object(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrixInverse, vin);
+ vout = transform_direction(ModelMatrixInverse, vout);
+}
+
+void direction_transform_world_to_view(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ViewMatrix, vin);
+}
+
+void direction_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = transform_direction(ModelMatrixInverse, vin);
+}
+
+void point_transform_object_to_world(vec3 vin, out vec3 vout)
+{
+ vout = point_object_to_world(vin);
+}
+
+void point_transform_object_to_view(vec3 vin, out vec3 vout)
+{
+ vout = point_object_to_view(vin);
+}
+
+void point_transform_view_to_world(vec3 vin, out vec3 vout)
+{
+ vout = point_view_to_world(vin);
+}
+
+void point_transform_view_to_object(vec3 vin, out vec3 vout)
+{
+ vout = point_view_to_object(vin);
+}
+
+void point_transform_world_to_view(vec3 vin, out vec3 vout)
+{
+ vout = point_world_to_view(vin);
+}
+
+void point_transform_world_to_object(vec3 vin, out vec3 vout)
+{
+ vout = point_world_to_object(vin);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
index e089aec1d92..157a6a27c15 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_rgb.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
fac = clamp(fac, 0.0, 1.0);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
index cc65b1eb57c..c84f34a834c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.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 */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
index 2b4a0204d97..e219e2b9bbe 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
@@ -1,13 +1,13 @@
-void node_normal_map(vec4 info, vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)
+void node_normal_map(vec4 tangent, vec3 texnormal, out vec3 outnormal)
{
if (all(equal(tangent, vec4(0.0, 0.0, 0.0, 1.0)))) {
- outnormal = normal;
+ outnormal = g_data.N;
return;
}
- tangent *= (gl_FrontFacing ? 1.0 : -1.0);
- vec3 B = tangent.w * cross(normal, tangent.xyz) * sign(info.w);
+ tangent *= (FrontFacing ? 1.0 : -1.0);
+ vec3 B = tangent.w * cross(g_data.N, tangent.xyz) * sign(ObjectInfo.w);
- outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal;
+ outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * g_data.N;
outnormal = normalize(outnormal);
}
@@ -21,7 +21,7 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
normal = vec3(2.0, -2.0, -2.0) * color - vec3(1.0);
}
-void node_normal_map_mix(float strength, vec3 newnormal, vec3 oldnormal, out vec3 outnormal)
+void node_normal_map_mix(float strength, vec3 newnormal, out vec3 outnormal)
{
- outnormal = normalize(mix(oldnormal, newnormal, max(strength, 0.0)));
+ outnormal = normalize(mix(g_data.N, newnormal, max(strength, 0.0)));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
index 607cf119b36..2dd2993ceb0 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_object_info.glsl
@@ -1,7 +1,4 @@
-void node_object_info(mat4 obmat,
- vec4 obcolor,
- vec4 info,
- float mat_index,
+void node_object_info(float mat_index,
out vec3 location,
out vec4 color,
out float alpha,
@@ -9,10 +6,11 @@ void node_object_info(mat4 obmat,
out float material_index,
out float random)
{
- location = obmat[3].xyz;
- color = obcolor;
- alpha = obcolor.w;
- object_index = info.x;
+ location = ModelMatrix[3].xyz;
+ color = ObjectColor;
+ alpha = ObjectColor.a;
+ object_index = ObjectInfo.x;
+ /* TODO(fclem): Put that inside the Material UBO. */
material_index = mat_index;
- random = info.z;
+ random = ObjectInfo.z;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
index 648994739bf..b166c3e4e9f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_aov.glsl
@@ -1,13 +1,5 @@
-void node_output_aov(vec4 color, float value, out Closure result)
+void node_output_aov(vec4 color, float value, float hash, out Closure dummy)
{
- result = CLOSURE_DEFAULT;
-#ifndef VOLUMETRICS
- if (render_pass_aov_is_color()) {
- result.radiance = color.rgb;
- }
- else {
- result.radiance = vec3(value);
- }
-#endif
+ output_aov(color, value, floatBitsToUint(hash));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
index 14271f9d107..2c24f50264c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
@@ -1,20 +1,20 @@
-void node_output_material(Closure surface,
- Closure volume,
- vec3 displacement,
- float alpha_threshold,
- float shadow_threshold,
- out Closure result)
+
+void node_output_material_surface(Closure surface, out Closure out_surface)
{
-#ifdef VOLUMETRICS
- result = volume;
-#else
- result = surface;
-# if defined(USE_ALPHA_HASH)
- /* Alpha clip emulation. */
- if ((rayType != EEVEE_RAY_SHADOW) ? (alpha_threshold >= 0.0) : (shadow_threshold >= 0.0)) {
- float alpha = saturate(1.0 - avg(result.transmittance));
- result.transmittance = vec3(step(alpha, max(alpha_threshold, shadow_threshold)));
- }
-# endif
-#endif
+ out_surface = surface;
+}
+
+void node_output_material_volume(Closure volume, out Closure out_volume)
+{
+ out_volume = volume;
+}
+
+void node_output_material_displacement(vec3 displacement, out vec3 out_displacement)
+{
+ out_displacement = displacement;
+}
+
+void node_output_material_thickness(float thickness, out float out_thickness)
+{
+ out_thickness = thickness;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
index 5eb853a4c1a..37c34a4f0d7 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_world.glsl
@@ -1,14 +1,10 @@
-uniform float backgroundAlpha;
-void node_output_world(Closure surface, Closure volume, out Closure result)
+void node_output_world_surface(Closure surface, out Closure out_surface)
{
-#ifndef VOLUMETRICS
- float alpha = renderPassEnvironment ? 1.0 : backgroundAlpha;
- result = CLOSURE_DEFAULT;
- result.radiance = surface.radiance * alpha;
- result.transmittance = vec3(0.0);
- result.holdout = (1.0 - alpha);
-#else
- result = volume;
-#endif /* VOLUMETRICS */
+ out_surface = surface;
+}
+
+void node_output_world_volume(Closure volume, out Closure out_volume)
+{
+ out_volume = volume;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
index bdd60c20a81..5602345ea4a 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_particle_info.glsl
@@ -1,8 +1,4 @@
-void particle_info(vec4 sprops,
- vec4 loc,
- vec3 vel,
- vec3 avel,
- out float index,
+void particle_info(out float index,
out float random,
out float age,
out float life_time,
@@ -11,13 +7,14 @@ void particle_info(vec4 sprops,
out vec3 velocity,
out vec3 angular_velocity)
{
- index = sprops.x;
- random = loc.w;
- age = sprops.y;
- life_time = sprops.z;
- size = sprops.w;
+ /* Unsupported for now. */
+ index = 0.0;
+ random = 0.0;
+ age = 0.0;
+ life_time = 0.0;
+ size = 0.0;
- location = loc.xyz;
- velocity = vel;
- angular_velocity = avel;
+ location = vec3(0.0);
+ velocity = vec3(0.0);
+ angular_velocity = vec3(0.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
index d717ac97b28..1b1fed9502e 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
void node_point_info(out vec3 position, out float radius, out float random)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index c97fc090fe2..033dc05c57d 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -1,4 +1,4 @@
-#ifndef VOLUMETRICS
+
vec3 tint_from_color(vec3 color)
{
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
@@ -13,8 +13,6 @@ float principled_sheen(float NV)
return sheen;
}
-CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction)
-
void node_bsdf_principled(vec4 base_color,
float subsurface,
vec3 subsurface_radius,
@@ -40,169 +38,137 @@ void node_bsdf_principled(vec4 base_color,
vec3 N,
vec3 CN,
vec3 T,
+ float weight,
const float do_diffuse,
const float do_clearcoat,
const float do_refraction,
const float do_multiscatter,
- float ssr_id,
- float sss_id,
- vec3 sss_scale,
+ float do_sss,
out Closure result)
{
/* Match cycles. */
- metallic = saturate(metallic);
- transmission = saturate(transmission);
+ metallic = clamp(metallic, 0.0, 1.0);
+ transmission = clamp(transmission, 0.0, 1.0) * (1.0 - metallic);
float diffuse_weight = (1.0 - transmission) * (1.0 - metallic);
- transmission *= (1.0 - metallic);
float specular_weight = (1.0 - transmission);
- clearcoat = max(clearcoat, 0.0);
+ float clearcoat_weight = max(clearcoat, 0.0) * 0.25;
transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness);
specular = max(0.0, specular);
- CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction);
-
- in_Diffuse_0.N = N; /* Normalized during eval. */
- in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface);
-
- in_Glossy_1.N = N; /* Normalized during eval. */
- in_Glossy_1.roughness = roughness;
-
- in_Glossy_2.N = CN; /* Normalized during eval. */
- in_Glossy_2.roughness = clearcoat_roughness;
-
- in_Refraction_3.N = N; /* Normalized during eval. */
- in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness;
- in_Refraction_3.ior = ior;
+ N = safe_normalize(N);
+ CN = safe_normalize(CN);
+ vec3 V = cameraVec(g_data.P);
+ float NV = dot(N, V);
- CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
+ float fresnel = (do_multiscatter != 0.0) ? btdf_lut(NV, roughness, ior).y : F_eta(ior, NV);
+ float glass_reflection_weight = fresnel * transmission;
+ float glass_transmission_weight = (1.0 - fresnel) * transmission;
- result = CLOSURE_DEFAULT;
+ vec3 base_color_tint = tint_from_color(base_color.rgb);
- /* This will tag the whole eval for optimisation. */
- if (do_diffuse == 0.0) {
- out_Diffuse_0.radiance = vec3(0);
- }
- if (do_clearcoat == 0.0) {
- out_Glossy_2.radiance = vec3(0);
- }
- if (do_refraction == 0.0) {
- out_Refraction_3.radiance = vec3(0);
+ vec2 split_sum = brdf_lut(NV, roughness);
+
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = vec3(1.0 - alpha);
+ transparency_data.holdout = 0.0;
+
+ weight *= alpha;
+
+ ClosureEmission emission_data;
+ emission_data.weight = weight;
+ emission_data.emission = emission.rgb * emission_strength;
+
+ /* Diffuse. */
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = diffuse_weight * weight;
+ diffuse_data.color = mix(base_color.rgb, subsurface_color.rgb, subsurface);
+ /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
+ vec3 sheen_color = mix(vec3(1.0), base_color_tint, sheen_tint);
+ diffuse_data.color += sheen * sheen_color * principled_sheen(NV);
+ diffuse_data.N = N;
+ diffuse_data.sss_radius = subsurface_radius * subsurface;
+ diffuse_data.sss_id = uint(do_sss);
+
+ /* NOTE(@fclem): We need to blend the reflection color but also need to avoid applying the
+ * weights so we compule the ratio. */
+ float reflection_weight = specular_weight + glass_reflection_weight;
+ float reflection_weight_inv = safe_rcp(reflection_weight);
+ specular_weight *= reflection_weight_inv;
+ glass_reflection_weight *= reflection_weight_inv;
+
+ /* Reflection. */
+ ClosureReflection reflection_data;
+ reflection_data.weight = reflection_weight * weight;
+ reflection_data.N = N;
+ reflection_data.roughness = roughness;
+ if (true) {
+ vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
+ vec3 metallic_f0_color = base_color.rgb;
+ vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
+ /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
+ * is already baked inside the split sum LUT. We approximate by changing the f90 color
+ * directly in a non linear fashion. */
+ vec3 f90 = mix(f0, vec3(1.0), fast_sqrt(specular));
+
+ vec3 reflection_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
+ F_brdf_single_scatter(f0, f90, split_sum);
+ reflection_data.color = reflection_brdf * specular_weight;
}
+ if (true) {
+ /* Poor approximation since we baked the LUT using a fixed IOR. */
+ vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
+ vec3 f90 = vec3(1.0);
- vec3 V = cameraVec(worldPosition);
+ vec3 glass_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
+ F_brdf_single_scatter(f0, f90, split_sum);
- /* Glossy_1 will always be evaluated. */
- float NV = dot(in_Glossy_1.N, V);
-
- vec3 base_color_tint = tint_from_color(base_color.rgb);
+ /* Avoid 3 glossy evaluation. Use the same closure for glass reflection. */
+ reflection_data.color += glass_brdf * glass_reflection_weight;
+ }
- float fresnel = (do_multiscatter != 0.0) ?
- btdf_lut(NV, in_Glossy_1.roughness, in_Refraction_3.ior).y :
- F_eta(in_Refraction_3.ior, NV);
-
- {
- /* Glossy reflections.
- * Separate Glass reflections and main specular reflections to match Cycles renderpasses. */
- out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id);
-
- vec2 split_sum = brdf_lut(NV, roughness);
-
- vec3 glossy_radiance_final = vec3(0.0);
- if (transmission > 1e-5) {
- /* Glass Reflection: Reuse radiance from Glossy1. */
- vec3 out_glass_refl_radiance = out_Glossy_1.radiance;
-
- /* Poor approximation since we baked the LUT using a fixed IOR. */
- vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint);
- vec3 f90 = vec3(1);
-
- vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
- F_brdf_single_scatter(f0, f90, split_sum);
-
- out_glass_refl_radiance *= brdf;
- out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance);
- out_glass_refl_radiance *= fresnel * transmission;
- glossy_radiance_final += out_glass_refl_radiance;
- }
- if (specular_weight > 1e-5) {
- vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint);
- vec3 metallic_f0_color = base_color.rgb;
- vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic);
- /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel
- * is already baked inside the split sum LUT. We approximate using by modifying the
- * changing the f90 color directly in a non linear fashion. */
- vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular));
-
- vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
- F_brdf_single_scatter(f0, f90, split_sum);
-
- out_Glossy_1.radiance *= brdf;
- out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance);
- out_Glossy_1.radiance *= specular_weight;
- glossy_radiance_final += out_Glossy_1.radiance;
- }
-
- closure_load_ssr_data(
- glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
+ ClosureReflection clearcoat_data;
+ clearcoat_data.weight = clearcoat_weight * weight;
+ clearcoat_data.N = CN;
+ clearcoat_data.roughness = clearcoat_roughness;
+ if (true) {
+ float NV = dot(clearcoat_data.N, V);
+ vec2 split_sum = brdf_lut(NV, clearcoat_data.roughness);
+ vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
+ clearcoat_data.color = brdf;
}
- if (diffuse_weight > 1e-5) {
- /* Mask over all diffuse radiance. */
- out_Diffuse_0.radiance *= diffuse_weight;
+ /* Refraction. */
+ ClosureRefraction refraction_data;
+ refraction_data.weight = glass_transmission_weight * weight;
+ float btdf = (do_multiscatter != 0.0) ? 1.0 : btdf_lut(NV, roughness, ior).x;
- /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
- vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint);
- vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV);
- out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance);
- out_sheen_radiance *= sheen * sheen_color;
- result.radiance += out_sheen_radiance;
+ refraction_data.color = base_color.rgb * btdf;
+ refraction_data.N = N;
+ refraction_data.roughness = do_multiscatter != 0.0 ? roughness :
+ max(roughness, transmission_roughness);
+ refraction_data.ior = ior;
- /* Diffuse / Subsurface. */
- float scale = avg(sss_scale) * subsurface;
- closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result);
+ if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat != 0.0) {
+ /* Metallic & Clearcoat case. */
+ result = closure_eval(reflection_data, clearcoat_data);
}
-
- if (transmission > 1e-5) {
- float btdf = (do_multiscatter != 0.0) ?
- 1.0 :
- btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x;
- /* TODO(@fclem): This could be going to a transmission render pass instead. */
- out_Refraction_3.radiance *= btdf;
- out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
- out_Refraction_3.radiance *= base_color.rgb;
- /* Simulate 2nd transmission event. */
- out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1);
- out_Refraction_3.radiance *= (1.0 - fresnel) * transmission;
- result.radiance += out_Refraction_3.radiance;
+ else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) {
+ /* Metallic case. */
+ result = closure_eval(reflection_data);
}
-
- if (clearcoat > 1e-5) {
- float NV = dot(in_Glossy_2.N, V);
- vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
- vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum);
-
- out_Glossy_2.radiance *= brdf * clearcoat * 0.25;
- out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance);
- result.radiance += out_Glossy_2.radiance;
+ else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) {
+ /* Dielectric case. */
+ result = closure_eval(diffuse_data, reflection_data);
}
-
- {
- vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
- out_emission_radiance *= emission_strength;
- result.radiance += out_emission_radiance;
+ else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_clearcoat == 0.0) {
+ /* Glass case. */
+ result = closure_eval(reflection_data, refraction_data);
}
-
- result.transmittance = vec3(1.0 - alpha);
- result.radiance *= alpha;
- result.ssr_data.rgb *= alpha;
-# ifdef USE_SSS
- result.sss_albedo *= alpha;
-# endif
+ else {
+ /* Un-optimized case. */
+ result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data);
+ }
+ result = closure_add(result, closure_eval(emission_data));
+ result = closure_add(result, closure_eval(transparency_data));
}
-
-#else
-/* clang-format off */
-/* Stub principled because it is not compatible with volumetrics. */
-# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, ee, ff, result) (result = CLOSURE_DEFAULT)
-/* clang-format on */
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
index 8a42a131f43..871fa00b3d4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
@@ -1,32 +1,15 @@
-#ifndef VOLUMETRICS
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction)
-
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
+void node_bsdf_refraction(
+ vec4 color, float roughness, float ior, vec3 N, float weight, out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Refraction);
-
- in_Refraction_0.N = N; /* Normalized during eval. */
- in_Refraction_0.roughness = roughness;
- in_Refraction_0.ior = ior;
-
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
+ N = safe_normalize(N);
- result = CLOSURE_DEFAULT;
+ ClosureRefraction refraction_data;
+ refraction_data.weight = weight;
+ refraction_data.color = color.rgb;
+ refraction_data.N = N;
+ refraction_data.roughness = roughness;
+ refraction_data.ior = ior;
- out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance);
- out_Refraction_0.radiance *= color.rgb;
- /* Simulate 2nd absorption event. */
- out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0);
-
- result.radiance = out_Refraction_0.radiance;
-
- /* TODO(@fclem): Try to not use this. */
- result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N,
- viewCameraVec(viewPosition));
+ result = closure_eval(refraction_data);
}
-
-#else
-/* Stub refraction because it is not compatible with volumetrics. */
-# define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
index fb64e424c6c..180e0fd1940 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_separate_hsv.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_color_util.glsl)
+
void separate_hsv(vec4 col, out float h, out float s, out float v)
{
vec4 hsv;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
index f0f2f79c60e..d791f067821 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
@@ -1,29 +1,6 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_shader_to_rgba, Glossy)
void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha)
{
- vec4 spec_accum = vec4(0.0);
- if (ssrToggle && FLAG_TEST(cl.flag, CLOSURE_SSR_FLAG)) {
- CLOSURE_VARS_DECLARE_1(Glossy);
-
- vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec(viewPosition));
- vec3 N = transform_direction(ViewMatrixInverse, vN);
-
- in_Glossy_0.N = N; /* Normalized during eval. */
- in_Glossy_0.roughness = cl.ssr_data.a;
-
- CLOSURE_EVAL_FUNCTION_1(node_shader_to_rgba, Glossy);
-
- spec_accum.rgb = out_Glossy_0.radiance;
- }
-
- outalpha = saturate(1.0 - avg(cl.transmittance));
- outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0);
-
-# ifdef USE_SSS
- outcol.rgb += cl.sss_irradiance.rgb * cl.sss_albedo;
-# endif
+ outcol = closure_to_rgba(cl);
+ outalpha = outcol.a;
}
-#endif /* VOLUMETRICS */
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
index 20b634aa801..c560dd01c4f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
@@ -1,6 +1,3 @@
-#ifndef VOLUMETRICS
-
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse)
void node_subsurface_scattering(vec4 color,
float scale,
@@ -8,25 +5,18 @@ void node_subsurface_scattering(vec4 color,
float ior,
float anisotropy,
vec3 N,
- float sss_id,
+ float weight,
+ float do_sss,
out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Diffuse);
-
- in_Diffuse_0.N = N; /* Normalized during eval. */
- in_Diffuse_0.albedo = color.rgb;
-
- CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse);
+ N = safe_normalize(N);
- result = CLOSURE_DEFAULT;
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_radius = radius * scale;
+ diffuse_data.sss_id = uint(do_sss);
- closure_load_sss_data(scale, out_Diffuse_0.radiance, color.rgb, int(sss_id), result);
-
- /* TODO(@fclem): Try to not use this. */
- closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
+ result = closure_eval(diffuse_data);
}
-
-#else
-/* Stub subsurface scattering because it is not compatible with volumetrics. */
-# define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
index ff2dbc7ead3..4e4bf759ec9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tangent.glsl
@@ -18,8 +18,8 @@ void node_tangentmap(vec4 attr_tangent, out vec3 tangent)
tangent = normalize(attr_tangent.xyz);
}
-void node_tangent(vec3 N, vec3 orco, mat4 objmat, out vec3 T)
+void node_tangent(vec3 orco, out vec3 T)
{
- T = (objmat * vec4(orco, 0.0)).xyz;
- T = cross(N, normalize(cross(T, N)));
+ T = transform_direction(ModelMatrix, orco);
+ T = cross(g_data.N, normalize(cross(T, g_data.N)));
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
index e252e5ba726..edc2fa32177 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
vec2 calc_brick_texture(vec3 p,
float mortar_size,
float mortar_smooth,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
index 434e07e7b86..89091316823 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -1,19 +1,5 @@
-void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
-{
-#ifdef MESH_SHADER
- worldvec = worldPosition;
-#else
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogeneous = (ProjectionMatrixInverse * v);
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
- vec3 co = co_homogeneous.xyz / co_homogeneous.w;
-# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- worldvec = mat3(ViewMatrixInverse) * co;
-# else
- worldvec = mat3(ModelMatrixInverse) * (mat3(ViewMatrixInverse) * co);
-# endif
-#endif
-}
void node_tex_environment_equirectangular(vec3 co, out vec3 uv)
{
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
index 586385b7e86..1552a2facc3 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_musgrave.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+
/* 1D Musgrave fBm
*
* H: fractal increment parameter
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
index 5745f11ede4..c90b2211dcf 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -1,3 +1,7 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl)
+
/* 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.
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
index c8219848e29..dd12b602edf 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -1,3 +1,6 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
/*
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
*
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
index 070f42a5e30..eed98232d0b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -1,3 +1,7 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_noise.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_material_fractal_noise.glsl)
+
float calc_wave(vec3 p,
float distortion,
float detail,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
index b11d13a0413..030b58f0736 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_white_noise.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_hash.glsl)
+
/* White Noise */
void node_white_noise_1d(vec3 vector, float w, out float value, out vec4 color)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
index a8ef9687b0a..a3666164cf7 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_texture_coordinates.glsl
@@ -1,38 +1,5 @@
-vec3 mtex_2d_mapping(vec3 vec)
-{
- return vec3(vec.xy * 0.5 + vec2(0.5), vec.z);
-}
-
-void generated_from_orco(vec3 orco, out vec3 generated)
-{
-#ifdef VOLUMETRICS
-# ifdef MESH_SHADER
- generated = volumeObjectLocalCoord;
-# else
- generated = worldPosition;
-# endif
-#else
- generated = orco;
-#endif
-}
-void generated_texco(vec3 I, vec3 attr_orco, out vec3 generated)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogeneous = (ProjectionMatrixInverse * v);
- vec4 co = vec4(co_homogeneous.xyz / co_homogeneous.w, 0.0);
- co.xyz = normalize(co.xyz);
-#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- generated = (ViewMatrixInverse * co).xyz;
-#else
- generated_from_orco(attr_orco, generated);
-#endif
-}
-
-void node_tex_coord(vec3 I,
- vec3 wN,
- mat4 obmatinv,
- vec4 camerafac,
+void node_tex_coord(mat4 obmatinv,
vec3 attr_orco,
vec3 attr_uv,
out vec3 generated,
@@ -44,49 +11,10 @@ void node_tex_coord(vec3 I,
out vec3 reflection)
{
generated = attr_orco;
- normal = normalize(normal_world_to_object(wN));
+ normal = normal_world_to_object(g_data.N);
uv = attr_uv;
- object = (obmatinv * (ViewMatrixInverse * vec4(I, 1.0))).xyz;
- camera = vec3(I.xy, -I.z);
- vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
- reflection = -reflect(cameraVec(worldPosition), normalize(wN));
-}
-
-void node_tex_coord_background(vec3 I,
- vec3 N,
- mat4 obmatinv,
- vec4 camerafac,
- vec3 attr_orco,
- vec3 attr_uv,
- out vec3 generated,
- out vec3 normal,
- out vec3 uv,
- out vec3 object,
- out vec3 camera,
- out vec3 window,
- out vec3 reflection)
-{
- vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
- vec4 co_homogeneous = (ProjectionMatrixInverse * v);
-
- vec4 co = vec4(co_homogeneous.xyz / co_homogeneous.w, 0.0);
-
- co = normalize(co);
-
- vec3 coords = (ViewMatrixInverse * co).xyz;
-
- generated = coords;
- normal = -coords;
- uv = vec3(attr_uv.xy, 0.0);
- object = (obmatinv * vec4(coords, 1.0)).xyz;
-
- camera = vec3(co.xy, -co.z);
- window = vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0);
-
- reflection = -coords;
+ object = transform_point((obmatinv[3][3] == 0.0) ? ModelMatrixInverse : obmatinv, g_data.P);
+ camera = coordinate_camera(g_data.P);
+ window = coordinate_screen(g_data.P);
+ reflection = coordinate_reflect(g_data.P, g_data.N);
}
-
-#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
-# define node_tex_coord node_tex_coord_background
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
index bbfc99ccc73..ae7d4fc5631 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_toon.glsl
@@ -1,9 +1,15 @@
-#ifndef VOLUMETRICS
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
+
+void node_bsdf_toon(
+ vec4 color, float size, float tsmooth, vec3 N, float weight, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+ N = safe_normalize(N);
+
+ /* Fallback to diffuse. */
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
+
+ result = closure_eval(diffuse_data);
}
-#else
-/* Stub toon because it is not compatible with volumetrics. */
-# define node_bsdf_toon(a, b, c, d, e) (e = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
index 80bd3941b22..0cc162f42f5 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl
@@ -1,21 +1,12 @@
-#ifndef VOLUMETRICS
-CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent)
-
-void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
+void node_bsdf_translucent(vec4 color, vec3 N, float weight, out Closure result)
{
- CLOSURE_VARS_DECLARE_1(Translucent);
-
- in_Translucent_0.N = -N; /* Normalized during eval. */
+ N = safe_normalize(N);
- CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent);
+ ClosureTranslucent translucent_data;
+ translucent_data.weight = weight;
+ translucent_data.color = color.rgb;
+ translucent_data.N = -N;
- result = CLOSURE_DEFAULT;
- closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result);
- result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb);
+ result = closure_eval(translucent_data);
}
-
-#else
-/* Stub translucent because it is not compatible with volumetrics. */
-# define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
index 9040f62bd3f..c650f10b6e4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_transparent.glsl
@@ -1,11 +1,10 @@
-#ifndef VOLUMETRICS
-void node_bsdf_transparent(vec4 color, out Closure result)
+
+void node_bsdf_transparent(vec4 color, float weight, out Closure result)
{
- result = CLOSURE_DEFAULT;
- result.radiance = vec3(0.0);
- result.transmittance = abs(color.rgb);
+ ClosureTransparency transparency_data;
+ transparency_data.weight = weight;
+ transparency_data.transmittance = color.rgb;
+ transparency_data.holdout = 0.0;
+
+ result = closure_eval(transparency_data);
}
-#else
-/* Stub transparent because it is not compatible with volumetrics. */
-# define node_bsdf_transparent(a, b) (b = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
index 4b5ed172081..0ff074bc04f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_displacement.glsl
@@ -1,30 +1,22 @@
-void node_vector_displacement_tangent(vec4 vector,
- float midlevel,
- float scale,
- vec4 tangent,
- vec3 normal,
- mat4 obmat,
- mat4 viewmat,
- out vec3 result)
+void node_vector_displacement_tangent(
+ vec4 vector, float midlevel, float scale, vec4 T, out vec3 result)
{
- /* TODO(fclem): this is broken. revisit latter. */
- vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz);
- vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz);
- vec3 B_object = tangent.w * normalize(cross(N_object, T_object));
+ vec3 oN = normalize(normal_world_to_object(g_data.N));
+ vec3 oT = normalize(normal_world_to_object(T.xyz));
+ vec3 oB = T.w * normalize(cross(oN, oT));
- vec3 offset = (vector.xyz - vec3(midlevel)) * scale;
- result = offset.x * T_object + offset.y * N_object + offset.z * B_object;
- result = (obmat * vec4(result, 0.0)).xyz;
+ result = (vector.xyz - midlevel) * scale;
+ result = result.x * oT + result.y * oN + result.z * oB;
+ result = transform_point(ModelMatrix, result);
}
-void node_vector_displacement_object(
- vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result)
+void node_vector_displacement_object(vec4 vector, float midlevel, float scale, out vec3 result)
{
- result = (vector.xyz - vec3(midlevel)) * scale;
- result = (obmat * vec4(result, 0.0)).xyz;
+ result = (vector.xyz - midlevel) * scale;
+ result = transform_point(ModelMatrix, result);
}
void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result)
{
- result = (vector.xyz - vec3(midlevel)) * scale;
+ result = (vector.xyz - midlevel) * scale;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
index 4ad5d4232de..8f6bf17f195 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
void vector_math_add(vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue)
{
outVector = a + b;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
index 41ad16cce0b..ff0fb1c0418 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_rotate.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_math_util.glsl)
+
vec3 rotate_around_axis(vec3 p, vec3 axis, float angle)
{
float costheta = cos(angle);
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
index 989f18b881a..97726bfe66f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_velvet.glsl
@@ -1,9 +1,14 @@
-#ifndef VOLUMETRICS
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
+
+void node_bsdf_velvet(vec4 color, float roughness, vec3 N, float weight, out Closure result)
{
- node_bsdf_diffuse(color, 0.0, N, result);
+ N = safe_normalize(N);
+
+ /* Fallback to diffuse. */
+ ClosureDiffuse diffuse_data;
+ diffuse_data.weight = weight;
+ diffuse_data.color = color.rgb;
+ diffuse_data.N = N;
+ diffuse_data.sss_id = 0u;
+
+ result = closure_eval(diffuse_data);
}
-#else
-/* Stub velvet because it is not compatible with volumetrics. */
-# define node_bsdf_velvet(a, b, c, d) (d = CLOSURE_DEFAULT)
-#endif
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
index e6c0880cd07..8fd2e179187 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_absorption.glsl
@@ -1,8 +1,9 @@
-void node_volume_absorption(vec4 color, float density, out Closure result)
+
+void node_volume_absorption(vec4 color, float density, float weight, out Closure result)
{
-#ifdef VOLUMETRICS
- result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ ClosureVolumeAbsorption volume_absorption_data;
+ volume_absorption_data.weight = weight;
+ volume_absorption_data.absorption = (1.0 - color.rgb) * density;
+
+ result = closure_eval(volume_absorption_data);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
index e6d7b9d3721..464cf5227b4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl
@@ -4,14 +4,8 @@ uniform vec3 volumeColor = vec3(1.0);
uniform vec2 volumeTemperature = vec2(0.0);
/* Generic volume attribute. */
-void node_attribute_volume(sampler3D tex, mat4 transform, out vec3 outvec)
+void node_attribute_volume(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec)
{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
/* Optional per-grid transform. */
if (transform[3][3] != 0.0) {
cos = (transform * vec4(cos, 1.0)).xyz;
@@ -21,14 +15,8 @@ void node_attribute_volume(sampler3D tex, mat4 transform, out vec3 outvec)
}
/* Special color attribute for smoke. */
-void node_attribute_volume_color(sampler3D tex, mat4 transform, out vec3 outvec)
+void node_attribute_volume_color(sampler3D tex, mat4 transform, vec3 cos, out vec3 outvec)
{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
/* Optional per-grid transform. */
if (transform[3][3] != 0.0) {
cos = (transform * vec4(cos, 1.0)).xyz;
@@ -44,14 +32,8 @@ void node_attribute_volume_color(sampler3D tex, mat4 transform, out vec3 outvec)
}
/* Special temperature attribute for smoke. */
-void node_attribute_volume_temperature(sampler3D tex, mat4 transform, out float outf)
+void node_attribute_volume_temperature(sampler3D tex, mat4 transform, vec3 cos, out float outf)
{
-#if defined(MESH_SHADER) && defined(VOLUMETRICS)
- vec3 cos = volumeObjectLocalCoord;
-#else
- vec3 cos = vec3(0.0);
-#endif
-
/* Optional per-grid transform. */
if (transform[3][3] != 0.0) {
cos = (transform * vec4(cos, 1.0)).xyz;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
index 884d5415c51..1127c34b3ac 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_principled.glsl
@@ -1,3 +1,5 @@
+#pragma BLENDER_REQUIRE(gpu_shader_material_blackbody.glsl)
+
void node_volume_principled(vec4 color,
float density,
float anisotropy,
@@ -7,6 +9,7 @@ void node_volume_principled(vec4 color,
float blackbody_intensity,
vec4 blackbody_tint,
float temperature,
+ float weight,
float density_attribute,
vec4 color_attribute,
float temperature_attribute,
@@ -14,7 +17,6 @@ void node_volume_principled(vec4 color,
float layer,
out Closure result)
{
-#ifdef VOLUMETRICS
vec3 absorption_coeff = vec3(0.0);
vec3 scatter_coeff = vec3(0.0);
vec3 emission_coeff = vec3(0.0);
@@ -60,8 +62,18 @@ void node_volume_principled(vec4 color,
}
}
- result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ 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);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
index 02c54658be5..f01ead3618f 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_scatter.glsl
@@ -1,8 +1,11 @@
-void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
+
+void node_volume_scatter(
+ vec4 color, float density, float anisotropy, float weight, out Closure result)
{
-#ifdef VOLUMETRICS
- result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
-#else
- result = CLOSURE_DEFAULT;
-#endif
+ 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);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
index e2789e046e1..0c02dab3ae4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl
@@ -1,20 +1,21 @@
-#ifndef VOLUMETRICS
-void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac)
+
+void node_wireframe(float size, out float fac)
{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
+ vec3 barys = g_data.barycentric_coords.xyy;
+ barys.z = 1.0 - barys.x - barys.y;
size *= 0.5;
- vec3 s = step(-size, -barys * barycentric_dist);
+ vec3 s = step(-size, -barys * g_data.barycentric_dists);
fac = max(s.x, max(s.y, s.z));
}
-void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
+void node_wireframe_screenspace(float size, out float fac)
{
- vec3 barys = barycentric.xyy;
- barys.z = 1.0 - barycentric.x - barycentric.y;
+ vec3 barys = g_data.barycentric_coords.xyy;
+ barys.z = 1.0 - barys.x - barys.y;
+#ifdef GPU_FRAGMENT_SHADER
size *= (1.0 / 3.0);
vec3 dx = dFdx(barys);
vec3 dy = dFdy(barys);
@@ -23,9 +24,7 @@ void node_wireframe_screenspace(float size, vec2 barycentric, out float fac)
vec3 s = step(-deltas * size, -barys);
fac = max(s.x, max(s.y, s.z));
-}
#else
-/* Stub wireframe because it is not compatible with volumetrics. */
-# define node_wireframe(a, b, c, d) (d = 0.0)
-# define node_wireframe_screenspace(a, b, c) (c = 0.0)
+ fac = 1.0;
#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
index 40e46bc250c..5a0aeb2f932 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
@@ -1,25 +1,5 @@
-/* TODO: clean this `ifdef` mess. */
+
void world_normals_get(out vec3 N)
{
-#ifndef VOLUMETRICS
-# ifdef HAIR_SHADER
- vec3 B = normalize(cross(worldNormal, hairTangent));
- float cos_theta;
- if (hairThicknessRes == 1) {
- vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy);
- /* Random cosine normal distribution on the hair surface. */
- cos_theta = rand.x * 2.0 - 1.0;
- }
- else {
- /* Shade as a cylinder. */
- cos_theta = hairThickTime / hairThickness;
- }
- float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
- N = normalize(worldNormal * sin_theta + B * cos_theta);
-# else
- N = gl_FrontFacing ? worldNormal : -worldNormal;
-# endif
-#else
- generated_from_orco(vec3(0.0), N);
-#endif
+ N = g_data.N;
}
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 5f909ea325b..1b9192c75cf 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -318,23 +318,12 @@ typedef struct bNode {
short preview_xsize, preview_ysize;
/** Used at runtime when going through the tree. Initialize before use. */
short tmp_flag;
- /** Used at runtime to tag derivatives branches. EEVEE only. */
- char branch_tag;
+
+ char _pad0;
/** Used at runtime when iterating over node branches. */
char iter_flag;
/**
- * XXX: eevee only, id of screen space reflection layer,
- * needs to be a float to feed GPU_uniform.
- */
- float ssr_id;
- /**
- * XXX: eevee only, id of screen subsurface scatter layer,
- * needs to be a float to feed GPU_uniform.
- */
- float sss_id;
-
- /**
* Describes the desired interface of the node. This is run-time data only.
* The actual interface of the node may deviate from the declaration temporarily.
* It's possible to sync the actual state of the node to the desired state. Currently, this is
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index f1c08f6a589..4996f12e27d 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -144,10 +144,7 @@ struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
/**
* This one needs to work on a local tree.
*/
-void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
- struct GPUMaterial *mat,
- bool *has_surface_output,
- bool *has_volume_output);
+void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index 03baebfd28b..42a31f39041 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -21,6 +21,7 @@
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -47,11 +48,7 @@
#include "node_shader_util.hh"
#include "node_util.h"
-struct nTreeTags {
- float ssr_id, sss_id;
-};
-
-static void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags);
+using blender::Vector;
static bool shader_tree_poll(const bContext *C, bNodeTreeType *UNUSED(treetype))
{
@@ -250,6 +247,18 @@ static bNodeSocket *ntree_shader_node_find_output(bNode *node, const char *ident
return ntree_shader_node_find_socket(&node->outputs, identifier);
}
+/* Find input socket at a specific position. */
+static bNodeSocket *ntree_shader_node_input_get(bNode *node, int n)
+{
+ return reinterpret_cast<bNodeSocket *>(BLI_findlink(&node->inputs, n));
+}
+
+/* Find output socket at a specific position. */
+static bNodeSocket *ntree_shader_node_output_get(bNode *node, int n)
+{
+ return reinterpret_cast<bNodeSocket *>(BLI_findlink(&node->outputs, n));
+}
+
/* Return true on success. */
static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
bNode *node,
@@ -522,125 +531,21 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
-/* Check whether shader has a displacement.
- *
- * Will also return a node and its socket which is connected to a displacement
- * output. Additionally, link which is attached to the displacement output is
- * also returned.
- */
-static bool ntree_shader_has_displacement(bNodeTree *ntree,
- bNode *output_node,
- bNode **r_node,
- bNodeSocket **r_socket,
- bNodeLink **r_link)
-{
- if (output_node == nullptr) {
- /* We can't have displacement without output node, apparently. */
- return false;
- }
- /* Make sure sockets links pointers are correct. */
- BKE_ntree_update_main_tree(G.main, ntree, nullptr);
- bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement");
-
- if (displacement == nullptr) {
- /* Non-cycles node is used as an output. */
- return false;
- }
-
- if ((displacement->link != nullptr) && !(displacement->link->flag & NODE_LINK_MUTED)) {
- *r_node = displacement->link->fromnode;
- *r_socket = displacement->link->fromsock;
- *r_link = displacement->link;
- return true;
- }
- return false;
-}
-
-static void ntree_shader_relink_node_normal(bNodeTree *ntree,
- bNode *node,
- bNode *node_from,
- bNodeSocket *socket_from)
-{
- /* TODO(sergey): Can we do something smarter here than just a name-based
- * matching?
- */
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- if (STREQ(sock->identifier, "Normal") && sock->link == nullptr) {
- /* It's a normal input and nothing is connected to it. */
- nodeAddLink(ntree, node_from, socket_from, node, sock);
- }
- else if (sock->link) {
- bNodeLink *link = sock->link;
- if (ELEM(link->fromnode->type, SH_NODE_NEW_GEOMETRY, SH_NODE_TEX_COORD) &&
- STREQ(link->fromsock->identifier, "Normal")) {
- /* Linked to a geometry node normal output. */
- nodeAddLink(ntree, node_from, socket_from, node, sock);
- }
- }
- }
-}
-
-/* Use specified node and socket as an input for unconnected normal sockets. */
-static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
- bNode *node_from,
- bNodeSocket *socket_from)
-{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node == node_from) {
- /* Don't connect node itself! */
- continue;
- }
- if (node->tmp_flag == -2) {
- /* This node is used inside the displacement tree. Skip to avoid cycles. */
- continue;
- }
- ntree_shader_relink_node_normal(ntree, node, node_from, socket_from);
- }
-}
-
-static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bNodeLink *bump_link)
-{
- /* Bypass bump nodes. This replicates cycles "implicit" behavior. */
- bNodeSocket *bump_normal_input = ntree_shader_node_find_input(bump_node, "Normal");
- bNode *fromnode;
- bNodeSocket *fromsock;
- /* Default to builtin normals if there is no link. */
- if (bump_normal_input->link) {
- fromsock = bump_normal_input->link->fromsock;
- fromnode = bump_normal_input->link->fromnode;
- }
- else {
- fromnode = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
- fromsock = ntree_shader_node_find_output(fromnode, "Normal");
- }
- /* Bypass the bump node by creating a link between the previous and next node. */
- nodeAddLink(ntree, fromnode, fromsock, bump_link->tonode, bump_link->tosock);
- nodeRemLink(ntree, bump_link);
-}
-
-static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
-{
- /* Bypass bump links inside copied nodes */
- LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
- bNode *node = link->fromnode;
- /* If node is a copy. */
- if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) {
- ntree_shader_bypass_bump_link(ntree, node, link);
- }
- }
- BKE_ntree_update_main_tree(G.main, ntree, nullptr);
-}
+struct branchIterData {
+ bool (*node_filter)(const bNode *node);
+ int node_count;
+};
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
{
- int *node_count = (int *)userdata;
- if (fromnode->tmp_flag == -1) {
- fromnode->tmp_flag = *node_count;
- (*node_count)++;
+ branchIterData *iter = (branchIterData *)userdata;
+ if (fromnode->tmp_flag == -1 && (iter->node_filter == nullptr || iter->node_filter(fromnode))) {
+ fromnode->tmp_flag = iter->node_count;
+ iter->node_count++;
}
- if (tonode->tmp_flag == -1) {
- tonode->tmp_flag = *node_count;
- (*node_count)++;
+ if (tonode->tmp_flag == -1 && (iter->node_filter == nullptr || iter->node_filter(tonode))) {
+ tonode->tmp_flag = iter->node_count;
+ iter->node_count++;
}
return true;
}
@@ -650,6 +555,7 @@ static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, voi
* Returns input node copy. */
static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
bNode *start_node,
+ bool (*node_filter)(const bNode *node),
void (*callback)(bNode *node, int user_data),
int user_data)
{
@@ -659,10 +565,13 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
}
/* Count and tag all nodes inside the displacement branch of the tree. */
start_node->tmp_flag = 0;
- int node_count = 1;
- nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1);
+ branchIterData iter_data;
+ iter_data.node_filter = node_filter;
+ iter_data.node_count = 1;
+ nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &iter_data, 1);
/* Make a full copy of the branch */
- bNode **nodes_copy = static_cast<bNode **>(MEM_mallocN(sizeof(bNode *) * node_count, __func__));
+ bNode **nodes_copy = static_cast<bNode **>(
+ MEM_mallocN(sizeof(bNode *) * iter_data.node_count, __func__));
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->tmp_flag >= 0) {
int id = node->tmp_flag;
@@ -690,7 +599,7 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
}
/* Per node callback. */
if (callback) {
- for (int i = 0; i < node_count; i++) {
+ for (int i = 0; i < iter_data.node_count; i++) {
callback(nodes_copy[i], user_data);
}
}
@@ -699,216 +608,441 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
return start_node_copy;
}
-static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
- bNode *displacement_node,
- bNodeSocket *displacement_socket,
- bNodeLink *displacement_link)
+/* Generate emission node to convert regular data to closure sockets.
+ * Returns validity of the tree.
+ */
+static bool ntree_shader_implicit_closure_cast(bNodeTree *ntree)
{
- /* Replace displacement socket/node/link. */
- bNode *tonode = displacement_link->tonode;
- bNodeSocket *tosock = displacement_link->tosock;
- displacement_node = ntree_shader_copy_branch(ntree, displacement_node, nullptr, 0);
- displacement_socket = ntree_shader_node_find_output(displacement_node,
- displacement_socket->identifier);
- nodeRemLink(ntree, displacement_link);
- nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
-
- BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+ bool modified = false;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if ((link->fromsock->type != SOCK_SHADER) && (link->tosock->type == SOCK_SHADER)) {
+ bNode *emission_node = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION);
+ bNodeSocket *in_sock = ntree_shader_node_find_input(emission_node, "Color");
+ bNodeSocket *out_sock = ntree_shader_node_find_output(emission_node, "Emission");
+ nodeAddLink(ntree, link->fromnode, link->fromsock, emission_node, in_sock);
+ nodeAddLink(ntree, emission_node, out_sock, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ modified = true;
+ }
+ else if ((link->fromsock->type == SOCK_SHADER) && (link->tosock->type != SOCK_SHADER)) {
+ /* Meh. Not directly visible to the user. But better than nothing. */
+ fprintf(stderr, "Shader Nodetree Error: Invalid implicit socket conversion\n");
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+ return false;
+ }
+ }
+ if (modified) {
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+ }
+ return true;
}
-/* Re-link displacement output to unconnected normal sockets via bump node.
- * This way material with have proper displacement in the viewport.
- */
-static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_node)
-{
- bNode *displacement_node;
- bNodeSocket *displacement_socket;
- bNodeLink *displacement_link;
- if (!ntree_shader_has_displacement(
- ntree, output_node, &displacement_node, &displacement_socket, &displacement_link)) {
- /* There is no displacement output connected, nothing to re-link. */
- return;
- }
-
- /* Copy the whole displacement branch to avoid cyclic dependency
- * and issue when bypassing bump nodes. */
- ntree_shader_copy_branch_displacement(
- ntree, displacement_node, displacement_socket, displacement_link);
- /* Bypass bump nodes inside the copied branch to mimic cycles behavior. */
- ntree_shader_bypass_tagged_bump_nodes(ntree);
-
- /* Displacement Node may have changed because of branch copy and bump bypass. */
- ntree_shader_has_displacement(
- ntree, output_node, &displacement_node, &displacement_socket, &displacement_link);
-
- /* We have to disconnect displacement output socket, otherwise we'll have
- * cycles in the Cycles material :)
- */
- nodeRemLink(ntree, displacement_link);
-
- /* Convert displacement vector to bump height. */
- bNode *dot_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_VECTOR_MATH);
- bNode *geo_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
- bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
- bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(dot_node->inputs.first);
- bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
- dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
-
- nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1);
- nodeAddLink(ntree, geo_node, normal_socket, dot_node, dot_input2);
- displacement_node = dot_node;
- displacement_socket = ntree_shader_node_find_output(dot_node, "Value");
-
- /* We can't connect displacement to normal directly, use bump node for that
- * and hope that it gives good enough approximation.
- */
- bNode *bump_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_BUMP);
- bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
- bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
- BLI_assert(bump_input_socket != nullptr);
- BLI_assert(bump_output_socket != nullptr);
- /* Connect bump node to where displacement output was originally
- * connected to.
- */
- nodeAddLink(ntree, displacement_node, displacement_socket, bump_node, bump_input_socket);
-
- /* Tag as part of the new displacement tree. */
- dot_node->tmp_flag = -2;
- geo_node->tmp_flag = -2;
- bump_node->tmp_flag = -2;
-
- BKE_ntree_update_main_tree(G.main, ntree, nullptr);
-
- /* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
- ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
- /* We modified the tree, it needs to be updated now. */
- BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+/* Socket already has a link to it. Add weights together. */
+static void ntree_weight_tree_merge_weight(bNodeTree *ntree,
+ bNode *UNUSED(fromnode),
+ bNodeSocket *fromsock,
+ bNode **tonode,
+ bNodeSocket **tosock)
+{
+ bNode *addnode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ addnode->custom1 = NODE_MATH_ADD;
+ addnode->tmp_flag = -2; /* Copy */
+ bNodeSocket *addsock_out = ntree_shader_node_output_get(addnode, 0);
+ bNodeSocket *addsock_in0 = ntree_shader_node_input_get(addnode, 0);
+ bNodeSocket *addsock_in1 = ntree_shader_node_input_get(addnode, 1);
+ bNodeLink *oldlink = fromsock->link;
+ nodeAddLink(ntree, oldlink->fromnode, oldlink->fromsock, addnode, addsock_in0);
+ nodeAddLink(ntree, *tonode, *tosock, addnode, addsock_in1);
+ nodeRemLink(ntree, oldlink);
+ *tonode = addnode;
+ *tosock = addsock_out;
}
-static void node_tag_branch_as_derivative(bNode *node, int dx)
+static bool ntree_weight_tree_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
{
- if (dx) {
- node->branch_tag = 1;
+ int *node_count = (int *)userdata;
+ bool to_node_from_weight_tree = ELEM(tonode->type,
+ SH_NODE_ADD_SHADER,
+ SH_NODE_MIX_SHADER,
+ SH_NODE_OUTPUT_WORLD,
+ SH_NODE_OUTPUT_MATERIAL,
+ SH_NODE_SHADERTORGB);
+ if (tonode->tmp_flag == -1 && to_node_from_weight_tree) {
+ tonode->tmp_flag = *node_count;
+ *node_count += (tonode->type == SH_NODE_MIX_SHADER) ? 4 : 1;
}
- else {
- node->branch_tag = 2;
+ if (fromnode->tmp_flag == -1 && ELEM(fromnode->type, SH_NODE_ADD_SHADER, SH_NODE_MIX_SHADER)) {
+ fromnode->tmp_flag = *node_count;
+ *node_count += (fromnode->type == SH_NODE_MIX_SHADER) ? 4 : 1;
}
+ return to_node_from_weight_tree;
}
-static bool ntree_shader_bump_branches(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
+/* Invert evaluation order of the weight tree (add & mix closure nodes) to feed the closure nodes
+ * with their respective weights. */
+static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node)
{
- bNodeTree *ntree = (bNodeTree *)userdata;
+ bNodeLink *displace_link = NULL;
+ bNodeSocket *displace_output = ntree_shader_node_find_input(output_node, "Displacement");
+ if (displace_output && displace_output->link) {
+ /* Remove any displacement link to avoid tagging it later on. */
+ displace_link = displace_output->link;
+ displace_output->link = NULL;
+ }
+ bNodeLink *thickness_link = NULL;
+ bNodeSocket *thickness_output = ntree_shader_node_find_input(output_node, "Thickness");
+ if (thickness_output && thickness_output->link) {
+ /* Remove any thickness link to avoid tagging it later on. */
+ thickness_link = thickness_output->link;
+ thickness_output->link = NULL;
+ }
+ /* Init tmp flag. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->tmp_flag = -1;
+ }
+ /* Tag nodes from the weight tree. Only tag output node and mix/add shader nodes. */
+ output_node->tmp_flag = 0;
+ int node_count = 1;
+ nodeChainIterBackwards(ntree, output_node, ntree_weight_tree_tag_nodes, &node_count, 0);
+ /* Make a mirror copy of the weight tree. */
+ bNode **nodes_copy = static_cast<bNode **>(MEM_mallocN(sizeof(bNode *) * node_count, __func__));
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->tmp_flag >= 0) {
+ int id = node->tmp_flag;
- if (fromnode->type == SH_NODE_BUMP) {
- bNodeSocket *height_dx_sock, *height_dy_sock, *bump_socket, *bump_dx_socket, *bump_dy_socket;
- bNode *bump = fromnode;
- bump_socket = ntree_shader_node_find_input(bump, "Height");
- bump_dx_socket = ntree_shader_node_find_input(bump, "Height_dx");
- bump_dy_socket = ntree_shader_node_find_input(bump, "Height_dy");
- if (bump_dx_socket->link) {
- /* Avoid reconnecting the same bump twice. */
+ switch (node->type) {
+ case SH_NODE_SHADERTORGB:
+ case SH_NODE_OUTPUT_WORLD:
+ case SH_NODE_OUTPUT_MATERIAL: {
+ /* Start the tree with full weight. */
+ nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_VALUE);
+ nodes_copy[id]->tmp_flag = -2; /* Copy */
+ ((bNodeSocketValueFloat *)ntree_shader_node_output_get(nodes_copy[id], 0)->default_value)
+ ->value = 1.0f;
+ break;
+ }
+ case SH_NODE_ADD_SHADER: {
+ /* Simple passthrough node. Each original inputs will get the same weight. */
+ /* TODO(fclem) Better use some kind of reroute node? */
+ nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ nodes_copy[id]->custom1 = NODE_MATH_ADD;
+ nodes_copy[id]->tmp_flag = -2; /* Copy */
+ ((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value)
+ ->value = 0.0f;
+ break;
+ }
+ case SH_NODE_MIX_SHADER: {
+ /* We need multiple nodes to emulate the mix node in reverse. */
+ bNode *fromnode, *tonode;
+ bNodeSocket *fromsock, *tosock;
+ int id_start = id;
+ /* output = (factor * input_weight) */
+ nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ nodes_copy[id]->custom1 = NODE_MATH_MULTIPLY;
+ nodes_copy[id]->tmp_flag = -2; /* Copy */
+ id++;
+ /* output = ((1.0 - factor) * input_weight) <=> (input_weight - factor * input_weight) */
+ nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ nodes_copy[id]->custom1 = NODE_MATH_SUBTRACT;
+ nodes_copy[id]->tmp_flag = -2; /* Copy */
+ id++;
+ /* Node sanitizes the input mix factor by clamping it. */
+ nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ nodes_copy[id]->custom1 = NODE_MATH_ADD;
+ nodes_copy[id]->custom2 = SHD_MATH_CLAMP;
+ nodes_copy[id]->tmp_flag = -2; /* Copy */
+ ((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value)
+ ->value = 0.0f;
+ /* Copy default value if no link present. */
+ bNodeSocket *fac_sock = ntree_shader_node_find_input(node, "Fac");
+ if (!fac_sock->link) {
+ float default_value = ((bNodeSocketValueFloat *)fac_sock->default_value)->value;
+ bNodeSocket *dst_sock = ntree_shader_node_input_get(nodes_copy[id], 1);
+ ((bNodeSocketValueFloat *)dst_sock->default_value)->value = default_value;
+ }
+ id++;
+ /* Reroute the weight input to the 3 processing nodes. Simplify linking later-on. */
+ /* TODO(fclem) Better use some kind of reroute node? */
+ nodes_copy[id] = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ nodes_copy[id]->custom1 = NODE_MATH_ADD;
+ nodes_copy[id]->tmp_flag = -2; /* Copy */
+ ((bNodeSocketValueFloat *)ntree_shader_node_input_get(nodes_copy[id], 0)->default_value)
+ ->value = 0.0f;
+ id++;
+ /* Link between nodes for the substraction. */
+ fromnode = nodes_copy[id_start];
+ tonode = nodes_copy[id_start + 1];
+ fromsock = ntree_shader_node_output_get(fromnode, 0);
+ tosock = ntree_shader_node_input_get(tonode, 1);
+ nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
+ /* Link mix input to first node. */
+ fromnode = nodes_copy[id_start + 2];
+ tonode = nodes_copy[id_start];
+ fromsock = ntree_shader_node_output_get(fromnode, 0);
+ tosock = ntree_shader_node_input_get(tonode, 1);
+ nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
+ /* Link weight input to both multiply nodes. */
+ fromnode = nodes_copy[id_start + 3];
+ fromsock = ntree_shader_node_output_get(fromnode, 0);
+ tonode = nodes_copy[id_start];
+ tosock = ntree_shader_node_input_get(tonode, 0);
+ nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
+ tonode = nodes_copy[id_start + 1];
+ tosock = ntree_shader_node_input_get(tonode, 0);
+ nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
+ break;
+ }
+ default:
+ BLI_assert(0);
+ break;
+ }
}
- else if (bump_socket && bump_socket->link) {
- bNodeLink *link = bump_socket->link;
- bNode *height = link->fromnode;
- bNode *height_dx = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 1);
- bNode *height_dy = ntree_shader_copy_branch(ntree, height, node_tag_branch_as_derivative, 0);
- height_dx_sock = ntree_shader_node_find_output(height_dx, link->fromsock->identifier);
- height_dy_sock = ntree_shader_node_find_output(height_dy, link->fromsock->identifier);
- nodeAddLink(ntree, height_dx, height_dx_sock, bump, bump_dx_socket);
- nodeAddLink(ntree, height_dy, height_dy_sock, bump, bump_dy_socket);
- /* We could end iter here, but other bump node could be plugged into other input sockets. */
+ }
+ /* Recreate links between copied nodes. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->tmp_flag >= 0) {
+ /* Naming can be confusing here. We use original nodelink name for from/to prefix.
+ * The final link is in reversed order. */
+ int socket_index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, socket_index) {
+ bNodeSocket *tosock;
+ bNode *tonode;
+
+ switch (node->type) {
+ case SH_NODE_SHADERTORGB:
+ case SH_NODE_OUTPUT_WORLD:
+ case SH_NODE_OUTPUT_MATERIAL:
+ case SH_NODE_ADD_SHADER: {
+ tonode = nodes_copy[node->tmp_flag];
+ tosock = ntree_shader_node_output_get(tonode, 0);
+ break;
+ }
+ case SH_NODE_MIX_SHADER: {
+ if (socket_index == 0) {
+ /* Mix Factor. */
+ tonode = nodes_copy[node->tmp_flag + 2];
+ tosock = ntree_shader_node_input_get(tonode, 1);
+ }
+ else if (socket_index == 1) {
+ /* Shader 1. */
+ tonode = nodes_copy[node->tmp_flag + 1];
+ tosock = ntree_shader_node_output_get(tonode, 0);
+ }
+ else {
+ /* Shader 2. */
+ tonode = nodes_copy[node->tmp_flag];
+ tosock = ntree_shader_node_output_get(tonode, 0);
+ }
+ break;
+ }
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ if (sock->link) {
+ bNodeSocket *fromsock;
+ bNode *fromnode = sock->link->fromnode;
+
+ switch (fromnode->type) {
+ case SH_NODE_ADD_SHADER: {
+ fromnode = nodes_copy[fromnode->tmp_flag];
+ fromsock = ntree_shader_node_input_get(fromnode, 1);
+ if (fromsock->link) {
+ ntree_weight_tree_merge_weight(ntree, fromnode, fromsock, &tonode, &tosock);
+ }
+ break;
+ }
+ case SH_NODE_MIX_SHADER: {
+ fromnode = nodes_copy[fromnode->tmp_flag + 3];
+ fromsock = ntree_shader_node_input_get(fromnode, 1);
+ if (fromsock->link) {
+ ntree_weight_tree_merge_weight(ntree, fromnode, fromsock, &tonode, &tosock);
+ }
+ break;
+ }
+ case SH_NODE_BACKGROUND:
+ case SH_NODE_BSDF_ANISOTROPIC:
+ case SH_NODE_BSDF_DIFFUSE:
+ case SH_NODE_BSDF_GLASS:
+ case SH_NODE_BSDF_GLOSSY:
+ case SH_NODE_BSDF_HAIR_PRINCIPLED:
+ case SH_NODE_BSDF_HAIR:
+ case SH_NODE_BSDF_PRINCIPLED:
+ case SH_NODE_BSDF_REFRACTION:
+ case SH_NODE_BSDF_TOON:
+ case SH_NODE_BSDF_TRANSLUCENT:
+ case SH_NODE_BSDF_TRANSPARENT:
+ case SH_NODE_BSDF_VELVET:
+ case SH_NODE_EEVEE_SPECULAR:
+ case SH_NODE_EMISSION:
+ case SH_NODE_HOLDOUT:
+ case SH_NODE_SUBSURFACE_SCATTERING:
+ case SH_NODE_VOLUME_ABSORPTION:
+ case SH_NODE_VOLUME_PRINCIPLED:
+ case SH_NODE_VOLUME_SCATTER:
+ fromsock = ntree_shader_node_find_input(fromnode, "Weight");
+ if (fromsock->link) {
+ ntree_weight_tree_merge_weight(ntree, fromnode, fromsock, &tonode, &tosock);
+ }
+ break;
+ default:
+ fromsock = sock->link->fromsock;
+ break;
+ }
+
+ /* Manually add the link to the socket to avoid calling
+ * BKE_ntree_update_main_tree(G.main, oop, nullptr. */
+ fromsock->link = nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
+ BLI_assert(fromsock->link);
+ }
+ }
}
}
- return true;
+ /* Restore displacement & thickness link. */
+ if (displace_link) {
+ nodeAddLink(
+ ntree, displace_link->fromnode, displace_link->fromsock, output_node, displace_output);
+ }
+ if (thickness_link) {
+ nodeAddLink(
+ ntree, thickness_link->fromnode, thickness_link->fromsock, output_node, thickness_output);
+ }
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+
+ MEM_freeN(nodes_copy);
}
-static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *userdata)
+static bool closure_node_filter(const bNode *node)
{
- switch (fromnode->type) {
+ switch (node->type) {
+ case SH_NODE_ADD_SHADER:
+ case SH_NODE_MIX_SHADER:
+ case SH_NODE_BACKGROUND:
case SH_NODE_BSDF_ANISOTROPIC:
- case SH_NODE_EEVEE_SPECULAR:
- case SH_NODE_BSDF_GLOSSY:
+ case SH_NODE_BSDF_DIFFUSE:
case SH_NODE_BSDF_GLASS:
- fromnode->ssr_id = ((nTreeTags *)userdata)->ssr_id;
- ((nTreeTags *)userdata)->ssr_id += 1;
- break;
- case SH_NODE_SUBSURFACE_SCATTERING:
- fromnode->sss_id = ((nTreeTags *)userdata)->sss_id;
- ((nTreeTags *)userdata)->sss_id += 1;
- break;
+ case SH_NODE_BSDF_GLOSSY:
+ case SH_NODE_BSDF_HAIR_PRINCIPLED:
+ case SH_NODE_BSDF_HAIR:
case SH_NODE_BSDF_PRINCIPLED:
- fromnode->ssr_id = ((nTreeTags *)userdata)->ssr_id;
- fromnode->sss_id = ((nTreeTags *)userdata)->sss_id;
- ((nTreeTags *)userdata)->sss_id += 1;
- ((nTreeTags *)userdata)->ssr_id += 1;
- break;
+ case SH_NODE_BSDF_REFRACTION:
+ case SH_NODE_BSDF_TOON:
+ case SH_NODE_BSDF_TRANSLUCENT:
+ case SH_NODE_BSDF_TRANSPARENT:
+ case SH_NODE_BSDF_VELVET:
+ case SH_NODE_EEVEE_SPECULAR:
+ case SH_NODE_EMISSION:
+ case SH_NODE_HOLDOUT:
+ case SH_NODE_SUBSURFACE_SCATTERING:
+ case SH_NODE_VOLUME_ABSORPTION:
+ case SH_NODE_VOLUME_PRINCIPLED:
+ case SH_NODE_VOLUME_SCATTER:
+ return true;
default:
- /* We could return false here but since we
- * allow the use of Closure as RGBA, we can have
- * BSDF nodes linked to other BSDF nodes. */
- break;
+ return false;
}
+}
+static bool shader_to_rgba_node_gather(bNode *UNUSED(fromnode), bNode *tonode, void *userdata)
+{
+ Vector<bNode *> &shader_to_rgba_nodes = *(Vector<bNode *> *)userdata;
+ if (tonode->tmp_flag == -1 && tonode->type == SH_NODE_SHADERTORGB) {
+ tonode->tmp_flag = 0;
+ shader_to_rgba_nodes.append(tonode);
+ }
return true;
}
-/* EEVEE: Scan the ntree to set the Screen Space Reflection
- * layer id of every specular node AND the Subsurface Scattering id of every SSS node.
- */
-void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags)
+/* Shader to rgba needs their associated closure duplicated and the weight tree generated for. */
+static void ntree_shader_shader_to_rgba_branch(bNodeTree *ntree, bNode *output_node)
{
- if (output_node == nullptr) {
- return;
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->tmp_flag = -1;
}
- /* Make sure sockets links pointers are correct. */
- BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+ /* First gather the shader_to_rgba nodes linked to the ouput. This is separate to avoid
+ * conflicting usage of the node->tmp_flag. */
+ Vector<bNode *> shader_to_rgba_nodes;
+ nodeChainIterBackwards(ntree, output_node, shader_to_rgba_node_gather, &shader_to_rgba_nodes, 0);
+
+ for (bNode *shader_to_rgba : shader_to_rgba_nodes) {
+ bNodeSocket *closure_input = ntree_shader_node_input_get(shader_to_rgba, 0);
+ if (closure_input->link == nullptr) {
+ continue;
+ }
+ bNode *start_node = closure_input->link->fromnode;
+ bNode *start_node_copy = ntree_shader_copy_branch(
+ ntree, start_node, closure_node_filter, nullptr, 0);
+ /* Replace node copy link. This assumes that every node possibly connected to the closure input
+ * has only one ouput. */
+ bNodeSocket *closure_output = ntree_shader_node_output_get(start_node_copy, 0);
+ nodeRemLink(ntree, closure_input->link);
+ nodeAddLink(ntree, start_node_copy, closure_output, shader_to_rgba, closure_input);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+
+ ntree_shader_weight_tree_invert(ntree, shader_to_rgba);
+ }
+}
- nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
+static bool ntree_branch_node_tag(bNode *fromnode, bNode *tonode, void *UNUSED(userdata))
+{
+ fromnode->tmp_flag = 1;
+ tonode->tmp_flag = 1;
+ return true;
}
-void ntreeGPUMaterialNodes(bNodeTree *localtree,
- GPUMaterial *mat,
- bool *has_surface_output,
- bool *has_volume_output)
+/* Avoid adding more node execution when multiple outputs are present. */
+/* NOTE(@fclem): This is also a workaround for the old EEVEE SSS implementation where only the
+ * first executed SSS node gets a SSS profile. */
+static void ntree_shader_pruned_unused(bNodeTree *ntree, bNode *output_node)
{
- bNodeTreeExec *exec;
+ bool changed = false;
- bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->tmp_flag = 0;
+ }
- ntree_shader_groups_remove_muted_links(localtree);
- ntree_shader_groups_expand_inputs(localtree);
+ /* Avoid deleting the output node if it is the only node in the tree. */
+ output_node->tmp_flag = 1;
- ntree_shader_groups_flatten(localtree);
+ nodeChainIterBackwards(ntree, output_node, ntree_branch_node_tag, nullptr, 0);
- if (output == nullptr) {
- /* Search again, now including flattened nodes. */
- output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_OUTPUT_AOV) {
+ nodeChainIterBackwards(ntree, node, ntree_branch_node_tag, nullptr, 0);
+ }
}
- /* Perform all needed modifications on the tree in order to support
- * displacement/bump mapping.
- */
- ntree_shader_relink_displacement(localtree, output);
-
- /* Duplicate bump height branches for manual derivatives.
- */
- nodeChainIterBackwards(localtree, output, ntree_shader_bump_branches, localtree, 0);
- LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
- if (node->type == SH_NODE_OUTPUT_AOV) {
- nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0);
- nTreeTags tags = {};
- tags.ssr_id = 1.0;
- tags.sss_id = 1.0;
- ntree_shader_tag_nodes(localtree, node, &tags);
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
+ if (node->tmp_flag == 0) {
+ ntreeFreeLocalNode(ntree, node);
+ changed = true;
}
}
- /* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
- nTreeTags tags = {};
- tags.ssr_id = 1.0;
- tags.sss_id = 1.0;
- ntree_shader_tag_nodes(localtree, output, &tags);
+ if (changed) {
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
+ }
+}
+
+void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat)
+{
+ bNodeTreeExec *exec;
+
+ ntree_shader_groups_remove_muted_links(localtree);
+ ntree_shader_groups_expand_inputs(localtree);
+ ntree_shader_groups_flatten(localtree);
+
+ bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+
+ /* Tree is valid if it contains no undefined implicit socket type cast. */
+ bool valid_tree = ntree_shader_implicit_closure_cast(localtree);
+
+ if (valid_tree && output != NULL) {
+ ntree_shader_pruned_unused(localtree, output);
+ ntree_shader_shader_to_rgba_branch(localtree, output);
+ ntree_shader_weight_tree_invert(localtree, output);
+ }
exec = ntreeShaderBeginExecTree(localtree);
ntreeExecGPUNodes(exec, mat, output);
@@ -918,23 +1052,6 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
}
}
ntreeShaderEndExecTree(exec);
-
- /* EEVEE: Find which material domain was used (volume, surface ...). */
- *has_surface_output = false;
- *has_volume_output = false;
-
- if (output != nullptr) {
- bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface");
- bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume");
-
- if (surface_sock != nullptr) {
- *has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0);
- }
-
- if (volume_sock != nullptr) {
- *has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0);
- }
- }
}
bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context,
diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc
index 728e2760f9a..c47b69e6b69 100644
--- a/source/blender/nodes/shader/node_shader_util.cc
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -284,26 +284,15 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node
}
}
-void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
+void node_shader_gpu_bump_tex_coord(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeLink **link)
{
- if (node->branch_tag == 1) {
- /* Add one time the value for derivative to the input vector. */
- GPU_link(mat, "dfdx_v3", *link, link);
- }
- else if (node->branch_tag == 2) {
- /* Add one time the value for derivative to the input vector. */
- GPU_link(mat, "dfdy_v3", *link, link);
- }
- else {
- /* nothing to do, reference center value. */
- }
+ GPU_link(mat, "differentiate_texco", *link, link);
}
void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
{
if (!*link) {
*link = GPU_attribute(mat, CD_ORCO, "");
- GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), *link, link);
node_shader_gpu_bump_tex_coord(mat, node, link);
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
index a24b4379e69..1e8df2e985d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
@@ -36,7 +36,7 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[2].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE);
+ GPU_material_flag_set(mat, GPU_MATFLAG_AO);
float inverted = (node->custom2 & SHD_AO_INSIDE) ? 1.0f : 0.0f;
float f_samples = divide_ceil_u(node->custom1, 4);
diff --git a/source/blender/nodes/shader/nodes/node_shader_background.cc b/source/blender/nodes/shader/nodes/node_shader_background.cc
index f5d3b6811f1..ea5c1f541ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_background.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_background.cc
@@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("Background"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.cc b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
index 8bce38baf73..4ae60af9974 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bevel.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
@@ -32,11 +32,7 @@ static int gpu_shader_bevel(GPUMaterial *mat,
GPUNodeStack *out)
{
if (!in[1].link) {
- GPU_link(mat,
- "direction_transform_m4v3",
- GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- &in[1].link);
+ GPU_link(mat, "world_normals_get", &in[1].link);
}
return GPU_stack_link(mat, node, "node_bevel", in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
index 13b4a034a51..761a833f377 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
@@ -24,6 +24,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
@@ -51,13 +52,8 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat,
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
- return GPU_stack_link(mat,
- node,
- "node_bsdf_anisotropic",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- GPU_constant(&node->ssr_id));
+ return GPU_stack_link(
+ mat, node, "node_bsdf_anisotropic", in, out, GPU_constant(&use_multi_scatter));
}
} // namespace blender::nodes::node_shader_bsdf_anisotropic_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
index 3f025b2ba39..5975e04450e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
@@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
index a1e5b705438..95869f13b7e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
@@ -15,6 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
@@ -37,17 +38,11 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
GPU_link(mat, "set_value_zero", &in[1].link);
}
- GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT));
+ GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
- return GPU_stack_link(mat,
- node,
- "node_bsdf_glass",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- GPU_constant(&node->ssr_id));
+ return GPU_stack_link(mat, node, "node_bsdf_glass", in, out, GPU_constant(&use_multi_scatter));
}
} // namespace blender::nodes::node_shader_bsdf_glass_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
index 9f0e172a5fe..07062a9730e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
@@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
@@ -40,13 +41,7 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat,
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
- return GPU_stack_link(mat,
- node,
- "node_bsdf_glossy",
- in,
- out,
- GPU_constant(&use_multi_scatter),
- GPU_constant(&node->ssr_id));
+ return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_constant(&use_multi_scatter));
}
} // namespace blender::nodes::node_shader_bsdf_glossy_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
index ef87f380bb9..1a1ba13e886 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
@@ -27,6 +27,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
index edae03bbd31..6495dcfffba 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
@@ -60,6 +60,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>(N_("Random")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
@@ -108,6 +109,15 @@ static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node)
}
}
+static int node_shader_gpu_hair_principled(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_bsdf_hair_principled", in, out);
+}
+
} // namespace blender::nodes::node_shader_bsdf_hair_principled_cc
/* node type definition */
@@ -124,6 +134,7 @@ void register_node_type_sh_bsdf_hair_principled()
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, file_ns::node_shader_init_hair_principled);
node_type_update(&ntype, file_ns::node_shader_update_hair_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_hair_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
index ba98a797f2a..a63c7aede04 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
@@ -103,6 +103,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Normal")).hide_value();
b.add_input<decl::Vector>(N_("Clearcoat Normal")).hide_value();
b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
@@ -128,8 +129,6 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- GPUNodeLink *sss_scale;
-
/* Normals */
if (!in[22].link) {
GPU_link(mat, "world_normals_get", &in[22].link);
@@ -145,36 +144,17 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
if (!in[24].link) {
GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
GPU_link(mat, "tangent_orco_z", orco, &in[24].link);
- GPU_link(mat,
- "node_tangent",
- GPU_builtin(GPU_WORLD_NORMAL),
- in[24].link,
- GPU_builtin(GPU_OBJECT_MATRIX),
- &in[24].link);
+ GPU_link(mat, "node_tangent", in[24].link, &in[24].link);
}
#endif
bool use_diffuse = socket_not_one(6) && socket_not_one(17);
- bool use_subsurf = socket_not_zero(1) && use_diffuse && node->sss_id > 0;
+ bool use_subsurf = socket_not_zero(1) && use_diffuse;
bool use_refract = socket_not_one(6) && socket_not_zero(17);
+ bool use_transparency = socket_not_one(21);
bool use_clear = socket_not_zero(14);
- /* SSS Profile */
- if (use_subsurf) {
- bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
- bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
- /* For some reason it seems that the socket value is in ARGB format. */
- GPU_material_sss_profile_create(mat, &socket_data->value[1]);
- }
-
- if (in[2].link) {
- sss_scale = in[2].link;
- }
- else {
- GPU_link(mat, "set_rgb_one", &sss_scale);
- }
-
- uint flag = GPU_MATFLAG_GLOSSY;
+ eGPUMaterialFlag flag = GPU_MATFLAG_GLOSSY;
if (use_diffuse) {
flag |= GPU_MATFLAG_DIFFUSE;
}
@@ -182,28 +162,37 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
flag |= GPU_MATFLAG_REFRACT;
}
if (use_subsurf) {
- flag |= GPU_MATFLAG_SSS;
+ flag |= GPU_MATFLAG_SUBSURFACE;
+ }
+ if (use_transparency) {
+ flag |= GPU_MATFLAG_TRANSPARENT;
+ }
+
+ if (use_subsurf) {
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
+ /* For some reason it seems that the socket value is in ARGB format. */
+ use_subsurf = GPU_material_sss_profile_create(mat, &socket_data->value[1]);
}
- float f_use_diffuse = use_diffuse ? 1.0f : 0.0f;
- float f_use_clearcoat = use_clear ? 1.0f : 0.0f;
- float f_use_refraction = use_refract ? 1.0f : 0.0f;
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
+ float use_sss = (use_subsurf) ? 1.0f : 0.0f;
+ float use_diffuse_f = (use_diffuse) ? 1.0f : 0.0f;
+ float use_clear_f = (use_clear) ? 1.0f : 0.0f;
+ float use_refract_f = (use_refract) ? 1.0f : 0.0f;
- GPU_material_flag_set(mat, (eGPUMatFlag)flag);
+ GPU_material_flag_set(mat, flag);
return GPU_stack_link(mat,
node,
"node_bsdf_principled",
in,
out,
- GPU_constant(&f_use_diffuse),
- GPU_constant(&f_use_clearcoat),
- GPU_constant(&f_use_refraction),
+ GPU_constant(&use_diffuse_f),
+ GPU_constant(&use_clear_f),
+ GPU_constant(&use_refract_f),
GPU_constant(&use_multi_scatter),
- GPU_constant(&node->ssr_id),
- GPU_constant(&node->sss_id),
- sss_scale);
+ GPU_uniform(&use_sss));
}
static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
index 73f58477b67..e814eb223e5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
@@ -15,6 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
index 9cb7c4c3bbb..c1c092e89c7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
@@ -22,6 +22,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
index 19e61d8140d..fd0dd9f93de 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
@@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
index 57fd7e3ef3b..291b3fdb2be 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
@@ -8,6 +8,7 @@ namespace blender::nodes::node_shader_bsdf_transparent_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
@@ -17,6 +18,9 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
+ if (in[0].link || !is_zero_v3(in[0].vec)) {
+ GPU_material_flag_set(mat, GPU_MATFLAG_TRANSPARENT);
+ }
return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
index 75bdb5b6f54..c86d70aecbf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
@@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.cc b/source/blender/nodes/shader/nodes/node_shader_bump.cc
index 5dd27e64ce3..ad2c56d96b5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc
@@ -27,8 +27,6 @@ static void node_declare(NodeDeclarationBuilder &b)
.min(-1000.0f)
.max(1000.0f)
.hide_value();
- b.add_input<decl::Float>(N_("Height_dx")).default_value(1.0f).unavailable();
- b.add_input<decl::Float>(N_("Height_dy")).default_value(1.0f).unavailable();
b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
b.add_output<decl::Vector>(N_("Normal"));
}
@@ -46,23 +44,26 @@ static int gpu_shader_bump(GPUMaterial *mat,
{
/* If there is no Height input, the node becomes a no-op. */
if (!in[2].link) {
- if (!in[5].link) {
+ if (!in[3].link) {
return GPU_link(mat, "world_normals_get", &out[0].link);
}
else {
/* Actually running the bump code would normalize, but Cycles handles it as total no-op. */
- return GPU_link(mat, "vector_copy", in[5].link, &out[0].link);
+ return GPU_link(mat, "vector_copy", in[3].link, &out[0].link);
}
}
- if (!in[5].link) {
- GPU_link(mat, "world_normals_get", &in[5].link);
+ if (!in[3].link) {
+ GPU_link(mat, "world_normals_get", &in[3].link);
}
+ const char *height_function = GPU_material_split_sub_function(mat, GPU_FLOAT, &in[2].link);
+
+ GPUNodeLink *dheight = GPU_differentiate_float_function(height_function);
+
float invert = (node->custom1) ? -1.0 : 1.0;
- return GPU_stack_link(
- mat, node, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_constant(&invert));
+ return GPU_stack_link(mat, node, "node_bump", in, out, dheight, GPU_constant(&invert));
}
} // namespace blender::nodes::node_shader_bump_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.cc b/source/blender/nodes/shader/nodes/node_shader_camera.cc
index 9d2858f56f7..99c82582456 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc
@@ -22,11 +22,7 @@ static int gpu_shader_camera(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- GPUNodeLink *viewvec;
-
- viewvec = GPU_builtin(GPU_VIEW_POSITION);
- GPU_link(mat, "invert_z", viewvec, &viewvec);
- return GPU_stack_link(mat, node, "camera", in, out, viewvec);
+ return GPU_stack_link(mat, node, "camera", in, out);
}
} // namespace blender::nodes::node_shader_camera_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
index 88d1fac13a4..6591396adda 100644
--- a/source/blender/nodes/shader/nodes/node_shader_displacement.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
@@ -33,16 +33,11 @@ static int gpu_shader_displacement(GPUMaterial *mat,
GPUNodeStack *out)
{
if (!in[3].link) {
- GPU_link(mat,
- "direction_transform_m4v3",
- GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- &in[3].link);
+ GPU_link(mat, "world_normals_get", &in[3].link);
}
if (node->custom1 == SHD_SPACE_OBJECT) {
- return GPU_stack_link(
- mat, node, "node_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
+ return GPU_stack_link(mat, node, "node_displacement_object", in, out);
}
return GPU_stack_link(mat, node, "node_displacement_world", in, out);
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
index c4aed523f61..d68b0c0c37c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
@@ -33,9 +33,12 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Clear Coat Normal")).hide_value();
b.add_input<decl::Float>(N_("Ambient Occlusion")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSDF"));
}
+#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
+
static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -59,9 +62,11 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link);
}
- GPU_material_flag_set(mat, static_cast<eGPUMatFlag>(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY));
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
+
+ float use_clear = (socket_not_zero(6)) ? 1.0f : 0.0f;
- return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id));
+ return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&use_clear));
}
} // namespace blender::nodes::node_shader_eevee_specular_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.cc b/source/blender/nodes/shader/nodes/node_shader_emission.cc
index d4d88857cd2..be98f096ce5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_emission.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc
@@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("Emission"));
}
@@ -18,7 +19,8 @@ static int node_shader_gpu_emission(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ GPU_material_flag_set(mat, GPU_MATFLAG_EMISSION);
+ return GPU_stack_link(mat, node, "node_emission", in, out);
}
} // namespace blender::nodes::node_shader_emission_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.cc b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
index 47b2c6b97d4..7b771d7dafd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
@@ -19,14 +19,10 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat,
GPUNodeStack *out)
{
if (!in[1].link) {
- in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- }
- else {
- GPU_link(
- mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
+ GPU_link(mat, "world_normals_get", &in[1].link);
}
- return GPU_stack_link(mat, node, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ return GPU_stack_link(mat, node, "node_fresnel", in, out);
}
} // namespace blender::nodes::node_shader_fresnel_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.cc b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
index 5bd984ddfc4..47df932f9d4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
@@ -24,29 +24,17 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- /* HACK: Don't request GPU_BARYCENTRIC_TEXCO if not used because it will
+ /* HACK: Don't request GPU_MATFLAG_BARYCENTRIC if not used because it will
* trigger the use of geometry shader (and the performance penalty it implies). */
- const float val[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- GPUNodeLink *bary_link = (!out[5].hasoutput) ? GPU_constant(val) :
- GPU_builtin(GPU_BARYCENTRIC_TEXCO);
if (out[5].hasoutput) {
GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC);
}
/* Opti: don't request orco if not needed. */
+ const float val[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPUNodeLink *orco_link = (!out[2].hasoutput) ? GPU_constant(val) :
GPU_attribute(mat, CD_ORCO, "");
- const bool success = GPU_stack_link(mat,
- node,
- "node_geometry",
- in,
- out,
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_builtin(GPU_WORLD_NORMAL),
- orco_link,
- GPU_builtin(GPU_OBJECT_MATRIX),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
- bary_link);
+ const bool success = GPU_stack_link(mat, node, "node_geometry", in, out, orco_link);
int i;
LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
@@ -55,7 +43,7 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
* This is the case for interpolated, non linear functions.
* The resulting vector can still be a bit wrong but not as much.
* (see T70644) */
- if (node->branch_tag != 0 && ELEM(i, 1, 2, 4)) {
+ if (ELEM(i, 1, 2, 4)) {
GPU_link(mat,
"vector_math_normalize",
out[i].link,
diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.cc b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
index b1a9ce75e1f..6a21fab28db 100644
--- a/source/blender/nodes/shader/nodes/node_shader_holdout.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
@@ -7,6 +7,7 @@ namespace blender::nodes::node_shader_holdout_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("Holdout"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
index b5097e71657..69825e472fb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
@@ -20,14 +20,10 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat,
GPUNodeStack *out)
{
if (!in[1].link) {
- in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
- }
- else {
- GPU_link(
- mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
+ GPU_link(mat, "world_normals_get", &in[1].link);
}
- return GPU_stack_link(mat, node, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION));
+ return GPU_stack_link(mat, node, "node_layer_weight", in, out);
}
} // namespace blender::nodes::node_shader_layer_weight_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
index f8a5e342ae3..d51d8def945 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
@@ -83,18 +83,16 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
GPU_link(mat, color_to_normal_fnc_name, newnormal, &newnormal);
switch (nm->space) {
case SHD_SPACE_TANGENT:
+ GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO);
GPU_link(mat,
"node_normal_map",
- GPU_builtin(GPU_OBJECT_INFO),
GPU_attribute(mat, CD_TANGENT, nm->uv_map),
- GPU_builtin(GPU_WORLD_NORMAL),
newnormal,
&newnormal);
break;
case SHD_SPACE_OBJECT:
case SHD_SPACE_BLENDER_OBJECT:
- GPU_link(
- mat, "direction_transform_m4v3", newnormal, GPU_builtin(GPU_OBJECT_MATRIX), &newnormal);
+ GPU_link(mat, "normal_transform_object_to_world", newnormal, &newnormal);
break;
case SHD_SPACE_WORLD:
case SHD_SPACE_BLENDER_WORLD:
@@ -102,8 +100,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
break;
}
- GPUNodeLink *oldnormal = GPU_builtin(GPU_WORLD_NORMAL);
- GPU_link(mat, "node_normal_map_mix", strength, newnormal, oldnormal, &out[0].link);
+ GPU_link(mat, "node_normal_map_mix", strength, newnormal, &out[0].link);
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.cc b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
index 03c1a018d37..8985ab6d0e9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
@@ -23,15 +23,8 @@ static int node_shader_gpu_object_info(GPUMaterial *mat,
{
Material *ma = GPU_material_get_material(mat);
float index = ma ? ma->index : 0.0f;
- return GPU_stack_link(mat,
- node,
- "node_object_info",
- in,
- out,
- GPU_builtin(GPU_OBJECT_MATRIX),
- GPU_builtin(GPU_OBJECT_COLOR),
- GPU_builtin(GPU_OBJECT_INFO),
- GPU_constant(&index));
+ GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO);
+ return GPU_stack_link(mat, node, "node_object_info", in, out, GPU_constant(&index));
}
} // namespace blender::nodes::node_shader_object_info_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.cc b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
index c0a116675ab..78dabc5c1c2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
@@ -35,12 +35,16 @@ static int node_shader_gpu_output_aov(GPUMaterial *mat,
{
GPUNodeLink *outlink;
NodeShaderOutputAOV *aov = (NodeShaderOutputAOV *)node->storage;
- /* Keep in sync with `renderpass_lib.glsl#render_pass_aov_hash` and
- * `EEVEE_renderpasses_aov_hash`. */
- unsigned int hash = BLI_hash_string(aov->name) << 1;
- GPU_stack_link(mat, node, "node_output_aov", in, out, &outlink);
- GPU_material_add_output_link_aov(mat, outlink, hash);
+ uint hash = BLI_hash_string(aov->name);
+ /* WORKAROUND: We don't support int/uint constants for now. So make sure the aliasing works.
+ * We cast back to uint in GLSL. */
+ BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint),
+ "GPUCodegen: AOV hash needs float and uint to be the same size.");
+ GPUNodeLink *hash_link = GPU_constant((float *)&hash);
+ GPU_material_flag_set(mat, GPU_MATFLAG_AOV);
+ GPU_stack_link(mat, node, "node_output_aov", in, out, hash_link, &outlink);
+ GPU_material_add_output_link_aov(mat, outlink, hash);
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.cc b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
index 3329ab7f8a0..54475d547da 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
@@ -12,39 +12,33 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Shader>(N_("Surface"));
b.add_input<decl::Shader>(N_("Volume"));
b.add_input<decl::Vector>(N_("Displacement")).hide_value();
+ b.add_input<decl::Float>(N_("Thickness")).hide_value();
}
static int node_shader_gpu_output_material(GPUMaterial *mat,
- bNode *node,
+ bNode *UNUSED(node),
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
- GPUNodeStack *out)
+ GPUNodeStack *UNUSED(out))
{
- GPUNodeLink *outlink, *alpha_threshold_link, *shadow_threshold_link;
- Material *ma = GPU_material_get_material(mat);
-
- static float no_alpha_threshold = -1.0f;
- if (ma) {
- alpha_threshold_link = GPU_uniform((ma->blend_method == MA_BM_CLIP) ? &ma->alpha_threshold :
- &no_alpha_threshold);
- shadow_threshold_link = GPU_uniform((ma->blend_shadow == MA_BS_CLIP) ? &ma->alpha_threshold :
- &no_alpha_threshold);
+ GPUNodeLink *outlink_surface, *outlink_volume, *outlink_displacement, *outlink_thickness;
+ /* Passthrough node in order to do the right socket conversions (important for displacement). */
+ if (in[0].link) {
+ GPU_link(mat, "node_output_material_surface", in[0].link, &outlink_surface);
+ GPU_material_output_surface(mat, outlink_surface);
}
- else {
- alpha_threshold_link = GPU_uniform(&no_alpha_threshold);
- shadow_threshold_link = GPU_uniform(&no_alpha_threshold);
+ if (in[1].link) {
+ GPU_link(mat, "node_output_material_volume", in[1].link, &outlink_volume);
+ GPU_material_output_volume(mat, outlink_volume);
+ }
+ if (in[2].link) {
+ GPU_link(mat, "node_output_material_displacement", in[2].link, &outlink_displacement);
+ GPU_material_output_displacement(mat, outlink_displacement);
+ }
+ if (in[3].link) {
+ GPU_link(mat, "node_output_material_thickness", in[3].link, &outlink_thickness);
+ GPU_material_output_thickness(mat, outlink_thickness);
}
-
- GPU_stack_link(mat,
- node,
- "node_output_material",
- in,
- out,
- alpha_threshold_link,
- shadow_threshold_link,
- &outlink);
- GPU_material_output_link(mat, outlink);
-
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.cc b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
index 77146876d9d..b0cf4c80bc5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
@@ -12,16 +12,20 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static int node_shader_gpu_output_world(GPUMaterial *mat,
- bNode *node,
+ bNode *UNUSED(node),
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
- GPUNodeStack *out)
+ GPUNodeStack *UNUSED(out))
{
- GPUNodeLink *outlink;
-
- GPU_stack_link(mat, node, "node_output_world", in, out, &outlink);
- GPU_material_output_link(mat, outlink);
-
+ GPUNodeLink *outlink_surface, *outlink_volume;
+ if (in[0].link) {
+ GPU_link(mat, "node_output_world_surface", in[0].link, &outlink_surface);
+ GPU_material_output_surface(mat, outlink_surface);
+ }
+ if (in[1].link) {
+ GPU_link(mat, "node_output_world_volume", in[1].link, &outlink_volume);
+ GPU_material_output_volume(mat, outlink_volume);
+ }
return true;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
index 66e859a8c69..71adbd5e5c4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
@@ -28,16 +28,9 @@ static int gpu_shader_particle_info(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
-
- return GPU_stack_link(mat,
- node,
- "particle_info",
- in,
- out,
- GPU_builtin(GPU_PARTICLE_SCALAR_PROPS),
- GPU_builtin(GPU_PARTICLE_LOCATION),
- GPU_builtin(GPU_PARTICLE_VELOCITY),
- GPU_builtin(GPU_PARTICLE_ANG_VELOCITY));
+ GPU_material_flag_set(mat, GPU_MATFLAG_OBJECT_INFO);
+ /* TODO(fclem) Pass particle data in obinfo. */
+ return GPU_stack_link(mat, node, "particle_info", in, out);
}
} // namespace blender::nodes::node_shader_particle_info_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
index 11dfa03ea40..0404158a803 100644
--- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
@@ -18,9 +18,7 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- /* Because node_shader_to_rgba is using fallback_cubemap()
- * we need to tag material as glossy. */
- GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
+ GPU_material_flag_set(mat, GPU_MATFLAG_SHADER_TO_RGBA);
return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
index 17173ef020a..e3ff4c28604 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
@@ -25,6 +25,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("BSSRDF"));
}
@@ -49,19 +50,16 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[5].link);
}
- if (node->sss_id > 0) {
- bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
- bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
- /* For some reason it seems that the socket value is in ARGB format. */
- GPU_material_sss_profile_create(mat, &socket_data->value[1]);
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
+ /* For some reason it seems that the socket value is in ARGB format. */
+ bool use_subsurf = GPU_material_sss_profile_create(mat, &socket_data->value[1]);
- /* sss_id is 0 only the node is not connected to any output.
- * In this case flagging the material would trigger a bug (see T68736). */
- GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS));
- }
+ float use_sss = (use_subsurf) ? 1.0f : 0.0f;
+
+ GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SUBSURFACE);
- return GPU_stack_link(
- mat, node, "node_subsurface_scattering", in, out, GPU_constant(&node->sss_id));
+ return GPU_stack_link(mat, node, "node_subsurface_scattering", in, out, GPU_uniform(&use_sss));
}
static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *node)
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.cc b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
index 25489632594..8e27ebed21b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
@@ -73,14 +73,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
GPU_link(mat, "tangent_orco_z", orco, &orco);
}
- return GPU_stack_link(mat,
- node,
- "node_tangent",
- in,
- out,
- GPU_builtin(GPU_WORLD_NORMAL),
- orco,
- GPU_builtin(GPU_OBJECT_MATRIX));
+ return GPU_stack_link(mat, node, "node_tangent", in, out, orco);
}
} // namespace blender::nodes::node_shader_tangent_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
index ac986787d65..ae683386bac 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
@@ -35,24 +35,18 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
{
Object *ob = (Object *)node->id;
- GPUNodeLink *inv_obmat = (ob != nullptr) ? GPU_uniform(&ob->imat[0][0]) :
- GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
+ /* Use special matrix to let the shader branch to using the render object's matrix. */
+ float dummy_matrix[4][4];
+ dummy_matrix[3][3] = 0.0f;
+ GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
+ GPU_uniform(&dummy_matrix[0][0]);
/* Opti: don't request orco if not needed. */
- const float default_coords[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(default_coords) :
- GPU_attribute(mat, CD_ORCO, "");
+ float4 zero(0.0f);
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(zero) : GPU_attribute(mat, CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, "");
- GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
- GPUNodeLink *worldnor = GPU_builtin(GPU_WORLD_NORMAL);
- GPUNodeLink *texcofacs = GPU_builtin(GPU_CAMERA_TEXCO_FACTORS);
- if (out[0].hasoutput) {
- GPU_link(mat, "generated_from_orco", orco, &orco);
- }
-
- GPU_stack_link(
- mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface);
+ GPU_stack_link(mat, node, "node_tex_coord", in, out, inv_obmat, orco, mtface);
int i;
LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
@@ -61,7 +55,7 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
* This is the case for interpolated, non linear functions.
* The resulting vector can still be a bit wrong but not as much.
* (see T70644) */
- if (node->branch_tag != 0 && ELEM(i, 1, 6)) {
+ if (ELEM(i, 1, 6)) {
GPU_link(mat,
"vector_math_normalize",
out[i].link,
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
index 41456091e1d..dbff092234b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
@@ -44,15 +44,13 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPUNodeLink *outalpha;
- if (!ima) {
+ /* HACK(fclem): For lookdev mode: do not compile an empty environment and just create an empty
+ * texture entry point. We manually bind to it after DRW_shgroup_add_material_resources(). */
+ if (!ima && !GPU_material_flag_get(mat, GPU_MATFLAG_LOOKDEV_HACK)) {
return GPU_stack_link(mat, node, "node_tex_environment_empty", in, out);
}
- if (!in[0].link) {
- GPU_link(mat, "node_tex_environment_texco", GPU_builtin(GPU_VIEW_POSITION), &in[0].link);
- node_shader_gpu_bump_tex_coord(mat, node, &in[0].link);
- }
-
+ node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
/* Compute texture coordinate. */
@@ -92,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
/* Sample texture with correct interpolation. */
GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha);
- if (out[0].hasoutput) {
+ if (out[0].hasoutput && ima) {
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
/* Don't let alpha affect color output in these cases. */
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index 19b5a50cd6b..d97f7d0375d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -88,13 +88,11 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
}
case SHD_PROJ_BOX: {
gpu_node_name = use_cubic ? "tex_box_sample_cubic" : "tex_box_sample_linear";
- GPUNodeLink *wnor, *col1, *col2, *col3;
- GPUNodeLink *vnor = GPU_builtin(GPU_WORLD_NORMAL);
- GPUNodeLink *ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
+ GPUNodeLink *vnor, *wnor, *col1, *col2, *col3;
GPUNodeLink *blend = GPU_uniform(&tex->projection_blend);
GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
- /* equivalent to normal_world_to_object */
- GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &wnor);
+ GPU_link(mat, "world_normals_get", &vnor);
+ GPU_link(mat, "normal_transform_world_to_object", vnor, &wnor);
GPU_link(mat, gpu_node_name, in[0].link, wnor, gpu_image, &col1, &col2, &col3);
GPU_link(mat, "tex_box_blend", wnor, col1, col2, col3, blend, &out[0].link, &out[1].link);
break;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
index 04cf0b72f32..9996e91177a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
@@ -24,23 +24,20 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- if (node->custom1 == SHD_SPACE_TANGENT) {
- return GPU_stack_link(mat,
- node,
- "node_vector_displacement_tangent",
- in,
- out,
- GPU_attribute(mat, CD_TANGENT, ""),
- GPU_builtin(GPU_WORLD_NORMAL),
- GPU_builtin(GPU_OBJECT_MATRIX),
- GPU_builtin(GPU_VIEW_MATRIX));
+ switch (node->custom1) {
+ case SHD_SPACE_TANGENT:
+ return GPU_stack_link(mat,
+ node,
+ "node_vector_displacement_tangent",
+ in,
+ out,
+ GPU_attribute(mat, CD_TANGENT, ""));
+ case SHD_SPACE_OBJECT:
+ return GPU_stack_link(mat, node, "node_vector_displacement_object", in, out);
+ case SHD_SPACE_WORLD:
+ default:
+ return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out);
}
- if (node->custom1 == SHD_SPACE_OBJECT) {
- return GPU_stack_link(
- mat, node, "node_vector_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX));
- }
-
- return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out);
}
} // namespace blender::nodes::node_shader_vector_displacement_cc
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
index d610e1309a7..de588f9005f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
@@ -43,7 +43,7 @@ static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = vect;
}
-static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
+static const char *get_gpufn_name_from_to(short from, short to, bool is_direction)
{
switch (from) {
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
@@ -51,9 +51,11 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return GPU_builtin(GPU_OBJECT_MATRIX);
+ return is_direction ? "direction_transform_object_to_world" :
+ "point_transform_object_to_world";
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return GPU_builtin(GPU_LOC_TO_VIEW_MATRIX);
+ return is_direction ? "direction_transform_object_to_view" :
+ "point_transform_object_to_view";
}
break;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
@@ -61,9 +63,11 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_WORLD:
return nullptr;
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return GPU_builtin(GPU_VIEW_MATRIX);
+ return is_direction ? "direction_transform_world_to_view" :
+ "point_transform_world_to_view";
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
+ return is_direction ? "direction_transform_world_to_object" :
+ "point_transform_world_to_object";
}
break;
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
@@ -71,14 +75,17 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return GPU_builtin(GPU_INVERSE_VIEW_MATRIX);
+ return is_direction ? "direction_transform_view_to_world" :
+ "point_transform_view_to_world";
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return GPU_builtin(GPU_INVERSE_LOC_TO_VIEW_MATRIX);
+ return is_direction ? "direction_transform_view_to_object" :
+ "point_transform_view_to_object";
}
break;
}
- return nullptr;
+ return NULL;
}
+
static int gpu_shader_vect_transform(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -86,11 +93,6 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
GPUNodeStack *out)
{
struct GPUNodeLink *inputlink;
- struct GPUNodeLink *fromto;
-
- const char *vtransform = "direction_transform_m4v3";
- const char *ptransform = "point_transform_m4v3";
- const char *func_name = nullptr;
NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
@@ -101,17 +103,20 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
inputlink = GPU_constant(in[0].vec);
}
- fromto = get_gpulink_matrix_from_to(nodeprop->convert_from, nodeprop->convert_to);
+ const bool is_direction = (nodeprop->type != SHD_VECT_TRANSFORM_TYPE_POINT);
+ const char *func_name = get_gpufn_name_from_to(
+ nodeprop->convert_from, nodeprop->convert_to, is_direction);
- func_name = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? ptransform : vtransform;
- if (fromto) {
+ if (func_name) {
/* For cycles we have inverted Z */
/* TODO: pass here the correct matrices */
if (nodeprop->convert_from == SHD_VECT_TRANSFORM_SPACE_CAMERA &&
nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
GPU_link(mat, "invert_z", inputlink, &inputlink);
}
- GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+
+ GPU_link(mat, func_name, inputlink, &out[0].link);
+
if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA &&
nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
GPU_link(mat, "invert_z", out[0].link, &out[0].link);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
index e0fef6b0d19..930fa6e5fb9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
@@ -9,6 +9,7 @@ static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("Volume"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index 980782f571c..d414b4b2ef7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -27,6 +27,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Color>(N_("Blackbody Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Float>(N_("Temperature")).default_value(1000.0f).min(0.0f).max(6500.0f);
b.add_input<decl::String>(N_("Temperature Attribute"));
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("Volume"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
index 6408efb769d..0c6859ad1fb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
@@ -14,6 +14,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.min(-1.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Weight")).unavailable();
b.add_output<decl::Shader>(N_("Volume"));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
index 1204c3a678f..6a1acda3353 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
@@ -28,17 +28,11 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
GPU_material_flag_set(mat, GPU_MATFLAG_BARYCENTRIC);
/* node->custom1 is use_pixel_size */
if (node->custom1) {
- return GPU_stack_link(
- mat, node, "node_wireframe_screenspace", in, out, GPU_builtin(GPU_BARYCENTRIC_TEXCO));
+ return GPU_stack_link(mat, node, "node_wireframe_screenspace", in, out);
+ }
+ else {
+ return GPU_stack_link(mat, node, "node_wireframe", in, out);
}
-
- return GPU_stack_link(mat,
- node,
- "node_wireframe",
- in,
- out,
- GPU_builtin(GPU_BARYCENTRIC_TEXCO),
- GPU_builtin(GPU_BARYCENTRIC_DIST));
}
} // namespace blender::nodes::node_shader_wireframe_cc