Cycles Bake
[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.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(uint sindex, mesh->used_shaders)
36                         if(scene->shaders[sindex]->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         vector<bool> done(mesh->verts.size(), false);
58         device_vector<uint4> d_input;
59         uint4 *d_input_data = d_input.resize(mesh->verts.size());
60         size_t d_input_size = 0;
61
62         for(size_t i = 0; i < mesh->triangles.size(); i++) {
63                 Mesh::Triangle t = mesh->triangles[i];
64                 Shader *shader = scene->shaders[mesh->shader[i]];
65
66                 if(!shader->has_displacement)
67                         continue;
68
69                 for(int j = 0; j < 3; j++) {
70                         if(done[t.v[j]])
71                                 continue;
72
73                         done[t.v[j]] = true;
74
75                         /* set up object, primitive and barycentric coordinates */
76                         /* when used, non-instanced convention: object = ~object */
77                         int object = ~object_index;
78                         int prim = mesh->tri_offset + i;
79                         float u, v;
80                         
81                         switch (j) {
82                                 case 0:
83                                         u = 1.0f;
84                                         v = 0.0f;
85                                         break;
86                                 case 1:
87                                         u = 0.0f;
88                                         v = 1.0f;
89                                         break;
90                                 default:
91                                         u = 0.0f;
92                                         v = 0.0f;
93                                         break;
94                         }
95
96                         /* back */
97                         uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
98                         d_input_data[d_input_size++] = in;
99                 }
100         }
101
102         if(d_input_size == 0)
103                 return false;
104         
105         /* run device task */
106         device_vector<float4> d_output;
107         d_output.resize(d_input_size);
108
109         /* needs to be up to data for attribute access */
110         device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
111
112         device->mem_alloc(d_input, MEM_READ_ONLY);
113         device->mem_copy_to(d_input);
114         device->mem_alloc(d_output, MEM_WRITE_ONLY);
115
116         DeviceTask task(DeviceTask::SHADER);
117         task.shader_input = d_input.device_pointer;
118         task.shader_output = d_output.device_pointer;
119         task.shader_eval_type = SHADER_EVAL_DISPLACE;
120         task.shader_x = 0;
121         task.shader_w = d_output.size();
122         task.get_cancel = function_bind(&Progress::get_cancel, &progress);
123
124         device->task_add(task);
125         device->task_wait();
126
127         if(progress.get_cancel()) {
128                 device->mem_free(d_input);
129                 device->mem_free(d_output);
130                 return false;
131         }
132
133         device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float4));
134         device->mem_free(d_input);
135         device->mem_free(d_output);
136
137         /* read result */
138         done.clear();
139         done.resize(mesh->verts.size(), false);
140         int k = 0;
141
142         float4 *offset = (float4*)d_output.data_pointer;
143
144         for(size_t i = 0; i < mesh->triangles.size(); i++) {
145                 Mesh::Triangle t = mesh->triangles[i];
146                 Shader *shader = scene->shaders[mesh->shader[i]];
147
148                 if(!shader->has_displacement)
149                         continue;
150
151                 for(int j = 0; j < 3; j++) {
152                         if(!done[t.v[j]]) {
153                                 done[t.v[j]] = true;
154                                 float3 off = float4_to_float3(offset[k++]);
155                                 mesh->verts[t.v[j]] += off;
156                         }
157                 }
158         }
159
160         /* for displacement method both, we only need to recompute the face
161          * normals, as bump mapping in the shader will already alter the
162          * vertex normal, so we start from the non-displaced vertex normals
163          * to avoid applying the perturbation twice. */
164         mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
165         mesh->add_face_normals();
166
167         if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
168                 mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
169                 mesh->add_vertex_normals();
170         }
171
172         return true;
173 }
174
175 CCL_NAMESPACE_END
176