1

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.

blue and red spheres ovelap to give purple. I want only red and blue to show How do I stop the colours from mixing into this purple-ish tone and keep my spheres red and blue?

See my source code below for more information:


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: data = f.readlines()

    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()

def add_bonds(self, atom_types, cutoff):
    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:
                self.bonds.add((i, j))

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))

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

def draw_atoms(self):
    for element, position in zip(self.atom_list, self.coordinates):
        bpy.ops.mesh.primitive_uv_sphere_add(radius=sizes[element], location=position)
        bpy.context.active_object.data.materials.append(bpy.data.materials[element])
        bpy.ops.object.shade_smooth()    

def draw_structure(self):
    self.draw_atoms()

self.draw_bonds()

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

hkh
  • 113
  • 2
  • Does it also happen with material alpha 1? Can you please add a sample data file? See https://blender.stackexchange.com/questions/55965/creating-many-primitive-objects-quickly-with-python re copying object rather than multiple create primitive operator calls. – batFINGER Jun 10 '20 at 13:28

2 Answers2

2

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) }
Tobias Einarsson
  • 2,202
  • 14
  • 18
1

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.

TheBeautifulOrc
  • 555
  • 4
  • 17