Blender V2.61 - r43446

mesh_displace.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "device.h"
00020 
00021 #include "mesh.h"
00022 #include "scene.h"
00023 #include "shader.h"
00024 
00025 #include "util_foreach.h"
00026 #include "util_progress.h"
00027 
00028 CCL_NAMESPACE_BEGIN
00029 
00030 bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& progress)
00031 {
00032     /* verify if we have a displacement shader */
00033     bool has_displacement = false;
00034 
00035     if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
00036         foreach(uint sindex, mesh->used_shaders)
00037             if(scene->shaders[sindex]->has_displacement)
00038                 has_displacement = true;
00039     }
00040     
00041     if(!has_displacement)
00042         return false;
00043 
00044     /* setup input for device task */
00045     vector<bool> done(mesh->verts.size(), false);
00046     device_vector<uint4> d_input;
00047     uint4 *d_input_data = d_input.resize(mesh->verts.size());
00048     size_t d_input_offset = 0;
00049 
00050     for(size_t i = 0; i < mesh->triangles.size(); i++) {
00051         Mesh::Triangle t = mesh->triangles[i];
00052         Shader *shader = scene->shaders[mesh->shader[i]];
00053 
00054         if(!shader->has_displacement)
00055             continue;
00056 
00057         for(int j = 0; j < 3; j++) {
00058             if(done[t.v[j]])
00059                 continue;
00060 
00061             done[t.v[j]] = true;
00062 
00063             /* set up object, primitive and barycentric coordinates */
00064             /* when used, non-instanced convention: object = -object-1; */
00065             int object = ~0; /* todo */
00066             int prim = mesh->tri_offset + i;
00067             float u, v;
00068 
00069             if(j == 0) {
00070                 u = 1.0f;
00071                 v = 0.0f;
00072             }
00073             else if(j == 1) {
00074                 u = 0.0f;
00075                 v = 1.0f;
00076             }
00077             else {
00078                 u = 0.0f;
00079                 v = 0.0f;
00080             }
00081 
00082             /* back */
00083             uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v));
00084             d_input_data[d_input_offset++] = in;
00085         }
00086     }
00087 
00088     if(d_input_offset == 0)
00089         return false;
00090     
00091     /* run device task */
00092     device_vector<float3> d_output;
00093     d_output.resize(d_input.size());
00094 
00095     device->mem_alloc(d_input, MEM_READ_ONLY);
00096     device->mem_copy_to(d_input);
00097     device->mem_alloc(d_output, MEM_WRITE_ONLY);
00098 
00099     DeviceTask task(DeviceTask::SHADER);
00100     task.shader_input = d_input.device_pointer;
00101     task.shader_output = d_output.device_pointer;
00102     task.shader_eval_type = SHADER_EVAL_DISPLACE;
00103     task.shader_x = 0;
00104     task.shader_w = d_input.size();
00105 
00106     device->task_add(task);
00107     device->task_wait();
00108 
00109     device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float3));
00110     device->mem_free(d_input);
00111     device->mem_free(d_output);
00112 
00113     if(progress.get_cancel())
00114         return false;
00115 
00116     /* read result */
00117     done.clear();
00118     done.resize(mesh->verts.size(), false);
00119     int k = 0;
00120 
00121     float3 *offset = (float3*)d_output.data_pointer;
00122 
00123     for(size_t i = 0; i < mesh->triangles.size(); i++) {
00124         Mesh::Triangle t = mesh->triangles[i];
00125         Shader *shader = scene->shaders[mesh->shader[i]];
00126 
00127         if(!shader->has_displacement)
00128             continue;
00129 
00130         for(int j = 0; j < 3; j++) {
00131             if(!done[t.v[j]]) {
00132                 done[t.v[j]] = true;
00133                 mesh->verts[t.v[j]] += offset[k++];
00134             }
00135         }
00136     }
00137 
00138     /* for displacement method both, we only need to recompute the face
00139      * normals, as bump mapping in the shader will already alter the
00140      * vertex normal, so we start from the non-displaced vertex normals
00141      * to avoid applying the perturbation twice. */
00142     mesh->attributes.remove(Attribute::STD_FACE_NORMAL);
00143     mesh->add_face_normals();
00144 
00145     if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
00146         mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
00147         mesh->add_vertex_normals();
00148     }
00149 
00150     return true;
00151 }
00152 
00153 CCL_NAMESPACE_END
00154