Code refactor: move more memory allocation logic into device API.
[blender-staging.git] / intern / cycles / render / mesh_displace.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "device/device.h"
18
19 #include "render/mesh.h"
20 #include "render/object.h"
21 #include "render/scene.h"
22 #include "render/shader.h"
23
24 #include "util/util_foreach.h"
25 #include "util/util_progress.h"
26
27 CCL_NAMESPACE_BEGIN
28
29 static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
30 {
31         float3 v0 = verts[t.v[0]];
32         float3 v1 = verts[t.v[1]];
33         float3 v2 = verts[t.v[2]];
34
35         float3 norm = cross(v1 - v0, v2 - v0);
36         float normlen = len(norm);
37
38         if(normlen == 0.0f)
39                 return make_float3(1.0f, 0.0f, 0.0f);
40
41         return norm / normlen;
42 }
43
44 bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
45 {
46         /* verify if we have a displacement shader */
47         if(!mesh->has_true_displacement()) {
48                 return false;
49         }
50
51         string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
52         progress.set_status("Updating Mesh", msg);
53
54         /* find object index. todo: is arbitrary */
55         size_t object_index = OBJECT_NONE;
56
57         for(size_t i = 0; i < scene->objects.size(); i++) {
58                 if(scene->objects[i]->mesh == mesh) {
59                         object_index = i;
60                         break;
61                 }
62         }
63
64         /* setup input for device task */
65         const size_t num_verts = mesh->verts.size();
66         vector<bool> done(num_verts, false);
67         device_vector<uint4> d_input(device, "displace_input", MEM_READ_ONLY);
68         uint4 *d_input_data = d_input.alloc(num_verts);
69         size_t d_input_size = 0;
70
71         size_t num_triangles = mesh->num_triangles();
72         for(size_t i = 0; i < num_triangles; i++) {
73                 Mesh::Triangle t = mesh->get_triangle(i);
74                 int shader_index = mesh->shader[i];
75                 Shader *shader = (shader_index < mesh->used_shaders.size()) ?
76                         mesh->used_shaders[shader_index] : scene->default_surface;
77
78                 if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
79                         continue;
80                 }
81
82                 for(int j = 0; j < 3; j++) {
83                         if(done[t.v[j]])
84                                 continue;
85
86                         done[t.v[j]] = true;
87
88                         /* set up object, primitive and barycentric coordinates */
89                         int object = object_index;
90                         int prim = mesh->tri_offset + i;
91                         float u, v;
92                         
93                         switch(j) {
94                                 case 0:
95                                         u = 1.0f;
96                                         v = 0.0f;
97                                         break;
98                                 case 1:
99                                         u = 0.0f;
100                                         v = 1.0f;
101                                         break;
102                                 default:
103                                         u = 0.0f;
104                                         v = 0.0f;
105                                         break;
106                         }
107
108                         /* back */
109                         uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
110                         d_input_data[d_input_size++] = in;
111                 }
112         }
113
114         if(d_input_size == 0)
115                 return false;
116         
117         /* run device task */
118         device_vector<float4> d_output(device, "displace_output", MEM_WRITE_ONLY);
119         d_output.alloc(d_input_size);
120         d_output.zero_to_device();
121         d_input.copy_to_device();
122
123         /* needs to be up to data for attribute access */
124         device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
125
126         DeviceTask task(DeviceTask::SHADER);
127         task.shader_input = d_input.device_pointer;
128         task.shader_output = d_output.device_pointer;
129         task.shader_eval_type = SHADER_EVAL_DISPLACE;
130         task.shader_x = 0;
131         task.shader_w = d_output.size();
132         task.num_samples = 1;
133         task.get_cancel = function_bind(&Progress::get_cancel, &progress);
134
135         device->task_add(task);
136         device->task_wait();
137
138         if(progress.get_cancel()) {
139                 d_input.free();
140                 d_output.free();
141                 return false;
142         }
143
144         d_output.copy_from_device(0, 1, d_output.size());
145         d_input.free();
146
147         /* read result */
148         done.clear();
149         done.resize(num_verts, false);
150         int k = 0;
151
152         float4 *offset = (float4*)d_output.data_pointer;
153
154         Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
155         for(size_t i = 0; i < num_triangles; i++) {
156                 Mesh::Triangle t = mesh->get_triangle(i);
157                 int shader_index = mesh->shader[i];
158                 Shader *shader = (shader_index < mesh->used_shaders.size()) ?
159                         mesh->used_shaders[shader_index] : scene->default_surface;
160
161                 if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
162                         continue;
163                 }
164
165                 for(int j = 0; j < 3; j++) {
166                         if(!done[t.v[j]]) {
167                                 done[t.v[j]] = true;
168                                 float3 off = float4_to_float3(offset[k++]);
169                                 /* Avoid illegal vertex coordinates. */
170                                 off = ensure_finite3(off);
171                                 mesh->verts[t.v[j]] += off;
172                                 if(attr_mP != NULL) {
173                                         for(int step = 0; step < mesh->motion_steps - 1; step++) {
174                                                 float3 *mP = attr_mP->data_float3() + step*num_verts;
175                                                 mP[t.v[j]] += off;
176                                         }
177                                 }
178                         }
179                 }
180         }
181
182         d_output.free();
183
184         /* for displacement method both, we only need to recompute the face
185          * normals, as bump mapping in the shader will already alter the
186          * vertex normal, so we start from the non-displaced vertex normals
187          * to avoid applying the perturbation twice. */
188         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
189         mesh->add_face_normals();
190
191         bool need_recompute_vertex_normals = false;
192
193         foreach(Shader *shader, mesh->used_shaders) {
194                 if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) {
195                         need_recompute_vertex_normals = true;
196                         break;
197                 }
198         }
199
200         if(need_recompute_vertex_normals) {
201                 bool flip = mesh->transform_negative_scaled;
202                 vector<bool> tri_has_true_disp(num_triangles, false);
203
204                 for(size_t i = 0; i < num_triangles; i++) {
205                         int shader_index = mesh->shader[i];
206                         Shader *shader = (shader_index < mesh->used_shaders.size()) ?
207                                 mesh->used_shaders[shader_index] : scene->default_surface;
208
209                         tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE;
210                 }
211
212                 /* static vertex normals */
213
214                 /* get attributes */
215                 Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
216                 Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
217
218                 float3 *fN = attr_fN->data_float3();
219                 float3 *vN = attr_vN->data_float3();
220
221                 /* compute vertex normals */
222
223                 /* zero vertex normals on triangles with true displacement */
224                 for(size_t i = 0; i < num_triangles; i++) {
225                         if(tri_has_true_disp[i]) {
226                                 for(size_t j = 0; j < 3; j++) {
227                                         vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
228                                 }
229                         }
230                 }
231
232                 /* add face normals to vertex normals */
233                 for(size_t i = 0; i < num_triangles; i++) {
234                         if(tri_has_true_disp[i]) {
235                                 for(size_t j = 0; j < 3; j++) {
236                                         vN[mesh->get_triangle(i).v[j]] += fN[i];
237                                 }
238                         }
239                 }
240
241                 /* normalize vertex normals */
242                 done.clear();
243                 done.resize(num_verts, false);
244
245                 for(size_t i = 0; i < num_triangles; i++) {
246                         if(tri_has_true_disp[i]) {
247                                 for(size_t j = 0; j < 3; j++) {
248                                         int vert = mesh->get_triangle(i).v[j];
249
250                                         if(done[vert]) {
251                                                 continue;
252                                         }
253
254                                         vN[vert] = normalize(vN[vert]);
255                                         if(flip)
256                                                 vN[vert] = -vN[vert];
257
258                                         done[vert] = true;
259                                 }
260                         }
261                 }
262
263                 /* motion vertex normals */
264                 Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
265                 Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
266
267                 if(mesh->has_motion_blur() && attr_mP && attr_mN) {
268                         for(int step = 0; step < mesh->motion_steps - 1; step++) {
269                                 float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
270                                 float3 *mN = attr_mN->data_float3() + step*mesh->verts.size();
271
272                                 /* compute */
273
274                                 /* zero vertex normals on triangles with true displacement */
275                                 for(size_t i = 0; i < num_triangles; i++) {
276                                         if(tri_has_true_disp[i]) {
277                                                 for(size_t j = 0; j < 3; j++) {
278                                                         mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
279                                                 }
280                                         }
281                                 }
282
283                                 /* add face normals to vertex normals */
284                                 for(size_t i = 0; i < num_triangles; i++) {
285                                         if(tri_has_true_disp[i]) {
286                                                 for(size_t j = 0; j < 3; j++) {
287                                                         float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
288                                                         mN[mesh->get_triangle(i).v[j]] += fN;
289                                                 }
290                                         }
291                                 }
292
293                                 /* normalize vertex normals */
294                                 done.clear();
295                                 done.resize(num_verts, false);
296
297                                 for(size_t i = 0; i < num_triangles; i++) {
298                                         if(tri_has_true_disp[i]) {
299                                                 for(size_t j = 0; j < 3; j++) {
300                                                         int vert = mesh->get_triangle(i).v[j];
301
302                                                         if(done[vert]) {
303                                                                 continue;
304                                                         }
305
306                                                         mN[vert] = normalize(mN[vert]);
307                                                         if(flip)
308                                                                 mN[vert] = -mN[vert];
309
310                                                         done[vert] = true;
311                                                 }
312                                         }
313                                 }
314                         }
315                 }
316         }
317
318         return true;
319 }
320
321 CCL_NAMESPACE_END
322