From 48b26d9c2e0f4f4b6b5b7279c5bfc40c3ec77a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Tue, 15 Feb 2022 17:51:19 +0100 Subject: Fix T95697: GPU subdivision ignores custom normals Similarly to the CPU subdivision, we interpolate custom loop normals from the coarse mesh, and this for the final normals. --- .../draw/intern/draw_cache_impl_subdivision.cc | 32 ++++++++++++++++-- source/blender/draw/intern/draw_subdivision.h | 5 +++ .../mesh_extractors/extract_mesh_vbo_pos_nor.cc | 39 ++++++++++++++++++++-- .../common_subdiv_normals_finalize_comp.glsl | 21 ++++++++++++ 4 files changed, 93 insertions(+), 4 deletions(-) diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index ea05ae799b0..e4c53604370 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -1355,8 +1355,9 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads); - /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ - GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. Put + * a barrier on the shader storage as we may use the result in another compute shader. */ + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY); /* Cleanup. */ GPU_shader_unbind(); @@ -1437,6 +1438,28 @@ void draw_subdiv_finalize_normals(const DRWSubdivCache *cache, GPU_shader_unbind(); } +void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache, + GPUVertBuf *src_custom_normals, + GPUVertBuf *pos_nor) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, "#define CUSTOM_NORMALS"); + GPU_shader_bind(shader); + + GPU_vertbuf_bind_as_ssbo(src_custom_normals, 0); + /* outputPosNor is bound at index 2 in the base shader. */ + GPU_vertbuf_bind_as_ssbo(pos_nor, 2); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. + * We also need it for subsequent compute shaders, so a barrier on the shader storage is also + * needed. */ + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, GPUIndexBuf *subdiv_tris, const int material_count) @@ -1828,6 +1851,11 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene, /* We can only evaluate limit normals if the patches are adaptive. */ draw_cache->do_limit_normals = settings.is_adaptive; + draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) && + (mesh_eval->flag & ME_AUTOSMOOTH) && + CustomData_has_layer(&mesh_eval->ldata, + CD_CUSTOMLOOPNORMAL); + if (DRW_ibo_requested(mbc->buff.ibo.tris)) { draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len); } diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h index 65e845c21a4..78313441a70 100644 --- a/source/blender/draw/intern/draw_subdivision.h +++ b/source/blender/draw/intern/draw_subdivision.h @@ -67,6 +67,7 @@ typedef struct DRWSubdivCache { struct Subdiv *subdiv; bool optimal_display; bool do_limit_normals; + bool use_custom_loop_normals; /* Coordinates used to evaluate patches for UVs, positions, and normals. */ struct GPUVertBuf *patch_coords; @@ -186,6 +187,10 @@ void draw_subdiv_finalize_normals(const DRWSubdivCache *cache, struct GPUVertBuf *subdiv_loop_subdiv_vert_index, struct GPUVertBuf *pos_nor); +void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache, + GPUVertBuf *src_custom_normals, + GPUVertBuf *pos_nor); + void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, struct GPUVertBuf *pos_nor, bool do_limit_normals); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc index c92cf554fda..ef88a34021e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -216,6 +216,16 @@ static GPUVertFormat *get_normals_format() return &format; } +static GPUVertFormat *get_custom_normals_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), @@ -223,7 +233,8 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, void *UNUSED(data)) { GPUVertBuf *vbo = static_cast(buffer); - const bool do_limit_normals = subdiv_cache->do_limit_normals; + const bool do_limit_normals = subdiv_cache->do_limit_normals && + !subdiv_cache->use_custom_loop_normals; /* Initialize the vertex buffer, it was already allocated. */ GPU_vertbuf_init_build_on_device( @@ -231,7 +242,31 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals); - if (!do_limit_normals) { + if (subdiv_cache->use_custom_loop_normals) { + Mesh *coarse_mesh = subdiv_cache->mesh; + float(*lnors)[3] = static_cast( + CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL)); + BLI_assert(lnors != NULL); + + GPUVertBuf *src_custom_normals = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(src_custom_normals, get_custom_normals_format()); + GPU_vertbuf_data_alloc(src_custom_normals, coarse_mesh->totloop); + + memcpy( + GPU_vertbuf_get_data(src_custom_normals), lnors, sizeof(float[3]) * coarse_mesh->totloop); + + GPUVertBuf *dst_custom_normals = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + dst_custom_normals, get_custom_normals_format(), subdiv_cache->num_subdiv_loops); + + draw_subdiv_interp_custom_data(subdiv_cache, src_custom_normals, dst_custom_normals, 3, 0); + + draw_subdiv_finalize_custom_normals(subdiv_cache, dst_custom_normals, vbo); + + GPU_vertbuf_discard(src_custom_normals); + GPU_vertbuf_discard(dst_custom_normals); + } + else if (!do_limit_normals) { /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */ GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer( subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops); diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl index 84cd65d4161..c2e0e752783 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl @@ -1,6 +1,18 @@ /* To be compile with common_subdiv_lib.glsl */ +#ifdef CUSTOM_NORMALS +struct CustomNormal { + float x; + float y; + float z; +}; + +layout(std430, binding = 0) readonly buffer inputNormals +{ + CustomNormal custom_normals[]; +}; +#else layout(std430, binding = 0) readonly buffer inputNormals { vec3 vertex_normals[]; @@ -10,6 +22,7 @@ layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap { uint vert_loop_map[]; }; +#endif layout(std430, binding = 2) buffer outputPosNor { @@ -26,9 +39,17 @@ void main() uint start_loop_index = quad_index * 4; +#ifdef CUSTOM_NORMALS + for (int i = 0; i < 4; i++) { + CustomNormal custom_normal = custom_normals[start_loop_index + i]; + vec3 nor = vec3(custom_normal.x, custom_normal.y, custom_normal.z); + set_vertex_nor(pos_nor[start_loop_index + i], normalize(nor)); + } +#else for (int i = 0; i < 4; i++) { uint subdiv_vert_index = vert_loop_map[start_loop_index + i]; vec3 nor = vertex_normals[subdiv_vert_index]; set_vertex_nor(pos_nor[start_loop_index + i], nor); } +#endif } -- cgit v1.2.3