diff options
Diffstat (limited to 'geometry.py')
-rw-r--r-- | geometry.py | 158 |
1 files changed, 141 insertions, 17 deletions
diff --git a/geometry.py b/geometry.py index 5cd1bf2..be31e4b 100644 --- a/geometry.py +++ b/geometry.py @@ -1,9 +1,117 @@ import numpy as np -import numpy.ma as ma import pycuda.driver as cuda from pycuda import gpuarray -from mesh import Mesh -from materials import standard_wavelengths + +# all material/surface properties are interpolated at these +# wavelengths when they are sent to the gpu +standard_wavelengths = np.arange(200, 810, 20).astype(np.float32) + +class Mesh(object): + def __init__(self, vertices, triangles): + vertices = np.asarray(vertices, dtype=np.float32) + triangles = np.asarray(triangles, dtype=np.int32) + + if len(vertices.shape) != 2 or vertices.shape[1] != 3: + raise ValueError('shape mismatch') + + if len(triangles.shape) != 2 or triangles.shape[1] != 3: + raise ValueError('shape mismatch') + + if (triangles < 0).any(): + raise ValueError('indices in `triangles` must be positive.') + + if (triangles >= len(vertices)).any(): + raise ValueError('indices in `triangles` must be less than the ' + 'length of the vertex array.') + + self.vertices = vertices + self.triangles = triangles + + def build(self): + return self.vertices[self.triangles] + + def __getitem__(self, key): + return self.vertices[self.triangles[key]] + + def __len__(self): + return len(self.triangles) + + def __add__(self, other): + return Mesh(np.concatenate((self.vertices, other.vertices)), np.concatenate((self.triangles, other.triangles + len(self.vertices)))) + +class Solid(object): + def __init__(self, mesh, material1=None, material2=None, surface=None, color=0xffffffff): + self.mesh = mesh + + if np.iterable(material1): + if len(material1) != len(mesh): + raise ValueError('shape mismatch') + self.material1 = np.array(material1, dtype=np.object) + else: + self.material1 = np.tile(material1, len(self.mesh)) + + if np.iterable(material2): + if len(material2) != len(mesh): + raise ValueError('shape mismatch') + self.material2 = np.array(material2, dtype=np.object) + else: + self.material2 = np.tile(material2, len(self.mesh)) + + if np.iterable(surface): + if len(surface) != len(mesh): + raise ValueError('shape mismatch') + self.surface = np.array(surface, dtype=np.object) + else: + self.surface = np.tile(surface, len(self.mesh)) + + if np.iterable(color): + if len(color) != len(mesh): + raise ValueError('shape mismatch') + self.color = np.array(color, dtype=np.uint32) + else: + self.color = np.tile(color, len(self.mesh)).astype(np.uint32) + + def __len__(self): + return len(self.mesh) + + def __add__(self, other): + return Solid(self.mesh + other.mesh, np.concatenate((self.material1, other.material1)), np.concatenate((self.material2, other.material2)), np.concatenate((self.surface, other.surface)), np.concatenate((self.color, other.color))) + +class Material(object): + """Material optical properties.""" + def __init__(self, name='none'): + self.name = name + + self.refractive_index = None + self.absorption_length = None + self.scattering_length = None + + def set(self, name, value, wavelengths=standard_wavelengths): + if np.iterable(value): + if len(value) != len(wavelengths): + raise ValueError('shape mismatch') + else: + value = np.tile(value, len(wavelengths)) + + self.__dict__[name] = np.array(zip(wavelengths, value), dtype=np.float32) + +class Surface(object): + """Surface optical properties.""" + def __init__(self, name='none'): + self.name = name + + self.absorption = None + self.reflection_diffuse = None + self.reflection_specular = None + + def set(self, name, value, wavelengths=standard_wavelengths): + if np.iterable(value): + if len(value) != len(wavelengths): + raise ValueError('shape mismatch') + else: + value = np.tile(value, len(wavelengths)) + + self.__dict__[name] = np.array(zip(wavelengths, value), dtype=np.float32) def interleave(arr, bits): """ @@ -51,15 +159,30 @@ def morton_order(mesh, bits): return interleave(mean_positions, bits) class Geometry(object): - def __init__(self, solids=None): - if solids is not None: - self.solids = list(solids) - else: - self.solids = [] + def __init__(self): + self.solids = [] + self.solid_rotations = [] + self.solid_displacements = [] + + def add_solid(self, solid, rotation=np.identity(3), displacement=(0,0,0)): + rotation = np.asarray(rotation, dtype=np.float32) + + if rotation.shape != (3,3): + raise ValueError('shape mismatch') + + self.solid_rotations.append(rotation.astype(np.float32)) + + displacement = np.asarray(displacement, dtype=np.float32) + + if displacement.shape != (3,): + raise ValueError('shape mismatch') + + self.solid_displacements.append(displacement) - def add_solid(self, solid): self.solids.append(solid) + return len(self.solids)-1 + def build(self, bits=8): offsets = [ (0,0) ] for solid in self.solids: @@ -69,15 +192,14 @@ class Geometry(object): vertices = np.zeros(shape=(offsets[-1][0], 3), dtype=np.float32) triangles = np.zeros(shape=(offsets[-1][1],3), dtype=np.int32) - for solid, (vertex_offset, triangle_offset) in zip(self.solids, offsets[:-1]): + for i, (solid, (vertex_offset, triangle_offset)) in \ + enumerate(zip(self.solids, offsets[:-1])): triangles[triangle_offset:triangle_offset+len(solid.mesh.triangles),:] = \ solid.mesh.triangles + vertex_offset - vertices[vertex_offset:vertex_offset + len(solid.mesh.vertices),:] = \ - np.inner(solid.mesh.vertices, solid.rotation) + solid.displacement + vertices[vertex_offset:vertex_offset+len(solid.mesh.vertices),:] = \ + np.inner(solid.mesh.vertices, self.solid_rotations[i]) + self.solid_displacements[i] self.mesh = Mesh(vertices, triangles) - #del vertices - #del triangles zvalues_mesh = morton_order(self.mesh[:], bits) reorder = np.argsort(zvalues_mesh) @@ -121,10 +243,12 @@ class Geometry(object): else: self.surface_index[i] = -1 - self.colors = np.concatenate([solid.color for solid in self.solids])[reorder] + self.colors = \ + np.concatenate([solid.color for solid in self.solids])[reorder] - self.solid_id = np.concatenate([np.tile(solid.id, len(solid.mesh)) \ - for solid in self.solids])[reorder] + self.solid_id = \ + np.concatenate([np.tile(i, len(solid.mesh)) for i, solid in \ + enumerate(self.solids)])[reorder] unique_zvalues = np.unique(zvalues_mesh) zvalues = np.empty(unique_zvalues.size, dtype=np.uint64) |