def spherePoint(mesh, position, radius=1, point_size=None, color=None): offset = len(mesh.vertices) v = toSphere(position, radius) v_tmp = toSphere([position[0] + 1, position[1] + 1], radius) theta = np.pi * .5 # 90 deg for i in range(4): a = np.pi + i * theta extrude_normal = perpendicular(v, v_tmp, a) normal = normalize(v) mesh.addTexCoord(QUAD_TEXTCOORDS[i]) if point_size: mesh.addNormal(normal) mesh.addVertex(v + extrude_normal * point_size) else: mesh.addNormal(extrude_normal) mesh.addVertex(v) if color: mesh.addColor(color) mesh.addTriangle(offset, offset + 1, offset + 2) mesh.addTriangle(offset + 2, offset + 3, offset) return mesh
def sphereSpline(mesh, points, radius=1, width=None, color=None): offset = len(mesh.vertices) for i in range(1, len(points)): v_prev = toSphere(points[i - 1], radius) v_this = toSphere(points[i], radius) theta = np.pi * .5 # 90 deg for i in range(4): a = theta * .5 + i * theta normal = perpendicular(v_prev, v_this, a) mesh.addTexCoord(QUAD_TEXTCOORDS[i]) if width: mesh.addNormal(normalize(v_prev)) if i < 2: mesh.addVertex(v_prev + np.array(normal) * width) else: mesh.addVertex(v_this + np.array(normal) * width) else: mesh.addNormal(normal) if i < 2: mesh.addVertex(v_prev) else: mesh.addVertex(v_this) if color: mesh.addColor(color) mesh.addTriangle(offset, offset + 1, offset + 2) mesh.addTriangle(offset + 2, offset + 3, offset) offset += 4 return mesh
def spherePolygon(mesh, points, radius=1, color=None): offset = len(mesh.vertices) if points[0][0] == points[-1][0]: points.pop() sphere_pts = [] for point in points: sphere_pts.append(point) v = toSphere(point, radius) normal = normalize(v) mesh.vertices_texcoords([.5 + point[0] / 360., .5 + point[1] / 180.]) # mesh.addNormal( normal ) mesh.addVertex(v) if color: mesh.addColor(color) segments = [] for i in range(len(points)): segments.append([i, (i + 1) % len(points)]) cndt = triangulate(dict(vertices=sphere_pts, segments=segments), 'p') for face in cndt['triangles']: mesh.addTriangle(offset + (face[0] % len(sphere_pts)), offset + (face[1] % len(sphere_pts)), offset + (face[2] % len(sphere_pts))) offset += len(points) return mesh
def axisangle_to_q(v, theta): v = normalize(v) x, y, z = v theta /= 2 w = cos(theta) x = x * sin(theta) y = y * sin(theta) z = z * sin(theta) return w, x, y, z
def quat_from_axis(theta, axis): axis = normalize(axis) x, y, z = axis theta /= 2 w = cos(theta) x = x * sin(theta) y = y * sin(theta) z = z * sin(theta) return w, x, y, z
def icosphere(mesh, radius=1, resolution=2, color=None): # Step 1 : Generate icosahedron sqrt5 = sqrt(5.0) phi = (1.0 + sqrt5) * 0.5 invnorm = 1.0 / sqrt(phi * phi + 1.0) mesh.addVertex(invnorm * np.array([-1, phi, 0])) #0 mesh.addVertex(invnorm * np.array([1, phi, 0])) #1 mesh.addVertex(invnorm * np.array([0, 1, -phi])) #2 mesh.addVertex(invnorm * np.array([0, 1, phi])) #3 mesh.addVertex(invnorm * np.array([-phi, 0, -1])) #4 mesh.addVertex(invnorm * np.array([-phi, 0, 1])) #5 mesh.addVertex(invnorm * np.array([phi, 0, -1])) #6 mesh.addVertex(invnorm * np.array([phi, 0, 1])) #7 mesh.addVertex(invnorm * np.array([0, -1, -phi])) #8 mesh.addVertex(invnorm * np.array([0, -1, phi])) #9 mesh.addVertex(invnorm * np.array([-1, -phi, 0])) #10 mesh.addVertex(invnorm * np.array([1, -phi, 0])) #11 if color: for i in range(12): mesh.addColor(color) firstFaces = [ 0, 1, 2, 0, 3, 1, 0, 4, 5, 1, 7, 6, 1, 6, 2, 1, 3, 7, 0, 2, 4, 0, 5, 3, 2, 6, 8, 2, 8, 4, 3, 5, 9, 3, 9, 7, 11, 6, 7, 10, 5, 4, 10, 4, 8, 10, 9, 5, 11, 8, 6, 11, 7, 9, 10, 8, 11, 10, 11, 9 ] for i in range(0, 60)[::3]: mesh.addTriangle(firstFaces[i], firstFaces[i + 1], firstFaces[i + 2]) size = len(mesh.indices) # Step 2: tessellate for iteration in range(0, resolution): size *= 4 newFaces = [] for i in range(0, int(size / 12)): i1 = mesh.indices[i * 3] i2 = mesh.indices[i * 3 + 1] i3 = mesh.indices[i * 3 + 2] i12 = len(mesh.vertices) i23 = i12 + 1 i13 = i12 + 2 v1 = mesh.vertices[i1] v2 = mesh.vertices[i2] v3 = mesh.vertices[i3] # make 1 vertice at the center of each edge and project it onto the mesh mesh.vertices.append(np.array(normalize(v1 + v2))) mesh.vertices.append(np.array(normalize(v2 + v3))) mesh.vertices.append(np.array(normalize(v1 + v3))) if color: for i in range(3): mesh.addColor(color) # now recreate indices newFaces.append(i1) newFaces.append(i12) newFaces.append(i13) newFaces.append(i2) newFaces.append(i23) newFaces.append(i12) newFaces.append(i3) newFaces.append(i13) newFaces.append(i23) newFaces.append(i12) newFaces.append(i23) newFaces.append(i13) mesh.indices = list(newFaces) # Step 3 : generate texcoords texCoords = [] for i in range(0, len(mesh.vertices)): vec = mesh.vertices[i] r0 = sqrt(vec[0] * vec[0] + vec[2] * vec[2]) alpha = atan2(vec[2], vec[0]) u = alpha / TAU + .5 v = atan2(vec[1], r0) / np.pi + .5 # reverse the u coord, so the default is texture mapped left to # right on the outside of a sphere # reverse the v coord, so that texture origin is at top left texCoords.append(np.array([1.0 - u, v])) # Step 4 : fix texcoords # find vertices to split indexToSplit = [] for i in range(0, int(len(mesh.indices) / 3)): t0 = texCoords[mesh.indices[i * 3 + 0]] t1 = texCoords[mesh.indices[i * 3 + 1]] t2 = texCoords[mesh.indices[i * 3 + 2]] if abs(t2[0] - t0[0]) > 0.5: if t0[0] < 0.5: indexToSplit.append(mesh.indices[i * 3]) else: indexToSplit.append(mesh.indices[i * 3 + 2]) if abs(t1[0] - t0[0]) > 0.5: if t0[0] < 0.5: indexToSplit.append(mesh.indices[i * 3]) else: indexToSplit.append(mesh.indices[i * 3 + 1]) if abs(t2[0] - t1[0]) > 0.5: if t1[0] < 0.5: indexToSplit.append(mesh.indices[i * 3 + 1]) else: indexToSplit.append(mesh.indices[i * 3 + 2]) # split vertices for i in range(0, int(len(indexToSplit) / 3)): index = indexToSplit[i] # duplicate vertex v = mesh.vertices[index] t = texCoords[index] + np.array([1., 0.]) mesh.vertices.append(v) texCoords.append(t) if color: mesh.addColor(color) newIndex = len(mesh.vertices) - 1 # reassign indices for j in range(len(mesh.indices)): if mesh.indices[j] == index: index1 = mesh.indices[int((j + 1) % 3 + (j / 3) * 3)] index2 = mesh.indices[int((j + 2) % 3 + (j / 3) * 3)] if (texCoords[index1][0] > 0.5) or (texCoords[index2][0] > 0.5): mesh.indices[j] = newIndex for vert in mesh.vertices: mesh.addNormal(normalize(vert)) for st in texCoords: mesh.addTexCoord(st) for i in range(len(mesh.vertices)): mesh.vertices[i] = mesh.vertices[i] * radius return mesh
def extrudeLine(mesh, positions, z=0.0, line_width=0.0, color=None, flipped=False): offset = len(mesh.vertices) UP_NORMAL = [0., 0., 1.] if flipped: UP_NORMAL = [0., 0., -1.] # Right normal to segment between previous and current m_points normi = [0.0, 0.0, 0.0] # Right normal to segment between current and next m_points normip1 = [0.0, 0.0, 0.0] # Right "normal" at current point, scaled for miter joint rightNorm = [0.0, 0.0, 0.0] # Make sure all points have XYZ points = [] for i in range(0, len(positions)): if len(positions[0]) == 1: points.append([positions[i][0], 0.0, z]) elif len(positions[0]) == 2: points.append([positions[i][0], positions[i][1], z]) else: points.append([positions[i][0], positions[i][1], positions[i][2]]) # Previous point coordinates im1 = [0.0, 0.0, 0.0] # Current point coordinates i0 = points[0] # Next point coordinates ip1 = points[1] # Get Perpendicular normip1[0] = ip1[1] - i0[1] normip1[1] = i0[0] - ip1[0] normip1[2] = 0.0 normip1 = normalize(normip1) rightNorm = normip1 * 0.8 mesh.addVertex(i0 + np.array(rightNorm) * line_width) mesh.addTexCoord([1.0, 0.0]) mesh.addVertex(i0 - np.array(rightNorm) * line_width) mesh.addTexCoord([0.0, 0.0]) if line_width == 0.0: mesh.addNormal(rightNorm) mesh.addNormal(-rightNorm) else: mesh.addNormal(UP_NORMAL) mesh.addNormal(UP_NORMAL) if color: mesh.addColor(color) mesh.addColor(color) for i in range(1, len(points) - 1): im1 = i0 i0 = ip1 ip1 = points[i + 1] normi = normip1 normip1[0] = ip1[1] - i0[1] normip1[1] = i0[0] - ip1[0] normip1[2] = 0.0 normip1 = normalize(normip1) rightNorm = normi + normip1 if line_width == 0.0: scale = sqrt(2.0 / (1.0 + dot(normi, normip1))) * 0.5 rightNorm *= scale mesh.addVertex(i0) mesh.addNormal(rightNorm) mesh.addVertex(i0) mesh.addNormal(-rightNorm) else: scale = sqrt(2.0 / (1.0 + dot(normi, normip1))) * line_width * 0.5 rightNorm *= scale mesh.addVertex(i0 + rightNorm) mesh.addNormal(UP_NORMAL) mesh.addVertex(i0 - rightNorm) mesh.addNormal(UP_NORMAL) y_pct = float(i) / float(len(points) - 1) mesh.addTexCoord([1.0, y_pct]) mesh.addTexCoord([0.0, y_pct]) if color: mesh.addColor(color) mesh.addColor(color) # Get Perpendicular normip1[0] = ip1[1] - i0[1] normip1[1] = i0[0] - ip1[0] normip1[2] = 0.0 normip1 = normalize(normip1) rightNorm = normip1 * 0.8 if line_width == 0.0: mesh.addVertex(ip1) mesh.addNormal(rightNorm) mesh.addVertex(ip1) mesh.addNormal(-rightNorm) else: mesh.addVertex(ip1 + rightNorm * line_width) mesh.addNormal(UP_NORMAL) mesh.addVertex(ip1 - rightNorm * line_width) mesh.addNormal(UP_NORMAL) mesh.addTexCoord([1.0, 1.0]) mesh.addTexCoord([0.0, 1.0]) if color: mesh.addColor(color) mesh.addColor(color) for i in range(len(points) - 1): mesh.addIndex(offset + 2 * i + 3) mesh.addIndex(offset + 2 * i + 2) mesh.addIndex(offset + 2 * i) mesh.addIndex(offset + 2 * i) mesh.addIndex(offset + 2 * i + 1) mesh.addIndex(offset + 2 * i + 3) return mesh