Cycles: add "density", "flame" and "color" attributes for smoke domains.
[blender.git] / intern / cycles / blender / blender_mesh.cpp
index e42af60c27b5cf875a077c0370a6653cb1179c96..fb667d1ba2f9535d0fb34650b6bcad028eb4c708 100644 (file)
@@ -206,6 +206,40 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la
        }
 }
 
+/* Create Volume Attribute */
+
+static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std)
+{
+       BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+
+       if(!b_domain)
+               return;
+       
+       Attribute *attr = mesh->attributes.add(std);
+       VoxelAttribute *volume_data = attr->data_voxel();
+       bool is_float, is_linear;
+       bool animated = false;
+
+       volume_data->manager = image_manager;
+       volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
+               b_ob.ptr.data, animated, is_float, is_linear, INTERPOLATION_LINEAR);
+}
+
+static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh)
+{
+       /* for smoke volume rendering */
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT);
+       if(mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY))
+               create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY);
+}
+
 /* Create Mesh */
 
 static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
@@ -249,8 +283,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                bool smooth = f->use_smooth();
 
                if(n == 4) {
-                       if(len_squared(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) == 0.0f ||
-                               len_squared(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])) == 0.0f) {
+                       if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
+                               is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) {
                                mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
                                mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
                        }
@@ -348,9 +382,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                }
        }
 
-       /* create generated coordinates. todo: we should actually get the orco
-        * coordinates from modifiers, for now we use texspace loc/size which
-        * is available in the api. */
+       /* create generated coordinates from undeformed coordinates */
        if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
                Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
 
@@ -363,9 +395,22 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
                for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
                        generated[i++] = get_float3(v->undeformed_co())*size - loc;
        }
+
+       /* for volume objects, create a matrix to transform from object space to
+        * mesh texture space. this does not work with deformations but that can
+        * probably only be done well with a volume grid mapping of coordinates */
+       if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
+               Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
+               Transform *tfm = attr->data_transform();
+
+               float3 loc, size;
+               mesh_texture_space(b_mesh, loc, size);
+
+               *tfm = transform_translate(-loc)*transform_scale(size);
+       }
 }
 
-static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
+static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
 {
        /* create subd mesh */
        SubdMesh sdmesh;
@@ -386,21 +431,25 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con
 
                if(n == 4)
                        sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
-#if 0
                else
                        sdmesh.add_face(vi[0], vi[1], vi[2]);
-#endif
        }
 
        /* finalize subd mesh */
-       sdmesh.link_boundary();
+       sdmesh.finish();
+
+       /* parameters */
+       bool need_ptex = mesh->need_attribute(scene, ATTR_STD_PTEX_FACE_ID) ||
+                        mesh->need_attribute(scene, ATTR_STD_PTEX_UV);
 
-       /* subdivide */
-       DiagSplit dsplit;
-       dsplit.camera = NULL;
-       dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
+       SubdParams sdparams(mesh, used_shaders[0], true, need_ptex);
+       sdparams.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
+       //scene->camera->update();
+       //sdparams.camera = scene->camera;
 
-       sdmesh.tessellate(&dsplit, false, mesh, used_shaders[0], true);
+       /* tesselate */
+       DiagSplit dsplit(sdparams);
+       sdmesh.tessellate(&dsplit);
 }
 
 /* Sync */
@@ -434,6 +483,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        Mesh *mesh;
 
        if(!mesh_map.sync(&mesh, key)) {
+               
                /* if transform was applied to mesh, need full update */
                if(object_updated && mesh->transform_applied);
                /* test if shaders changed, these can be object level so mesh
@@ -466,7 +516,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        
        /* compares curve_keys rather than strands in order to handle quick hair
         * adjustsments in dynamic BVH - other methods could probably do this better*/
-       vector<Mesh::CurveKey> oldcurve_keys = mesh->curve_keys;
+       vector<float4> oldcurve_keys = mesh->curve_keys;
 
        mesh->clear();
        mesh->used_shaders = used_shaders;
@@ -482,13 +532,15 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
                if(b_mesh) {
                        if(render_layer.use_surfaces && !hide_tris) {
                                if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
-                                       create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
+                                       create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders);
                                else
                                        create_mesh(scene, mesh, b_mesh, used_shaders);
+
+                               create_mesh_volume_attributes(scene, b_ob, mesh);
                        }
 
                        if(render_layer.use_hair)
-                               sync_curves(mesh, b_mesh, b_ob, 0);
+                               sync_curves(mesh, b_mesh, b_ob, false);
 
                        /* free derived mesh */
                        b_data.meshes.remove(b_mesh);
@@ -520,7 +572,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        if(oldcurve_keys.size() != mesh->curve_keys.size())
                rebuild = true;
        else if(oldcurve_keys.size()) {
-               if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0)
+               if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(float4)*oldcurve_keys.size()) != 0)
                        rebuild = true;
        }
        
