diff options
author | Germano Cavalcante <germano.costa@ig.com.br> | 2021-10-27 00:16:33 +0300 |
---|---|---|
committer | Germano Cavalcante <germano.costa@ig.com.br> | 2021-10-27 00:23:59 +0300 |
commit | 3e3ff1a464b93c39cf31f30ef11b87e5b5786735 (patch) | |
tree | 4d988a153799280e7831d7ea69fabe411f3931c6 /source/blender/draw/intern/mesh_extractors | |
parent | 485c634c4cdadebfc293a4d9f6ffd1631f3ac959 (diff) |
Revert "Revert "Eevee: support accessing custom mesh attributes""
This reverts commit e7fedf6dba5fe2ec39260943361915a6b2b8270a.
And also fix a compilation issue on windows.
Differential Revision: https://developer.blender.org/D12969
Diffstat (limited to 'source/blender/draw/intern/mesh_extractors')
3 files changed, 401 insertions, 62 deletions
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h index d9f397fd8b8..d1ffef4fe92 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h @@ -328,6 +328,7 @@ extern const MeshExtract extract_poly_idx; extern const MeshExtract extract_edge_idx; extern const MeshExtract extract_vert_idx; extern const MeshExtract extract_fdot_idx; +extern const MeshExtract extract_attr[GPU_MAX_ATTR]; #ifdef __cplusplus } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc new file mode 100644 index 00000000000..f8cc92de1eb --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -0,0 +1,398 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include <functional> + +#include "BLI_float2.hh" +#include "BLI_float3.hh" +#include "BLI_float4.hh" +#include "BLI_string.h" + +#include "BKE_attribute.h" + +#include "extract_mesh.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Attributes + * \{ */ + +static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain) +{ + switch (domain) { + default: { + return nullptr; + } + case ATTR_DOMAIN_POINT: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; + } + case ATTR_DOMAIN_CORNER: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + } + case ATTR_DOMAIN_FACE: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata; + } + case ATTR_DOMAIN_EDGE: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata; + } + } +} + +/* Utility to convert from the type used in the attributes to the types for the VBO. + * This is mostly used to promote integers and booleans to floats, as other types (float, float2, + * etc.) directly map to avalaible GPU types. Booleans are still converted as attributes are vec4 + * in the shader. + */ +template<typename AttributeType, typename VBOType> struct attribute_type_converter { + static VBOType convert_value(AttributeType value) + { + if constexpr (std::is_same_v<AttributeType, VBOType>) { + return value; + } + + /* This should only concern bools which are converted to floats. */ + return static_cast<VBOType>(value); + } +}; + +/* Similar to the one in #extract_mesh_vcol_vbo.cc */ +struct gpuMeshCol { + ushort r, g, b, a; +}; + +template<> struct attribute_type_converter<MPropCol, gpuMeshCol> { + static gpuMeshCol convert_value(MPropCol value) + { + gpuMeshCol result; + result.r = unit_float_to_ushort_clamp(value.color[0]); + result.g = unit_float_to_ushort_clamp(value.color[1]); + result.b = unit_float_to_ushort_clamp(value.color[2]); + result.a = unit_float_to_ushort_clamp(value.color[3]); + return result; + } +}; + +/* Return the number of component for the attribute's value type, or 0 if is it unsupported. */ +static uint gpu_component_size_for_attribute_type(CustomDataType type) +{ + switch (type) { + case CD_PROP_BOOL: + case CD_PROP_INT32: + case CD_PROP_FLOAT: { + /* TODO(kevindietrich) : should be 1 when scalar attributes conversion is handled by us. See + * comment #extract_attr_init. */ + return 3; + } + case CD_PROP_FLOAT2: { + return 2; + } + case CD_PROP_FLOAT3: { + return 3; + } + case CD_PROP_COLOR: { + return 4; + } + default: { + return 0; + } + } +} + +static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type) +{ + switch (type) { + case CD_PROP_INT32: { + return GPU_FETCH_INT_TO_FLOAT; + } + case CD_PROP_COLOR: { + return GPU_FETCH_INT_TO_FLOAT_UNIT; + } + default: { + return GPU_FETCH_FLOAT; + } + } +} + +static GPUVertCompType get_comp_type_for_type(CustomDataType type) +{ + switch (type) { + case CD_PROP_INT32: { + return GPU_COMP_I32; + } + case CD_PROP_COLOR: { + return GPU_COMP_U16; + } + default: { + return GPU_COMP_F32; + } + } +} + +static void init_vbo_for_attribute(const MeshRenderData *mr, + GPUVertBuf *vbo, + const DRW_AttributeRequest &request) +{ + GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type); + GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type); + const uint comp_size = gpu_component_size_for_attribute_type(request.cd_type); + /* We should not be here if the attribute type is not supported. */ + BLI_assert(comp_size != 0); + + const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name( + custom_data, request.cd_type, request.layer_index); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + /* Attributes use auto-name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + + GPUVertFormat format = {0}; + GPU_vertformat_deinterleave(&format); + GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode); + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len)); +} + +template<typename AttributeType, typename VBOType> +static void fill_vertbuf_with_attribute(const MeshRenderData *mr, + VBOType *vbo_data, + const DRW_AttributeRequest &request) +{ + const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); + BLI_assert(custom_data); + const int layer_index = request.layer_index; + + const MPoly *mpoly = mr->mpoly; + const MLoop *mloop = mr->mloop; + + const AttributeType *attr_data = static_cast<AttributeType *>( + CustomData_get_layer_n(custom_data, request.cd_type, layer_index)); + + using converter = attribute_type_converter<AttributeType, VBOType>; + + switch (request.domain) { + default: { + BLI_assert(false); + break; + } + case ATTR_DOMAIN_POINT: { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) { + *vbo_data = converter::convert_value(attr_data[mloop->v]); + } + break; + } + case ATTR_DOMAIN_CORNER: { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) { + *vbo_data = converter::convert_value(attr_data[ml_index]); + } + break; + } + case ATTR_DOMAIN_EDGE: { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) { + *vbo_data = converter::convert_value(attr_data[mloop->e]); + } + break; + } + case ATTR_DOMAIN_FACE: { + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + const MPoly &poly = mpoly[mp_index]; + const VBOType value = converter::convert_value(attr_data[mp_index]); + for (int l = 0; l < poly.totloop; l++) { + *vbo_data++ = value; + } + } + break; + } + } +} + +template<typename AttributeType, typename VBOType> +static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr, + VBOType *&vbo_data, + const DRW_AttributeRequest &request) +{ + const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); + BLI_assert(custom_data); + const int layer_index = request.layer_index; + + int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index); + + using converter = attribute_type_converter<AttributeType, VBOType>; + + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const AttributeType *attr_data = nullptr; + if (request.domain == ATTR_DOMAIN_POINT) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs)); + } + else if (request.domain == ATTR_DOMAIN_CORNER) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs)); + } + else if (request.domain == ATTR_DOMAIN_FACE) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(efa, cd_ofs)); + } + else if (request.domain == ATTR_DOMAIN_EDGE) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs)); + } + else { + BLI_assert(false); + continue; + } + *vbo_data = converter::convert_value(*attr_data); + vbo_data++; + } while ((l_iter = l_iter->next) != l_first); + } +} + +template<typename AttributeType, typename VBOType = AttributeType> +static void extract_attr_generic(const MeshRenderData *mr, + GPUVertBuf *vbo, + const DRW_AttributeRequest &request) +{ + VBOType *vbo_data = static_cast<VBOType *>(GPU_vertbuf_get_data(vbo)); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + fill_vertbuf_with_attribute_bm<AttributeType>(mr, vbo_data, request); + } + else { + fill_vertbuf_with_attribute<AttributeType>(mr, vbo_data, request); + } +} + +static void extract_attr_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data), + int index) +{ + const DRW_MeshAttributes *attrs_used = &cache->attr_used; + const DRW_AttributeRequest &request = attrs_used->requests[index]; + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + + init_vbo_for_attribute(mr, vbo, request); + + /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by + * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the + * Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar + * texture as for volume attribute, so we can control the conversion ourselves. */ + switch (request.cd_type) { + case CD_PROP_BOOL: { + extract_attr_generic<bool, float3>(mr, vbo, request); + break; + } + case CD_PROP_INT32: { + extract_attr_generic<int32_t, float3>(mr, vbo, request); + break; + } + case CD_PROP_FLOAT: { + extract_attr_generic<float, float3>(mr, vbo, request); + break; + } + case CD_PROP_FLOAT2: { + extract_attr_generic<float2>(mr, vbo, request); + break; + } + case CD_PROP_FLOAT3: { + extract_attr_generic<float3>(mr, vbo, request); + break; + } + case CD_PROP_COLOR: { + extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request); + break; + } + default: { + BLI_assert(false); + } + } +} + +/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to + * extract. The overall API does not allow us to pass this in a convenient way. */ +#define EXTRACT_INIT_WRAPPER(index) \ + static void extract_attr_init##index( \ + const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \ + { \ + extract_attr_init(mr, cache, buf, tls_data, index); \ + } + +EXTRACT_INIT_WRAPPER(0) +EXTRACT_INIT_WRAPPER(1) +EXTRACT_INIT_WRAPPER(2) +EXTRACT_INIT_WRAPPER(3) +EXTRACT_INIT_WRAPPER(4) +EXTRACT_INIT_WRAPPER(5) +EXTRACT_INIT_WRAPPER(6) +EXTRACT_INIT_WRAPPER(7) +EXTRACT_INIT_WRAPPER(8) +EXTRACT_INIT_WRAPPER(9) +EXTRACT_INIT_WRAPPER(10) +EXTRACT_INIT_WRAPPER(11) +EXTRACT_INIT_WRAPPER(12) +EXTRACT_INIT_WRAPPER(13) +EXTRACT_INIT_WRAPPER(14) + +template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn) +{ + MeshExtract extractor = {nullptr}; + extractor.init = fn; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +#define CREATE_EXTRACTOR_ATTR(index) \ + blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index) + +const MeshExtract extract_attr[GPU_MAX_ATTR] = { + CREATE_EXTRACTOR_ATTR(0), + CREATE_EXTRACTOR_ATTR(1), + CREATE_EXTRACTOR_ATTR(2), + CREATE_EXTRACTOR_ATTR(3), + CREATE_EXTRACTOR_ATTR(4), + CREATE_EXTRACTOR_ATTR(5), + CREATE_EXTRACTOR_ATTR(6), + CREATE_EXTRACTOR_ATTR(7), + CREATE_EXTRACTOR_ATTR(8), + CREATE_EXTRACTOR_ATTR(9), + CREATE_EXTRACTOR_ATTR(10), + CREATE_EXTRACTOR_ATTR(11), + CREATE_EXTRACTOR_ATTR(12), + CREATE_EXTRACTOR_ATTR(13), + CREATE_EXTRACTOR_ATTR(14), +}; +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index 2c7770c8e72..f8878eb2617 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -43,9 +43,7 @@ static void extract_vcol_init(const MeshRenderData *mr, GPU_vertformat_deinterleave(&format); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; uint32_t vcol_layers = cache->cd_used.vcol; - uint32_t svcol_layers = cache->cd_used.sculpt_vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -64,42 +62,14 @@ static void extract_vcol_init(const MeshRenderData *mr, } /* Gather number of auto layers. */ - /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */ - if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 && - CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) { + /* We only do `vcols` that are not overridden by `uvs`. */ + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); GPU_vertformat_alias_add(&format, attr_name); } } } - /* Sculpt Vertex Colors */ - if (U.experimental.use_sculpt_vertex_colors) { - for (int i = 0; i < 8; i++) { - if (svcol_layers & (1 << i)) { - char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i); - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - - BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - - if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { - GPU_vertformat_alias_add(&format, "c"); - } - if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { - GPU_vertformat_alias_add(&format, "ac"); - } - /* Gather number of auto layers. */ - /* We only do `vcols` that are not overridden by `uvs`. */ - if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { - BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); - } - } - } - } - GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); @@ -108,7 +78,6 @@ static void extract_vcol_init(const MeshRenderData *mr, }; gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo); - MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP); for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -139,35 +108,6 @@ static void extract_vcol_init(const MeshRenderData *mr, } } } - - if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) { - if (mr->extract_type == MR_EXTRACT_BMESH) { - int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i); - BMIter f_iter; - BMFace *efa; - BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const MPropCol *prop_col = (const MPropCol *)BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs); - vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]); - vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]); - vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]); - vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]); - vcol_data++; - } while ((l_iter = l_iter->next) != l_first); - } - } - else { - MPropCol *vcol = (MPropCol *)CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) { - vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]); - vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]); - vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]); - vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]); - } - } - } } } |