From e868b459bb8efc35012b2364762f3d25d96b8b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 27 Apr 2017 22:27:09 +0200 Subject: Eevee: World nodetree gpumaterial compatibility. - Unify GPUMaterial creation (world/mesh). - Support for multiple shader variations (not used for now). - Convert GPUInputs to DRWUniforms to be used with the draw manager. - Nodetree Update is not supported. The only way to refresh the shaders is to change render engine. - Cleanup in GPUPass. - Add new temporary Node Compatibility type. Compatibility types should be removed in the future. --- source/blender/blenkernel/BKE_node.h | 1 + source/blender/draw/engines/eevee/eevee_engine.c | 64 ++++++++--- .../engines/eevee/shaders/bsdf_common_lib.glsl | 4 +- .../draw/engines/eevee/shaders/default_frag.glsl | 4 +- .../engines/eevee/shaders/lit_surface_frag.glsl | 2 - .../draw/engines/eevee/shaders/probe_geom.glsl | 2 +- source/blender/draw/intern/DRW_render.h | 3 + source/blender/draw/intern/draw_manager.c | 76 +++++++++++++ source/blender/gpu/GPU_material.h | 6 +- source/blender/gpu/intern/gpu_codegen.c | 123 ++++++++++++++++++++- source/blender/gpu/intern/gpu_codegen.h | 6 +- source/blender/gpu/intern/gpu_material.c | 56 +++++++++- .../blender/gpu/shaders/gpu_shader_material.glsl | 11 +- source/blender/makesrna/intern/rna_world.c | 1 + .../shader/nodes/node_shader_tex_environment.c | 4 +- 15 files changed, 333 insertions(+), 30 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 01d93d98540..219bca0a1a9 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -253,6 +253,7 @@ typedef struct bNodeType { /* nodetype->compatibility */ #define NODE_OLD_SHADING 1 #define NODE_NEW_SHADING 2 +#define NODE_NEWER_SHADING 3 /* node resize directions */ #define NODE_RESIZE_TOP 1 diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 6fa99b37ced..5f7c7787cfc 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -29,6 +29,8 @@ #include "BLI_dynstr.h" #include "BLI_rand.h" + +#include "GPU_material.h" #include "GPU_glew.h" #include "eevee_engine.h" @@ -39,6 +41,8 @@ /* *********** STATIC *********** */ static struct { + char *frag_shader_lib; + struct GPUShader *default_lit; struct GPUShader *default_world; struct GPUShader *depth_sh; @@ -214,6 +218,16 @@ static void EEVEE_engine_init(void *ved) (int)viewport_size[0], (int)viewport_size[1], &tex, 1); + if (!e_data.frag_shader_lib) { + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl); + e_data.frag_shader_lib = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + } + if (!e_data.depth_sh) { e_data.depth_sh = DRW_shader_create_3D_depth_only(); } @@ -222,10 +236,7 @@ static void EEVEE_engine_init(void *ved) char *frag_str = NULL; DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ltc_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lit_surface_frag_glsl); + BLI_dynstr_append(ds_frag, e_data.frag_shader_lib); BLI_dynstr_append(ds_frag, datatoc_default_frag_glsl); frag_str = BLI_dynstr_get_cstring(ds_frag); BLI_dynstr_free(ds_frag); @@ -345,6 +356,8 @@ static DRWShadingGroup *eevee_cascade_shadow_shgroup( static void EEVEE_cache_init(void *vedata) { + static int zero = 0; + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; @@ -373,26 +386,48 @@ static void EEVEE_cache_init(void *vedata) psl->probe_background = DRW_pass_create("Probe Background Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR); struct Batch *geom = DRW_cache_fullscreen_quad_get(); - DRWShadingGroup *grp; + DRWShadingGroup *grp = NULL; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; World *wo = scene->world; - if (false) { /* TODO check for world nodetree */ - // GPUMaterial *gpumat = GPU_material_from_nodetree(struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options) + float *col = ts.colorBackground; + if (wo) { + col = &wo->horr; } - else { - float *col = ts.colorBackground; - static int zero = 0; - if (wo) { - col = &wo->horr; + if (wo && wo->use_nodes && wo->nodetree) { + struct GPUMaterial *gpumat = GPU_material_from_nodetree( + wo->nodetree, &wo->gpumaterial, &DRW_engine_viewport_eevee_type, 0, + datatoc_probe_vert_glsl, datatoc_probe_geom_glsl, e_data.frag_shader_lib, + "#define PROBE_CAPTURE\n" + "#define MAX_LIGHT 128\n" + "#define MAX_SHADOW_CUBE 42\n" + "#define MAX_SHADOW_MAP 64\n" + "#define MAX_SHADOW_CASCADE 8\n" + "#define MAX_CASCADE_NUM 4\n"); + + grp = DRW_shgroup_material_instance_create(gpumat, psl->probe_background, geom); + + if (grp) { + DRW_shgroup_uniform_int(grp, "Layer", &zero, 1); + + for (int i = 0; i < 6; ++i) + DRW_shgroup_call_dynamic_add_empty(grp); + } + else { + /* Shader failed : pink background */ + static float pink[3] = {1.0f, 0.0f, 1.0f}; + col = pink; } + } + /* Fallback if shader fails or if not using nodetree. */ + if (grp == NULL) { grp = eevee_cube_shgroup(e_data.default_world, psl->probe_background, geom); - DRW_shgroup_uniform_int(grp, "Layer", &zero, 1); DRW_shgroup_uniform_vec3(grp, "color", col, 1); + DRW_shgroup_uniform_int(grp, "Layer", &zero, 1); } } @@ -591,6 +626,7 @@ static void EEVEE_draw_scene(void *vedata) static void EEVEE_engine_free(void) { + MEM_SAFE_FREE(e_data.frag_shader_lib); DRW_SHADER_FREE_SAFE(e_data.default_lit); DRW_SHADER_FREE_SAFE(e_data.shadow_sh); DRW_SHADER_FREE_SAFE(e_data.default_world); @@ -628,7 +664,7 @@ DrawEngineType draw_engine_eevee_type = { RenderEngineType DRW_engine_viewport_eevee_type = { NULL, NULL, - EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_OGL_PIPELINE, + EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_OGL_PIPELINE | RE_USE_SHADING_NODES, NULL, NULL, NULL, NULL, NULL, NULL, &EEVEE_collection_settings_create, &draw_engine_eevee_type, {NULL, NULL, NULL} diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index fddc9c54cb2..ef8af646ec1 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -54,7 +54,7 @@ struct ShadowMapData { #define sh_map_bias near_far_bias.z #ifndef MAX_CASCADE_NUM -#define MAX_CASCADE_NUM 1 +#define MAX_CASCADE_NUM 4 #endif struct ShadowCascadeData { @@ -94,8 +94,6 @@ vec4 saturate(vec4 a) { return vec4(saturate(a.x), saturate(a.y), saturate(a.z), float distance_squared(vec2 a, vec2 b) { a -= b; return dot(a, a); } float distance_squared(vec3 a, vec3 b) { a -= b; return dot(a, a); } -float hypot(float x, float y) { return sqrt(x*x + y*y); } - float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); } float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal) diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl index 4cb229e392b..8d4a1e6d523 100644 --- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl @@ -3,9 +3,11 @@ uniform vec3 diffuse_col; uniform vec3 specular_col; uniform int hardness; +out vec4 FragColor; + void main() { float roughness = 1.0 - float(hardness) / 511.0; roughness *= roughness; - fragColor = vec4(eevee_surface_lit(worldNormal, diffuse_col, specular_col, roughness), 1.0); + FragColor = vec4(eevee_surface_lit(worldNormal, diffuse_col, specular_col, roughness), 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 7a0a7b8da91..10d9ce7c4c0 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -28,8 +28,6 @@ layout(std140) uniform shadow_block { in vec3 worldPosition; in vec3 worldNormal; -out vec4 fragColor; - /* type */ #define POINT 0.0 #define SUN 1.0 diff --git a/source/blender/draw/engines/eevee/shaders/probe_geom.glsl b/source/blender/draw/engines/eevee/shaders/probe_geom.glsl index ad112977e9f..5f79e1c6eb8 100644 --- a/source/blender/draw/engines/eevee/shaders/probe_geom.glsl +++ b/source/blender/draw/engines/eevee/shaders/probe_geom.glsl @@ -8,7 +8,7 @@ in vec4 vPos[]; in int face[]; out vec3 worldPosition; -out vec3 worldNormal; +out vec3 worldNormal; /* Required. otherwise generate linking error on AMD. */ const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3( 0.0, 0.0, 1.0), vec3( 0.0, 0.0, -1.0)); const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0), vec3( 0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3( 1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0)); diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 39b8e23db80..29295e8f06d 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -56,6 +56,7 @@ struct bContext; struct GPUFrameBuffer; struct GPUShader; +struct GPUMaterial; struct GPUTexture; struct GPUUniformBuffer; struct Object; @@ -245,6 +246,8 @@ typedef enum { } DRWState; DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); +DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass); +DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, struct Batch *geom); DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, struct Batch *geom); DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 97cd1102406..059ebc6eab3 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -47,11 +47,13 @@ #include "ED_space_api.h" #include "ED_screen.h" +#include "intern/gpu_codegen.h" #include "GPU_batch.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_lamp.h" +#include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" #include "GPU_uniformbuffer.h" @@ -614,6 +616,80 @@ DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) return shgroup; } +DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass) +{ + double time = 0.0; /* TODO make time variable */ + const int max_tex = GPU_max_textures() - 1; + + /* TODO : Ideally we should not convert. But since the whole codegen + * is relying on GPUPass we keep it as is for now. */ + + GPUPass *gpupass = GPU_material_get_pass(material); + + if (!gpupass) { + /* Shader compilation error */ + return NULL; + } + + struct GPUShader *shader = GPU_pass_shader(gpupass); + + DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + + /* Converting dynamic GPUInput to DRWUniform */ + ListBase *inputs = &gpupass->inputs; + + for (GPUInput *input = inputs->first; input; input = input->next) { + /* Textures */ + if (input->ima) { + GPUTexture *tex = GPU_texture_from_blender(input->ima, input->iuser, input->textarget, input->image_isdata, time, 1); + + if (input->bindtex) { + /* TODO maybe track texture slot usage to avoid clash with engine textures */ + DRW_shgroup_uniform_texture(grp, input->shadername, tex, max_tex - input->texid); + } + } + /* Floats */ + else { + switch (input->type) { + case 1: + DRW_shgroup_uniform_float(grp, input->shadername, (float *)input->dynamicvec, 1); + break; + case 2: + DRW_shgroup_uniform_vec2(grp, input->shadername, (float *)input->dynamicvec, 1); + break; + case 3: + DRW_shgroup_uniform_vec3(grp, input->shadername, (float *)input->dynamicvec, 1); + break; + case 4: + DRW_shgroup_uniform_vec4(grp, input->shadername, (float *)input->dynamicvec, 1); + break; + case 9: + DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec); + break; + case 16: + DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec); + break; + default: + break; + } + } + } + + return grp; +} + +DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, Batch *geom) +{ + DRWShadingGroup *shgroup = DRW_shgroup_material_create(material, pass); + + if (shgroup) { + shgroup->type = DRW_SHG_INSTANCE; + shgroup->instance_geom = geom; + } + + return shgroup; +} + DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, Batch *geom) { DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 7d08e72bb7b..31785a0121f 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -56,6 +56,7 @@ struct GPUTexture; struct GPULamp; struct PreviewImage; struct World; +struct bNodeTree; typedef struct GPUNode GPUNode; typedef struct GPUNodeLink GPUNodeLink; @@ -218,7 +219,9 @@ GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); /* High level functions to create and use GPU materials */ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo); - +GPUMaterial *GPU_material_from_nodetree( + struct bNodeTree *ntree, struct ListBase *gpumaterials, void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv); GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv); void GPU_material_free(struct ListBase *gpumaterial); @@ -235,6 +238,7 @@ void GPU_material_unbind(GPUMaterial *material); bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); GPUMatType GPU_Material_get_type(GPUMaterial *material); +struct GPUPass *GPU_material_get_pass(GPUMaterial *material); void GPU_material_vertex_attributes(GPUMaterial *material, struct GPUVertexAttribs *attrib); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index de2b94482f4..89c58eb8495 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -928,6 +928,67 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } +static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes) +{ + GPUShader *shader = pass->shader; + GPUNode *node; + GPUInput *next, *input; + ListBase *inputs = &pass->inputs; + int extract, z; + + memset(inputs, 0, sizeof(*inputs)); + + if (!shader) + return; + + GPU_shader_bind(shader); + + for (node = nodes->first; node; node = node->next) { + z = 0; + for (input = node->inputs.first; input; input = next, z++) { + next = input->next; + + /* attributes don't need to be bound, they already have + * an id that the drawing functions will use */ + if (input->source == GPU_SOURCE_ATTRIB) { + continue; + } + + if (input->source == GPU_SOURCE_BUILTIN || + input->source == GPU_SOURCE_OPENGL_BUILTIN) + { + continue; + } + + if (input->ima || input->tex || input->prv) + BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); + else + BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); + + /* pass non-dynamic uniforms to opengl */ + extract = 0; + + if (input->ima || input->tex || input->prv) { + if (input->bindtex) + extract = 1; + } + else if (input->dynamicvec) + extract = 1; + + if (extract) + input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); + + /* extract nodes */ + if (extract) { + BLI_remlink(&node->inputs, input); + BLI_addtail(inputs, input); + } + } + } + + GPU_shader_unbind(); +} + static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) { GPUShader *shader = pass->shader; @@ -1647,6 +1708,67 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } +GPUPass *GPU_generate_pass_new(ListBase *nodes, struct GPUNodeLink *frag_outlink, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines) +{ + GPUShader *shader; + GPUPass *pass; + char *vertexgen, *geometrygen, *fragmentgen, *tmp; + char *vertexcode, *geometrycode, *fragmentcode; + + /* prune unused nodes */ + gpu_nodes_prune(nodes, frag_outlink); + + /* generate code and compile with opengl */ + fragmentgen = code_generate_fragment(nodes, frag_outlink->output); + // vertexgen = code_generate_vertex(nodes, GPU_MATERIAL_TYPE_MESH); + // geometrygen = code_generate_geometry(nodes, false); + UNUSED_VARS(vertexgen, geometrygen); + + tmp = BLI_strdupcat(frag_lib, glsl_material_library); + fragmentcode = BLI_strdupcat(tmp, fragmentgen); + vertexcode = BLI_strdup(vert_code); + geometrycode = BLI_strdup(geom_code); + + shader = GPU_shader_create(vertexcode, + fragmentcode, + geometrycode, + NULL, + defines); + + MEM_freeN(tmp); + + /* failed? */ + if (!shader) { + if (fragmentcode) + MEM_freeN(fragmentcode); + if (vertexcode) + MEM_freeN(vertexcode); + if (geometrycode) + MEM_freeN(geometrycode); + MEM_freeN(fragmentgen); + gpu_nodes_free(nodes); + return NULL; + } + + /* create pass */ + pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = shader; + pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; + pass->vertexcode = vertexcode; + pass->libcode = glsl_material_library; + + /* extract dynamic inputs and throw away nodes */ + gpu_nodes_extract_dynamic_inputs_new(pass, nodes); + gpu_nodes_free(nodes); + + MEM_freeN(fragmentgen); + + return pass; +} + GPUPass *GPU_generate_pass( ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, @@ -1705,7 +1827,6 @@ GPUPass *GPU_generate_pass( /* create pass */ pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->output = outlink->output; pass->shader = shader; pass->fragmentcode = fragmentcode; pass->geometrycode = geometrycode; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 7af17f9122d..9263fe3bc3f 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -156,10 +156,7 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { - struct GPUPass *next, *prev; - ListBase inputs; - struct GPUOutput *output; struct GPUShader *shader; char *fragmentcode; char *geometrycode; @@ -170,6 +167,9 @@ struct GPUPass { typedef struct GPUPass GPUPass; +GPUPass *GPU_generate_pass_new(ListBase *nodes, struct GPUNodeLink *frag_outlink, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines); GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink, struct GPUVertexAttribs *attribs, int *builtin, const GPUMatType type, const char *name, diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index aa7a104ff86..083b0596b1c 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -94,12 +94,15 @@ static struct GPUWorld { } GPUWorld; struct GPUMaterial { - Scene *scene; + Scene *scene; /* DEPRECATED was only usefull for lamps */ Material *ma; /* material for mesh surface, worlds or something else. * some code generation is done differently depending on the use case */ - int type; + int type; /* DEPRECATED */ + + void *engine; /* attached engine type */ + int options; /* to identify shader variations (shadow, probe, world background...) */ /* for creating the material */ ListBase nodes; @@ -436,6 +439,10 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material) return material->type; } +GPUPass *GPU_material_get_pass(GPUMaterial *material) +{ + return material->pass; +} void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { @@ -470,6 +477,10 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node) bool GPU_material_do_color_management(GPUMaterial *mat) { + /* XXX mat->scene == NULL in that case */ + if (mat->engine) + return true; + if (!BKE_scene_check_color_management_enabled(mat->scene)) return false; @@ -2096,6 +2107,47 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) return mat; } +/* TODO : This is supposed to replace GPU_material_from_blender/_world in the future */ +GPUMaterial *GPU_material_from_nodetree( + struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat; + GPUNodeLink *outlink; + LinkData *link; + + for (link = gpumaterials->first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial *)link->data; + if (current_material->engine == engine_type && + current_material->options == options) + { + return current_material; + } + } + + /* allocate material */ + mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */ + mat->engine = engine_type; + mat->options = options; + + ntreeGPUMaterialNodes(ntree, mat, NODE_NEWER_SHADING); + + /* Let Draw manager finish the construction. */ + if (mat->outlink) { + outlink = mat->outlink; + mat->pass = GPU_generate_pass_new(&mat->nodes, outlink, vert_code, geom_code, frag_lib, defines); + } + + /* note that even if building the shader fails in some way, we still keep + * it to avoid trying to compile again and again, and simple do not use + * the actual shader on drawing */ + + link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + link->data = mat; + BLI_addtail(gpumaterials, link); + + return mat; +} GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) { diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 857db4f7f7c..a0c56e9ebf4 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1,6 +1,8 @@ uniform mat4 ModelViewMatrix; +#ifndef PROBE_CAPTURE uniform mat4 ProjectionMatrix; +#endif uniform mat4 ModelViewMatrixInverse; uniform mat4 ProjectionMatrixInverse; uniform mat3 NormalMatrix; @@ -172,7 +174,7 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal) } #define M_PI 3.14159265358979323846 -#define M_1_PI 0.31830988618379069 +#define M_1_PI 0.318309886183790671538 /*********** SHADER NODES ***************/ @@ -2813,6 +2815,13 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec) worldvec = (ModelViewMatrixInverse * co).xyz; } +#ifdef PROBE_CAPTURE +void environment_default_vector(out vec3 worldvec) +{ + worldvec = normalize(worldPosition); +} +#endif + void node_background(vec4 color, float strength, vec3 N, out vec4 result) { result = color * strength; diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index 7c1ef6b0d87..202ba63c850 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -119,6 +119,7 @@ static void rna_World_use_nodes_update(bContext *C, PointerRNA *ptr) ED_node_shader_default(C, &wrld->id); rna_World_update(CTX_data_main(C), CTX_data_scene(C), ptr); + rna_World_draw_update(CTX_data_main(C), CTX_data_scene(C), ptr); } #else diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 2f8f95b0675..e090f26ab6b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -69,8 +69,10 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE if (type == GPU_MATERIAL_TYPE_MESH) in[0].link = GPU_builtin(GPU_VIEW_POSITION); - else + else if (type == GPU_MATERIAL_TYPE_WORLD) GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link); + else + GPU_link(mat, "environment_default_vector", &in[0].link); } node_shader_gpu_tex_mapping(mat, node, in, out); -- cgit v1.2.3