Refactor: Node Wrangler: PreviewNode operator
[blender-addons.git] / io_mesh_atomic / utility_panel.py
blobe6ff0dd9b1ecf6a91e4faf3c50d052b6108b57a1
1 # SPDX-FileCopyrightText: 2019-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 import os
6 import bpy
7 import bmesh
8 from mathutils import Vector
9 from math import sqrt
10 from copy import copy
12 # -----------------------------------------------------------------------------
13 # Atom and element data
16 # This is a list that contains some data of all possible elements. The structure
17 # is as follows:
19 # 1, "Hydrogen", "H", [0.0,0.0,1.0], 0.32, 0.32, 0.32 , -1 , 1.54 means
21 # No., name, short name, color, radius (used), radius (covalent), radius (atomic),
23 # charge state 1, radius (ionic) 1, charge state 2, radius (ionic) 2, ... all
24 # charge states for any atom are listed, if existing.
25 # The list is fixed and cannot be changed ... (see below)
27 ELEMENTS_DEFAULT = (
28 ( 1, "Hydrogen", "H", ( 1.0, 1.0, 1.0, 1.0), 0.32, 0.32, 0.79 , -1 , 1.54 ),
29 ( 2, "Helium", "He", ( 0.85, 1.0, 1.0, 1.0), 0.93, 0.93, 0.49 ),
30 ( 3, "Lithium", "Li", ( 0.8, 0.50, 1.0, 1.0), 1.23, 1.23, 2.05 , 1 , 0.68 ),
31 ( 4, "Beryllium", "Be", ( 0.76, 1.0, 0.0, 1.0), 0.90, 0.90, 1.40 , 1 , 0.44 , 2 , 0.35 ),
32 ( 5, "Boron", "B", ( 1.0, 0.70, 0.70, 1.0), 0.82, 0.82, 1.17 , 1 , 0.35 , 3 , 0.23 ),
33 ( 6, "Carbon", "C", ( 0.56, 0.56, 0.56, 1.0), 0.77, 0.77, 0.91 , -4 , 2.60 , 4 , 0.16 ),
34 ( 7, "Nitrogen", "N", ( 0.18, 0.31, 0.97, 1.0), 0.75, 0.75, 0.75 , -3 , 1.71 , 1 , 0.25 , 3 , 0.16 , 5 , 0.13 ),
35 ( 8, "Oxygen", "O", ( 1.0, 0.05, 0.05, 1.0), 0.73, 0.73, 0.65 , -2 , 1.32 , -1 , 1.76 , 1 , 0.22 , 6 , 0.09 ),
36 ( 9, "Fluorine", "F", ( 0.56, 0.87, 0.31, 1.0), 0.72, 0.72, 0.57 , -1 , 1.33 , 7 , 0.08 ),
37 (10, "Neon", "Ne", ( 0.70, 0.89, 0.96, 1.0), 0.71, 0.71, 0.51 , 1 , 1.12 ),
38 (11, "Sodium", "Na", ( 0.67, 0.36, 0.94, 1.0), 1.54, 1.54, 2.23 , 1 , 0.97 ),
39 (12, "Magnesium", "Mg", ( 0.54, 1.0, 0.0, 1.0), 1.36, 1.36, 1.72 , 1 , 0.82 , 2 , 0.66 ),
40 (13, "Aluminium", "Al", ( 0.74, 0.65, 0.65, 1.0), 1.18, 1.18, 1.82 , 3 , 0.51 ),
41 (14, "Silicon", "Si", ( 0.94, 0.78, 0.62, 1.0), 1.11, 1.11, 1.46 , -4 , 2.71 , -1 , 3.84 , 1 , 0.65 , 4 , 0.42 ),
42 (15, "Phosphorus", "P", ( 1.0, 0.50, 0.0, 1.0), 1.06, 1.06, 1.23 , -3 , 2.12 , 3 , 0.44 , 5 , 0.35 ),
43 (16, "Sulfur", "S", ( 1.0, 1.0, 0.18, 1.0), 1.02, 1.02, 1.09 , -2 , 1.84 , 2 , 2.19 , 4 , 0.37 , 6 , 0.30 ),
44 (17, "Chlorine", "Cl", ( 0.12, 0.94, 0.12, 1.0), 0.99, 0.99, 0.97 , -1 , 1.81 , 5 , 0.34 , 7 , 0.27 ),
45 (18, "Argon", "Ar", ( 0.50, 0.81, 0.89, 1.0), 0.98, 0.98, 0.88 , 1 , 1.54 ),
46 (19, "Potassium", "K", ( 0.56, 0.25, 0.83, 1.0), 2.03, 2.03, 2.77 , 1 , 0.81 ),
47 (20, "Calcium", "Ca", ( 0.23, 1.0, 0.0, 1.0), 1.74, 1.74, 2.23 , 1 , 1.18 , 2 , 0.99 ),
48 (21, "Scandium", "Sc", ( 0.90, 0.90, 0.90, 1.0), 1.44, 1.44, 2.09 , 3 , 0.73 ),
49 (22, "Titanium", "Ti", ( 0.74, 0.76, 0.78, 1.0), 1.32, 1.32, 2.00 , 1 , 0.96 , 2 , 0.94 , 3 , 0.76 , 4 , 0.68 ),
50 (23, "Vanadium", "V", ( 0.65, 0.65, 0.67, 1.0), 1.22, 1.22, 1.92 , 2 , 0.88 , 3 , 0.74 , 4 , 0.63 , 5 , 0.59 ),
51 (24, "Chromium", "Cr", ( 0.54, 0.6, 0.78, 1.0), 1.18, 1.18, 1.85 , 1 , 0.81 , 2 , 0.89 , 3 , 0.63 , 6 , 0.52 ),
52 (25, "Manganese", "Mn", ( 0.61, 0.47, 0.78, 1.0), 1.17, 1.17, 1.79 , 2 , 0.80 , 3 , 0.66 , 4 , 0.60 , 7 , 0.46 ),
53 (26, "Iron", "Fe", ( 0.87, 0.4, 0.2, 1.0), 1.17, 1.17, 1.72 , 2 , 0.74 , 3 , 0.64 ),
54 (27, "Cobalt", "Co", ( 0.94, 0.56, 0.62, 1.0), 1.16, 1.16, 1.67 , 2 , 0.72 , 3 , 0.63 ),
55 (28, "Nickel", "Ni", ( 0.31, 0.81, 0.31, 1.0), 1.15, 1.15, 1.62 , 2 , 0.69 ),
56 (29, "Copper", "Cu", ( 0.78, 0.50, 0.2, 1.0), 1.17, 1.17, 1.57 , 1 , 0.96 , 2 , 0.72 ),
57 (30, "Zinc", "Zn", ( 0.49, 0.50, 0.69, 1.0), 1.25, 1.25, 1.53 , 1 , 0.88 , 2 , 0.74 ),
58 (31, "Gallium", "Ga", ( 0.76, 0.56, 0.56, 1.0), 1.26, 1.26, 1.81 , 1 , 0.81 , 3 , 0.62 ),
59 (32, "Germanium", "Ge", ( 0.4, 0.56, 0.56, 1.0), 1.22, 1.22, 1.52 , -4 , 2.72 , 2 , 0.73 , 4 , 0.53 ),
60 (33, "Arsenic", "As", ( 0.74, 0.50, 0.89, 1.0), 1.20, 1.20, 1.33 , -3 , 2.22 , 3 , 0.58 , 5 , 0.46 ),
61 (34, "Selenium", "Se", ( 1.0, 0.63, 0.0, 1.0), 1.16, 1.16, 1.22 , -2 , 1.91 , -1 , 2.32 , 1 , 0.66 , 4 , 0.50 , 6 , 0.42 ),
62 (35, "Bromine", "Br", ( 0.65, 0.16, 0.16, 1.0), 1.14, 1.14, 1.12 , -1 , 1.96 , 5 , 0.47 , 7 , 0.39 ),
63 (36, "Krypton", "Kr", ( 0.36, 0.72, 0.81, 1.0), 1.31, 1.31, 1.24 ),
64 (37, "Rubidium", "Rb", ( 0.43, 0.18, 0.69, 1.0), 2.16, 2.16, 2.98 , 1 , 1.47 ),
65 (38, "Strontium", "Sr", ( 0.0, 1.0, 0.0, 1.0), 1.91, 1.91, 2.45 , 2 , 1.12 ),
66 (39, "Yttrium", "Y", ( 0.58, 1.0, 1.0, 1.0), 1.62, 1.62, 2.27 , 3 , 0.89 ),
67 (40, "Zirconium", "Zr", ( 0.58, 0.87, 0.87, 1.0), 1.45, 1.45, 2.16 , 1 , 1.09 , 4 , 0.79 ),
68 (41, "Niobium", "Nb", ( 0.45, 0.76, 0.78, 1.0), 1.34, 1.34, 2.08 , 1 , 1.00 , 4 , 0.74 , 5 , 0.69 ),
69 (42, "Molybdenum", "Mo", ( 0.32, 0.70, 0.70, 1.0), 1.30, 1.30, 2.01 , 1 , 0.93 , 4 , 0.70 , 6 , 0.62 ),
70 (43, "Technetium", "Tc", ( 0.23, 0.61, 0.61, 1.0), 1.27, 1.27, 1.95 , 7 , 0.97 ),
71 (44, "Ruthenium", "Ru", ( 0.14, 0.56, 0.56, 1.0), 1.25, 1.25, 1.89 , 4 , 0.67 ),
72 (45, "Rhodium", "Rh", ( 0.03, 0.49, 0.54, 1.0), 1.25, 1.25, 1.83 , 3 , 0.68 ),
73 (46, "Palladium", "Pd", ( 0.0, 0.41, 0.52, 1.0), 1.28, 1.28, 1.79 , 2 , 0.80 , 4 , 0.65 ),
74 (47, "Silver", "Ag", ( 0.75, 0.75, 0.75, 1.0), 1.34, 1.34, 1.75 , 1 , 1.26 , 2 , 0.89 ),
75 (48, "Cadmium", "Cd", ( 1.0, 0.85, 0.56, 1.0), 1.48, 1.48, 1.71 , 1 , 1.14 , 2 , 0.97 ),
76 (49, "Indium", "In", ( 0.65, 0.45, 0.45, 1.0), 1.44, 1.44, 2.00 , 3 , 0.81 ),
77 (50, "Tin", "Sn", ( 0.4, 0.50, 0.50, 1.0), 1.41, 1.41, 1.72 , -4 , 2.94 , -1 , 3.70 , 2 , 0.93 , 4 , 0.71 ),
78 (51, "Antimony", "Sb", ( 0.61, 0.38, 0.70, 1.0), 1.40, 1.40, 1.53 , -3 , 2.45 , 3 , 0.76 , 5 , 0.62 ),
79 (52, "Tellurium", "Te", ( 0.83, 0.47, 0.0, 1.0), 1.36, 1.36, 1.42 , -2 , 2.11 , -1 , 2.50 , 1 , 0.82 , 4 , 0.70 , 6 , 0.56 ),
80 (53, "Iodine", "I", ( 0.58, 0.0, 0.58, 1.0), 1.33, 1.33, 1.32 , -1 , 2.20 , 5 , 0.62 , 7 , 0.50 ),
81 (54, "Xenon", "Xe", ( 0.25, 0.61, 0.69, 1.0), 1.31, 1.31, 1.24 ),
82 (55, "Caesium", "Cs", ( 0.34, 0.09, 0.56, 1.0), 2.35, 2.35, 3.35 , 1 , 1.67 ),
83 (56, "Barium", "Ba", ( 0.0, 0.78, 0.0, 1.0), 1.98, 1.98, 2.78 , 1 , 1.53 , 2 , 1.34 ),
84 (57, "Lanthanum", "La", ( 0.43, 0.83, 1.0, 1.0), 1.69, 1.69, 2.74 , 1 , 1.39 , 3 , 1.06 ),
85 (58, "Cerium", "Ce", ( 1.0, 1.0, 0.78, 1.0), 1.65, 1.65, 2.70 , 1 , 1.27 , 3 , 1.03 , 4 , 0.92 ),
86 (59, "Praseodymium", "Pr", ( 0.85, 1.0, 0.78, 1.0), 1.65, 1.65, 2.67 , 3 , 1.01 , 4 , 0.90 ),
87 (60, "Neodymium", "Nd", ( 0.78, 1.0, 0.78, 1.0), 1.64, 1.64, 2.64 , 3 , 0.99 ),
88 (61, "Promethium", "Pm", ( 0.63, 1.0, 0.78, 1.0), 1.63, 1.63, 2.62 , 3 , 0.97 ),
89 (62, "Samarium", "Sm", ( 0.56, 1.0, 0.78, 1.0), 1.62, 1.62, 2.59 , 3 , 0.96 ),
90 (63, "Europium", "Eu", ( 0.38, 1.0, 0.78, 1.0), 1.85, 1.85, 2.56 , 2 , 1.09 , 3 , 0.95 ),
91 (64, "Gadolinium", "Gd", ( 0.27, 1.0, 0.78, 1.0), 1.61, 1.61, 2.54 , 3 , 0.93 ),
92 (65, "Terbium", "Tb", ( 0.18, 1.0, 0.78, 1.0), 1.59, 1.59, 2.51 , 3 , 0.92 , 4 , 0.84 ),
93 (66, "Dysprosium", "Dy", ( 0.12, 1.0, 0.78, 1.0), 1.59, 1.59, 2.49 , 3 , 0.90 ),
94 (67, "Holmium", "Ho", ( 0.0, 1.0, 0.61, 1.0), 1.58, 1.58, 2.47 , 3 , 0.89 ),
95 (68, "Erbium", "Er", ( 0.0, 0.90, 0.45, 1.0), 1.57, 1.57, 2.45 , 3 , 0.88 ),
96 (69, "Thulium", "Tm", ( 0.0, 0.83, 0.32, 1.0), 1.56, 1.56, 2.42 , 3 , 0.87 ),
97 (70, "Ytterbium", "Yb", ( 0.0, 0.74, 0.21, 1.0), 1.74, 1.74, 2.40 , 2 , 0.93 , 3 , 0.85 ),
98 (71, "Lutetium", "Lu", ( 0.0, 0.67, 0.14, 1.0), 1.56, 1.56, 2.25 , 3 , 0.85 ),
99 (72, "Hafnium", "Hf", ( 0.30, 0.76, 1.0, 1.0), 1.44, 1.44, 2.16 , 4 , 0.78 ),
100 (73, "Tantalum", "Ta", ( 0.30, 0.65, 1.0, 1.0), 1.34, 1.34, 2.09 , 5 , 0.68 ),
101 (74, "Tungsten", "W", ( 0.12, 0.58, 0.83, 1.0), 1.30, 1.30, 2.02 , 4 , 0.70 , 6 , 0.62 ),
102 (75, "Rhenium", "Re", ( 0.14, 0.49, 0.67, 1.0), 1.28, 1.28, 1.97 , 4 , 0.72 , 7 , 0.56 ),
103 (76, "Osmium", "Os", ( 0.14, 0.4, 0.58, 1.0), 1.26, 1.26, 1.92 , 4 , 0.88 , 6 , 0.69 ),
104 (77, "Iridium", "Ir", ( 0.09, 0.32, 0.52, 1.0), 1.27, 1.27, 1.87 , 4 , 0.68 ),
105 (78, "Platinum", "Pt", ( 0.81, 0.81, 0.87, 1.0), 1.30, 1.30, 1.83 , 2 , 0.80 , 4 , 0.65 ),
106 (79, "Gold", "Au", ( 1.0, 0.81, 0.13, 1.0), 1.34, 1.34, 1.79 , 1 , 1.37 , 3 , 0.85 ),
107 (80, "Mercury", "Hg", ( 0.72, 0.72, 0.81, 1.0), 1.49, 1.49, 1.76 , 1 , 1.27 , 2 , 1.10 ),
108 (81, "Thallium", "Tl", ( 0.65, 0.32, 0.30, 1.0), 1.48, 1.48, 2.08 , 1 , 1.47 , 3 , 0.95 ),
109 (82, "Lead", "Pb", ( 0.34, 0.34, 0.38, 1.0), 1.47, 1.47, 1.81 , 2 , 1.20 , 4 , 0.84 ),
110 (83, "Bismuth", "Bi", ( 0.61, 0.30, 0.70, 1.0), 1.46, 1.46, 1.63 , 1 , 0.98 , 3 , 0.96 , 5 , 0.74 ),
111 (84, "Polonium", "Po", ( 0.67, 0.36, 0.0, 1.0), 1.46, 1.46, 1.53 , 6 , 0.67 ),
112 (85, "Astatine", "At", ( 0.45, 0.30, 0.27, 1.0), 1.45, 1.45, 1.43 , -3 , 2.22 , 3 , 0.85 , 5 , 0.46 ),
113 (86, "Radon", "Rn", ( 0.25, 0.50, 0.58, 1.0), 1.00, 1.00, 1.34 ),
114 (87, "Francium", "Fr", ( 0.25, 0.0, 0.4, 1.0), 1.00, 1.00, 1.00 , 1 , 1.80 ),
115 (88, "Radium", "Ra", ( 0.0, 0.49, 0.0, 1.0), 1.00, 1.00, 1.00 , 2 , 1.43 ),
116 (89, "Actinium", "Ac", ( 0.43, 0.67, 0.98, 1.0), 1.00, 1.00, 1.00 , 3 , 1.18 ),
117 (90, "Thorium", "Th", ( 0.0, 0.72, 1.0, 1.0), 1.65, 1.65, 1.00 , 4 , 1.02 ),
118 (91, "Protactinium", "Pa", ( 0.0, 0.63, 1.0, 1.0), 1.00, 1.00, 1.00 , 3 , 1.13 , 4 , 0.98 , 5 , 0.89 ),
119 (92, "Uranium", "U", ( 0.0, 0.56, 1.0, 1.0), 1.42, 1.42, 1.00 , 4 , 0.97 , 6 , 0.80 ),
120 (93, "Neptunium", "Np", ( 0.0, 0.50, 1.0, 1.0), 1.00, 1.00, 1.00 , 3 , 1.10 , 4 , 0.95 , 7 , 0.71 ),
121 (94, "Plutonium", "Pu", ( 0.0, 0.41, 1.0, 1.0), 1.00, 1.00, 1.00 , 3 , 1.08 , 4 , 0.93 ),
122 (95, "Americium", "Am", ( 0.32, 0.36, 0.94, 1.0), 1.00, 1.00, 1.00 , 3 , 1.07 , 4 , 0.92 ),
123 (96, "Curium", "Cm", ( 0.47, 0.36, 0.89, 1.0), 1.00, 1.00, 1.00 ),
124 (97, "Berkelium", "Bk", ( 0.54, 0.30, 0.89, 1.0), 1.00, 1.00, 1.00 ),
125 (98, "Californium", "Cf", ( 0.63, 0.21, 0.83, 1.0), 1.00, 1.00, 1.00 ),
126 (99, "Einsteinium", "Es", ( 0.70, 0.12, 0.83, 1.0), 1.00, 1.00, 1.00 ),
127 (100, "Fermium", "Fm", ( 0.70, 0.12, 0.72, 1.0), 1.00, 1.00, 1.00 ),
128 (101, "Mendelevium", "Md", ( 0.70, 0.05, 0.65, 1.0), 1.00, 1.00, 1.00 ),
129 (102, "Nobelium", "No", ( 0.74, 0.05, 0.52, 1.0), 1.00, 1.00, 1.00 ),
130 (103, "Lawrencium", "Lr", ( 0.78, 0.0, 0.4, 1.0), 1.00, 1.00, 1.00 ),
131 (104, "Vacancy", "Vac", ( 0.5, 0.5, 0.5, 1.0), 1.00, 1.00, 1.00),
132 (105, "Default", "Default", ( 1.0, 1.0, 1.0, 1.0), 1.00, 1.00, 1.00),
133 (106, "Stick", "Stick", ( 0.5, 0.5, 0.5, 1.0), 1.00, 1.00, 1.00),
136 # The list 'ELEMENTS' contains all data of the elements and will be used during
137 # runtime. The list will be initialized with the fixed
138 # data from above via the class below (ElementProp). One fixed list (above),
139 # which cannot be changed, and a list of classes with same data (ELEMENTS) exist.
140 # The list 'ELEMENTS' can be modified by e.g. loading a separate custom
141 # data file.
142 ELEMENTS = []
145 # This is the class, which stores the properties for one element.
146 class ElementProp(object):
147 __slots__ = ('number',
148 'name',
149 'short_name',
150 'color',
151 'radii',
152 'radii_ionic',
153 'mat_P_BSDF',
154 'mat_Eevee')
155 def __init__(self,
156 number,
157 name,
158 short_name,
159 color,
160 radii,
161 radii_ionic,
162 mat_P_BSDF,
163 mat_Eevee):
164 self.number = number
165 self.name = name
166 self.short_name = short_name
167 self.color = color
168 self.radii = radii
169 self.radii_ionic = radii_ionic
170 self.mat_P_BSDF = mat_P_BSDF
171 self.mat_Eevee = mat_Eevee
174 class PBSDFProp(object):
175 __slots__ = ('Subsurface_method',
176 'Distribution',
177 'Subsurface_weight',
178 'Subsurface_radius',
179 'Metallic',
180 'Specular_ior_level',
181 'Specular_tint',
182 'Roughness',
183 'Anisotropic',
184 'Anisotropic_rotation',
185 'Sheen_weight',
186 'Sheen_tint',
187 'Coat_weight',
188 'Coat_roughness',
189 'IOR',
190 'Transmission_weight',
191 'Emission',
192 'Emission_strength',
193 'Alpha')
194 def __init__(self,
195 Subsurface_method,
196 Distribution,
197 Subsurface_weight,
198 Subsurface_radius,
199 Metallic,
200 Specular_ior_level,
201 Specular_tint,
202 Roughness,
203 Anisotropic,
204 Anisotropic_rotation,
205 Sheen_weight,
206 Sheen_tint,
207 Coat_weight,
208 Coat_roughness,
209 IOR,
210 Transmission_weight,
211 Emission,
212 Emission_strength,
213 Alpha):
214 self.Subsurface_method = Subsurface_method
215 self.Distribution = Distribution
216 self.Subsurface_weight = Subsurface_weight
217 self.Subsurface_radius = Subsurface_radius
218 self.Metallic = Metallic
219 self.Specular_ior_level = Specular_ior_level
220 self.Specular_tint = Specular_tint
221 self.Roughness = Roughness
222 self.Anisotropic = Anisotropic
223 self.Anisotropic_rotation = Anisotropic_rotation
224 self.Sheen_weight = Sheen_weight
225 self.Sheen_tint = Sheen_tint
226 self.Coat_weight = Coat_weight
227 self.Coat_roughness = Coat_roughness
228 self.IOR = IOR
229 self.Transmission_weight = Transmission_weight
230 self.Emission = Emission
231 self.Emission_strength = Emission_strength
232 self.Alpha = Alpha
235 class EeveeProp(object):
236 __slots__ = ('use_backface',
237 'blend_method',
238 'shadow_method',
239 'clip_threshold',
240 'use_screen_refraction',
241 'refraction_depth',
242 'use_sss_translucency',
243 'pass_index')
244 def __init__(self,
245 use_backface,
246 blend_method,
247 shadow_method,
248 clip_threshold,
249 use_screen_refraction,
250 refraction_depth,
251 use_sss_translucency,
252 pass_index):
253 self.use_backface = use_backface
254 self.blend_method = blend_method
255 self.shadow_method = shadow_method
256 self.clip_threshold = clip_threshold
257 self.use_screen_refraction = use_screen_refraction
258 self.refraction_depth = refraction_depth
259 self.use_sss_translucency = use_sss_translucency
260 self.pass_index = pass_index
263 # This function measures the distance between two selected objects.
264 def distance():
266 # In the 'EDIT' mode
267 if bpy.context.mode == 'EDIT_MESH':
269 atom = bpy.context.edit_object
270 bm = bmesh.from_edit_mesh(atom.data)
271 locations = []
273 for v in bm.verts:
274 if v.select:
275 locations.append(atom.matrix_world @ v.co)
277 if len(locations) > 1:
278 location1 = locations[0]
279 location2 = locations[1]
280 else:
281 return "N.A"
282 # In the 'OBJECT' mode
283 else:
285 if len(bpy.context.selected_objects) > 1:
286 location1 = bpy.context.selected_objects[0].location
287 location2 = bpy.context.selected_objects[1].location
288 else:
289 return "N.A."
291 dv = location2 - location1
292 dist = str(dv.length)
293 pos = str.find(dist, ".")
294 dist = dist[:pos+4]
295 dist = dist + " A"
297 return dist
300 def choose_objects(action_type,
301 radius_all,
302 radius_pm,
303 radius_type,
304 radius_type_ionic,
305 sticks_all):
307 # Note all selected objects first.
308 change_objects_all = []
309 for atom in bpy.context.selected_objects:
310 change_objects_all.append(atom)
312 # This is very important now: If there are dupliverts structures, note
313 # only the parents and NOT the children! Otherwise the double work is
314 # done or the system can even crash if objects are deleted. - The
315 # chidlren are accessed anyways (see below).
316 change_objects = []
317 for atom in change_objects_all:
318 if atom.parent != None:
319 FLAG = False
320 for atom2 in change_objects:
321 if atom2 == atom.parent:
322 FLAG = True
323 if FLAG == False:
324 change_objects.append(atom)
325 else:
326 change_objects.append(atom)
328 # And now, consider all objects, which are in the list 'change_objects'.
329 for atom in change_objects:
330 if len(atom.children) != 0:
331 for atom_child in atom.children:
332 if atom_child.type in {'SURFACE', 'MESH', 'META'}:
333 modify_objects(action_type,
334 atom_child,
335 radius_all,
336 radius_pm,
337 radius_type,
338 radius_type_ionic,
339 sticks_all)
340 else:
341 if atom.type in {'SURFACE', 'MESH', 'META'}:
342 modify_objects(action_type,
343 atom,
344 radius_all,
345 radius_pm,
346 radius_type,
347 radius_type_ionic,
348 sticks_all)
351 # Modifying the radius of a selected atom or stick
352 def modify_objects(action_type,
353 atom,
354 radius_all,
355 radius_pm,
356 radius_type,
357 radius_type_ionic,
358 sticks_all):
360 # Modify atom radius (in pm)
361 if action_type == "ATOM_RADIUS_PM" and "STICK" not in atom.name.upper():
362 if radius_pm[0] in atom.name:
363 atom.scale = (radius_pm[1]/100,) * 3
365 # Modify atom radius (all selected)
366 if action_type == "ATOM_RADIUS_ALL" and "STICK" not in atom.name.upper():
367 atom.scale *= radius_all
369 # Modify atom radius (type, van der Waals, atomic or ionic)
370 if action_type == "ATOM_RADIUS_TYPE" and "STICK" not in atom.name.upper():
371 for element in ELEMENTS:
372 if element.name in atom.name:
373 # For ionic radii
374 if radius_type == '3':
375 charge_states = element.radii_ionic[::2]
376 charge_radii = element.radii_ionic[1::2]
377 charge_state_chosen = int(radius_type_ionic) - 4
379 find = (lambda searchList, elem:
380 [[i for i, x in enumerate(searchList) if x == e]
381 for e in elem])
382 index = find(charge_states,[charge_state_chosen])[0]
384 # Is there a charge state?
385 if index != []:
386 atom.scale = (charge_radii[index[0]],) * 3
388 # For atomic and van der Waals radii.
389 else:
390 atom.scale = (element.radii[int(radius_type)],) * 3
392 # Modify atom sticks
393 if (action_type == "STICKS_RADIUS_ALL" and 'STICK' in atom.name.upper() and
394 ('CUP' in atom.name.upper() or
395 'CYLINDER' in atom.name.upper())):
397 # For dupliverts structures only: Make the cylinder or cup visible
398 # first, otherwise one cannot go into EDIT mode. Note that 'atom' here
399 # is in fact a 'stick' (cylinder or cup).
400 # First, identify if it is a normal cylinder object or a dupliverts
401 # structure. The identifier for a dupliverts structure is the parent's
402 # name, which includes "_sticks_mesh"
403 if "_sticks_mesh" in atom.parent.name:
404 atom.hide_set(False)
406 bpy.context.view_layer.objects.active = atom
407 bpy.ops.object.mode_set(mode='EDIT', toggle=False)
408 bm = bmesh.from_edit_mesh(atom.data)
410 locations = []
411 for v in bm.verts:
412 locations.append(v.co)
414 center = Vector((0.0,0.0,0.0))
415 center = sum([location for location in locations], center)/len(locations)
417 radius = sum([(loc[0]-center[0])**2+(loc[1]-center[1])**2
418 for loc in locations], 0)
419 radius_new = radius * sticks_all
421 for v in bm.verts:
422 v.co[0] = ((v.co[0] - center[0]) / radius) * radius_new + center[0]
423 v.co[1] = ((v.co[1] - center[1]) / radius) * radius_new + center[1]
425 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
426 # Hide again the representative stick (cylinder or cup) if it is a
427 # dupliverts structure.
428 if "_sticks_mesh" in atom.parent.name:
429 atom.hide_set(True)
431 bpy.context.view_layer.objects.active = None
433 # Change the atom objects
434 if action_type == "ATOM_REPLACE_OBJ" and "STICK" not in atom.name.upper():
436 scn = bpy.context.scene.atom_blend
438 material = atom.active_material
439 new_material = draw_obj_material(scn.replace_objs_material, material)
441 # Special object (like halo, etc.)
442 if scn.replace_objs_special != '0':
443 atom = draw_obj_special(scn.replace_objs_special, atom)
444 # Standard geometrical objects
445 else:
446 # If the atom shape shall not be changed, then:
447 if scn.replace_objs == '0':
448 atom.active_material = new_material
449 # If the atom shape shall change, then:
450 else:
451 atom = draw_obj(scn.replace_objs, atom, new_material)
453 # Find the sticks, if present.
454 sticks_cylinder, sticks_cup = find_sticks_of_atom(atom)
456 # Dupliverts sticks
457 if sticks_cylinder != None and sticks_cup != None:
458 sticks_cylinder.active_material = new_material
459 sticks_cup.active_material = new_material
460 if sticks_cylinder != None and sticks_cup == None:
461 # Normal sticks
462 if type(sticks_cylinder) == list:
463 for stick in sticks_cylinder:
464 stick.active_material = new_material
465 # Skin sticks
466 else:
467 sticks_cylinder.active_material = new_material
469 # If the atom is the representative ball of a dupliverts structure,
470 # then make it invisible.
471 if atom.parent != None:
472 atom.hide_set(True)
474 # Default shape and colors for atoms
475 if action_type == "ATOM_DEFAULT_OBJ" and "STICK" not in atom.name.upper():
477 scn = bpy.context.scene.atom_blend
479 # We first obtain the element form the list of elements.
480 for element in ELEMENTS:
481 if element.name in atom.name:
482 break
484 # Create now a new material with normal properties. Note that the
485 # 'normal material' initially used during the import could have been
486 # deleted by the user. This is why we create a new one.
487 if "vacancy" in atom.name.lower():
488 new_material = draw_obj_material('2', atom.active_material)
489 else:
490 new_material = draw_obj_material('1', atom.active_material)
491 # Assign now the correct color.
492 mat_P_BSDF = next(n for n in new_material.node_tree.nodes
493 if n.type == "BSDF_PRINCIPLED")
494 mat_P_BSDF.inputs['Base Color'].default_value = element.color
495 new_material.name = element.name + "_normal"
497 # Create a new atom because the current atom might have any kind
498 # of shape. For this, we use a definition from below since it also
499 # deletes the old atom.
500 if "vacancy" in atom.name.lower():
501 new_atom = draw_obj('2', atom, new_material)
502 else:
503 new_atom = draw_obj('1b', atom, new_material)
505 # Now assign the material properties, name and size.
506 new_atom.active_material = new_material
507 new_atom.name = element.name + "_ball"
508 new_atom.scale = (element.radii[0],) * 3
510 # Find the sticks, if present.
511 sticks_cylinder, sticks_cup = find_sticks_of_atom(new_atom)
513 # Dupliverts sticks
514 if sticks_cylinder != None and sticks_cup != None:
515 sticks_cylinder.active_material = new_material
516 sticks_cup.active_material = new_material
517 if sticks_cylinder != None and sticks_cup == None:
518 # Normal sticks
519 if type(sticks_cylinder) == list:
520 for stick in sticks_cylinder:
521 stick.active_material = new_material
522 # Skin sticks
523 else:
524 sticks_cylinder.active_material = new_material
527 # Separating atoms from a dupliverts structure.
528 def separate_atoms(scn):
530 # Get the mesh.
531 mesh = bpy.context.edit_object
533 # Do nothing if it is not a dupliverts structure.
534 if not mesh.instance_type == "VERTS":
535 return {'FINISHED'}
537 # This is the name of the mesh
538 mesh_name = mesh.name
539 # Get the collection
540 coll = mesh.users_collection[0]
542 # Get the coordinates of the selected vertices (atoms)
543 bm = bmesh.from_edit_mesh(mesh.data)
544 locations = []
545 for v in bm.verts:
546 if v.select:
547 locations.append(mesh.matrix_world @ v.co)
549 # Free memory
550 bm.free()
552 # Delete already the selected vertices
553 bpy.ops.mesh.delete(type='VERT')
555 # Find the representative ball within the collection.
556 for obj in coll.objects:
557 if obj.parent != None:
558 if obj.parent.name == mesh_name:
559 break
561 # Create balls and put them at the places where the vertices (atoms) have
562 # been before.
563 for location in locations:
564 obj_dupli = obj.copy()
565 obj_dupli.data = obj.data.copy()
566 obj_dupli.parent = None
567 coll.objects.link(obj_dupli)
568 obj_dupli.location = location
569 obj_dupli.name = obj.name + "_sep"
570 # Do not hide the object!
571 obj_dupli.hide_set(False)
573 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
574 bpy.context.view_layer.objects.active = mesh
577 # Prepare a new material
578 def draw_obj_material(material_type, material):
580 mat_P_BSDF_default = next(n for n in material.node_tree.nodes
581 if n.type == "BSDF_PRINCIPLED")
582 default_color = mat_P_BSDF_default.inputs['Base Color'].default_value
584 if material_type == '0': # Unchanged
585 material_new = material
586 if material_type == '1': # Normal
587 # We create again the 'normal' material. Why? It's because the old
588 # one could have been deleted by the user during the course of the
589 # user's work in Blender ... .
590 material_new = bpy.data.materials.new(material.name + "_normal")
591 material_new.use_nodes = True
592 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
593 if n.type == "BSDF_PRINCIPLED")
594 mat_P_BSDF.inputs['Base Color'].default_value = default_color
595 mat_P_BSDF.inputs['Metallic'].default_value = 0.0
596 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.5
597 mat_P_BSDF.inputs['Roughness'].default_value = 0.5
598 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.03
599 mat_P_BSDF.inputs['IOR'].default_value = 1.45
600 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.0
601 mat_P_BSDF.inputs['Alpha'].default_value = 1.0
602 # Some additional stuff for eevee.
603 material_new.blend_method = 'OPAQUE'
604 material_new.shadow_method = 'OPAQUE'
605 if material_type == '2': # Transparent
606 material_new = bpy.data.materials.new(material.name + "_transparent")
607 material_new.use_nodes = True
608 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
609 if n.type == "BSDF_PRINCIPLED")
610 mat_P_BSDF.inputs['Base Color'].default_value = default_color
611 mat_P_BSDF.inputs['Metallic'].default_value = 0.0
612 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.15
613 mat_P_BSDF.inputs['Roughness'].default_value = 0.2
614 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.37
615 mat_P_BSDF.inputs['IOR'].default_value = 1.45
616 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.8
617 mat_P_BSDF.inputs['Alpha'].default_value = 0.4
618 # Some additional stuff for eevee.
619 material_new.blend_method = 'HASHED'
620 material_new.shadow_method = 'HASHED'
621 material_new.use_backface_culling = False
622 if material_type == '3': # Reflecting
623 material_new = bpy.data.materials.new(material.name + "_reflecting")
624 material_new.use_nodes = True
625 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
626 if n.type == "BSDF_PRINCIPLED")
627 mat_P_BSDF.inputs['Base Color'].default_value = default_color
628 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
629 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.15
630 mat_P_BSDF.inputs['Roughness'].default_value = 0.1
631 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.5
632 mat_P_BSDF.inputs['IOR'].default_value = 0.8
633 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.0
634 mat_P_BSDF.inputs['Alpha'].default_value = 1.0
635 # Some additional stuff for eevee.
636 material_new.blend_method = 'OPAQUE'
637 material_new.shadow_method = 'OPAQUE'
638 if material_type == '4': # Transparent + reflecting
639 material_new = bpy.data.materials.new(material.name + "_trans+refl")
640 material_new.use_nodes = True
641 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
642 if n.type == "BSDF_PRINCIPLED")
643 mat_P_BSDF.inputs['Base Color'].default_value = default_color
644 mat_P_BSDF.inputs['Metallic'].default_value = 0.5
645 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.15
646 mat_P_BSDF.inputs['Roughness'].default_value = 0.05
647 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.37
648 mat_P_BSDF.inputs['IOR'].default_value = 1.45
649 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.6
650 mat_P_BSDF.inputs['Alpha'].default_value = 0.6
651 # Some additional stuff for eevee.
652 material_new.blend_method = 'HASHED'
653 material_new.shadow_method = 'HASHED'
654 material_new.use_backface_culling = False
656 # Always, when the material is changed, a new name is created. Note that
657 # this makes sense: Imagine, an other object uses the same material as the
658 # selected one. After changing the material of the selected object the old
659 # material should certainly not change and remain the same.
660 if material_type in {'1','2','3','4'}:
661 if "_repl" in material.name:
662 pos = material.name.rfind("_repl")
663 if material.name[pos+5:].isdigit():
664 counter = int(material.name[pos+5:])
665 material_new.name = material.name[:pos]+"_repl"+str(counter+1)
666 else:
667 material_new.name = material.name+"_repl1"
668 else:
669 material_new.name = material.name+"_repl1"
670 material_new.diffuse_color = material.diffuse_color
672 return material_new
675 # Get the collection of an object.
676 def get_collection_object(obj):
678 coll_all = obj.users_collection
679 if len(coll_all) > 0:
680 coll = coll_all[0]
681 else:
682 coll = bpy.context.scene.collection
684 return coll
687 # Find the sticks of an atom.
688 def find_sticks_of_atom(atom):
690 # Initialization of the stick objects 'cylinder' and 'cup'.
691 sticks_cylinder = None
692 sticks_cup = None
694 # This is for dupliverts structures.
695 if atom.parent != None:
697 D = bpy.data
698 C = bpy.context
700 # Get a list of all scenes.
701 cols_scene = [c for c in D.collections if C.scene.user_of_id(c)]
703 # This is the collection where the atom is inside.
704 col_atom = atom.parent.users_collection[0]
706 # Get the parent collection of the latter collection.
707 col_parent = [c for c in cols_scene if c.user_of_id(col_atom)][0]
709 # Get **all** children collections inside this parent collection.
710 parent_childrens = col_parent.children_recursive
712 # This is for dupliverts stick structures now: for each child
713 # collection do:
714 for child in parent_childrens:
715 # It should not have the name of the atom collection.
716 if child.name != col_atom.name:
717 # If the sticks are inside then ...
718 if "sticks" in child.name:
719 # For all objects do ...
720 for obj in child.objects:
721 # If the stick objects are inside then note them.
722 if "sticks_cylinder" in obj.name:
723 sticks_cylinder = obj
724 if "sticks_cup" in obj.name:
725 sticks_cup = obj
727 # No dupliverts stick structures found? Then lets search for
728 # 'normal' and 'skin' sticks. Such sticks are in the collection
729 # 'Sticks' of the atomic structure.
730 if sticks_cylinder == None and sticks_cup == None:
732 # Get the grandparent collection of the parent collection.
733 col_grandparent = [c for c in cols_scene if c.user_of_id(col_parent)][0]
735 # Skin sticks:
736 list_objs = col_grandparent.objects
737 for obj in list_objs:
738 if "Sticks" in obj.name:
739 sticks_cylinder = obj
740 break
742 # Normal sticks
743 if sticks_cylinder == None:
744 # For each child collection do:
745 for child in col_grandparent.children_recursive:
746 # If the sticks are inside then ...
747 if "Sticks_cylinders" in child.name:
748 sticks_cylinder = []
749 for obj in child.objects:
750 sticks_cylinder.append(obj)
751 break
753 # Return the stick objects 'cylinder' and 'cup'.
755 # Dupliverts sticks => sticks_cylinder = 1, sticks_cup = 1
756 # Skin sticks => sticks_cylinder = 1, sticks_cup = None
757 # Normal sticks => sticks_cylinder = [n], sticks_cup = None
758 return sticks_cylinder, sticks_cup
761 # Draw an object (e.g. cube, sphere, cylinder, ...)
762 def draw_obj(atom_shape, atom, new_material):
764 # No change
765 if atom_shape == '0':
766 return None
768 if atom_shape == '1a': #Sphere mesh
769 bpy.ops.mesh.primitive_uv_sphere_add(
770 segments=32,
771 ring_count=32,
772 radius=1,
773 align='WORLD',
774 enter_editmode=False,
775 location=atom.location,
776 rotation=(0, 0, 0))
777 if atom_shape == '1b': #Sphere NURBS
778 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
779 align='WORLD',
780 enter_editmode=False,
781 location=atom.location,
782 rotation=(0.0, 0.0, 0.0))
783 if atom_shape == '2': #Cube
784 bpy.ops.mesh.primitive_cube_add(
785 align='WORLD',
786 enter_editmode=False,
787 location=atom.location,
788 rotation=(0.0, 0.0, 0.0))
789 if atom_shape == '3': #Plane
790 bpy.ops.mesh.primitive_plane_add(
791 align='WORLD',
792 enter_editmode=False,
793 location=atom.location,
794 rotation=(0.0, 0.0, 0.0))
795 if atom_shape == '4a': #Circle
796 bpy.ops.mesh.primitive_circle_add(
797 vertices=32,
798 radius=1,
799 fill_type='NOTHING',
800 align='WORLD',
801 enter_editmode=False,
802 location=atom.location,
803 rotation=(0, 0, 0))
804 if atom_shape == '4b': #Circle NURBS
805 bpy.ops.surface.primitive_nurbs_surface_circle_add(
806 align='WORLD',
807 enter_editmode=False,
808 location=atom.location,
809 rotation=(0, 0, 0))
810 if atom_shape in {'5a','5b','5c','5d','5e'}: #Icosphere
811 index = {'5a':1,'5b':2,'5c':3,'5d':4,'5e':5}
812 bpy.ops.mesh.primitive_ico_sphere_add(
813 subdivisions=int(index[atom_shape]),
814 radius=1,
815 align='WORLD',
816 enter_editmode=False,
817 location=atom.location,
818 rotation=(0, 0, 0))
819 if atom_shape == '6a': #Cylinder
820 bpy.ops.mesh.primitive_cylinder_add(
821 vertices=32,
822 radius=1,
823 depth=2,
824 end_fill_type='NGON',
825 align='WORLD',
826 enter_editmode=False,
827 location=atom.location,
828 rotation=(0, 0, 0))
829 if atom_shape == '6b': #Cylinder NURBS
830 bpy.ops.surface.primitive_nurbs_surface_cylinder_add(
831 align='WORLD',
832 enter_editmode=False,
833 location=atom.location,
834 rotation=(0, 0, 0))
835 if atom_shape == '7': #Cone
836 bpy.ops.mesh.primitive_cone_add(
837 vertices=32,
838 radius1=1,
839 radius2=0,
840 depth=2,
841 end_fill_type='NGON',
842 align='WORLD',
843 enter_editmode=False,
844 location=atom.location,
845 rotation=(0, 0, 0))
846 if atom_shape == '8a': #Torus
847 bpy.ops.mesh.primitive_torus_add(
848 rotation=(0, 0, 0),
849 location=atom.location,
850 align='WORLD',
851 major_radius=1,
852 minor_radius=0.25,
853 major_segments=48,
854 minor_segments=12,
855 abso_major_rad=1,
856 abso_minor_rad=0.5)
857 if atom_shape == '8b': #Torus NURBS
858 bpy.ops.surface.primitive_nurbs_surface_torus_add(
859 align='WORLD',
860 enter_editmode=False,
861 location=atom.location,
862 rotation=(0, 0, 0))
864 new_atom = bpy.context.view_layer.objects.active
865 new_atom.scale = atom.scale + Vector((0.0,0.0,0.0))
866 new_atom.name = atom.name
867 new_atom.select_set(True)
869 new_atom.active_material = new_material
871 # If it is the representative object of a duplivert structure then
872 # transfer the parent and hide the new object.
873 if atom.parent != None:
874 new_atom.parent = atom.parent
875 new_atom.hide_set(True)
877 # Note the collection where the old object was placed into.
878 coll_old_atom = get_collection_object(atom)
880 # Note the collection where the new object was placed into.
881 coll_new_atom_past = get_collection_object(new_atom)
883 # If it is not the same collection then ...
884 if coll_new_atom_past != coll_old_atom:
885 # Put the new object into the collection of the old object and ...
886 coll_old_atom.objects.link(new_atom)
887 # ... unlink the new atom from its original collection.
888 coll_new_atom_past.objects.unlink(new_atom)
890 # If necessary, remove the childrens of the old object.
891 for child in atom.children:
892 bpy.ops.object.select_all(action='DESELECT')
893 child.hide_set(True)
894 child.select_set(True)
895 child.parent = None
896 coll_child = get_collection_object(child)
897 coll_child.objects.unlink(child)
898 bpy.ops.object.delete()
900 # Deselect everything
901 bpy.ops.object.select_all(action='DESELECT')
902 # Make the old atom visible.
903 atom.hide_set(True)
904 # Select the old atom.
905 atom.select_set(True)
906 # Remove the parent if necessary.
907 atom.parent = None
908 # Unlink the old object from the collection.
909 coll_old_atom.objects.unlink(atom)
910 # Delete the old atom
911 bpy.ops.object.delete()
913 #if "_F2+_center" or "_F+_center" or "_F0_center" in coll_old_atom:
914 # print("Delete the collection")
916 return new_atom
919 # Draw a special object (e.g. halo, etc. ...)
920 def draw_obj_special(atom_shape, atom):
922 # Note the collection where 'atom' is placed into.
923 coll_atom = get_collection_object(atom)
925 # Now, create a collection for the new objects
926 coll_new = atom.name
927 # Create the new collection and ...
928 coll_new = bpy.data.collections.new(coll_new)
929 # ... link it to the collection, which contains 'atom'.
930 coll_atom.children.link(coll_new)
932 # Get the color of the selected atom.
933 material = atom.active_material
934 mat_P_BSDF_default = next(n for n in material.node_tree.nodes
935 if n.type == "BSDF_PRINCIPLED")
936 default_color = mat_P_BSDF_default.inputs['Base Color'].default_value
938 # Create first a cube
939 bpy.ops.mesh.primitive_cube_add(align='WORLD',
940 enter_editmode=False,
941 location=atom.location,
942 rotation=(0.0, 0.0, 0.0))
943 cube = bpy.context.view_layer.objects.active
944 cube.scale = atom.scale + Vector((0.0,0.0,0.0))
945 cube.select_set(True)
947 # F2+ center
948 if atom_shape == '1':
949 cube.name = atom.name + "_F2+_vac"
951 # New material for this cube
952 material_new = bpy.data.materials.new(atom.name + "_F2+_vac")
953 material_new.use_nodes = True
954 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
955 if n.type == "BSDF_PRINCIPLED")
956 mat_P_BSDF.inputs['Base Color'].default_value = default_color
957 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
958 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.0
959 mat_P_BSDF.inputs['Roughness'].default_value = 0.65
960 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.0
961 mat_P_BSDF.inputs['IOR'].default_value = 1.45
962 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.6
963 mat_P_BSDF.inputs['Alpha'].default_value = 0.6
964 # Some additional stuff for eevee.
965 material_new.blend_method = 'HASHED'
966 material_new.shadow_method = 'HASHED'
967 material_new.use_backface_culling = False
968 cube.active_material = material_new
970 # Put a point lamp inside the defect.
971 lamp_data = bpy.data.lights.new(name=atom.name + "_F2+_lamp", type="POINT")
972 lamp_data.distance = atom.scale[0] * 2.0
973 lamp_data.energy = 2000.0
974 lamp_data.color = (0.8, 0.8, 0.8)
975 lamp = bpy.data.objects.new(atom.name + "_F2+_lamp", lamp_data)
976 lamp.location = Vector((0.0, 0.0, 0.0))
977 bpy.context.collection.objects.link(lamp)
978 lamp.parent = cube
980 # The new 'atom' is the F2+ defect
981 new_atom = cube
983 # Note the collection where all the new objects were placed into.
984 # We use only one object, the cube
985 coll_ori = get_collection_object(cube)
987 # If it is not the same collection then ...
988 if coll_ori != coll_new:
989 # Put all new objects into the new collection and ...
990 coll_new.objects.link(cube)
991 coll_new.objects.link(lamp)
992 # ... unlink them from their original collection.
993 coll_ori.objects.unlink(cube)
994 coll_ori.objects.unlink(lamp)
996 coll_new.name = atom.name + "_F2+_center"
998 if atom.parent != None:
999 cube.parent = atom.parent
1000 cube.hide_set(True)
1001 lamp.hide_set(True)
1003 # F+ center
1004 if atom_shape == '2':
1005 cube.name = atom.name + "_F2+_vac"
1007 # New material for this cube
1008 material_new = bpy.data.materials.new(atom.name + "_F2+_vac")
1009 material_new.use_nodes = True
1010 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
1011 if n.type == "BSDF_PRINCIPLED")
1012 mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0]
1013 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
1014 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.0
1015 mat_P_BSDF.inputs['Roughness'].default_value = 0.65
1016 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.0
1017 mat_P_BSDF.inputs['IOR'].default_value = 1.45
1018 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.6
1019 mat_P_BSDF.inputs['Alpha'].default_value = 0.6
1020 # Some additional stuff for eevee.
1021 material_new.blend_method = 'HASHED'
1022 material_new.shadow_method = 'HASHED'
1023 material_new.use_backface_culling = False
1024 cube.active_material = material_new
1026 # Create now an electron
1027 scale = atom.scale / 10.0
1028 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
1029 align='WORLD',
1030 enter_editmode=False,
1031 location=(0.0, 0.0, 0.0),
1032 rotation=(0.0, 0.0, 0.0))
1033 electron = bpy.context.view_layer.objects.active
1034 electron.scale = scale
1035 electron.name = atom.name + "_F+_electron"
1036 electron.parent = cube
1037 # New material for the electron
1038 material_electron = bpy.data.materials.new(atom.name + "_F+-center")
1039 material_electron.use_nodes = True
1040 mat_P_BSDF = next(n for n in material_electron.node_tree.nodes
1041 if n.type == "BSDF_PRINCIPLED")
1042 mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0]
1043 mat_P_BSDF.inputs['Metallic'].default_value = 0.8
1044 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.0
1045 mat_P_BSDF.inputs['Roughness'].default_value = 0.3
1046 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.0
1047 mat_P_BSDF.inputs['IOR'].default_value = 1.45
1048 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.6
1049 mat_P_BSDF.inputs['Alpha'].default_value = 1.0
1050 # Some additional stuff for eevee.
1051 material_electron.blend_method = 'OPAQUE'
1052 material_electron.shadow_method = 'OPAQUE'
1053 material_electron.use_backface_culling = False
1054 electron.active_material = material_electron
1056 # Put a point lamp inside the electron
1057 lamp_data = bpy.data.lights.new(name=atom.name + "_F+_lamp", type="POINT")
1058 lamp_data.distance = atom.scale[0] * 2.0
1059 lamp_data.energy = 100000.0
1060 lamp_data.color = (0.0, 0.0, 0.8)
1061 lamp = bpy.data.objects.new(atom.name + "_F+_lamp", lamp_data)
1062 lamp.location = Vector((scale[0]*1.5, 0.0, 0.0))
1063 bpy.context.collection.objects.link(lamp)
1064 lamp.parent = cube
1066 # The new 'atom' is the F+ defect complex + lamp
1067 new_atom = cube
1069 # Note the collection where all the new objects were placed into.
1070 # We use only one object, the cube
1071 coll_ori = get_collection_object(cube)
1073 # If it is not the same collection then ...
1074 if coll_ori != coll_new:
1075 # Put all new objects into the new collection and ...
1076 coll_new.objects.link(cube)
1077 coll_new.objects.link(electron)
1078 coll_new.objects.link(lamp)
1079 # ... unlink them from their original collection.
1080 coll_ori.objects.unlink(cube)
1081 coll_ori.objects.unlink(electron)
1082 coll_ori.objects.unlink(lamp)
1084 coll_new.name = atom.name + "_F+_center"
1086 if atom.parent != None:
1087 cube.parent = atom.parent
1088 cube.hide_set(True)
1089 electron.hide_set(True)
1090 lamp.hide_set(True)
1092 # F0 center
1093 if atom_shape == '3':
1094 cube.name = atom.name + "_F2+_vac"
1096 # New material for this cube
1097 material_new = bpy.data.materials.new(atom.name + "_F2+_vac")
1098 material_new.use_nodes = True
1099 mat_P_BSDF = next(n for n in material_new.node_tree.nodes
1100 if n.type == "BSDF_PRINCIPLED")
1101 mat_P_BSDF.inputs['Base Color'].default_value = [0.8, 0.0, 0.0, 1.0]
1102 mat_P_BSDF.inputs['Metallic'].default_value = 0.7
1103 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.0
1104 mat_P_BSDF.inputs['Roughness'].default_value = 0.65
1105 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.0
1106 mat_P_BSDF.inputs['IOR'].default_value = 1.45
1107 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.6
1108 mat_P_BSDF.inputs['Alpha'].default_value = 0.6
1109 # Some additional stuff for eevee.
1110 material_new.blend_method = 'HASHED'
1111 material_new.shadow_method = 'HASHED'
1112 material_new.use_backface_culling = False
1113 cube.active_material = material_new
1115 # Create now two electrons ... .
1116 scale = atom.scale / 10.0
1117 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
1118 align='WORLD',
1119 enter_editmode=False,
1120 location=(scale[0]*1.5,0.0,0.0),
1121 rotation=(0.0, 0.0, 0.0))
1122 electron1 = bpy.context.view_layer.objects.active
1123 electron1.scale = scale
1124 electron1.name = atom.name + "_F0_electron_1"
1125 electron1.parent = cube
1126 bpy.ops.surface.primitive_nurbs_surface_sphere_add(
1127 align='WORLD',
1128 enter_editmode=False,
1129 location=(-scale[0]*1.5,0.0,0.0),
1130 rotation=(0.0, 0.0, 0.0))
1131 electron2 = bpy.context.view_layer.objects.active
1132 electron2.scale = scale
1133 electron2.name = atom.name + "_F0_electron_2"
1134 electron2.parent = cube
1135 # Create a new material for the two electrons.
1136 material_electron = bpy.data.materials.new(atom.name + "_F0-center")
1137 material_electron.use_nodes = True
1138 mat_P_BSDF = next(n for n in material_electron.node_tree.nodes
1139 if n.type == "BSDF_PRINCIPLED")
1140 mat_P_BSDF.inputs['Base Color'].default_value = [0.0, 0.0, 0.8, 1.0]
1141 mat_P_BSDF.inputs['Metallic'].default_value = 0.8
1142 mat_P_BSDF.inputs['Specular IOR Level'].default_value = 0.0
1143 mat_P_BSDF.inputs['Roughness'].default_value = 0.3
1144 mat_P_BSDF.inputs['Coat Roughness'].default_value = 0.0
1145 mat_P_BSDF.inputs['IOR'].default_value = 1.45
1146 mat_P_BSDF.inputs['Transmission Weight'].default_value = 0.6
1147 mat_P_BSDF.inputs['Alpha'].default_value = 1.0
1148 # Some additional stuff for eevee.
1149 material_electron.blend_method = 'OPAQUE'
1150 material_electron.shadow_method = 'OPAQUE'
1151 material_electron.use_backface_culling = False
1152 # We assign the materials to the two electrons.
1153 electron1.active_material = material_electron
1154 electron2.active_material = material_electron
1156 # Put two point lamps inside the electrons.
1157 lamp1_data = bpy.data.lights.new(name=atom.name + "_F0_lamp_1", type="POINT")
1158 lamp1_data.distance = atom.scale[0] * 2.0
1159 lamp1_data.energy = 20000.0
1160 lamp1_data.color = (0.8, 0.0, 0.0)
1161 lamp1 = bpy.data.objects.new(atom.name + "_F0_lamp", lamp1_data)
1162 lamp1.location = Vector((scale[0]*1.5, 0.0, 0.0))
1163 bpy.context.collection.objects.link(lamp1)
1164 lamp1.parent = cube
1165 lamp2_data = bpy.data.lights.new(name=atom.name + "_F0_lamp_2", type="POINT")
1166 lamp2_data.distance = atom.scale[0] * 2.0
1167 lamp2_data.energy = 20000.0
1168 lamp2_data.color = (0.8, 0.0, 0.0)
1169 lamp2 = bpy.data.objects.new(atom.name + "_F0_lamp", lamp2_data)
1170 lamp2.location = Vector((-scale[0]*1.5, 0.0, 0.0))
1171 bpy.context.collection.objects.link(lamp2)
1172 lamp2.parent = cube
1174 # The new 'atom' is the F0 defect complex + lamps
1175 new_atom = cube
1177 # Note the collection where all the new objects were placed into.
1178 # We use only one object, the cube
1179 coll_ori = get_collection_object(cube)
1181 # If it is not the same collection then ...
1182 if coll_ori != coll_new:
1183 # Put all new objects into the collection of 'atom' and ...
1184 coll_new.objects.link(cube)
1185 coll_new.objects.link(electron1)
1186 coll_new.objects.link(electron2)
1187 coll_new.objects.link(lamp1)
1188 coll_new.objects.link(lamp2)
1189 # ... unlink them from their original collection.
1190 coll_ori.objects.unlink(cube)
1191 coll_ori.objects.unlink(electron1)
1192 coll_ori.objects.unlink(electron2)
1193 coll_ori.objects.unlink(lamp1)
1194 coll_ori.objects.unlink(lamp2)
1196 coll_new.name = atom.name + "_F0_center"
1198 if atom.parent != None:
1199 cube.parent = atom.parent
1200 cube.hide_set(True)
1201 electron1.hide_set(True)
1202 electron2.hide_set(True)
1203 lamp1.hide_set(True)
1204 lamp2.hide_set(True)
1206 # Deselect everything
1207 bpy.ops.object.select_all(action='DESELECT')
1208 # Make the old atom visible.
1209 atom.hide_set(True)
1210 # Select the old atom.
1211 atom.select_set(True)
1212 # Remove the parent if necessary.
1213 atom.parent = None
1214 # Unlink the old object from the collection.
1215 coll_atom.objects.unlink(atom)
1216 # Delete the old atom
1217 bpy.ops.object.delete()
1219 return new_atom
1222 # Initialization of the list 'ELEMENTS'.
1223 def read_elements():
1225 del ELEMENTS[:]
1227 for item in ELEMENTS_DEFAULT:
1229 # All three radii into a list
1230 radii = [item[4],item[5],item[6]]
1231 # The handling of the ionic radii will be done later. So far, it is an
1232 # empty list.
1233 radii_ionic = item[7:]
1235 li = ElementProp(item[0], item[1], item[2], item[3], radii, radii_ionic, [], [])
1237 ELEMENTS.append(li)
1240 # Custom data file: changing color and radii by using the list 'ELEMENTS'.
1241 def custom_datafile_change_atom_props():
1243 for atom in bpy.context.selected_objects:
1245 FLAG = False
1246 if len(atom.children) != 0:
1247 child = atom.children[0]
1248 if child.type in {'SURFACE', 'MESH', 'META'}:
1249 for element in ELEMENTS:
1250 if element.name in atom.name:
1251 obj = child
1252 e = element
1253 FLAG = True
1254 else:
1255 if atom.type in {'SURFACE', 'MESH', 'META'}:
1256 for element in ELEMENTS:
1257 if element.name in atom.name:
1258 obj = atom
1259 e = element
1260 FLAG = True
1262 if FLAG:
1263 obj.scale = (e.radii[0],) * 3
1264 mat = obj.active_material
1265 mat_P_BSDF = next(n for n in mat.node_tree.nodes
1266 if n.type == "BSDF_PRINCIPLED")
1268 mat_P_BSDF.inputs['Base Color'].default_value = e.color
1269 mat_P_BSDF.subsurface_method = e.mat_P_BSDF.Subsurface_method
1270 mat_P_BSDF.distribution = e.mat_P_BSDF.Distribution
1271 mat_P_BSDF.inputs['Subsurface Weight'].default_value = e.mat_P_BSDF.Subsurface_weight
1272 mat_P_BSDF.inputs['Subsurface Radius'].default_value = e.mat_P_BSDF.Subsurface_radius
1273 mat_P_BSDF.inputs['Metallic'].default_value = e.mat_P_BSDF.Metallic
1274 mat_P_BSDF.inputs['Specular IOR Level'].default_value = e.mat_P_BSDF.Specular_ior_level
1275 mat_P_BSDF.inputs['Specular Tint'].default_value = e.mat_P_BSDF.Specular_tint
1276 mat_P_BSDF.inputs['Roughness'].default_value = e.mat_P_BSDF.Roughness
1277 mat_P_BSDF.inputs['Anisotropic'].default_value = e.mat_P_BSDF.Anisotropic
1278 mat_P_BSDF.inputs['Anisotropic Rotation'].default_value = e.mat_P_BSDF.Anisotropic_rotation
1279 mat_P_BSDF.inputs['Sheen Weight'].default_value = e.mat_P_BSDF.Sheen_weight
1280 mat_P_BSDF.inputs['Sheen Tint'].default_value = e.mat_P_BSDF.Sheen_tint
1281 mat_P_BSDF.inputs['Coat Weight'].default_value = e.mat_P_BSDF.Coat_weight
1282 mat_P_BSDF.inputs['Coat Roughness'].default_value = e.mat_P_BSDF.Coat_roughness
1283 mat_P_BSDF.inputs['IOR'].default_value = e.mat_P_BSDF.IOR
1284 mat_P_BSDF.inputs['Transmission Weight'].default_value = e.mat_P_BSDF.Transmission_weight
1285 mat_P_BSDF.inputs['Emission'].default_value = e.mat_P_BSDF.Emission
1286 mat_P_BSDF.inputs['Emission Strength'].default_value = e.mat_P_BSDF.Emission_strength
1287 mat_P_BSDF.inputs['Alpha'].default_value = e.mat_P_BSDF.Alpha
1289 mat.use_backface_culling = e.mat_Eevee.use_backface
1290 mat.blend_method = e.mat_Eevee.blend_method
1291 mat.shadow_method = e.mat_Eevee.shadow_method
1292 mat.alpha_threshold = e.mat_Eevee.clip_threshold
1293 mat.use_screen_refraction = e.mat_Eevee.use_screen_refraction
1294 mat.refraction_depth = e.mat_Eevee.refraction_depth
1295 mat.use_sss_translucency = e.mat_Eevee.use_sss_translucency
1296 mat.pass_index = e.mat_Eevee.pass_index
1298 FLAG = False
1300 bpy.ops.object.select_all(action='DESELECT')
1303 # Reading a custom data file and modifying the list 'ELEMENTS'.
1304 def custom_datafile(path_datafile):
1306 if path_datafile == "":
1307 return False
1309 path_datafile = bpy.path.abspath(path_datafile)
1311 if os.path.isfile(path_datafile) == False:
1312 return False
1314 # The whole list gets deleted! We build it new.
1315 del ELEMENTS[:]
1317 # Read the data file, which contains all data
1318 # (atom name, radii, colors, etc.)
1319 data_file_p = open(path_datafile, "r")
1321 for line in data_file_p:
1323 if "#" == line[0]:
1324 continue
1326 if "Atom" in line:
1328 list_radii_ionic = []
1329 while True:
1331 if len(line) in [0,1]:
1332 break
1334 # Number
1335 if "Number :" in line:
1336 pos = line.rfind(':') + 1
1337 number = line[pos:].strip()
1338 # Name
1339 if "Name :" in line:
1340 pos = line.rfind(':') + 1
1341 name = line[pos:].strip()
1342 # Short name
1343 if "Short name :" in line:
1344 pos = line.rfind(':') + 1
1345 short_name = line[pos:].strip()
1346 # Color
1347 if "Color :" in line:
1348 pos = line.rfind(':') + 1
1349 color_value = line[pos:].strip().split(',')
1350 color = [float(color_value[0]),
1351 float(color_value[1]),
1352 float(color_value[2]),
1353 float(color_value[3])]
1354 # Used radius
1355 if "Radius used :" in line:
1356 pos = line.rfind(':') + 1
1357 radius_used = float(line[pos:].strip())
1358 # Covalent radius
1359 if "Radius, covalent :" in line:
1360 pos = line.rfind(':') + 1
1361 radius_covalent = float(line[pos:].strip())
1362 # Atomic radius
1363 if "Radius, atomic :" in line:
1364 pos = line.rfind(':') + 1
1365 radius_atomic = float(line[pos:].strip())
1366 if "Charge state :" in line:
1367 pos = line.rfind(':') + 1
1368 charge_state = float(line[pos:].strip())
1369 line = data_file_p.readline()
1370 pos = line.rfind(':') + 1
1371 radius_ionic = float(line[pos:].strip())
1372 list_radii_ionic.append(charge_state)
1373 list_radii_ionic.append(radius_ionic)
1375 # Some Principled BSDF properties
1378 if "P BSDF Subsurface method :" in line:
1379 pos = line.rfind(':') + 1
1380 P_BSDF_subsurface_method = line[pos:].strip()
1381 if "P BSDF Distribution :" in line:
1382 pos = line.rfind(':') + 1
1383 P_BSDF_distribution = line[pos:].strip()
1384 if "P BSDF Subsurface Weight :" in line:
1385 pos = line.rfind(':') + 1
1386 P_BSDF_subsurface_weight = float(line[pos:].strip())
1387 if "P BSDF Subsurface Radius :" in line:
1388 pos = line.rfind(':') + 1
1389 radii_values = line[pos:].strip().split(',')
1390 P_BSDF_subsurface_radius = [float(color_value[0]),
1391 float(color_value[1]),
1392 float(color_value[2])]
1393 if "P BSDF Metallic :" in line:
1394 pos = line.rfind(':') + 1
1395 P_BSDF_metallic = float(line[pos:].strip())
1396 if "P BSDF Specular IOR Level :" in line:
1397 pos = line.rfind(':') + 1
1398 P_BSDF_specular_ior_level = float(line[pos:].strip())
1399 if "P BSDF Specular Tint :" in line:
1400 pos = line.rfind(':') + 1
1401 color_value = line[pos:].strip().split(',')
1402 P_BSDF_specular_tint = [float(color_value[0]),
1403 float(color_value[1]),
1404 float(color_value[2]),
1405 float(color_value[3])]
1406 if "P BSDF Roughness :" in line:
1407 pos = line.rfind(':') + 1
1408 P_BSDF_roughness = float(line[pos:].strip())
1409 if "P BSDF Anisotropic :" in line:
1410 pos = line.rfind(':') + 1
1411 P_BSDF_anisotropic = float(line[pos:].strip())
1412 if "P BSDF Anisotropic Rotation :" in line:
1413 pos = line.rfind(':') + 1
1414 P_BSDF_anisotropic_rotation = float(line[pos:].strip())
1415 if "P BSDF Sheen Weight : " in line:
1416 pos = line.rfind(':') + 1
1417 P_BSDF_sheen_weight = float(line[pos:].strip())
1418 if "P BSDF Sheen Tint : " in line:
1419 pos = line.rfind(':') + 1
1420 P_BSDF_sheen_tint = float(line[pos:].strip())
1421 if "P BSDF Coat Weight :" in line:
1422 pos = line.rfind(':') + 1
1423 P_BSDF_coat_weight = float(line[pos:].strip())
1424 if "P BSDF Coat Roughness :" in line:
1425 pos = line.rfind(':') + 1
1426 P_BSDF_coat_roughness = float(line[pos:].strip())
1427 if "P BSDF IOR :" in line:
1428 pos = line.rfind(':') + 1
1429 P_BSDF_IOR = float(line[pos:].strip())
1430 if "P BSDF Transmission Weight :" in line:
1431 pos = line.rfind(':') + 1
1432 P_BSDF_transmission_weight = float(line[pos:].strip())
1433 if "P BSDF Emisssion : " in line:
1434 pos = line.rfind(':') + 1
1435 color_value = line[pos:].strip().split(',')
1436 P_BSDF_emission = [float(color_value[0]),
1437 float(color_value[1]),
1438 float(color_value[2]),
1439 float(color_value[3])]
1440 if "P BSDF Emission Strength :" in line:
1441 pos = line.rfind(':') + 1
1442 P_BSDF_emission_strength = float(line[pos:].strip())
1443 if "P BSDF Alpha :" in line:
1444 pos = line.rfind(':') + 1
1445 P_BSDF_alpha = float(line[pos:].strip())
1447 if "Eevee Use Backface Culling :" in line:
1448 pos = line.rfind(':') + 1
1449 line = line[pos:].strip()
1450 if line.lower() in ("yes", "true", "1"):
1451 Eevee_use_backface = True
1452 else:
1453 Eevee_use_backface = False
1454 if "Eevee Blend Method :" in line:
1455 pos = line.rfind(':') + 1
1456 Eevee_blend_method = line[pos:].strip()
1457 if "Eevee Shadow Method :" in line:
1458 pos = line.rfind(':') + 1
1459 Eevee_shadow_method = line[pos:].strip()
1460 if "Eevee Clip Threshold :" in line:
1461 pos = line.rfind(':') + 1
1462 Eevee_clip_threshold = float(line[pos:].strip())
1463 if "Eevee Use Screen Refraction :" in line:
1464 pos = line.rfind(':') + 1
1465 line = line[pos:].strip()
1466 if line.lower() in ("yes", "true", "1"):
1467 Eevee_use_screen_refraction = True
1468 else:
1469 Eevee_use_screen_refraction = False
1470 if "Eevee Refraction depth : " in line:
1471 pos = line.rfind(':') + 1
1472 Eevee_refraction_depth = float(line[pos:].strip())
1473 if "Eevee Use SSS Translucency :" in line:
1474 pos = line.rfind(':') + 1
1475 line = line[pos:].strip()
1476 if line.lower() in ("yes", "true", "1"):
1477 Eevee_use_sss_translucency = True
1478 else:
1479 Eevee_use_sss_translucency = False
1480 if "Eevee Pass Index :" in line:
1481 pos = line.rfind(':') + 1
1482 Eevee_pass_index = int(line[pos:].strip())
1485 line = data_file_p.readline()
1487 list_radii = [radius_used, radius_covalent, radius_atomic]
1489 Eevee_material = EeveeProp(Eevee_use_backface,
1490 Eevee_blend_method,
1491 Eevee_shadow_method,
1492 Eevee_clip_threshold,
1493 Eevee_use_screen_refraction,
1494 Eevee_refraction_depth,
1495 Eevee_use_sss_translucency,
1496 Eevee_pass_index)
1498 P_BSDF_material = PBSDFProp(P_BSDF_subsurface_method,
1499 P_BSDF_distribution,
1500 P_BSDF_subsurface_weight,
1501 P_BSDF_subsurface_radius,
1502 P_BSDF_metallic,
1503 P_BSDF_specular_ior_level,
1504 P_BSDF_specular_tint,
1505 P_BSDF_roughness,
1506 P_BSDF_anisotropic,
1507 P_BSDF_anisotropic_rotation,
1508 P_BSDF_sheen_weight,
1509 P_BSDF_sheen_tint,
1510 P_BSDF_coat_weight,
1511 P_BSDF_coat_roughness,
1512 P_BSDF_IOR,
1513 P_BSDF_transmission_weight,
1514 P_BSDF_emission,
1515 P_BSDF_emission_strength,
1516 P_BSDF_alpha)
1518 element = ElementProp(number,
1519 name,
1520 short_name,
1521 color,
1522 list_radii,
1523 list_radii_ionic,
1524 P_BSDF_material,
1525 Eevee_material)
1527 ELEMENTS.append(element)
1529 data_file_p.close()
1531 return True