def generate_octahedra(): view = create_lookat(eye=[-15, -60, 120], target=[0, 0, 0], up=[0, 1, 0]) projection = create_perspective(fovy=15, aspect=1, near=10, far=200) camera = svg3d.Camera(view, projection) verts, faces = icosahedron() verts, faces = np.float32(verts), np.uint32(faces) faces = 15 * verts[faces] centroids = [] for face in faces: centroid = np.float32([0, 0, 0]) for vert in face: centroid += vert centroid /= len(face) centroids.append(centroid) centroids = np.float32([centroids]) point_style = dict(fill="black", fill_opacity="0.75", stroke="none") poly_style = dict( fill="#f0f0f0", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.01", ) left_viewport = svg3d.Viewport.from_string("-1.0 -0.5 1.0 1.0") right_viewport = svg3d.Viewport.from_string("0.0 -0.5 1.0 1.0") back_shader = lambda face_index, winding: None if winding >= 0 else poly_style front_shader = lambda face_index, winding: None if winding < 0 else poly_style two_pass_scene = svg3d.Scene([]) two_pass_scene.add_mesh(svg3d.Mesh(faces, back_shader)) two_pass_scene.add_mesh(svg3d.Mesh(faces, front_shader)) two_pass_scene.add_mesh( svg3d.Mesh(centroids, style=point_style, circle_radius=0.005) ) one_pass_scene = svg3d.Scene([]) one_pass_scene.add_mesh(svg3d.Mesh(faces, style=poly_style)) one_pass_scene.add_mesh( svg3d.Mesh(centroids, style=point_style, circle_radius=0.005) ) view0 = svg3d.View(camera, one_pass_scene, left_viewport) view1 = svg3d.View(camera, two_pass_scene, right_viewport) svg3d.Engine([view0, view1]).render( "octahedra.svg", (512, 256), "-1.0 -0.5 2.0 1.0" )
def capsule(): verts, indices = octasphere(ndivisions=3, radius=4, width=18, height=0, depth=0) view_matrix = create_lookat(eye=[25, 20, 60], target=[0, 0, 0], up=[0, 1, 0]) faces = verts[indices] ones = np.ones(faces.shape[:2] + (1, )) eyespace_faces = np.dstack([faces, ones]) eyespace_faces = np.dot(eyespace_faces, view_matrix)[:, :, :3] L = pyrr.vector.normalize(np.float32([20, 20, 50])) E = np.float32([0, 0, 1]) H = pyrr.vector.normalize(L + E) def frontface_shader(face_index, winding): if winding < 0: return None face = eyespace_faces[face_index] p0, p1, p2 = face[0], face[1], face[2] N = pyrr.vector3.cross(p1 - p0, p2 - p0) l2 = pyrr.vector3.squared_length(N) if l2 > 0: N = N / np.sqrt(l2) df = max(0, np.dot(N, L)) sf = pow(max(0, np.dot(N, H)), SHININESS) color = df * DIFFUSE + sf * SPECULAR color = np.power(color, 1.0 / 2.2) return dict(fill=rgb(*color), stroke="black", stroke_width="0.001") return svg3d.Mesh(faces, frontface_shader)
def create_surface_plot(): divs = 25 X, Y = np.meshgrid(np.linspace(-2, 2, divs), np.linspace(-2, 2, divs)) Z = 2 * X * np.exp(-X * X - Y * Y) verts = np.reshape(np.dstack([X, Y, Z]), [divs * divs, 3]) i, j = np.mgrid[0 : divs * 2, 0 : divs * 2] coords = np.uint32(np.dstack([i / 2, j / 2])) coords = coords[1 : divs * 2 - 1, 1 : divs * 2 - 1] indices = coords[:, :, 0] * divs + coords[:, :, 1] nw = indices[0::2][:, 0::2] ne = indices[0::2][:, 1::2] sw = indices[1::2][:, 0::2] se = indices[1::2][:, 1::2] indices = np.dstack([nw, ne, se, sw]) indices = np.reshape(indices, [(divs - 1) * (divs - 1), 4]) faces = verts[indices] view = create_lookat(eye=[5, 20, 5], target=[0, 0, 0], up=[0, 0, 1]) projection = create_perspective(fovy=15, aspect=1, near=1, far=100) camera = svg3d.Camera(view, projection) style = dict( fill="#f0f0f0", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.001", ) rgb = apply_turbo_colormap(Z) colors = np.reshape(rgb, [divs * divs, 3]) colors = colors[indices] def shader(face_index, winding): face_colors = colors[face_index] rgb = ",".join([str(int(num * 255)) for num in face_colors[0]]) style["fill"] = f"rgb({rgb})" return style scene = svg3d.Scene([svg3d.Mesh(faces, shader)]) view = svg3d.View(camera, scene) svg3d.Engine([view]).render("plot.svg")
def make_octaspheres(ndivisions: int, radius: float, width=0, height=0, depth=0): verts, indices = octasphere(ndivisions, radius, width, height, depth) faces = verts[indices] left = translate_faces(faces, [-12, 0, 0]) right = translate_faces(rotate_faces(faces), [12, 0, 0]) faces = merge_faces(left, right) ones = np.ones(faces.shape[:2] + (1, )) eyespace_faces = np.dstack([faces, ones]) eyespace_faces = np.dot(eyespace_faces, view_matrix)[:, :, :3] L = pyrr.vector.normalize(np.float32([20, 20, 50])) E = np.float32([0, 0, 1]) H = pyrr.vector.normalize(L + E) def frontface_shader(face_index, winding): if winding < 0: return None face = eyespace_faces[face_index] p0, p1, p2 = face[0], face[1], face[2] N = pyrr.vector3.cross(p1 - p0, p2 - p0) l2 = pyrr.vector3.squared_length(N) if l2 > 0: N = N / np.sqrt(l2) df = max(0, np.dot(N, L)) sf = pow(max(0, np.dot(N, H)), SHININESS) color = df * DIFFUSE + sf * SPECULAR color = np.power(color, 1.0 / 2.2) return dict(fill=rgb(*color), stroke="black", stroke_width="0.001") print( f"Generated octasphere: {ndivisions}, {radius}, {width}, {height}, {depth}" ) return [svg3d.Mesh(faces, frontface_shader)]
def generate_overlapping_triangles(): X = 1 Y = 2 view = create_lookat(eye=[1.5, 1.5, 5], target=[1.5, 1.5, 0], up=[0, 1, 0]) projection = create_ortho(-X, X, -Y, Y, 0, 10) pick = pyrr.matrix44.create_from_translation([1, 0, 0]) left_camera = svg3d.Camera(view, np.dot(projection, pick)) projection = create_ortho(-X, X, -Y, Y, 0, 10) pick = pyrr.matrix44.create_from_translation([-1, 0, 0]) right_camera = svg3d.Camera(view, np.dot(pick, projection)) z0 = 0.00 z1 = 0.01 z2 = 0.02 z3 = -0.03 faces = np.float32( [ [(0, 0, z0), (1, 0, z0), (0.5, 3, z0)], [(0, 2, z1), (0, 3, z1), (3, 2.5, z1)], [(2, 3, z2), (3, 3, z2), (2.5, 0, z2)], [(3, 0, z3), (3, 1, z3), (0, 0.5, z3)], ] ) poly_style = dict( fill="#e0e0e0", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.01", ) left_scene = svg3d.Scene([svg3d.Mesh(faces, style=poly_style)]) left_view = svg3d.View( left_camera, left_scene, svg3d.Viewport.from_string("-.5 -.5 .5 1") ) z3 = 0.03 faces = np.float32( [ [(0, 0, z0), (1, 0, z0), (0.5, 3, z0)], [(0, 2, z1), (0, 3, z1), (3, 2.5, z1)], [(2, 3, z2), (3, 3, z2), (2.5, 0, z2)], [(3, 0, z3), (3, 1, z3), (0, 0.5, z3)], ] ) poly_style = dict( fill="#e0e0e0", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.01", ) right_scene = svg3d.Scene([svg3d.Mesh(faces, style=poly_style)]) right_view = svg3d.View( right_camera, right_scene, svg3d.Viewport.from_string("0 -.5 .5 1") ) svg3d.Engine([left_view, right_view]).render("overlapping_triangles.svg")
def create_complex_shapes(): projection = create_perspective(fovy=25, aspect=1, near=10, far=200) view = create_lookat(eye=[25, 20, 60], target=[0, 0, 0], up=[0, 1, 0]) camera = svg3d.Camera(view, projection) # Parametric Sphere slices, stacks, radius = 64, 64, 12 faces = radius * parametric_surface(slices, stacks, sphere) antialiasing = "auto" # use 'crispEdges' to fix cracks def shader(face_index, winding): slice = int(face_index / 64) stack = int(face_index % 64) if slice % 3 == 0 or stack % 3 == 0: return dict( fill="black", fill_opacity="1.0", stroke="none", shape_rendering=antialiasing, ) return dict( fill="white", fill_opacity="0.75", stroke="none", shape_rendering=antialiasing, ) scene = svg3d.Scene([svg3d.Mesh(faces, shader)]) svg3d.Engine([svg3d.View(camera, scene)]).render("parametric_sphere.svg") # Sphere Shell verts, faces = icosahedron() verts, faces = subdivide(verts, faces) verts, faces = subdivide(verts, faces) verts, faces = np.float32(verts), np.int32(faces) faces = verts[faces] def backface_shader(face_index, winding): if winding >= 0: return None return dict( fill="#7f7fff", fill_opacity="1.0", stroke="black", stroke_linejoin="round", stroke_width="0.001", stroke_dasharray="0.01", ) def frontface_shader(face_index, winding): if winding < 0 or faces[face_index][0][2] > 0.9: return None return dict( fill="#7fff7f", fill_opacity="0.6", stroke="black", stroke_linejoin="round", stroke_width="0.003", ) scene = svg3d.Scene([]) scene.add_mesh(svg3d.Mesh(12.0 * faces, backface_shader)) scene.add_mesh(svg3d.Mesh(12.0 * faces, frontface_shader)) svg3d.Engine([svg3d.View(camera, scene)]).render("sphere_shell.svg") # Sphere Lighting ones = np.ones(faces.shape[:2] + (1,)) eyespace_faces = np.dstack([faces, ones]) eyespace_faces = np.dot(eyespace_faces, view)[:, :, :3] shininess = 100 L = pyrr.vector.normalize(np.float32([20, 20, 50])) E = np.float32([0, 0, 1]) H = pyrr.vector.normalize(L + E) def frontface_shader(face_index, winding): if winding < 0: return None face = eyespace_faces[face_index] p0, p1, p2 = face[0], face[1], face[2] N = pyrr.vector.normalize(pyrr.vector3.cross(p1 - p0, p2 - p0)) df = max(0, np.dot(N, L)) sf = pow(max(0, np.dot(N, H)), shininess) color = df * np.float32([1, 1, 0]) + sf * np.float32([1, 1, 1]) color = np.power(color, 1.0 / 2.2) return dict( fill=rgb(*color), fill_opacity="1.0", stroke="black", stroke_width="0.001" ) scene = svg3d.Scene([]) scene.add_mesh(svg3d.Mesh(12.0 * faces, frontface_shader)) svg3d.Engine([svg3d.View(camera, scene)]).render("sphere_lighting.svg") # Mobius Tube slices, stacks, radius = 48, 32, 7 faces = radius * parametric_surface(slices, stacks, mobius_tube) ones = np.ones(faces.shape[:2] + (1,)) eyespace_faces = np.dstack([faces, ones]) eyespace_faces = np.dot(eyespace_faces, view)[:, :, :3] shininess = 75 L = pyrr.vector.normalize(np.float32([10, -10, 50])) E = np.float32([0, 0, 1]) H = pyrr.vector.normalize(L + E) def frontface_shader(face_index, winding): if winding < 0: return None face = eyespace_faces[face_index] p0, p1, p2 = face[0], face[1], face[2] N = pyrr.vector.normalize(pyrr.vector3.cross(p1 - p0, p2 - p0)) df = max(0, np.dot(N, L)) sf = pow(max(0, np.dot(N, H)), shininess) color = df * np.float32([0, 0.8, 1]) + sf * np.float32([1, 1, 1]) color = np.power(color, 1.0 / 2.2) return dict( fill=rgb(*color), fill_opacity="1.0", stroke=rgb(*(color * 1.5)), stroke_width="0.001", ) scene = svg3d.Scene([]) scene.add_mesh(svg3d.Mesh(faces, frontface_shader)) svg3d.Engine([svg3d.View(camera, scene)]).render("mobius_tube.svg") # Filmstrip def shader(face_index, winding): return dict( fill="white", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.005", ) thin = dict( fill="white", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.001", ) view = create_lookat(eye=[50, 40, 120], target=[0, 0, 0], up=[0, 1, 0]) projection = create_perspective(fovy=15, aspect=1, near=10, far=200) camera = svg3d.Camera(view, projection) viewport0 = svg3d.Viewport.from_string("-2.5 -0.5 1.0 1.0") viewport1 = svg3d.Viewport.from_string("-1.5 -0.5 1.0 1.0") viewport2 = svg3d.Viewport.from_string("-0.5 -0.5 1.0 1.0") viewport3 = svg3d.Viewport.from_string(" 0.5 -0.5 1.0 1.0") viewport4 = svg3d.Viewport.from_string(" 1.5 -0.5 1.0 1.0") slices, stacks = 24, 32 sphere_faces = 15.0 * parametric_surface(slices, stacks, sphere) slices, stacks = 32, 24 klein_faces = 3.0 * parametric_surface(slices, stacks, klein) slices, stacks, radius = 48, 32, 7 mobius_faces = radius * parametric_surface(slices, stacks, mobius_tube) # cube view0 = svg3d.View(camera, svg3d.Scene([svg3d.Mesh(cube(), shader)]), viewport0) # octahedron view1 = svg3d.View( camera, svg3d.Scene([svg3d.Mesh(12.0 * octahedron(), shader)]), viewport1 ) # sphere view2 = svg3d.View( camera, svg3d.Scene([svg3d.Mesh(sphere_faces, style=thin)]), viewport2 ) # klein klein_view = create_lookat(eye=[50, 120, 50], target=[0, 0, 0], up=[0, 0, 1]) klein_projection = create_perspective(fovy=28, aspect=1, near=10, far=200) klein_camera = svg3d.Camera(klein_view, klein_projection) view3 = svg3d.View( klein_camera, svg3d.Scene([svg3d.Mesh(klein_faces, style=thin)]), viewport3 ) # mobius view4 = svg3d.View( camera, svg3d.Scene([svg3d.Mesh(mobius_faces, frontface_shader)]), viewport4 ) drawing = svgwrite.Drawing( "filmstrip.svg", (256 * 5, 256), viewBox="-2.5 -0.5 5.0 1.0" ) svg3d.Engine([view0, view1, view2, view3, view4]).render_to_drawing(drawing) drawing.save()
def create_simple_shapes(): view = create_lookat(eye=[50, 40, 120], target=[0, 0, 0], up=[0, 1, 0]) projection = create_perspective(fovy=15, aspect=1, near=10, far=200) camera = svg3d.Camera(view, projection) thin_style = dict( fill="white", stroke="black", stroke_linejoin="round", fill_opacity="0.75", stroke_width="0.002", ) thick_style = dict( fill="white", stroke="black", stroke_linejoin="round", fill_opacity="0.75", stroke_width="0.005", ) left_viewport = svg3d.Viewport.from_string("-1.0 -0.5 1.0 1.0") right_viewport = svg3d.Viewport.from_string("0.0 -0.5 1.0 1.0") # Octahedron style = dict( fill="white", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.005", ) mesh = svg3d.Mesh(15.0 * octahedron(), style=style) view = svg3d.View(camera, svg3d.Scene([mesh])) svg3d.Engine([view]).render("octahedron.svg") # Sphere and Klein def shader(face_index, winding): return dict( fill="white", fill_opacity="0.75", stroke="black", stroke_linejoin="round", stroke_width="0.002", ) slices, stacks = 32, 32 faces = 15.0 * parametric_surface(slices, stacks, sphere) sphere_view = svg3d.View( camera, svg3d.Scene([svg3d.Mesh(faces, shader)]), left_viewport ) klein_view = create_lookat(eye=[50, 120, 50], target=[0, 0, 0], up=[0, 0, 1]) klein_projection = create_perspective(fovy=28, aspect=1, near=10, far=200) klein_camera = svg3d.Camera(klein_view, klein_projection) faces = 3.0 * parametric_surface(slices, stacks, klein) klein_view = svg3d.View( klein_camera, svg3d.Scene([svg3d.Mesh(faces, shader)]), right_viewport ) svg3d.Engine([sphere_view, klein_view]).render( "sphere_and_klein.svg", (512, 256), "-1.0 -0.5 2.0 1.0" )
def create_octahedron_pair(filename): vp = svg3d.Viewport.from_aspect(2) projection = create_perspective(fovy=25, aspect=2, near=10, far=200) view = create_lookat(eye=[0, 20, 60], target=[0, 0, 0], up=[0, 1, 0]) camera = svg3d.Camera(view, projection) scene = svg3d.Scene([]) faces = octahedron() def backface_shader(face_index, winding): if winding >= 0: return None return dict( fill="#7f7fff", fill_opacity="1.0", stroke="black", stroke_linejoin="round", stroke_width="0.002", stroke_dasharray="0.01", ) def frontface_shader(face_index, winding): if winding < 0: return None return dict( fill="#7fff7f", fill_opacity="0.4", stroke="black", stroke_linejoin="round", stroke_width="0.003", ) faces += np.array([-1.25, 0, 0]) scene.add_mesh(svg3d.Mesh(12.0 * faces, backface_shader)) scene.add_mesh(svg3d.Mesh(12.0 * faces, frontface_shader)) faces2 = hexahedron() * 0.8 def backface_shader2(face_index, winding): if winding >= 0: return None return dict( fill="#7f7fff", fill_opacity="1.0", stroke="black", stroke_linejoin="round", stroke_width="0.002", stroke_dasharray="0.01", ) def frontface_shader2(face_index, winding): if winding < 0: return None return dict( fill="#7fff7f", fill_opacity="0.4", stroke="black", stroke_linejoin="round", stroke_width="0.003", ) q = quaternion.create_from_eulers([0, pi * 0.25, 0]) for f in faces2: for v in f: v[:] = quaternion.apply_to_vector(q, v) faces2 += np.array([12.0, 0, 0]) scene.add_mesh(svg3d.Mesh(faces2, backface_shader2)) scene.add_mesh(svg3d.Mesh(faces2, frontface_shader2)) e = svg3d.Engine([svg3d.View(camera, scene, vp)]) e.render(filename, (1024, 512))