diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-09-20 18:41:07 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-09-20 18:53:47 +0300 |
commit | 667add5fc5b743a324b508e3c5cedfde1df218c0 (patch) | |
tree | e3f3d9f7b4f46d0ce6e351959ba669f13382e650 /source/blender | |
parent | 5c20161f81c75a4139cb3c865955f53a9880f627 (diff) |
Eevee: Implement Wireframe Node
This implementation is a bit hacky but match cycles pretty close.
If pixel size is not enabled, it will use the geom shader to
compute distances between vertices. This will have a cost.
Implementation is a bit hacky in gpu_codegen to make the geom shader works
in an optional manner.
Diffstat (limited to 'source/blender')
6 files changed, 163 insertions, 10 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl index 3418ea2f4ad..142afa5705b 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -1,9 +1,9 @@ uniform mat4 ModelViewProjectionMatrix; -uniform mat4 ModelMatrix; uniform mat4 ModelViewMatrix; uniform mat3 WorldNormalMatrix; #ifndef ATTRIB +uniform mat4 ModelMatrix; uniform mat3 NormalMatrix; uniform mat4 ModelMatrixInverse; #endif diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 6b6479089f6..cfd24ae8d65 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -1,10 +1,10 @@ uniform mat4 ModelViewProjectionMatrix; #ifdef MESH_SHADER -uniform mat4 ModelMatrix; uniform mat4 ModelViewMatrix; uniform mat3 WorldNormalMatrix; # ifndef ATTRIB +uniform mat4 ModelMatrix; uniform mat3 NormalMatrix; # endif #endif diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index c8f66e33202..b724299935b 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -114,6 +114,7 @@ typedef enum GPUBuiltin { GPU_VOLUME_FLAME = (1 << 17), GPU_VOLUME_TEMPERATURE = (1 << 18), GPU_BARYCENTRIC_TEXCO = (1 << 19), + GPU_BARYCENTRIC_DIST = (1 << 20), } GPUBuiltin; typedef enum GPUMatType { diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 2b2bba435b8..2cc83294949 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -507,6 +507,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unftemperature"; else if (builtin == GPU_BARYCENTRIC_TEXCO) return "unfbarycentrictex"; + else if (builtin == GPU_BARYCENTRIC_DIST) + return "unfbarycentricdist"; else return ""; } @@ -715,6 +717,8 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final BLI_dynstr_append(ds, "viewmat"); else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) BLI_dynstr_append(ds, "camtexfac"); + else if (input->builtin == GPU_BARYCENTRIC_DIST) + BLI_dynstr_append(ds, "barycentricDist"); else if (input->builtin == GPU_BARYCENTRIC_TEXCO) BLI_dynstr_append(ds, "barytexco"); else if (input->builtin == GPU_OBJECT_MATRIX) @@ -774,6 +778,9 @@ static char *code_generate_fragment(GPUMaterial *material, ListBase *nodes, GPUO if (builtins & GPU_BARYCENTRIC_TEXCO) BLI_dynstr_append(ds, "\tin vec2 barycentricTexCo;\n"); + if (builtins & GPU_BARYCENTRIC_DIST) + BLI_dynstr_append(ds, "\tflat in vec3 barycentricDist;\n"); + BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); if (builtins & GPU_BARYCENTRIC_TEXCO) { @@ -903,6 +910,11 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u use_geom ? "g" : ""); } + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_appendf(ds, "out vec3 barycentricPosg;\n"); + } + + BLI_dynstr_append(ds, "\n"); BLI_dynstr_append( @@ -910,6 +922,7 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u "#define ATTRIB\n" "uniform mat3 NormalMatrix;\n" "uniform mat4 ModelMatrixInverse;\n" + "uniform mat4 ModelMatrix;\n" "vec3 srgb_to_linear_attrib(vec3 c) {\n" "\tc = max(c, vec3(0.0));\n" "\tvec3 c1 = c * (1.0 / 12.92);\n" @@ -947,6 +960,10 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u use_geom ? "g" : ""); } + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_appendf(ds, "\tbarycentricPosg = position;\n"); + } + for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { @@ -981,6 +998,10 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u use_geom ? "g" : ""); } + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_appendf(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n"); + } + for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { @@ -1020,7 +1041,27 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, "}\n"); - BLI_dynstr_append(ds, vert_code); + if (use_geom) { + /* XXX HACK: Eevee specific. */ + char *vert_new, *vert_new2; + vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong"); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong"); + MEM_freeN(vert_new2); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg"); + MEM_freeN(vert_new2); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg"); + MEM_freeN(vert_new2); + + BLI_dynstr_append(ds, vert_new); + + MEM_freeN(vert_new); + } + else { + BLI_dynstr_append(ds, vert_code); + } code = BLI_dynstr_get_cstring(ds); @@ -1043,10 +1084,9 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code) /* Create prototype because attributes cannot be declared before layout. */ BLI_dynstr_appendf(ds, "void pass_attrib(in int vert);\n"); + BLI_dynstr_appendf(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2);\n"); BLI_dynstr_append(ds, "#define ATTRIB\n"); - BLI_dynstr_append(ds, geom_code); - /* Generate varying declarations. */ for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { @@ -1068,14 +1108,91 @@ static char *code_generate_geometry(ListBase *nodes, const char *geom_code) if (builtins & GPU_BARYCENTRIC_TEXCO) { BLI_dynstr_appendf(ds, "in vec2 barycentricTexCog[];\n"); - BLI_dynstr_appendf(ds, "out vec2 barycentricTexCo[];\n"); + BLI_dynstr_appendf(ds, "out vec2 barycentricTexCo;\n"); + } + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_appendf(ds, "in vec3 barycentricPosg[];\n"); + BLI_dynstr_appendf(ds, "flat out vec3 barycentricDist;\n"); + } + + if (geom_code == NULL) { + if ((builtins & GPU_BARYCENTRIC_DIST) == 0) { + /* Early out */ + BLI_dynstr_free(ds); + return NULL; + } + else { + /* Force geom shader usage */ + /* TODO put in external file. */ + BLI_dynstr_appendf(ds, "layout(triangles) in;\n"); + BLI_dynstr_appendf(ds, "layout(triangle_strip, max_vertices=3) out;\n"); + + BLI_dynstr_appendf(ds, "in vec3 worldPositiong[];\n"); + BLI_dynstr_appendf(ds, "in vec3 viewPositiong[];\n"); + BLI_dynstr_appendf(ds, "in vec3 worldNormalg[];\n"); + BLI_dynstr_appendf(ds, "in vec3 viewNormalg[];\n"); + + BLI_dynstr_appendf(ds, "out vec3 worldPosition;\n"); + BLI_dynstr_appendf(ds, "out vec3 viewPosition;\n"); + BLI_dynstr_appendf(ds, "out vec3 worldNormal;\n"); + BLI_dynstr_appendf(ds, "out vec3 viewNormal;\n"); + + BLI_dynstr_appendf(ds, "void main(){\n"); + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_appendf(ds, "\tcalc_barycentric_distances(barycentricPosg[0], barycentricPosg[1], barycentricPosg[2]);\n"); + } + + BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[0].gl_Position;\n"); + BLI_dynstr_appendf(ds, "\tpass_attrib(0);\n"); + BLI_dynstr_appendf(ds, "\tEmitVertex();\n"); + + BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[1].gl_Position;\n"); + BLI_dynstr_appendf(ds, "\tpass_attrib(1);\n"); + BLI_dynstr_appendf(ds, "\tEmitVertex();\n"); + + BLI_dynstr_appendf(ds, "\tgl_Position = gl_in[2].gl_Position;\n"); + BLI_dynstr_appendf(ds, "\tpass_attrib(2);\n"); + BLI_dynstr_appendf(ds, "\tEmitVertex();\n"); + BLI_dynstr_appendf(ds, "};\n"); + } + } + else { + BLI_dynstr_append(ds, geom_code); + } + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_appendf(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2) {\n"); + BLI_dynstr_appendf(ds, "\tvec3 edge21 = pos2 - pos1;\n"); + BLI_dynstr_appendf(ds, "\tvec3 edge10 = pos1 - pos0;\n"); + BLI_dynstr_appendf(ds, "\tvec3 edge02 = pos0 - pos2;\n"); + BLI_dynstr_appendf(ds, "\tvec3 d21 = normalize(edge21);\n"); + BLI_dynstr_appendf(ds, "\tvec3 d10 = normalize(edge10);\n"); + BLI_dynstr_appendf(ds, "\tvec3 d02 = normalize(edge02);\n"); + + BLI_dynstr_appendf(ds, "\tfloat d = dot(d21, edge02);\n"); + BLI_dynstr_appendf(ds, "\tbarycentricDist.x = sqrt(dot(edge02, edge02) - d * d);\n"); + BLI_dynstr_appendf(ds, "\td = dot(d02, edge10);\n"); + BLI_dynstr_appendf(ds, "\tbarycentricDist.y = sqrt(dot(edge10, edge10) - d * d);\n"); + BLI_dynstr_appendf(ds, "\td = dot(d10, edge21);\n"); + BLI_dynstr_appendf(ds, "\tbarycentricDist.z = sqrt(dot(edge21, edge21) - d * d);\n"); + BLI_dynstr_append(ds, "}\n"); } /* Generate varying assignments. */ BLI_dynstr_appendf(ds, "void pass_attrib(in int vert) {\n"); + /* XXX HACK: Eevee specific. */ + if (geom_code == NULL) { + BLI_dynstr_appendf(ds, "\tworldPosition = worldPositiong[vert];\n"); + BLI_dynstr_appendf(ds, "\tviewPosition = viewPositiong[vert];\n"); + BLI_dynstr_appendf(ds, "\tworldNormal = worldNormalg[vert];\n"); + BLI_dynstr_appendf(ds, "\tviewNormal = viewNormalg[vert];\n"); + } + if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_appendf(ds, "\tbarycentricTexCo = barycentricTexCog;\n"); + BLI_dynstr_appendf(ds, "\tbarycentricTexCo = barycentricTexCog[vert];\n"); } for (node = nodes->first; node; node = node->next) { @@ -1710,8 +1827,8 @@ GPUPass *GPU_generate_pass( * continue generating the shader strings. */ char *tmp = BLI_strdupcat(frag_lib, glsl_material_library); - vertexcode = code_generate_vertex(nodes, vert_code, (geom_code != NULL)); - geometrycode = (geom_code) ? code_generate_geometry(nodes, geom_code) : NULL; + geometrycode = code_generate_geometry(nodes, geom_code); + vertexcode = code_generate_vertex(nodes, vert_code, (geometrycode != NULL)); fragmentcode = BLI_strdupcat(tmp, fragmentgen); MEM_freeN(fragmentgen); diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 84e4165ac00..8fa1828bd9c 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1,10 +1,10 @@ -uniform mat4 ModelMatrix; uniform mat4 ModelViewMatrix; uniform mat4 ModelViewMatrixInverse; uniform mat3 NormalMatrix; #ifndef ATTRIB +uniform mat4 ModelMatrix; uniform mat4 ModelMatrixInverse; #endif @@ -1423,6 +1423,29 @@ void node_emission(vec4 color, float strength, vec3 vN, out Closure result) #endif } +void node_wireframe(float size, vec2 barycentric, vec3 barycentric_dist, out float fac) +{ + vec3 barys = barycentric.xyy; + barys.z = 1.0 - barycentric.x - barycentric.y; + + size *= 0.5; + vec3 s = step(-size, -barys * barycentric_dist); + + fac = max(s.x, max(s.y, s.z)); +} + +void node_wireframe_screenspace(float size, vec2 barycentric, out float fac) +{ + vec3 barys = barycentric.xyy; + barys.z = 1.0 - barycentric.x - barycentric.y; + + size *= (1.0 / 3.0); + vec3 deltas = fwidth(barys); + vec3 s = step(-deltas * size, -barys); + + fac = max(s.x, max(s.y, s.z)); +} + /* background */ void background_transform_to_world(vec3 viewvec, out vec3 worldvec) diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.c index 11d889def31..3592f98d81d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c +++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.c @@ -38,6 +38,17 @@ static bNodeSocketTemplate sh_node_wireframe_out[] = { { -1, 0, "" } }; +static int node_shader_gpu_wireframe(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + /* node->custom1 is use_pixel_size */ + if (node->custom1) { + return GPU_stack_link(mat, node, "node_wireframe_screenspace", in, out, GPU_builtin(GPU_BARYCENTRIC_TEXCO)); + } + else { + return GPU_stack_link(mat, node, "node_wireframe", in, out, GPU_builtin(GPU_BARYCENTRIC_TEXCO), GPU_builtin(GPU_BARYCENTRIC_DIST)); + } +} + /* node type definition */ void register_node_type_sh_wireframe(void) { @@ -47,6 +58,7 @@ void register_node_type_sh_wireframe(void) node_type_socket_templates(&ntype, sh_node_wireframe_in, sh_node_wireframe_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, node_shader_gpu_wireframe); nodeRegisterType(&ntype); } |