@@ -529,46 +581,119 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
        return mesh;
 }
 
-void BlenderSync::sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion)
+void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
 {
-       /* todo: displacement, subdivision */
-       size_t size = mesh->verts.size();
-
-       /* skip objects without deforming modifiers. this is not a totally reliable,
-        * would need a more extensive check to see which objects are animated */
-       if(!size || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
-               return;
-
        /* ensure we only sync instanced meshes once */
+       Mesh *mesh = object->mesh;
+
        if(mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
                return;
 
        mesh_motion_synced.insert(mesh);
 
+       /* for motion pass always compute, for motion blur it can be disabled */
+       int time_index = 0;
+
+       if(scene->need_motion() == Scene::MOTION_BLUR) {
+               if(!mesh->use_motion_blur)
+                       return;
+               
+               /* see if this mesh needs motion data at this time */
+               vector<float> object_times = object->motion_times();
+               bool found = false;
+
+               foreach(float object_time, object_times) {
+                       if(motion_time == object_time) {
+                               found = true;
+                               break;
+                       }
+                       else
+                               time_index++;
+               }
+
+               if(!found)
+                       return;
+       }
+       else {
+               if(motion_time == -1.0f)
+                       time_index = 0;
+               else if(motion_time == 1.0f)
+                       time_index = 1;
+               else
+                       return;
+       }
+
+       /* skip objects without deforming modifiers. this is not totally reliable,
+        * would need a more extensive check to see which objects are animated */
+       size_t numverts = mesh->verts.size();
+       size_t numkeys = mesh->curve_keys.size();
+
+       if((!numverts && !numkeys) || !ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview))
+               return;
+       
        /* get derived mesh */
        BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
 
-       if(b_mesh) {
-               BL::Mesh::vertices_iterator v;
-               AttributeStandard std = (motion == -1)? ATTR_STD_MOTION_PRE: ATTR_STD_MOTION_POST;
-               Attribute *attr_M = mesh->attributes.add(std);
-               float3 *M = attr_M->data_float3(), *cur_M;
-               size_t i = 0;
+       if(!b_mesh)
+               return;
+       
+       if(numverts) {
+               /* find attributes */
+               Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+               Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+               Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+               bool new_attribute = false;
+
+               /* add new attributes if they don't exist already */
+               if(!attr_mP) {
+                       attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+                       if(attr_N)
+                               attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
+
+                       new_attribute = true;
+               }
 
-               for(b_mesh.vertices.begin(v), cur_M = M; v != b_mesh.vertices.end() && i < size; ++v, cur_M++, i++)
-                       *cur_M = get_float3(v->co());
+               /* load vertex data from mesh */
+               float3 *mP = attr_mP->data_float3() + time_index*numverts;
+               float3 *mN = (attr_mN)? attr_mN->data_float3() + time_index*numverts: NULL;
 
-               /* if number of vertices changed, or if coordinates stayed the same, drop it */
-               if(i != size || memcmp(M, &mesh->verts[0], sizeof(float3)*size) == 0)
-                       mesh->attributes.remove(std);
+               BL::Mesh::vertices_iterator v;
+               int i = 0;
 
-               /* hair motion */
-               if(render_layer.use_hair)
-                       sync_curves(mesh, b_mesh, b_ob, motion);
+               for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) {
+                       mP[i] = get_float3(v->co());
+                       if(mN)
+                               mN[i] = get_float3(v->normal());
+               }
 
-               /* free derived mesh */
-               b_data.meshes.remove(b_mesh);
+               /* in case of new attribute, we verify if there really was any motion */
+               if(new_attribute) {
+                       if(i != numverts || memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) {
+                               /* no motion, remove attributes again */
+                               mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
+                               if(attr_mN)
+                                       mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
+                       }
+                       else if(time_index > 0) {
+                               /* motion, fill up previous steps that we might have skipped because
+                                * they had no motion, but we need them anyway now */
+                               float3 *P = &mesh->verts[0];
+                               float3 *N = (attr_N)? attr_N->data_float3(): NULL;
+
+                               for(int step = 0; step < time_index; step++) {
+                                       memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
+                                       memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
+                               }
+                       }
+               }
        }
+
+       /* hair motion */
+       if(numkeys)
+               sync_curves(mesh, b_mesh, b_ob, true, time_index);
+
+       /* free derived mesh */
+       b_data.meshes.remove(b_mesh);
 }
 
 CCL_NAMESPACE_END