# Flattening the intersection of overlapping spheres [duplicate]

as everybody know, when you put two spheres close to each other they intersect other like this :

How do I flatten the spheres at the region where they intersect each, I tried to illustrate this with a quickdraw :

I don't know if it's possible with physics like soft body or collision. does anyone know how to get this result, i need this for a still image not for animation.

I'm more looking for something like this:

• This works but i want the effect even when i'm note playing the animation, i need this for a fix image not for animation, is there a way to get the physics result in one frame ? – amby Oct 14 '17 at 19:58
• This is for a personal project and i have absolutely no dead line, so do it only if you got the time, thank you very much – amby Oct 14 '17 at 23:07

Bmesh script

Script to flatten spheres on their intersection plane. See intersection of two spheres on Paul Bourke's magnificent geometry site The code runs through each selected sphere, checks if they intersect, if they do clalculates the location of the circle of hit.

If there's a collision, for both spheres, selects all vertices that are within the conic angle of the collision and moves them to the point of intersection with the collision disc. NOTE: script relies on the origin of the spheres being the (default) centre of geometry.

Test run on UV Spheres.

The script

Select all the spheres you want to modify and run script. Alter the scale to change the angle of effect of flattening vertices.

import bpy
import bmesh
from math import acos, degrees, radians
from mathutils import Vector
from mathutils.geometry import intersect_line_plane
context = bpy.context
scene = context.scene
spheres = [(o, max(axis for axis in o.dimensions) / 2) for o in context.selected_objects]
bmeshes = {}

scale = 1.0 # alter to widen bump angle.
def new_bmesh(me):
bm = bmesh.new()
bm.from_mesh(me)
return bm

def squish(sphere, angle, global_plane_co, global_plane_no):
mw = sphere.matrix_world
mwi = mw.inverted()

bm = bmeshes.setdefault(sphere.name, new_bmesh(sphere.data))
local_p = mwi * global_plane_co
local_norm = mwi * (global_plane_co + global_plane_no) - local_p
# select all verts via angle
if proj:
verts = [v for v in bm.verts if v.co.angle(local_p) > angle]
else:
verts = [v for v in bm.verts if v.co.angle(local_p) < angle]
for v in verts:
v.select = True
d = local_norm if proj else v.co
o = v.co if proj else Vector()
hit = intersect_line_plane(o, d, local_p, local_norm)
if hit and hit.length < v.co.length:
v.co = hit

while spheres:
sphere, R = spheres.pop()
P = sphere.matrix_world.translation
for s, r in spheres:
p = s.matrix_world.translation
v = (p - P)
d = v.length
v.normalize()
if d >= r + R:
continue
elif abs(r - R) > d:
continue
elif d < 0.0001:
continue

x = (d * d - r * r + R * R) / (2 * d)
# define plane
pt = P + x * v
norm = v
angle1 = acos(x / R)
angle2 = acos((d - x) / r)
#print(R, r, x, degrees(angle1), degrees(angle2))
squish(sphere, scale * angle1, pt, norm)
squish(s, scale * angle2, pt, norm)

for name, bm in bmeshes.items():
me = scene.objects[name].data
bm.to_mesh(me)
me.update()

scene.update()


Sample run on icosphere cluster on left, result on right

EDIT: fix for inside cases, now projects back onto plane if hit is inside (angle is greater than 90 degrees.

• that's exactly what i was looking for, i try it as soon as possible, thank you for your answer batFINGER – amby Oct 15 '17 at 18:17
• @amby given this comment, I've edited your question. Re-edit it if it's not your intention. – batFINGER Oct 15 '17 at 18:41
• it was my intention, i just have some trouble to explain my idea in english (i'm french), so i make lots of mistakes in english.. – amby Oct 15 '17 at 21:15
• @amby edited script to handle inside cases better. – batFINGER Oct 17 '17 at 16:44

If i understood the question maybe your looking for this

I have added 2 sphere and to 1 i have added the cast modifier

With the reference of pencil drawing sphere to deform when they touch each other.

In the cast modifier you can play with the settings and get the effect.