# How to stop colours of overlapping spheres from mixing?

I have plotted a series of blue and red spheres to replicate an atomic structure.

I would like the blue and red spheres to remain distinct; such that when I rotate the model, and the spheres overlap, the colours stay blue and red.

The problem I am facing is that the colours mix where the spheres overlap.

E.g) Plotting Blue and Red spheres. I want the spheres to remain blue of red, however when I move the camera, the overlapping spheres appear pink at the intersection.

How do I stop the colours from mixing into this purple-ish tone and keep my spheres red and blue?


import bpy
import numpy as np

sizes = { 'In' : 0.7, 'Ga' : 0.7 }
colors = { 'In' : (0.0, 0.0, 255.0, 0.3), 'Ga' : (255.0, 0.4, 0.4, 0.7), 'bond': (0.05, 0.05, 0.05 , 0.1) }

for key in colors.keys():
bpy.data.materials.new(name=key)
bpy.data.materials[key].diffuse_color = colors[key]
bpy.data.materials[key].specular_intensity = 0.1

def distance(a, b):
return np.sqrt(np.dot(a - b, a - b))

def normalize(a):
return np.array(a) / np.sqrt(np.dot(a, a))

class Structure:
def __init__(self, filename):
with open(filename, 'r') as f:

self.n_atoms = int(data[0].split()[0])

self.atom_list = [line.split()[0] for line in data[2:]]

coordinates = []

for i, line in enumerate(data[2:]):
coordinates.append([float(value) for value in line.split()[1:4]])

self.coordinates = np.array(coordinates)
self.bonds = set()

for i in range(self.n_atoms - 1):
position_1 = self.coordinates[i]
element_1 = self.atom_list[i]

if not element_1 in atom_types:
continue

for j in range(i + 1, self.n_atoms):
position_2 = self.coordinates[j]
element_2 = self.atom_list[j]

if not element_2 in atom_types:
continue

dist = distance(position_1, position_2)
if dist <= cutoff:

def draw_bonds(self):
for atom_1, atom_2 in self.bonds:
pos_1 = self.coordinates[atom_1]
pos_2 = self.coordinates[atom_2]

difference = pos_2 - pos_1
center = (pos_2 + pos_1) / 2.0
magnitude = distance(pos_1, pos_2)

bond_direction = normalize(difference)
vertical = np.array((0.0, 0.0, 1.0))
rotation_axis = np.cross(bond_direction, vertical)
angle = -np.arccos(np.dot(bond_direction, vertical))

depth=magnitude,
location=center)
bpy.context.active_object.data.materials.append(bpy.data.materials['bond'])
bpy.ops.transform.rotate(value=angle, axis=rotation_axis)

def draw_atoms(self):
for element, position in zip(self.atom_list, self.coordinates):
bpy.context.active_object.data.materials.append(bpy.data.materials[element])

def draw_structure(self):
self.draw_atoms()
#        self.draw_bonds()

InGaN = Structure(r'\8x8x5-xIn=0.5.xyz')
InGaN.draw_structure()


• Does it also happen with material alpha 1? Can you please add a sample data file? See blender.stackexchange.com/questions/55965/… re copying object rather than multiple create primitive operator calls. Commented Jun 10, 2020 at 13:28

Try changing the "color" line to:

colors = { 'In' : (0.0, 0.0, 255.0, 1.0), 'Ga' : (255.0, 0.4, 0.4, 1.0), 'bond': (0.05, 0.05, 0.05 , 1.0) }

• This did the trick! Thanks for the one-line fix :)
– hkh
Commented Jun 10, 2020 at 15:04

The materials you create in your script seem to be translucent, as you can clearly make out the contours of what is behind individual balls (hence the "color-blending" effect resulting in this pinkish color).

I do not know why this is the case, since the API clearly states that the default blend mode is set to OPAQUE when creating a new material via scripting.

My suggestion would be to create your necessary materials manually with Blender's powerful Node-Editor to get the desired result.

If you need an amount of different materials that would be unfeasible to create individually by hand, start out with one handmade non-translucent "Base"-material and copy it via scripting and just modify it's diffuse color every time you copy it.