Blender V5.0
extract_mesh_vbo_tan.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <climits>
10
11#include "BLI_string.h"
12
14
15#include "BKE_attribute.hh"
17#include "BKE_mesh.hh"
18#include "BKE_mesh_tangent.hh"
19
20#include "extract_mesh.hh"
21
22#include "draw_subdivision.hh"
23
24namespace blender::draw {
25
27 const MeshBatchCache &cache,
29 gpu::VertAttrType gpu_attr_type)
30{
32
33 const CustomData *cd_ldata = (mr.extract_type == MeshExtractType::BMesh) ? &mr.bm->ldata :
34 &mr.mesh->corner_data;
35 uint32_t tan_layers = cache.cd_used.tan;
36 bool use_orco_tan = cache.cd_used.tan_orco != 0;
37
38 /* FIXME(#91838): This is to avoid a crash when orco tangent was requested but there are valid
39 * uv layers. It would be better to fix the root cause. */
40 if (tan_layers == 0 && use_orco_tan &&
42 {
43 tan_layers = 1;
44 use_orco_tan = false;
45 }
46
47 if (use_orco_tan) {
48 Array<float4> tangents;
52 mr.edit_bmesh, mr.bm_face_normals, mr.bm_loop_normals, positions);
53 }
54 else {
55 Span<float3> orco;
56 Array<float3> orco_allocated;
57 if (const float3 *orco_ptr = static_cast<const float3 *>(
59 {
60 orco = Span(orco_ptr, mr.verts_num);
61 }
62 else {
63 orco_allocated = mr.vert_positions;
64 /* TODO: This is not thread-safe. Draw extraction should not modify the mesh. */
65 BKE_mesh_orco_verts_transform(const_cast<Mesh *>(mr.mesh), orco_allocated, false);
66 orco = orco_allocated;
67 }
69 mr.faces,
70 mr.corner_verts,
71 mr.mesh->corner_tris(),
72 mr.mesh->corner_tri_faces(),
73 mr.sharp_faces,
74 mr.mesh->vert_normals(),
75 mr.face_normals,
77 orco);
78 }
79
80 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
82 SNPRINTF(attr_name, "t%s", attr_safe_name);
83 GPU_vertformat_attr_add(format, attr_name, gpu_attr_type);
86
87 return {std::move(tangents)};
88 }
89
90 Vector<StringRef> uv_names;
91 for (int i = 0; i < MAX_MTFACE; i++) {
92 if (tan_layers & (1 << i)) {
93 char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
94 const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_PROP_FLOAT2, i);
95 GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
96 /* Tangent layer name. */
97 SNPRINTF(attr_name, "t%s", attr_safe_name);
98 GPU_vertformat_attr_add(format, attr_name, gpu_attr_type);
99 /* Active render layer name. */
100 if (i == CustomData_get_render_layer(cd_ldata, CD_PROP_FLOAT2)) {
102 }
103 /* Active display layer name. */
104 if (i == CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2)) {
106 }
107
108 uv_names.append(layer_name);
109 }
110 }
111
112 if (uv_names.is_empty()) {
113 GPU_vertformat_attr_add(format, "dummy", blender::gpu::VertAttrType::SFLOAT_32);
114 return {};
115 }
116
117 Array<Array<float4>> results;
120 mr.edit_bmesh, mr.bm_face_normals, mr.bm_loop_normals, uv_names);
121 }
122 else {
123 Array<VArraySpan<float2>> uv_maps(uv_names.size());
124 Array<Span<float2>> uv_map_spans(uv_names.size());
125 const bke::AttributeAccessor attributes = mr.mesh->attributes();
126 for (const int i : uv_names.index_range()) {
127 uv_maps[i] = *attributes.lookup<float2>(uv_names[i], bke::AttrDomain::Corner);
128 uv_map_spans[i] = uv_maps[i];
129 }
131 mr.faces,
132 mr.corner_verts,
133 mr.mesh->corner_tris(),
134 mr.mesh->corner_tri_faces(),
135 mr.sharp_faces,
136 mr.mesh->vert_normals(),
137 mr.face_normals,
139 uv_map_spans);
140 }
141
142 if (format->attr_len == 0) {
143 GPU_vertformat_attr_add(format, "dummy", blender::gpu::VertAttrType::SFLOAT_32);
144 }
145
146 return results;
147}
148
150 const MeshBatchCache &cache,
151 const bool use_hq)
152{
153 gpu::VertAttrType gpu_attr_type = use_hq ? gpu::VertAttrType::SNORM_16_16_16_16 :
154 gpu::VertAttrType::SNORM_10_10_10_2;
155
156 GPUVertFormat format = {0};
157 const Array<Array<float4>> tangents = extract_tan_init_common(mr, cache, &format, gpu_attr_type);
158
161
162 if (use_hq) {
163 MutableSpan tan_data = vbo->data<short4>();
164 int vbo_index = 0;
165 for (const int i : tangents.index_range()) {
166 const Span<float4> layer_data = tangents[i];
167 for (int corner = 0; corner < mr.corners_num; corner++) {
168 tan_data[vbo_index] = gpu::convert_normal<short4>(float3(layer_data[corner]));
169 tan_data[vbo_index].w = (layer_data[corner][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
170 vbo_index++;
171 }
172 }
173 BLI_assert(vbo_index == tan_data.size());
174 }
175 else {
176 MutableSpan tan_data = vbo->data<gpu::PackedNormal>();
177 int vbo_index = 0;
178 for (const int i : tangents.index_range()) {
179 const Span<float4> layer_data = tangents[i];
180 for (int corner = 0; corner < mr.corners_num; corner++) {
181 tan_data[vbo_index] = gpu::convert_normal<gpu::PackedNormal>(float3(layer_data[corner]));
182 tan_data[vbo_index].w = (layer_data[corner][3] > 0.0f) ? 1 : -2;
183 vbo_index++;
184 }
185 }
186 BLI_assert(vbo_index == tan_data.size());
187 }
188
189 return vbo;
190}
191
193{
195 "tan", gpu::VertAttrType::SFLOAT_32_32_32_32);
196 return format;
197}
198
200 const DRWSubdivCache &subdiv_cache,
201 const MeshBatchCache &cache)
202{
203 gpu::VertAttrType gpu_attr_type = gpu::VertAttrType::SFLOAT_32_32_32_32;
204 GPUVertFormat format = {0};
205 const Array<Array<float4>> tangents = extract_tan_init_common(mr, cache, &format, gpu_attr_type);
206
209
210 gpu::VertBuf *coarse_vbo = GPU_vertbuf_calloc();
211 /* Dynamic as we upload and interpolate layers one at a time. */
213 GPU_vertbuf_data_alloc(*coarse_vbo, mr.corners_num);
214
215 /* Index of the tangent layer in the compact buffer. Used layers are stored in a single buffer.
216 */
217 int pack_layer_index = 0;
218 for (const int i : tangents.index_range()) {
219 float4 *tan_data = coarse_vbo->data<float4>().data();
220 const Span<float4> values = tangents[i];
221 for (int corner = 0; corner < mr.corners_num; corner++) {
222 *tan_data = values[corner];
223 (*tan_data)[3] = (values[corner][3] > 0.0f) ? 1.0f : -1.0f;
224 tan_data++;
225 }
226
227 /* Ensure data is uploaded properly. */
228 GPU_vertbuf_tag_dirty(coarse_vbo);
229 /* Include stride in offset. */
230 const int dst_offset = int(subdiv_cache.num_subdiv_loops) * 4 * pack_layer_index++;
231 draw_subdiv_interp_custom_data(subdiv_cache, *coarse_vbo, *vbo, GPU_COMP_F32, 4, dst_offset);
232 }
233
234 GPU_vertbuf_discard(coarse_vbo);
235 return vbo;
236}
237
238} // namespace blender::draw
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
int CustomData_get_active_layer(const CustomData *data, eCustomDataType type)
int CustomData_get_render_layer(const CustomData *data, eCustomDataType type)
blender::Array< blender::float4 > BKE_editmesh_orco_tangents_calc(BMEditMesh *em, blender::Span< blender::float3 > face_normals, blender::Span< blender::float3 > corner_normals, blender::Span< blender::float3 > vert_orco)
blender::Array< blender::Array< blender::float4 > > BKE_editmesh_uv_tangents_calc(BMEditMesh *em, blender::Span< blender::float3 > face_normals, blender::Span< blender::float3 > corner_normals, blender::Span< blender::StringRef > uv_names)
void BKE_mesh_orco_verts_transform(Mesh *mesh, blender::MutableSpan< blender::float3 > orco, bool invert)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
@ CD_PROP_FLOAT2
#define MAX_MTFACE
blender::gpu::VertBuf * GPU_vertbuf_create_on_device(const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_tag_dirty(blender::gpu::VertBuf *verts)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_init_with_format_ex(blender::gpu::VertBuf &verts, const GPUVertFormat &format, GPUUsageType)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_USAGE_DYNAMIC
void GPU_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, blender::gpu::VertAttrType type)
void GPU_vertformat_safe_attr_name(blender::StringRef attr_name, char *r_safe_name, uint max_len)
static constexpr int GPU_MAX_SAFE_ATTR_NAME
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
@ GPU_COMP_F32
BMesh const char void * data
Array< float3 > BM_mesh_vert_coords_alloc(BMesh *bm)
AttributeSet attributes
IndexRange index_range() const
Definition BLI_array.hh:360
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T * data() const
Definition BLI_span.hh:539
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
GAttributeReader lookup(const StringRef attribute_id) const
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
format
Array< float4 > calc_orco_tangents(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int3 > corner_tris, Span< int > corner_tri_faces, Span< bool > sharp_faces, Span< float3 > vert_normals, Span< float3 > face_normals, Span< float3 > corner_normals, Span< float3 > vert_orco)
Array< Array< float4 > > calc_uv_tangents(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int3 > corner_tris, Span< int > corner_tri_faces, Span< bool > sharp_faces, Span< float3 > vert_normals, Span< float3 > face_normals, Span< float3 > corner_normals, Span< Span< float2 > > uv_maps)
gpu::VertBufPtr extract_tangents_subdiv(const MeshRenderData &mr, const DRWSubdivCache &subdiv_cache, const MeshBatchCache &cache)
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data, GPUVertCompType comp_type, int dimensions, int dst_offset)
gpu::VertBufPtr extract_tangents(const MeshRenderData &mr, const MeshBatchCache &cache, bool use_hq)
static Array< Array< float4 > > extract_tan_init_common(const MeshRenderData &mr, const MeshBatchCache &cache, GPUVertFormat *format, gpu::VertAttrType gpu_attr_type)
static const GPUVertFormat & get_coarse_tan_format()
GPUType convert_normal(const float3 &src)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
blender::VecBase< int16_t, 4 > short4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
CustomData ldata
CustomData corner_data
CustomData vert_data
VArraySpan< bool > sharp_faces
OffsetIndices< int > faces
i
Definition text_draw.cc:230