Compare commits
73 Commits
temp-T9904
...
tmp-new-gp
Author | SHA1 | Date | |
---|---|---|---|
89b9ceaa2e | |||
0c0b59ecb8 | |||
5caa96a265 | |||
85235c0d4f | |||
c7cde8130d | |||
e1ed665e72 | |||
a794d08844 | |||
9c4ae4d6d3 | |||
03a3ca56a3 | |||
5435efdffb | |||
c8b749d316 | |||
d902a2063c | |||
72ad2f3497 | |||
3f87596b63 | |||
24d79e4897 | |||
144900ac2d | |||
1d0eaa7892 | |||
8acee6ab65 | |||
2036c6719a | |||
c0c2831350 | |||
422de5bf9d | |||
4a2495f974 | |||
b0975356de | |||
16412b8b17 | |||
0575785be2 | |||
a4fcf67667 | |||
e8da2ad3dd | |||
5ebdb485d3 | |||
7361e7c14b | |||
ce99226259 | |||
029916d602 | |||
9435666ebd | |||
6af5b66137 | |||
0ad19b6c60 | |||
5450537ef1 | |||
ba41c62aef | |||
50bc8fa12f | |||
231ba11086 | |||
ed63f5ac4c | |||
121023ad64 | |||
80e88724a9 | |||
f03f60f9ba | |||
7ac9e76c10 | |||
825e46dfb8 | |||
0c8db18d9b | |||
8145706fe0 | |||
63119a9ce4 | |||
4f4072b187 | |||
c61ff2ce11 | |||
815d9163eb | |||
761c7d2fac | |||
aa681372e1 | |||
932118f742 | |||
dd076971da | |||
5f305fa599 | |||
c6dc9c9c33 | |||
be2135cff7 | |||
cc267ab8cf | |||
24fa1bec70 | |||
16d90555d7 | |||
1f2b944114 | |||
57db023981 | |||
36488fed68 | |||
d7cbaa8de1 | |||
3c4e90a6cf | |||
88516cda45 | |||
5291db4e10 | |||
0d18d4c349 | |||
8cdbf0e3b9 | |||
d9f902321e | |||
9db82cc87f | |||
0d6b5c5485 | |||
e7d106c5fc |
@@ -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
Reference in New Issue
Block a user