Example #1
0
CCL_NAMESPACE_BEGIN

/* Utilities */

bool BlenderSync::BKE_object_is_modified(BL::Object& b_ob)
{
	/* test if we can instance or if the object is modified */
	if(b_ob.type() == BL::Object::type_META) {
		/* multi-user and dupli metaballs are fused, can't instance */
		return true;
	}
	else if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
		/* modifiers */
		return true;
	}
	else {
		/* object level material links */
		BL::Object::material_slots_iterator slot;
		for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
			if(slot->link() == BL::MaterialSlot::link_OBJECT)
				return true;
	}

	return false;
}
Example #2
0
Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
                             BL::Object &b_ob,
                             BL::Object &b_ob_instance,
                             bool object_updated,
                             bool show_self,
                             bool show_particles)
{
  /* test if we can instance or if the object is modified */
  BL::ID b_ob_data = b_ob.data();
  BL::ID key = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
  BL::Material material_override = view_layer.material_override;

  /* find shader indices */
  vector<Shader *> used_shaders;

  BL::Object::material_slots_iterator slot;
  for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
    if (material_override) {
      find_shader(material_override, used_shaders, scene->default_surface);
    }
    else {
      BL::ID b_material(slot->material());
      find_shader(b_material, used_shaders, scene->default_surface);
    }
  }

  if (used_shaders.size() == 0) {
    if (material_override)
      find_shader(material_override, used_shaders, scene->default_surface);
    else
      used_shaders.push_back(scene->default_surface);
  }

  /* test if we need to sync */
  int requested_geometry_flags = Mesh::GEOMETRY_NONE;
  if (view_layer.use_surfaces) {
    requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
  }
  if (view_layer.use_hair) {
    requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
  }
  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
     * does not get tagged for recalc */
    else if (mesh->used_shaders != used_shaders)
      ;
    else if (requested_geometry_flags != mesh->geometry_flags)
      ;
    else {
      /* even if not tagged for recalc, we may need to sync anyway
       * because the shader needs different mesh attributes */
      bool attribute_recalc = false;

      foreach (Shader *shader, mesh->used_shaders)
        if (shader->need_update_mesh)
          attribute_recalc = true;

      if (!attribute_recalc)
        return mesh;
    }
  }

  /* ensure we only sync instanced meshes once */
  if (mesh_synced.find(mesh) != mesh_synced.end())
    return mesh;

  progress.set_sync_status("Synchronizing object", b_ob.name());

  mesh_synced.insert(mesh);

  /* create derived mesh */
  array<int> oldtriangles;
  array<Mesh::SubdFace> oldsubd_faces;
  array<int> oldsubd_face_corners;
  oldtriangles.steal_data(mesh->triangles);
  oldsubd_faces.steal_data(mesh->subd_faces);
  oldsubd_face_corners.steal_data(mesh->subd_face_corners);

  /* compares curve_keys rather than strands in order to handle quick hair
   * adjustments in dynamic BVH - other methods could probably do this better*/
  array<float3> oldcurve_keys;
  array<float> oldcurve_radius;
  oldcurve_keys.steal_data(mesh->curve_keys);
  oldcurve_radius.steal_data(mesh->curve_radius);

  mesh->clear();
  mesh->used_shaders = used_shaders;
  mesh->name = ustring(b_ob_data.name().c_str());

  if (requested_geometry_flags != Mesh::GEOMETRY_NONE) {
    /* Adaptive subdivision setup. Not for baking since that requires
     * exact mapping to the Blender mesh. */
    if (scene->bake_manager->get_baking()) {
      mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
    }
    else {
      mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
    }

    /* For some reason, meshes do not need this... */
    bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);

    BL::Mesh b_mesh = object_to_mesh(
        b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type);

    if (b_mesh) {
      /* Sync mesh itself. */
      if (view_layer.use_surfaces && show_self) {
        if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
          create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions);
        else
          create_mesh(scene, mesh, b_mesh, used_shaders, false);

        create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current());
      }

      /* Sync hair curves. */
      if (view_layer.use_hair && show_particles &&
          mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
        sync_curves(mesh, b_mesh, b_ob, false);
      }

      free_object_to_mesh(b_data, b_ob, b_mesh);
    }
  }
  mesh->geometry_flags = requested_geometry_flags;

  /* fluid motion */
  sync_mesh_fluid_motion(b_ob, scene, mesh);

  /* tag update */
  bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
                 (oldsubd_face_corners != mesh->subd_face_corners) ||
                 (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius);

  mesh->tag_update(scene, rebuild);

  return mesh;
}
Example #3
0
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
{
	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (object_is_modified(b_ob))? b_ob: b_ob_data;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		BL::Material material_override = render_layers.front().material_override;

		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			find_shader(slot->material(), used_shaders, scene->default_surface);
	}

	if(used_shaders.size() == 0)
		used_shaders.push_back(scene->default_surface);
	
	/* test if we need to sync */
	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
		   does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;
	
	mesh_synced.insert(mesh);

	/* create derived mesh */
	BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(b_mesh) {
		if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
			create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
		else
			create_mesh(scene, mesh, b_mesh, used_shaders);

		/* free derived mesh */
		object_remove_mesh(b_data, b_mesh);
	}

	/* displacement method */
	if(cmesh.data) {
		int method = RNA_enum_get(&cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}
	
	mesh->tag_update(scene, rebuild);

	return mesh;
}
Example #4
0
Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
                             bool object_updated,
                             bool hide_tris)
{
	/* When viewport display is not needed during render we can force some
	 * caches to be releases from blender side in order to reduce peak memory
	 * footprint during synchronization process.
	 */
	const bool is_interface_locked = b_engine.render() &&
	                                 b_engine.render().use_lock_interface();
	const bool can_free_caches = BlenderSession::headless || is_interface_locked;

	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
	BL::Material material_override = render_layer.material_override;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		if(material_override) {
			find_shader(material_override, used_shaders, scene->default_surface);
		}
		else {
			BL::ID b_material(slot->material());
			find_shader(b_material, used_shaders, scene->default_surface);
		}
	}

	if(used_shaders.size() == 0) {
		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			used_shaders.push_back(scene->default_surface);
	}
	
	/* test if we need to sync */
	int requested_geometry_flags = Mesh::GEOMETRY_NONE;
	if(render_layer.use_surfaces) {
		requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
	}
	if(render_layer.use_hair) {
		requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
	}
	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
		 * does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else if(requested_geometry_flags != mesh->geometry_flags);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;
	
	mesh_synced.insert(mesh);

	/* create derived mesh */
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;
	
	/* compares curve_keys rather than strands in order to handle quick hair
	 * adjustments in dynamic BVH - other methods could probably do this better*/
	vector<float4> oldcurve_keys = mesh->curve_keys;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(requested_geometry_flags != Mesh::GEOMETRY_NONE) {
		/* mesh objects does have special handle in the dependency graph,
		 * they're ensured to have properly updated.
		 *
		 * updating meshes here will end up having derived mesh referencing
		 * freed data from the blender side.
		 */
		if(preview && b_ob.type() != BL::Object::type_MESH)
			b_ob.update_from_editmode();

		bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
		BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);

		if(b_mesh) {
			if(render_layer.use_surfaces && !hide_tris) {
				if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
					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, b_scene.frame_current());
			}

			if(render_layer.use_hair)
				sync_curves(mesh, b_mesh, b_ob, false);

			if(can_free_caches) {
				b_ob.cache_release();
			}

			/* free derived mesh */
			b_data.meshes.remove(b_mesh);
		}
	}
	mesh->geometry_flags = requested_geometry_flags;

	/* displacement method */
	if(cmesh.data) {
		const int method = get_enum(cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}

	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(float4)*oldcurve_keys.size()) != 0)
			rebuild = true;
	}
	
	mesh->tag_update(scene, rebuild);

	return mesh;
}
Example #5
0
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
{
	/* test if we can instance or if the object is modified */
	BL::ID b_ob_data = b_ob.data();
	BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
	BL::Material material_override = render_layer.material_override;

	/* find shader indices */
	vector<uint> used_shaders;

	BL::Object::material_slots_iterator slot;
	for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			find_shader(slot->material(), used_shaders, scene->default_surface);
	}

	if(used_shaders.size() == 0) {
		if(material_override)
			find_shader(material_override, used_shaders, scene->default_surface);
		else
			used_shaders.push_back(scene->default_surface);
	}
	
	/* test if we need to sync */
	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
		 * does not get tagged for recalc */
		else if(mesh->used_shaders != used_shaders);
		else {
			/* even if not tagged for recalc, we may need to sync anyway
			 * because the shader needs different mesh attributes */
			bool attribute_recalc = false;

			foreach(uint shader, mesh->used_shaders)
				if(scene->shaders[shader]->need_update_attributes)
					attribute_recalc = true;

			if(!attribute_recalc)
				return mesh;
		}
	}

	/* ensure we only sync instanced meshes once */
	if(mesh_synced.find(mesh) != mesh_synced.end())
		return mesh;
	
	mesh_synced.insert(mesh);

	/* create derived mesh */
	PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");

	vector<Mesh::Triangle> oldtriangle = mesh->triangles;
	
	/* compares curve_keys rather than strands in order to handle quick hair
	 * adjustsments in dynamic BVH - other methods could probably do this better*/
	vector<float4> oldcurve_keys = mesh->curve_keys;

	mesh->clear();
	mesh->used_shaders = used_shaders;
	mesh->name = ustring(b_ob_data.name().c_str());

	if(render_layer.use_surfaces || render_layer.use_hair) {
		if(preview)
			b_ob.update_from_editmode();

		bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
		BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);

		if(b_mesh) {
			if(render_layer.use_surfaces && !hide_tris) {
				if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
					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, false);

			/* free derived mesh */
			b_data.meshes.remove(b_mesh);
		}
	}

	/* displacement method */
	if(cmesh.data) {
		const int method = RNA_enum_get(&cmesh, "displacement_method");

		if(method == 0 || !experimental)
			mesh->displacement_method = Mesh::DISPLACE_BUMP;
		else if(method == 1)
			mesh->displacement_method = Mesh::DISPLACE_TRUE;
		else
			mesh->displacement_method = Mesh::DISPLACE_BOTH;
	}

	/* tag update */
	bool rebuild = false;

	if(oldtriangle.size() != mesh->triangles.size())
		rebuild = true;
	else if(oldtriangle.size()) {
		if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
			rebuild = true;
	}

	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(float4)*oldcurve_keys.size()) != 0)
			rebuild = true;
	}
	
	mesh->tag_update(scene, rebuild);

	return mesh;
}