Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/blender/blender_mesh.cpp
| Show First 20 Lines • Show All 341 Lines • ▼ Show 20 Lines | switch (element) { | ||||
| } | } | ||||
| default: { | default: { | ||||
| assert(false); | assert(false); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) | static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale) | ||||
| { | |||||
| if (!(b_attribute.domain() == BL::Attribute::domain_POINT) && | |||||
| (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) { | |||||
| return; | |||||
| } | |||||
| BL::FloatVectorAttribute b_vector_attribute(b_attribute); | |||||
| const int numverts = mesh->get_verts().size(); | |||||
| /* Find or add attribute */ | |||||
| float3 *P = &mesh->get_verts()[0]; | |||||
| Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); | |||||
| if (!attr_mP) { | |||||
| attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); | |||||
| } | |||||
| /* Only export previous and next frame, we don't have any in between data. */ | |||||
| float motion_times[2] = {-1.0f, 1.0f}; | |||||
| for (int step = 0; step < 2; step++) { | |||||
| const float relative_time = motion_times[step] * 0.5f * motion_scale; | |||||
| float3 *mP = attr_mP->data_float3() + step * numverts; | |||||
| for (int i = 0; i < numverts; i++) { | |||||
| mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void attr_create_generic(Scene *scene, | |||||
| Mesh *mesh, | |||||
| BL::Mesh &b_mesh, | |||||
| const bool subdivision, | |||||
| const bool need_motion, | |||||
| const float motion_scale) | |||||
| { | { | ||||
| if (subdivision) { | if (subdivision) { | ||||
| /* TODO: Handle subdivision correctly. */ | /* TODO: Handle subdivision correctly. */ | ||||
| return; | return; | ||||
| } | } | ||||
| AttributeSet &attributes = mesh->attributes; | AttributeSet &attributes = mesh->attributes; | ||||
| static const ustring u_velocity("velocity"); | |||||
| for (BL::Attribute &b_attribute : b_mesh.attributes) { | for (BL::Attribute &b_attribute : b_mesh.attributes) { | ||||
| const ustring name{b_attribute.name().c_str()}; | const ustring name{b_attribute.name().c_str()}; | ||||
| if (need_motion && name == u_velocity) { | |||||
| attr_create_motion(mesh, b_attribute, motion_scale); | |||||
| } | |||||
| if (!mesh->need_attribute(scene, name)) { | if (!mesh->need_attribute(scene, name)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (attributes.find(name)) { | if (attributes.find(name)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| const BL::Attribute::domain_enum b_domain = b_attribute.domain(); | const BL::Attribute::domain_enum b_domain = b_attribute.domain(); | ||||
| ▲ Show 20 Lines • Show All 486 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* Create Mesh */ | /* Create Mesh */ | ||||
| static void create_mesh(Scene *scene, | static void create_mesh(Scene *scene, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| BL::Mesh &b_mesh, | BL::Mesh &b_mesh, | ||||
| const array<Node *> &used_shaders, | const array<Node *> &used_shaders, | ||||
| bool subdivision = false, | const bool need_motion, | ||||
| bool subdivide_uvs = true) | const float motion_scale, | ||||
| const bool subdivision = false, | |||||
| const bool subdivide_uvs = true) | |||||
| { | { | ||||
| /* count vertices and faces */ | /* count vertices and faces */ | ||||
| int numverts = b_mesh.vertices.length(); | int numverts = b_mesh.vertices.length(); | ||||
| int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); | int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); | ||||
| int numtris = 0; | int numtris = 0; | ||||
| int numcorners = 0; | int numcorners = 0; | ||||
| int numngons = 0; | int numngons = 0; | ||||
| bool use_loop_normals = b_mesh.use_auto_smooth() && | bool use_loop_normals = b_mesh.use_auto_smooth() && | ||||
| ▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | static void create_mesh(Scene *scene, | ||||
| /* Create all needed attributes. | /* Create all needed attributes. | ||||
| * The calculate functions will check whether they're needed or not. | * The calculate functions will check whether they're needed or not. | ||||
| */ | */ | ||||
| attr_create_pointiness(scene, mesh, b_mesh, subdivision); | attr_create_pointiness(scene, mesh, b_mesh, subdivision); | ||||
| attr_create_vertex_color(scene, mesh, b_mesh, subdivision); | attr_create_vertex_color(scene, mesh, b_mesh, subdivision); | ||||
| attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision); | attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision); | ||||
| attr_create_random_per_island(scene, mesh, b_mesh, subdivision); | attr_create_random_per_island(scene, mesh, b_mesh, subdivision); | ||||
| attr_create_generic(scene, mesh, b_mesh, subdivision); | attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale); | ||||
| if (subdivision) { | if (subdivision) { | ||||
| attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); | attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); | ||||
| } | } | ||||
| else { | else { | ||||
| attr_create_uv_map(scene, mesh, b_mesh); | attr_create_uv_map(scene, mesh, b_mesh); | ||||
| } | } | ||||
| Show All 11 Lines | static void create_mesh(Scene *scene, | ||||
| } | } | ||||
| } | } | ||||
| static void create_subd_mesh(Scene *scene, | static void create_subd_mesh(Scene *scene, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| BObjectInfo &b_ob_info, | BObjectInfo &b_ob_info, | ||||
| BL::Mesh &b_mesh, | BL::Mesh &b_mesh, | ||||
| const array<Node *> &used_shaders, | const array<Node *> &used_shaders, | ||||
| const bool need_motion, | |||||
| const float motion_scale, | |||||
| float dicing_rate, | float dicing_rate, | ||||
| int max_subdivisions) | int max_subdivisions) | ||||
| { | { | ||||
| BL::Object b_ob = b_ob_info.real_object; | BL::Object b_ob = b_ob_info.real_object; | ||||
| BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]); | BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]); | ||||
| bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; | bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; | ||||
| create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs); | create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs); | ||||
| /* export creases */ | /* export creases */ | ||||
| size_t num_creases = 0; | size_t num_creases = 0; | ||||
| for (BL::MeshEdge &e : b_mesh.edges) { | for (BL::MeshEdge &e : b_mesh.edges) { | ||||
| if (e.crease() != 0.0f) { | if (e.crease() != 0.0f) { | ||||
| num_creases++; | num_creases++; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | if (need_motion == Scene::MOTION_BLUR) { | ||||
| } | } | ||||
| } | } | ||||
| /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object | /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object | ||||
| * level. */ | * level. */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| static void sync_mesh_cached_velocities(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh) | |||||
| { | |||||
| if (!mesh_need_motion_attribute(b_ob_info, scene)) { | |||||
| return; | |||||
| } | |||||
| BL::Object b_ob = b_ob_info.real_object; | |||||
| BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr); | |||||
| if (!b_mesh_cache) { | |||||
| return; | |||||
| } | |||||
| if (!MeshSequenceCacheModifier_read_velocity_get(&b_mesh_cache.ptr)) { | |||||
| return; | |||||
| } | |||||
| const size_t numverts = mesh->get_verts().size(); | |||||
| if (b_mesh_cache.vertex_velocities.length() != numverts) { | |||||
| return; | |||||
| } | |||||
| /* Find or add attribute */ | |||||
| float3 *P = &mesh->get_verts()[0]; | |||||
| Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); | |||||
| if (!attr_mP) { | |||||
| attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); | |||||
| } | |||||
| /* Only export previous and next frame, we don't have any in between data. */ | |||||
| float motion_times[2] = {-1.0f, 1.0f}; | |||||
| for (int step = 0; step < 2; step++) { | |||||
| const float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; | |||||
| float3 *mP = attr_mP->data_float3() + step * numverts; | |||||
| BL::MeshSequenceCacheModifier::vertex_velocities_iterator vvi; | |||||
| int i = 0; | |||||
| for (b_mesh_cache.vertex_velocities.begin(vvi); vvi != b_mesh_cache.vertex_velocities.end(); | |||||
| ++vvi, ++i) { | |||||
| mP[i] = P[i] + get_float3(vvi->velocity()) * relative_time; | |||||
| } | |||||
| } | |||||
| } | |||||
| static void sync_mesh_fluid_motion(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh) | |||||
| { | |||||
| if (!b_ob_info.is_real_object_data()) { | |||||
| return; | |||||
| } | |||||
| if (!mesh_need_motion_attribute(b_ob_info, scene)) { | |||||
| return; | |||||
| } | |||||
| BL::Object b_ob = b_ob_info.real_object; | |||||
| BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob); | |||||
| if (!b_fluid_domain) | |||||
| return; | |||||
| /* If the mesh has modifiers following the fluid domain we can't export motion. */ | |||||
| if (b_fluid_domain.mesh_vertices.length() != mesh->get_verts().size()) | |||||
| return; | |||||
| /* Find or add attribute */ | |||||
| float3 *P = &mesh->get_verts()[0]; | |||||
| Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); | |||||
| if (!attr_mP) { | |||||
| attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); | |||||
| } | |||||
| /* Only export previous and next frame, we don't have any in between data. */ | |||||
| float motion_times[2] = {-1.0f, 1.0f}; | |||||
| for (int step = 0; step < 2; step++) { | |||||
| float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; | |||||
| float3 *mP = attr_mP->data_float3() + step * mesh->get_verts().size(); | |||||
| BL::FluidDomainSettings::mesh_vertices_iterator svi; | |||||
| int i = 0; | |||||
| for (b_fluid_domain.mesh_vertices.begin(svi); svi != b_fluid_domain.mesh_vertices.end(); | |||||
| ++svi, ++i) { | |||||
| mP[i] = P[i] + get_float3(svi->velocity()) * relative_time; | |||||
| } | |||||
| } | |||||
| } | |||||
| void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh) | void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh) | ||||
| { | { | ||||
| /* make a copy of the shaders as the caller in the main thread still need them for syncing the | /* make a copy of the shaders as the caller in the main thread still need them for syncing the | ||||
| * attributes */ | * attributes */ | ||||
| array<Node *> used_shaders = mesh->get_used_shaders(); | array<Node *> used_shaders = mesh->get_used_shaders(); | ||||
| Mesh new_mesh; | Mesh new_mesh; | ||||
| new_mesh.set_used_shaders(used_shaders); | new_mesh.set_used_shaders(used_shaders); | ||||
| if (view_layer.use_surfaces) { | if (view_layer.use_surfaces) { | ||||
| /* Adaptive subdivision setup. Not for baking since that requires | /* Adaptive subdivision setup. Not for baking since that requires | ||||
| * exact mapping to the Blender mesh. */ | * exact mapping to the Blender mesh. */ | ||||
| if (!scene->bake_manager->get_baking()) { | if (!scene->bake_manager->get_baking()) { | ||||
| new_mesh.set_subdivision_type( | new_mesh.set_subdivision_type( | ||||
| object_subdivision_type(b_ob_info.real_object, preview, experimental)); | object_subdivision_type(b_ob_info.real_object, preview, experimental)); | ||||
| } | } | ||||
| /* For some reason, meshes do not need this... */ | /* For some reason, meshes do not need this... */ | ||||
| bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED); | bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED); | ||||
| BL::Mesh b_mesh = object_to_mesh( | BL::Mesh b_mesh = object_to_mesh( | ||||
| b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type()); | b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type()); | ||||
| if (b_mesh) { | if (b_mesh) { | ||||
| /* Motion blur attribute is relative to seconds, we need it relative to frames. */ | |||||
| const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene); | |||||
| const float motion_scale = (need_motion) ? | |||||
| scene->motion_shutter_time() / | |||||
| (b_scene.render().fps() / b_scene.render().fps_base()) : | |||||
kevindietrich: This should be `scene->motion_shutter_time() / (b_scene.render().fps() / b_scene.render(). | |||||
| 0.0f; | |||||
| /* Sync mesh itself. */ | /* Sync mesh itself. */ | ||||
| if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE) | if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE) | ||||
| create_subd_mesh(scene, | create_subd_mesh(scene, | ||||
| &new_mesh, | &new_mesh, | ||||
| b_ob_info, | b_ob_info, | ||||
| b_mesh, | b_mesh, | ||||
| new_mesh.get_used_shaders(), | new_mesh.get_used_shaders(), | ||||
| need_motion, | |||||
| motion_scale, | |||||
| dicing_rate, | dicing_rate, | ||||
| max_subdivisions); | max_subdivisions); | ||||
| else | else | ||||
| create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false); | create_mesh(scene, | ||||
| &new_mesh, | |||||
| b_mesh, | |||||
| new_mesh.get_used_shaders(), | |||||
| need_motion, | |||||
| motion_scale, | |||||
| false); | |||||
| free_object_to_mesh(b_data, b_ob_info, b_mesh); | free_object_to_mesh(b_data, b_ob_info, b_mesh); | ||||
| } | } | ||||
| } | } | ||||
| /* cached velocities (e.g. from alembic archive) */ | |||||
| sync_mesh_cached_velocities(b_ob_info, scene, &new_mesh); | |||||
| /* mesh fluid motion mantaflow */ | |||||
| sync_mesh_fluid_motion(b_ob_info, scene, &new_mesh); | |||||
| /* update original sockets */ | /* update original sockets */ | ||||
| mesh->clear_non_sockets(); | mesh->clear_non_sockets(); | ||||
| for (const SocketType &socket : new_mesh.type->inputs) { | for (const SocketType &socket : new_mesh.type->inputs) { | ||||
| /* Those sockets are updated in sync_object, so do not modify them. */ | /* Those sockets are updated in sync_object, so do not modify them. */ | ||||
| if (socket.name == "use_motion_blur" || socket.name == "motion_steps" || | if (socket.name == "use_motion_blur" || socket.name == "motion_steps" || | ||||
| socket.name == "used_shaders") { | socket.name == "used_shaders") { | ||||
| Show All 17 Lines | void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh) | ||||
| mesh->tag_update(scene, rebuild); | mesh->tag_update(scene, rebuild); | ||||
| } | } | ||||
| void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, | void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, | ||||
| BObjectInfo &b_ob_info, | BObjectInfo &b_ob_info, | ||||
| Mesh *mesh, | Mesh *mesh, | ||||
| int motion_step) | int motion_step) | ||||
| { | { | ||||
| /* Fluid motion blur already exported. */ | |||||
| BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob_info.real_object); | |||||
| if (b_fluid_domain) { | |||||
| return; | |||||
| } | |||||
| /* Cached motion blur already exported. */ | |||||
| BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find( | |||||
| b_ob_info.real_object, true, nullptr); | |||||
| if (mesh_cache) { | |||||
| return; | |||||
| } | |||||
| /* Skip if no vertices were exported. */ | /* Skip if no vertices were exported. */ | ||||
| size_t numverts = mesh->get_verts().size(); | size_t numverts = mesh->get_verts().size(); | ||||
| if (numverts == 0) { | if (numverts == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Skip objects without deforming modifiers. this is not totally reliable, | /* Skip objects without deforming modifiers. this is not totally reliable, | ||||
| * would need a more extensive check to see which objects are animated. */ | * would need a more extensive check to see which objects are animated. */ | ||||
| ▲ Show 20 Lines • Show All 85 Lines • Show Last 20 Lines | |||||
This should be scene->motion_shutter_time() / (b_scene.render().fps() / b_scene.render().fps_base()).
b_scene.render().fps() / b_scene.render().fps_base() is basically what's behind the FPS macro in Blender, so we need to divide by it here.