diff options
Diffstat (limited to 'source')
5 files changed, 95 insertions, 6 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index 7efd0de7a44..ac2e5bbca2e 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -1340,8 +1340,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(); @@ -1422,6 +1423,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) @@ -1813,6 +1836,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 394482c0862..6714ba571e5 100644 --- a/source/blender/draw/intern/draw_subdivision.h +++ b/source/blender/draw/intern/draw_subdivision.h @@ -52,6 +52,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; @@ -171,6 +172,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 6e2cb8ad3e3..bd7f1ba0128 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 @@ -200,6 +200,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), @@ -207,7 +217,8 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, void *UNUSED(data)) { GPUVertBuf *vbo = static_cast<GPUVertBuf *>(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( @@ -215,7 +226,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<float(*)[3]>( + 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_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl index 36c3970d9a0..df0016761e2 100644 --- a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl +++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl @@ -185,7 +185,7 @@ void main() } else { /* Interpolate the src data for the center. */ - uint loop_end = loop_start + number_of_vertices - 1; + uint loop_end = loop_start + number_of_vertices; Vertex center_value; clear(center_value); @@ -202,7 +202,7 @@ void main() uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) % number_of_vertices; - v0 = read_vertex(loop_start); + v0 = read_vertex(loop_start + current_coarse_corner); v1 = average(v0, read_vertex(loop_start + next_coarse_corner)); v3 = average(v0, read_vertex(loop_start + prev_coarse_corner)); 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 } |