Blender V5.0
mesh_displace.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "device/device.h"
6
8
9#include "scene/mesh.h"
10#include "scene/object.h"
11#include "scene/scene.h"
12#include "scene/shader.h"
13
14#include "util/progress.h"
15
17
18/* Fill in coordinates for mesh displacement shader evaluation on device. */
19static int fill_shader_input(const Scene *scene,
20 const Mesh *mesh,
21 const size_t object_index,
23{
24 int d_input_size = 0;
25 KernelShaderEvalInput *d_input_data = d_input.data();
26
27 const array<int> &mesh_shaders = mesh->get_shader();
28 const array<Node *> &mesh_used_shaders = mesh->get_used_shaders();
29 const array<float3> &mesh_verts = mesh->get_verts();
30
31 const int num_verts = mesh_verts.size();
32 vector<bool> done(num_verts, false);
33
34 const int num_triangles = mesh->num_triangles();
35 for (int i = 0; i < num_triangles; i++) {
36 const Mesh::Triangle t = mesh->get_triangle(i);
37 const int shader_index = mesh_shaders[i];
38 Shader *shader = (shader_index < mesh_used_shaders.size()) ?
39 static_cast<Shader *>(mesh_used_shaders[shader_index]) :
40 scene->default_surface;
41
42 if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
43 continue;
44 }
45
46 for (int j = 0; j < 3; j++) {
47 if (done[t.v[j]]) {
48 continue;
49 }
50
51 done[t.v[j]] = true;
52
53 /* set up object, primitive and barycentric coordinates */
54 const int object = object_index;
55 const int prim = mesh->prim_offset + i;
56 float u;
57 float v;
58
59 switch (j) {
60 case 0:
61 u = 0.0f;
62 v = 0.0f;
63 break;
64 case 1:
65 u = 1.0f;
66 v = 0.0f;
67 break;
68 default:
69 u = 0.0f;
70 v = 1.0f;
71 break;
72 }
73
74 /* back */
76 in.object = object;
77 in.prim = prim;
78 in.u = u;
79 in.v = v;
80 d_input_data[d_input_size++] = in;
81 }
82 }
83
84 return d_input_size;
85}
86
87/* Read back mesh displacement shader output. */
88static void read_shader_output(const Scene *scene,
89 Mesh *mesh,
90 const device_vector<float> &d_output)
91{
92 const array<int> &mesh_shaders = mesh->get_shader();
93 const array<Node *> &mesh_used_shaders = mesh->get_used_shaders();
94 const array<float3> &mesh_verts = mesh->get_verts();
95
96 const int num_verts = mesh_verts.size();
97 const int num_motion_steps = mesh->get_motion_steps();
98 vector<bool> done(num_verts, false);
99
100 const float *d_output_data = d_output.data();
101 int d_output_index = 0;
102
104 const int num_triangles = mesh->num_triangles();
105 for (int i = 0; i < num_triangles; i++) {
106 const Mesh::Triangle t = mesh->get_triangle(i);
107 const int shader_index = mesh_shaders[i];
108 Shader *shader = (shader_index < mesh_used_shaders.size()) ?
109 static_cast<Shader *>(mesh_used_shaders[shader_index]) :
110 scene->default_surface;
111
112 if (!shader->has_displacement || shader->get_displacement_method() == DISPLACE_BUMP) {
113 continue;
114 }
115
116 for (int j = 0; j < 3; j++) {
117 if (!done[t.v[j]]) {
118 done[t.v[j]] = true;
119 float3 off = make_float3(d_output_data[d_output_index + 0],
120 d_output_data[d_output_index + 1],
121 d_output_data[d_output_index + 2]);
122 d_output_index += 3;
123
124 /* Avoid illegal vertex coordinates. */
125 off = ensure_finite(off);
126 mesh_verts[t.v[j]] += off;
127 if (attr_mP != nullptr) {
128 for (int step = 0; step < num_motion_steps - 1; step++) {
129 float3 *mP = attr_mP->data_float3() + step * num_verts;
130 mP[t.v[j]] += off;
131 }
132 }
133 }
134 }
135 }
136}
137
138bool GeometryManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress)
139{
140 /* verify if we have a displacement shader */
141 if (!mesh->has_true_displacement()) {
142 return false;
143 }
144
145 /* Add undisplaced attributes right before doing displacement. */
146 mesh->add_undisplaced(scene);
147
148 const size_t num_verts = mesh->verts.size();
149 const size_t num_triangles = mesh->num_triangles();
150
151 if (num_triangles == 0) {
152 return false;
153 }
154
155 const string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
156 progress.set_status("Updating Mesh", msg);
157
158 /* find object index. todo: is arbitrary */
159 size_t object_index = OBJECT_NONE;
160
161 for (size_t i = 0; i < scene->objects.size(); i++) {
162 if (scene->objects[i]->get_geometry() == mesh) {
163 object_index = i;
164 break;
165 }
166 }
167
168 /* Evaluate shader on device. */
169 ShaderEval shader_eval(device, progress);
170 if (!shader_eval.eval(
172 num_verts,
173 3,
174 [scene, mesh, object_index](device_vector<KernelShaderEvalInput> &d_input) {
175 return fill_shader_input(scene, mesh, object_index, d_input);
176 },
177 [scene, mesh](const device_vector<float> &d_output) {
178 read_shader_output(scene, mesh, d_output);
179 }))
180 {
181 return false;
182 }
183
184 /* For displacement method both, we don't need to recompute the vertex normals
185 * as bump mapping in the shader will already alter the vertex normal, so we start
186 * from the non-displaced vertex normals to avoid applying the perturbation twice. */
187 bool need_recompute_vertex_normals = false;
188
189 for (Node *node : mesh->get_used_shaders()) {
190 Shader *shader = static_cast<Shader *>(node);
191 if (shader->has_displacement && shader->get_displacement_method() == DISPLACE_TRUE) {
192 need_recompute_vertex_normals = true;
193 break;
194 }
195 }
196
197 if (need_recompute_vertex_normals) {
198 const bool flip = mesh->transform_negative_scaled;
199 vector<bool> tri_has_true_disp(num_triangles, false);
200
201 for (size_t i = 0; i < num_triangles; i++) {
202 const int shader_index = mesh->shader[i];
203 Shader *shader = (shader_index < mesh->used_shaders.size()) ?
204 static_cast<Shader *>(mesh->used_shaders[shader_index]) :
205 scene->default_surface;
206
207 tri_has_true_disp[i] = shader->has_displacement &&
208 shader->get_displacement_method() == DISPLACE_TRUE;
209 }
210
211 /* static vertex normals */
212
213 /* get attributes */
215 float3 *vN = attr_vN->data_float3();
216
217 /* compute vertex normals */
218
219 /* zero vertex normals on triangles with true displacement */
220 for (size_t i = 0; i < num_triangles; i++) {
221 if (tri_has_true_disp[i]) {
222 const Mesh::Triangle triangle = mesh->get_triangle(i);
223 for (size_t j = 0; j < 3; j++) {
224 vN[triangle.v[j]] = zero_float3();
225 }
226 }
227 }
228
229 /* add face normals to vertex normals */
230 const float3 *verts_data = mesh->get_verts().data();
231 for (size_t i = 0; i < num_triangles; i++) {
232 if (tri_has_true_disp[i]) {
233 const Mesh::Triangle triangle = mesh->get_triangle(i);
234 const float3 fN = triangle.compute_normal(verts_data);
235
236 for (size_t j = 0; j < 3; j++) {
237 const int vert = triangle.v[j];
238 vN[vert] += fN;
239 }
240 }
241 }
242
243 /* normalize vertex normals */
244 vector<bool> done(num_verts, false);
245
246 for (size_t i = 0; i < num_triangles; i++) {
247 if (tri_has_true_disp[i]) {
248 const Mesh::Triangle triangle = mesh->get_triangle(i);
249 for (size_t j = 0; j < 3; j++) {
250 const int vert = triangle.v[j];
251
252 if (done[vert]) {
253 continue;
254 }
255
256 vN[vert] = normalize(vN[vert]);
257 if (flip) {
258 vN[vert] = -vN[vert];
259 }
260
261 done[vert] = true;
262 }
263 }
264 }
265
266 /* motion vertex normals */
269
270 if (mesh->has_motion_blur() && attr_mP && attr_mN) {
271 for (int step = 0; step < mesh->motion_steps - 1; step++) {
272 float3 *mP = attr_mP->data_float3() + step * mesh->verts.size();
273 float3 *mN = attr_mN->data_float3() + step * mesh->verts.size();
274
275 /* compute */
276
277 /* zero vertex normals on triangles with true displacement */
278 for (size_t i = 0; i < num_triangles; i++) {
279 if (tri_has_true_disp[i]) {
280 const Mesh::Triangle triangle = mesh->get_triangle(i);
281 for (size_t j = 0; j < 3; j++) {
282 mN[triangle.v[j]] = zero_float3();
283 }
284 }
285 }
286
287 /* add face normals to vertex normals */
288 for (size_t i = 0; i < num_triangles; i++) {
289 if (tri_has_true_disp[i]) {
290 const Mesh::Triangle triangle = mesh->get_triangle(i);
291 const float3 fN = triangle.compute_normal(mP);
292
293 for (size_t j = 0; j < 3; j++) {
294 const int vert = triangle.v[j];
295 mN[vert] += fN;
296 }
297 }
298 }
299
300 /* normalize vertex normals */
301 vector<bool> done(num_verts, false);
302
303 for (size_t i = 0; i < num_triangles; i++) {
304 if (tri_has_true_disp[i]) {
305 const Mesh::Triangle triangle = mesh->get_triangle(i);
306 for (size_t j = 0; j < 3; j++) {
307 const int vert = triangle.v[j];
308
309 if (done[vert]) {
310 continue;
311 }
312
313 mN[vert] = normalize(mN[vert]);
314 if (flip) {
315 mN[vert] = -mN[vert];
316 }
317
318 done[vert] = true;
319 }
320 }
321 }
322 }
323 }
324 }
325
326 mesh->update_tangents(scene, false);
327
328 return true;
329}
330
ATTR_WARN_UNUSED_RESULT const BMVert * v
Attribute * find(ustring name) const
bool displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress)
bool has_true_displacement() const
size_t prim_offset
AttributeSet attributes
bool transform_negative_scaled
void set_status(const string &status_, const string &substatus_="")
Definition progress.h:248
bool eval(const ShaderEvalType type, const int max_num_inputs, const int num_channels, const std::function< int(device_vector< KernelShaderEvalInput > &)> &fill_input, const std::function< void(device_vector< float > &)> &read_output)
bool has_displacement
size_t size() const
size_t size() const
#define OBJECT_NONE
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define in
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
@ ATTR_STD_MOTION_VERTEX_NORMAL
@ ATTR_STD_VERTEX_NORMAL
@ ATTR_STD_MOTION_VERTEX_POSITION
ccl_device_inline float ensure_finite(const float v)
Definition math_base.h:356
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:17
static void read_shader_output(const Scene *scene, Mesh *mesh, const device_vector< float > &d_output)
static CCL_NAMESPACE_BEGIN int fill_shader_input(const Scene *scene, const Mesh *mesh, const size_t object_index, device_vector< KernelShaderEvalInput > &d_input)
@ DISPLACE_BUMP
@ DISPLACE_TRUE
@ SHADER_EVAL_DISPLACE
Definition shader_eval.h:19
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition string.cpp:23
float3 * data_float3()
float3 compute_normal(const float3 *verts) const
void add_undisplaced(Scene *scene)
bool has_motion_blur() const override
size_t num_triangles() const
Definition scene/mesh.h:77
Triangle get_triangle(const size_t i) const
Definition scene/mesh.h:71
void update_tangents(Scene *scene, bool undisplaced)
ustring name
Definition graph/node.h:177
Shader * default_surface
Definition scene.h:157
unique_ptr_vector< Object > objects
Definition scene.h:141
i
Definition text_draw.cc:230