95f46ff02a2b21ec80e51ca87f9af4ef525195e2
[blender.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.h"
18
19 #include "mesh.h"
20 #include "object.h"
21 #include "scene.h"
22 #include "shader.h"
23
24 #include "util_foreach.h"
25 #include "util_progress.h"
26
27 CCL_NAMESPACE_BEGIN
28
29 bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
30 {
31         /* verify if we have a displacement shader */
32         bool has_displacement = false;
33
34         if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
35                 foreach(Shader *shader, mesh->used_shaders)
36                         if(shader->has_displacement)
37                                 has_displacement = true;
38         }
39         
40         if(!has_displacement)
41                 return false;
42
43         string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
44         progress.set_status("Updating Mesh", msg);
45
46         /* find object index. todo: is arbitrary */
47         size_t object_index = OBJECT_NONE;
48
49         for(size_t i = 0; i < scene->objects.size(); i++) {
50                 if(scene->objects[i]->mesh == mesh) {
51                         object_index = i;
52                         break;
53                 }
54         }
55
56         /* setup input for device task */
57         const size_t num_verts = mesh->verts.size();
58         vector<bool> done(num_verts, false);
59         device_vector<uint4> d_input;
60         uint4 *d_input_data = d_input.resize(num_verts);
61         size_t d_input_size = 0;
62
63         size_t num_triangles = mesh->num_triangles();
64         for(size_t i = 0; i < num_triangles; i++) {
65                 Mesh::Triangle t = mesh->get_triangle(i);
66                 int shader_index = mesh->shader[i];
67                 Shader *shader = (shader_index < mesh->used_shaders.size()) ?
68                         mesh->used_shaders[shader_index] : scene->default_surface;
69
70                 if(!shader->has_displacement)
71                         continue;
72
73                 for(int j = 0; j < 3; j++) {
74                         if(done[t.v[j]])
75                                 continue;
76
77                         done[t.v[j]] = true;
78
79                         /* set up object, primitive and barycentric coordinates */
80                         /* when used, non-instanced convention: object = ~object */
81                         int object = ~object_index;
82                         int prim = mesh->tri_offset + i;
83                         float u, v;
84                         
85                         switch(j) {
86                                 case 0:
87                                         u = 1.0f;
88                                         v = 0.0f;
89                                         break;
90                                 case 1:
91                                         u = 0.0f;
92                                         v = 1.0f;
93                                         break;
94                                 default:
95                                         u = 0.0f;
96                                         v = 0.0f;
97                                         break;
98                         }
99
100                         /* back */
101                         uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
102                         d_input_data[d_input_size++] = in;
103                 }
104         }
105
106         if(d_input_size == 0)
107                 return false;
108         
109         /* run device task */
110         device_vector<float4> d_output;
111         d_output.resize(d_input_size);
112
113         /* needs to be up to data for attribute access */
114         device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
115
116         device->mem_alloc(d_input, MEM_READ_ONLY);
117         device->mem_copy_to(d_input);
118         device->mem_alloc(d_output, MEM_WRITE_ONLY);
119
120         DeviceTask task(DeviceTask::SHADER);
121         task.shader_input = d_input.device_pointer;
122         task.shader_output = d_output.device_pointer;
123         task.shader_eval_type = SHADER_EVAL_DISPLACE;
124         task.shader_x = 0;
125         task.shader_w = d_output.size();
126         task.num_samples = 1;
127         task.get_cancel = function_bind(&Progress::get_cancel, &progress);
128
129         device->task_add(task);
130         device->task_wait();
131
132         if(progress.get_cancel()) {
133                 device->mem_free(d_input);
134                 device->mem_free(d_output);
135                 return false;
136         }
137
138         device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
139         device->mem_free(d_input);
140         device->mem_free(d_output);
141
142         /* read result */
143         done.clear();
144         done.resize(num_verts, false);
145         int k = 0;
146
147         float4 *offset = (float4*)d_output.data_pointer;
148
149         Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
150         for(size_t i = 0; i < num_triangles; i++) {
151                 Mesh::Triangle t = mesh->get_triangle(i);
152                 int shader_index = mesh->shader[i];
153                 Shader *shader = (shader_index < mesh->used_shaders.size()) ?
154                         mesh->used_shaders[shader_index] : scene->default_surface;
155
156                 if(!shader->has_displacement)
157                         continue;
158
159                 for(int j = 0; j < 3; j++) {
160                         if(!done[t.v[j]]) {
161                                 done[t.v[j]] = true;
162                                 float3 off = float4_to_float3(offset[k++]);
163                                 mesh->verts[t.v[j]] += off;
164                                 if(attr_mP != NULL) {
165                                         for(int step = 0; step < mesh->motion_steps - 1; step++) {
166                                                 float3 *mP = attr_mP->data_float3() + step*num_verts;
167                                                 mP[t.v[j]] += off;
168                                         }
169                                 }
170                         }
171                 }
172         }
173
174         /* for displacement method both, we only need to recompute the face
175          * normals, as bump mapping in the shader will already alter the
176          * vertex normal, so we start from the non-displaced vertex normals
177          * to avoid applying the perturbation twice. */
178         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
179         mesh->add_face_normals();
180
181         if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
182                 mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
183                 mesh->add_vertex_normals();
184         }
185
186         return true;
187 }
188
189 CCL_NAMESPACE_END
190