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.
This commit is contained in:
parent
66dc4d4efb
commit
80859a6cb2
Notes:
blender-bot
2025-02-14 01:31:17 +00:00
Referenced by commit 48d2f536e1
, Fix crash when loading Blender due to recent change
Referenced by issue #120791, EEVEE-Next: Subsurface Scattering breaks when passed through Shader to RGB
Referenced by issue #103903, Regression: Eevee render takes 3x longer in 3.4 than 3.1.2 - shading related?
Referenced by issue #102423, Regression: Screen Space Reflections on EEVEE render shaders with roughness a minimum regardless the value or map in the shader
Referenced by issue #101175, Eevee displacement behavior changed
Referenced by issue #100904, SSS effect disappears when Mix Shader Node includes Shader To RGB Node
Referenced by issue #100649, Regression: Environment texture is stretched when added to mesh
Referenced by issue #100377, 3.2 normalmap node broken in eevee
Referenced by issue #100278, EEVEE AOV blank if not attached or too distantly connected to material output node
Referenced by issue #100163, Regression: Eevee: Displacement maps affected by the object's rotation.
Referenced by issue #100166, Diffuse Light pass not working as expected in 3.2 Eevee with 'shader to RGB'
Referenced by issue #100125, shader to RGB node doesn't work correctly in blender3.2
Referenced by issue #99606, Regression: Texture Coordinate node still losing precision when camera moves away from origin of scene.
Referenced by issue #99138, Regression: Principled volume in world shader density with texture does not work anymore since 3.2 (Eevee)
Referenced by issue #99120, Regression: Crash due to high memory usage when compiling Eevee shaders on AMD GPUs
Referenced by issue #99104, Shader Light output of mesh object leads to crash with Eevee
Referenced by issue #99018, EEVEE: Regression: Specular BSDF apply specular color input twice
Referenced by issue #99019, EEVEE: Regression: Specular BSDF does not apply occlusion
Referenced by issue #98989, Regression: Eevee bad performance when using procedural bump map.
Referenced by issue #98940, Texture nodes CPU evaluation design
Referenced by issue #98919, Regression: AOV passes doesn´t work on eevee
Referenced by issue #98901, Procedural Textures Crashing Blender 3.2 - Eevee
Referenced by issue #98865, 3.2 eevee bad performance
Referenced by issue #98647, Blender 3.2.0 Camera Data Node's View Vector Broken in Eevee
Referenced by issue #98538, Geometry input node breaks after adding Displacement Texture in Shader Editor
Referenced by issue #98245, Regression: Missing viewport update when shader to RGB is used in nodegroup
Referenced by issue #98247, Regression: Shader To RGB not displaying textures
Referenced by issue #98251, Regression: Wrong normalmaps on scaled objects
Referenced by issue #98231, Regression: Material Output inside node group not working if there is a Group Output Node
Referenced by issue #98190, Render of 3D image is very slow
Referenced by issue #98128, Regression: EEVEE: Default Cube is black on Intel
Referenced by issue #98026, Regression: Crash when rendering with Eevee and Cryptomatte passes enabled
Referenced by issue #97983, Regression: Tangent Normal of Curves info behaves differently in Eevee
Referenced by issue #97916, Regression: Blending materials ( color attributes ) glitchy
Referenced by issue #97881, Regression: Specular highlights are missing in Glossy BSDF(Eevee).
Referenced by issue #97796, Regression: alpha clipped materials render fuzzy (exactly like alpha hashed materials)
Referenced by issue #97779, Regression: World volume noise stopped working
Referenced by issue #97617, Regression: Missing light on macOS in recent versions
Referenced by issue #88219, Regression: Massive drops in Animation playback (fps) in the viewport
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
static struct GPUMaterial *eevee_material_get_ex(
|
||||
struct Scene *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;
|
||||
|
||||
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);
|
||||
char *defines = eevee_get_defines(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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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 *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;
|
||||
|
||||
GPUMaterial *mat = NULL;
|
||||
GPUCodegenCallbackFn cbfn = &eevee_material_post_eval;
|
||||
|
||||
if (ma) {
|
||||
bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma);
|
||||
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_from_world(wo, ntree, options, is_volume, deferred, cbfn, NULL);
|
||||
}
|
||||
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);
|
||||
|
173
source/blender/draw/engines/eevee/eevee_shaders_extra.cc
Normal file
173
source/blender/draw/engines/eevee/eevee_shaders_extra.cc
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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)
|
@ -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)
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -30,8 +30,30 @@ void main()
|
||||
vPos.w = 1.0;
|
||||
|
||||
PASS_RESOURCE_ID
|
||||
|
||||
#ifdef USE_ATTR
|
||||
pass_attr(vec3(0.0), mat3(1), mat4(1));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
24
source/blender/draw/engines/eevee/shaders/world_vert.glsl
Normal file
24
source/blender/draw/engines/eevee/shaders/world_vert.glsl
Normal file
@ -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);
|
||||
}
|
@ -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 { \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
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 (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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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;
|
||||
|
21
source/blender/draw/intern/shaders/common_attribute_lib.glsl
Normal file
21
source/blender/draw/intern/shaders/common_attribute_lib.glsl
Normal file
@ -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);
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
825
source/blender/gpu/intern/gpu_codegen.cc
Normal file
825
source/blender/gpu/intern/gpu_codegen.cc
Normal file
@ -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();
|
||||
}
|
||||
|
||||
/** \} */
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
/** 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;
|
||||
|
||||
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 */
|
||||
/** 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
|
||||
# undef SSS_EXPONENT
|
||||
# undef SSS_SAMPLES
|
||||
#endif
|
||||
|
||||
ListBase GPU_material_attributes(GPUMaterial *material)
|
||||
void GPU_material_output_surface(GPUMaterial *material, GPUNodeLink *link)
|
||||
{
|
||||
return material->graph.attributes;
|
||||
if (!material->graph.outlink_surface) {
|
||||
material->graph.outlink_surface = link;
|
||||
material->has_surface_output = true;
|
||||
}
|
||||
}
|
||||
|
||||
ListBase GPU_material_textures(GPUMaterial *material)
|
||||
void GPU_material_output_volume(GPUMaterial *material, GPUNodeLink *link)
|
||||
{
|
||||
return material->graph.textures;
|
||||
if (!material->graph.outlink_volume) {
|
||||
material->graph.outlink_volume = link;
|
||||
material->has_volume_output = true;
|
||||
}
|
||||
}
|
||||
|
||||
ListBase GPU_material_volume_grids(GPUMaterial *material)
|
||||
void GPU_material_output_displacement(GPUMaterial *material, GPUNodeLink *link)
|
||||
{
|
||||
return material->graph.volume_grids;
|
||||
if (!material->graph.outlink_displacement) {
|
||||
material->graph.outlink_displacement = link;
|
||||
}
|
||||
}
|
||||
|
||||
GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
|
||||
void GPU_material_output_thickness(GPUMaterial *material, GPUNodeLink *link)
|
||||
{
|
||||
GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
|
||||
return attrs->count > 0 ? attrs : NULL;
|
||||
}
|
||||
|
||||
void GPU_material_output_link(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)
|
||||
{
|
||||
return material->used_libraries;
|
||||
}
|
||||
|
||||
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
|
||||
{
|
||||
return mat->status;
|
||||
}
|
||||
|
||||
void GPU_material_status_set(GPUMaterial *mat, eGPUMaterialStatus 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)
|
||||
{
|
||||
return mat->is_volume_shader;
|
||||
}
|
||||
|
||||
void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag)
|
||||
void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag)
|
||||
{
|
||||
mat->flag |= flag;
|
||||
}
|
||||
|
||||
bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag)
|
||||
bool GPU_material_flag_get(const GPUMaterial *mat, eGPUMaterialFlag flag)
|
||||
{
|
||||
return (mat->flag & flag) != 0;
|
||||
}
|
||||
|
||||
GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
|
||||
const void *engine_type,
|
||||
int options)
|
||||
eGPUMaterialFlag GPU_material_flag(const 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;
|
||||
}
|
||||
}
|
||||
return mat->flag;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
/* Note: Consumes the flags. */
|
||||
bool GPU_material_recalc_flag_get(GPUMaterial *mat)
|
||||
{
|
||||
bool updated = (mat->flag & GPU_MATFLAG_UPDATED) != 0;
|
||||
mat->flag &= ~GPU_MATFLAG_UPDATED;
|
||||
return updated;
|
||||
}
|
||||
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
/* Return 1 one error. */
|
||||
int init_dependencies(const GPUSourceDictionnary &dict)
|
||||
void material_functions_parse(GPUFunctionDictionnary *g_functions)
|
||||
{
|
||||
if (dependencies_init) {
|
||||
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,
|
||||
const GPUFunctionDictionnary &g_functions)
|
||||
{
|
||||
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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,28 +1,19 @@
|
||||
void dfdx_v3(vec3 v, out vec3 dy)
|
||||
|
||||
void differentiate_texco(vec3 v, out vec3 df)
|
||||
{
|
||||
dy = v + DFDX_SIGN * dFdx(v);
|
||||
/* Implementation defined. */
|
||||
df = v + dF_impl(v);
|
||||
}
|
||||
|
||||
void dfdy_v3(vec3 v, out vec3 dy)
|
||||
void node_bump(
|
||||
float strength, float dist, float height, vec3 N, vec2 dHd, float invert, out vec3 result)
|
||||
{
|
||||
dy = v + DFDY_SIGN * dFdy(v);
|
||||
}
|
||||
N = normalize(N);
|
||||
dist *= FrontFacing ? invert : -invert;
|
||||
|
||||
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)
|
||||
{
|
||||
N = mat3(ViewMatrix) * normalize(N);
|
||||
dist *= gl_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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
ClosureDiffuse diffuse_data;
|
||||
diffuse_data.weight = weight;
|
||||
diffuse_data.color = color.rgb;
|
||||
diffuse_data.N = N;
|
||||
diffuse_data.sss_id = 0u;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
N = safe_normalize(N);
|
||||
CN = safe_normalize(CN);
|
||||
vec3 V = cameraVec(g_data.P);
|
||||
|
||||
in_common.occlusion = occlusion;
|
||||
ClosureEmission emission_data;
|
||||
emission_data.weight = weight;
|
||||
emission_data.emission = emissive.rgb;
|
||||
|
||||
in_Diffuse_0.N = normal; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = diffuse.rgb;
|
||||
ClosureTransparency transparency_data;
|
||||
transparency_data.weight = weight;
|
||||
transparency_data.transmittance = vec3(transp);
|
||||
transparency_data.holdout = 0.0;
|
||||
|
||||
in_Glossy_1.N = normal; /* Normalized during eval. */
|
||||
in_Glossy_1.roughness = roughness;
|
||||
float alpha = (1.0 - transp) * weight;
|
||||
|
||||
in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */
|
||||
in_Glossy_2.roughness = clearcoat_roughness;
|
||||
ClosureDiffuse diffuse_data;
|
||||
diffuse_data.weight = alpha;
|
||||
diffuse_data.color = diffuse.rgb;
|
||||
diffuse_data.N = N;
|
||||
diffuse_data.sss_id = 0u;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
incoming = coordinate_incoming(g_data.P);
|
||||
position = g_data.P;
|
||||
normal = g_data.N;
|
||||
true_normal = g_data.Ng;
|
||||
|
||||
#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
|
||||
if (g_data.is_strand) {
|
||||
tangent = g_data.T;
|
||||
}
|
||||
else {
|
||||
tangent_orco_z(orco, orco);
|
||||
node_tangent(orco, tangent);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
# ifdef HAIR_SHADER
|
||||
tangent = -hairTangent;
|
||||
# else
|
||||
tangent_orco_z(orco, orco);
|
||||
node_tangent(N, orco, objmat, tangent);
|
||||
# endif
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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);
|
||||
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 = btdf_lut(NV, roughness, ior);
|
||||
|
||||
in_Refraction_1.N = N; /* Normalized during eval. */
|
||||
in_Refraction_1.roughness = roughness;
|
||||
in_Refraction_1.ior = ior;
|
||||
float fresnel = (do_multiscatter != 0.0) ? split_sum.y : F_eta(ior, NV);
|
||||
float btdf = (do_multiscatter != 0.0) ? 1.0 : split_sum.x;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction);
|
||||
ClosureReflection reflection_data;
|
||||
reflection_data.weight = fresnel * weight;
|
||||
reflection_data.color = color.rgb;
|
||||
reflection_data.N = N;
|
||||
reflection_data.roughness = roughness;
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
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;
|
||||
|
||||
float NV = dot(in_Refraction_1.N, cameraVec(worldPosition));
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
N = safe_normalize(N);
|
||||
vec3 V = cameraVec(g_data.P);
|
||||
float NV = dot(N, V);
|
||||
|
||||
CLOSURE_VARS_DECLARE_1(Glossy);
|
||||
vec2 split_sum = brdf_lut(NV, roughness);
|
||||
|
||||
in_Glossy_0.N = N; /* Normalized during eval. */
|
||||
in_Glossy_0.roughness = 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;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy);
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
N = safe_normalize(N);
|
||||
CN = safe_normalize(CN);
|
||||
vec3 V = cameraVec(g_data.P);
|
||||
float NV = dot(N, V);
|
||||
|
||||
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;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
vec3 V = cameraVec(worldPosition);
|
||||
|
||||
/* Glossy_1 will always be evaluated. */
|
||||
float NV = dot(in_Glossy_1.N, V);
|
||||
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;
|
||||
|
||||
vec3 base_color_tint = tint_from_color(base_color.rgb);
|
||||
|
||||
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);
|
||||
vec2 split_sum = brdf_lut(NV, roughness);
|
||||
|
||||
{
|
||||
/* 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);
|
||||
ClosureTransparency transparency_data;
|
||||
transparency_data.weight = weight;
|
||||
transparency_data.transmittance = vec3(1.0 - alpha);
|
||||
transparency_data.holdout = 0.0;
|
||||
|
||||
vec2 split_sum = brdf_lut(NV, roughness);
|
||||
weight *= alpha;
|
||||
|
||||
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;
|
||||
ClosureEmission emission_data;
|
||||
emission_data.weight = weight;
|
||||
emission_data.emission = emission.rgb * emission_strength;
|
||||
|
||||
/* 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);
|
||||
/* 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);
|
||||
|
||||
vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
/* 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;
|
||||
|
||||
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));
|
||||
/* 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 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
vec3 glass_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
|
||||
F_brdf_single_scatter(f0, f90, split_sum);
|
||||
|
||||
closure_load_ssr_data(
|
||||
glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result);
|
||||
/* Avoid 3 glossy evaluation. Use the same closure for glass reflection. */
|
||||
reflection_data.color += glass_brdf * glass_reflection_weight;
|
||||
}
|
||||
|
||||
if (diffuse_weight > 1e-5) {
|
||||
/* Mask over all diffuse radiance. */
|
||||
out_Diffuse_0.radiance *= diffuse_weight;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 (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;
|
||||
}
|
||||
|
||||
if (clearcoat > 1e-5) {
|
||||
float NV = dot(in_Glossy_2.N, V);
|
||||
vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness);
|
||||
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);
|
||||
|
||||
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;
|
||||
clearcoat_data.color = brdf;
|
||||
}
|
||||
|
||||
{
|
||||
vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb);
|
||||
out_emission_radiance *= emission_strength;
|
||||
result.radiance += out_emission_radiance;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
result.transmittance = vec3(1.0 - alpha);
|
||||
result.radiance *= alpha;
|
||||
result.ssr_data.rgb *= alpha;
|
||||
# ifdef USE_SSS
|
||||
result.sss_albedo *= alpha;
|
||||
# endif
|
||||
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;
|
||||
|
||||
if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat != 0.0) {
|
||||
/* Metallic & Clearcoat case. */
|
||||
result = closure_eval(reflection_data, clearcoat_data);
|
||||
}
|
||||
else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) {
|
||||
/* Metallic case. */
|
||||
result = closure_eval(reflection_data);
|
||||
}
|
||||
else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) {
|
||||
/* Dielectric case. */
|
||||
result = closure_eval(diffuse_data, reflection_data);
|
||||
}
|
||||
else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_clearcoat == 0.0) {
|
||||
/* Glass case. */
|
||||
result = closure_eval(reflection_data, refraction_data);
|
||||
}
|
||||
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
|
||||
|
@ -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);
|
||||
N = safe_normalize(N);
|
||||
|
||||
in_Refraction_0.N = N; /* Normalized during eval. */
|
||||
in_Refraction_0.roughness = roughness;
|
||||
in_Refraction_0.ior = ior;
|
||||
ClosureRefraction refraction_data;
|
||||
refraction_data.weight = weight;
|
||||
refraction_data.color = color.rgb;
|
||||
refraction_data.N = N;
|
||||
refraction_data.roughness = roughness;
|
||||
refraction_data.ior = ior;
|
||||
|
||||
CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
N = safe_normalize(N);
|
||||
|
||||
in_Diffuse_0.N = N; /* Normalized during eval. */
|
||||
in_Diffuse_0.albedo = color.rgb;
|
||||
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_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse);
|
||||
|
||||
result = CLOSURE_DEFAULT;
|
||||
|
||||
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
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user