def __init__(self, whl_pos, whl_radius, car_h): GameObject.__init__(self) self.radius = whl_radius v_f = GeomVertexFormat.getV3() vdata = GeomVertexData('skid', v_f, Geom.UHDynamic) prim = GeomTriangles(Geom.UHStatic) self.vtx_cnt = 1 self.last_pos = whl_pos geom = Geom(vdata) geom.add_primitive(prim) self.node = GeomNode('gnode') self.node.add_geom(geom) nodepath = self.eng.gfx.root.attach_node(self.node) nodepath.set_transparency(True) nodepath.set_depth_offset(1) nodepath.node.set_two_sided(True) # for self-shadowing issues self.__set_material(nodepath) nodepath.p3dnode.set_bounds(OmniBoundingVolume()) self.add_vertices(whl_radius, car_h) self.add_vertices(whl_radius, car_h) def alpha(time, n_p): if not n_p.is_empty: n_p.node.set_shader_input('alpha', time) # this if seems necessary since, if there are skidmarks and you # exit from the race (e.g. back to the menu), then alpha is being # called from the interval manager even if the interval manager # correctly says that there are 0 intervals. self.remove_seq = Sequence( Wait(8), LerpFunc(alpha, 8, .5, 0, 'easeInOut', [nodepath]), Func(nodepath.remove_node)) self.remove_seq.start()
def mesh(vertices, normals, colours, triangles): # TODO: Make this name meaningful in some way name = 'test' v3n3c4 = GeomVertexFormat.get_v3n3c4() data = GeomVertexData(name, v3n3c4, Geom.UHStatic) data.set_num_rows(len(vertices)) vertex_writer = GeomVertexWriter(data, 'vertex') normal_writer = GeomVertexWriter(data, 'normal') colour_writer = GeomVertexWriter(data, 'color') for vertex in vertices: vertex_writer.add_data3(*vertex) for normal in normals: normal_writer.add_data3(*normal) for colour in colours: colour_writer.add_data4(*colour) prim = GeomTriangles(Geom.UHStatic) for triangle in triangles: prim.add_vertices(*triangle) geom = Geom(data) geom.add_primitive(prim) node = GeomNode(name) node.add_geom(geom) return node
def _make_fullscreen_tri(self): """ Creates the oversized triangle used for rendering """ vformat = GeomVertexFormat.get_v3() vdata = GeomVertexData("vertices", vformat, Geom.UH_static) vdata.set_num_rows(3) vwriter = GeomVertexWriter(vdata, "vertex") vwriter.add_data3f(-1, 0, -1) vwriter.add_data3f(3, 0, -1) vwriter.add_data3f(-1, 0, 3) gtris = GeomTriangles(Geom.UH_static) gtris.add_next_vertices(3) geom = Geom(vdata) geom.add_primitive(gtris) geom_node = GeomNode("gn") geom_node.add_geom(geom) geom_node.set_final(True) geom_node.set_bounds(OmniBoundingVolume()) tri = NodePath(geom_node) tri.set_depth_test(False) tri.set_depth_write(False) tri.set_attrib(TransparencyAttrib.make(TransparencyAttrib.M_none), 10000) tri.set_color(Vec4(1)) tri.set_bin("unsorted", 10) tri.reparent_to(self._node) self._tri = tri
def wrap_up(self): self.prim.close_primitive() geom = Geom(self.vdata) geom.add_primitive(self.prim) node = GeomNode('point') node.add_geom(geom) return NodePath(node)
def get_p3d_geom_node(self, name='UnnamedGeom'): # type: (Optional[str]) -> GeomNode """Returns a Panda3D GeomNode object""" vertex_data = GeomVertexData(name, GeomVertexFormat.get_v3c4(), Geom.UH_static) total_triangles = len(self.__triangles__) # Every triangle gets its unique set of vertices for flat shading num_rows = total_triangles * 3 vertex_data.set_num_rows(num_rows) vertex_writer = GeomVertexWriter(vertex_data, 'vertex') color_writer = GeomVertexWriter(vertex_data, 'color') for i in range(total_triangles): triangle = self.vertices[self.triangles[i]] vertex_writer.add_data3f(*triangle[0]) vertex_writer.add_data3f(*triangle[1]) vertex_writer.add_data3f(*triangle[2]) triangle_color = self.colors[self.triangles[i]].sum(axis=0) / 3 for _ in [0, 0, 0]: color_writer.add_data4f(*triangle_color) geom = Geom(vertex_data) for i in range(total_triangles): triangle = GeomTriangles(Geom.UH_static) first = i * 3 triangle.add_vertex(first) triangle.add_vertex(first + 1) triangle.add_vertex(first + 2) geom.add_primitive(triangle) node = GeomNode(name) node.add_geom(geom) return node
class Grid: """A grid of lines for visual reference.""" focus: NodePath node_path: NodePath spacing: float size: float def __init__(self, spacing: float, size: float, parent: NodePath, focus: NodePath): self.spacing = spacing self.size = size self.focus = focus self._create_geom() node = GeomNode('grid') node.add_geom(self.geom) self.node_path = parent.attach_new_node(node) self.node_path.set_z(0.1) self.node_path.set_transparency(TransparencyAttrib.M_alpha) self.node_path.set_light_off() self.node_path.set_shader_off() def update(self): """Update callback.""" x, y = self.focus.get_x(), self.focus.get_y() self.node_path.set_x(x - x % self.spacing) self.node_path.set_y(y - y % self.spacing) def _create_geom(self): color = ConfigVariableColor('grid-color', DEFAULT_GRID_COLOR) radius = floor(self.size / (2 * self.spacing)) diameter = (2 * radius + 1) start = -radius * self.spacing vertex_format = GeomVertexFormat.get_v3c4() vertex_data = GeomVertexData('grid', vertex_format, Geom.UH_static) vertex_data.set_num_rows(diameter * 4) vertex_writer = GeomVertexWriter(vertex_data, 'vertex') color_writer = GeomVertexWriter(vertex_data, 'color') for i, j in product(range(diameter), repeat=2): vertex_writer.add_data3f(start + i * self.spacing, start + j * self.spacing, 0.0) alpha = GRID_ALPHA - GRID_ALPHA * ( Vector(i - radius, j - radius).norm() / radius) color_writer.add_data4f(color[0], color[1], color[2], alpha) primitive = GeomLinestrips(Geom.UH_static) for vertex in vertex_indexes(diameter): primitive.add_vertex(vertex) primitive.close_primitive() self.geom = Geom(vertex_data) self.geom.add_primitive(primitive)
def create_hidden_area_mesh(self, mask): """ Using the provided mask configuration, create the mesh that will cover the area not visible from the HMD """ gvf = GeomVertexFormat.get_v3() gvd = GeomVertexData('gvd', gvf, Geom.UH_static) geom = Geom(gvd) gvw = GeomVertexWriter(gvd, InternalName.get_vertex()) for i in range(mask.unTriangleCount * 3): vertex = mask.pVertexData[i] # The clip space in Panda3D has [-1, 1] coordinates, the received coordinates are in [0, 1] gvw.add_data3(vertex[0] * 2 - 1, vertex[1] * 2 - 1, -1) prim = GeomTriangles(Geom.UH_static) for i in range(mask.unTriangleCount): prim.add_vertices(i * 3, i * 3 + 1, i * 3 + 2) geom.add_primitive(prim) node = GeomNode('hidden-area-mesh') node.add_geom(geom) return node
def _generate_mesh(way: Way) -> Geom: """Generate mesh for a Way.""" geometry = way.geometry rows = 2 * len(geometry.segments) + 2 vertex_data = GeomVertexData(str(way.id), VERTEX_FORMAT, Geom.UH_static) vertex_data.set_num_rows(rows) vertex_writer = GeomVertexWriter(vertex_data, 'vertex') normal_writer = GeomVertexWriter(vertex_data, 'normal') texcoord_writer = GeomVertexWriter(vertex_data, 'texcoord') start_z = way.start.level * LEVEL_HEIGHT end_z = way.end.level * LEVEL_HEIGHT lanes_float = float(way.total_lane_count) segment = geometry.segments[0] for vertex in (segment.start_left, segment.start_right): vertex_writer.add_data3f(vertex.x, vertex.y, start_z) normal_writer.add_data3f(0.0, 0.0, 1.0) texture_v = 0.0 texcoord_writer.add_data2f(0.0, texture_v) texcoord_writer.add_data2f(lanes_float, texture_v) lengths = [s.length() for s in geometry.segments] total_len = sum(lengths) for segment, acc_len in zip(geometry.segments, accumulate(lengths)): height = start_z + (end_z - start_z) * acc_len / total_len for vertex in (segment.end_left, segment.end_right): vertex_writer.add_data3f(vertex.x, vertex.y, height) normal_writer.add_data3f(0.0, 0.0, 1.0) texture_v = acc_len / LANE_WIDTH texcoord_writer.add_data2f(0.0, texture_v) texcoord_writer.add_data2f(lanes_float, texture_v) primitive = GeomTristrips(Geom.UH_static) primitive.add_consecutive_vertices(0, rows) primitive.close_primitive() geom = Geom(vertex_data) geom.add_primitive(primitive) return geom
def addLine(self, points): """ Adds a line to class GeomNode from a pair of points """ #Creates objects needed to draw a geometry on the HUD #The vertex data which will define the rendered geometry vertex_data = GeomVertexData("graph", GeomVertexFormat.getV3(), Geom.UHStatic) #The object that writes vertexes the vertex data writer = GeomVertexWriter(vertex_data, "vertex") for point in points: writer.add_data3f(point[0], 0, point[1]) #Defines that this geometry represents a polyline primitive = GeomLinestrips(Geom.UHStatic) #Tells geometry how many verticies will be added(?) primitive.add_consecutive_vertices(0, 2) primitive.close_primitive() geometry = Geom(vertex_data) geometry.add_primitive(primitive) #Draws a graph on the HUD self.geom_node.add_geom(geometry)
def __init__(self, base): # Load texture tex = Loader(base).loadTexture((Path(path.realpath(__file__)).parent.parent.parent / "res/images/checkerboard.png").absolute()) tex.setMagfilter(SamplerState.FT_nearest) tex.setMinfilter(SamplerState.FT_nearest) # Set up vertex data vdata = GeomVertexData("floor_data", GeomVertexFormat.get_v3t2(), Geom.UHStatic) vdata.setNumRows(6) vertex = GeomVertexWriter(vdata, "vertex") texcoord = GeomVertexWriter(vdata, "texcoord") vertex.addData3(-5, -5, 0) texcoord.addData3(0, 0, 0) vertex.addData3(-5, 5, 0) texcoord.addData3(0, 10, 0) vertex.addData3(5, 5, 0) texcoord.addData3(10, 10, 0) vertex.addData3(5, 5, 0) texcoord.addData3(10, 10, 0) vertex.addData3(5, -5, 0) texcoord.addData3(10, 0, 0) vertex.addData3(-5, -5, 0) texcoord.addData3(0, 0, 0) # Create primitive prim = GeomTriangles(Geom.UHStatic) prim.addVertices(0, 1, 2) prim.addVertices(3, 4, 5) geom = Geom(vdata) geom.add_primitive(prim) # Initialize geometry node GeomNode.__init__(self, "floor") attrib = TextureAttrib.make(tex) state = RenderState.make(attrib) self.addGeom(geom, state)
def _generate_mesh(node: Node) -> Geom: """Generate mesh for a Node.""" size = len(node.geometry.polygon) vertex_data = GeomVertexData(str(node.id), VERTEX_FORMAT, Geom.UH_static) vertex_data.set_num_rows(size) vertex_writer = GeomVertexWriter(vertex_data, 'vertex') normal_writer = GeomVertexWriter(vertex_data, 'normal') texcoord_writer = GeomVertexWriter(vertex_data, 'texcoord') indexes = [range(i - 1, i + 2) for i in range(0, size, 2)] triangles = [[node.geometry.polygon[j] for j in t] for t in indexes] for point in node.geometry.polygon: vertex_writer.add_data3f(point.x, point.y, LEVEL_HEIGHT * node.level) normal_writer.add_data3f(0.0, 0.0, 1.0) texcoord_writer.add_data2f(point.x / LANE_WIDTH, point.y / LANE_WIDTH) indexes = [ i for i, t in zip(indexes, triangles) if not t[0].close_to(t[1]) and not t[1].close_to(t[2]) ] geom = Geom(vertex_data) primitive = GeomTriangles(Geom.UH_static) for index in chain.from_iterable(indexes): primitive.add_vertex(index % size) primitive.close_primitive() geom.add_primitive(primitive) if size > 4: primitive = GeomTristrips(Geom.UH_static) for index in (i if i % 2 else -i - 1 for i in range(size // 2)): primitive.add_vertex(index % size) primitive.close_primitive() geom.add_primitive(primitive) return geom
def create_geometry_from_mesh(mesh): # Define the individual array formats for vertex attributes. vertex_position_format = GeomVertexArrayFormat("vertex", 3, Geom.NT_float32, Geom.C_point) vertex_normal_format = GeomVertexArrayFormat("normal", 3, Geom.NT_float32, Geom.C_normal) vertex_color_format = GeomVertexArrayFormat("color", 4, Geom.NT_uint8, Geom.C_color) # Define the vertex data format with positions and colors. vertex_format = GeomVertexFormat() vertex_format.addArray(vertex_position_format) vertex_format.addArray(vertex_normal_format) vertex_format.addArray(vertex_color_format) vertex_format = GeomVertexFormat.registerFormat(vertex_format) # Populate the vertex position and color arrays. vertex_data = GeomVertexData("mesh_vertices", vertex_format, Geom.UH_static) vertex_data.modifyArrayHandle(0).copyDataFrom( np.array(mesh.positions, dtype=np.float32)) vertex_data.modifyArrayHandle(1).copyDataFrom( np.array(mesh.normals, dtype=np.float32)) vertex_data.modifyArrayHandle(2).copyDataFrom( np.array(mesh.colors, dtype=np.uint8)) # Populate the triangle indices. triangles = GeomTriangles(Geom.UH_static) triangles.setIndexType(Geom.NT_uint32) triangles.modifyVertices().modifyHandle().copyDataFrom( np.array(mesh.triangles, dtype=np.uint32)) geometry = Geom(vertex_data) geometry.add_primitive(triangles) return geometry
def _generate_mesh(radius: float, count: int) -> Geom: """Generate mesh for the ground plane.""" vertex_data = GeomVertexData('ground', VERTEX_FORMAT, Geom.UH_static) vertex_data.set_num_rows(count**2) vertex_writer = GeomVertexWriter(vertex_data, 'vertex') normal_writer = GeomVertexWriter(vertex_data, 'normal') texcoord_writer = GeomVertexWriter(vertex_data, 'texcoord') step = 2 * radius / count for i, j in product(range(count + 1), repeat=2): vertex_writer.add_data3f(i * step - radius, j * step - radius, 0.0) normal_writer.add_data3f(0.0, 0.0, 1.0) texcoord_writer.add_data2f(i * 512, j * 512) geom = Geom(vertex_data) primitive = GeomTristrips(Geom.UH_static) for j in range(count): rows = range(count + 1) if j % 2 else reversed(range(count + 1)) for i in rows: primitive.add_vertex((j + (j + 1) % 2) * (count + 1) + i) primitive.add_vertex((j + j % 2) * (count + 1) + i) primitive.close_primitive() geom.add_primitive(primitive) return geom
def get_node(self): geom = Geom(self._vert_data) geom.add_primitive(self._prim) node = GeomNode(self._name) node.add_geom(geom) return node
class SquareMesh(): name: Final[str] mesh: Final[Geom] depth: Final[float] __vertex_data_format: GeomVertexFormat __vertex_data: GeomVertexData __triangles: GeomTriangles __triangle_data: GeomVertexArrayData __vertex: GeomVertexWriter __normal: GeomVertexWriter __texcoord: GeomVertexWriter def __init__(self, width: int = 1, height: int = 1, depth: Real = 0.1, name: str = 'SquareMesh') -> None: self.name = name self.depth = depth self.__vertex_data_format = GeomVertexFormat. getV3n3t2() self.__vertex_data = GeomVertexData(name, self.__vertex_data_format, Geom.UHStatic) self.__vertex_data.set_num_rows(4) self.mesh = Geom(self.__vertex_data) self.__triangles = GeomTriangles(Geom.UHStatic) self.__triangle_data = self.__triangles.modifyVertices() self.__vertex = GeomVertexWriter(self.__vertex_data, 'vertex') self.__normal = GeomVertexWriter(self.__vertex_data, 'normal') self.__texcoord = GeomVertexWriter(self.__vertex_data, 'texcoord') self.__face_count = 0 def make(x1, y1, z1, x2, y2, z2, tex) -> None: if x1 == x2: self.__vertex.add_data3f(x1, y1, z1) self.__vertex.add_data3f(x2, y2, z1) self.__vertex.add_data3f(x2, y2, z2) self.__vertex.add_data3f(x1, y1, z2) self.__normal.add_data3(normalise(2 * x1 - 1, 2 * y1 - 1, 2 * z1 - 1)) self.__normal.add_data3(normalise(2 * x2 - 1, 2 * y2 - 1, 2 * z1 - 1)) self.__normal.add_data3(normalise(2 * x2 - 1, 2 * y2 - 1, 2 * z2 - 1)) self.__normal.add_data3(normalise(2 * x1 - 1, 2 * y1 - 1, 2 * z2 - 1)) else: self.__vertex.add_data3f(x1, y1, z1) self.__vertex.add_data3f(x2, y1, z1) self.__vertex.add_data3f(x2, y2, z2) self.__vertex.add_data3f(x1, y2, z2) self.__normal.add_data3(normalise(2 * x1 - 1, 2 * y1 - 1, 2 * z1 - 1)) self.__normal.add_data3(normalise(2 * x2 - 1, 2 * y1 - 1, 2 * z1 - 1)) self.__normal.add_data3(normalise(2 * x2 - 1, 2 * y2 - 1, 2 * z2 - 1)) self.__normal.add_data3(normalise(2 * x1 - 1, 2 * y2 - 1, 2 * z2 - 1)) for data in tex: self.__texcoord.addData2f(*data) vertex_id = self.__face_count * 4 self.__triangles.addVertices(vertex_id, vertex_id + 1, vertex_id + 3) self.__triangles.addVertices(vertex_id + 1, vertex_id + 2, vertex_id + 3) self.__face_count += 1 if self.depth == 0: make(0, 0, 0, width, height, 0, [(1.0, 1.0), (0.0, 1.0), (0.0, 0.0), (1.0, 0.0)]) else: make(0, height, -self.depth, 0, 0, 0, ((0.0, 1.0), (0.0, 0.0), (0.0, 0.0), (0.0, 1.0))) # SIDE make(0, 0, -self.depth, width, 0, 0, ((0.0, 0.0), (1.0, 0.0), (1.0, 0.0), (0.0, 0.0))) # SIDE make(width, height, -self.depth, 0, height, 0, ((1.0, 1.0), (0.0, 1.0), (0.0, 1.0), (1.0, 1.0))) # SIDE make(width, 0, -self.depth, width, height, 0, ((1.0, 0.0), (1.0, 1.0), (1.0, 1.0), (1.0, 0.0))) # SIDE make(width, height, 0, 0, 0, 0, ((1.0, 1.0), (0.0, 1.0), (0.0, 0.0), (1.0, 0.0))) # TOP make(0, height, -self.depth, width, 0, -self.depth, ((0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0))) # BOTTOM self.__triangles.close_primitive() self.mesh.add_primitive(self.__triangles) @property def geom_node(self) -> str: return 'geom_node' @geom_node.getter def geom_node(self) -> GeomNode: node = GeomNode(self.name) node.addGeom(self.mesh) return node
def make_points(vertices, colors=None, texture_coords=None, geom=None): """Make or update existing points set geometry. Arguments: root_path {str} -- path to the group's root node name {str} -- node name within a group vertices {list} -- point coordinates (and other data in a point cloud format) Keyword Arguments: colors {list} -- colors (default: {None}) texture_coords {list} -- texture coordinates (default: {None}) geom {Geom} -- geometry to update (default: {None}) Returns: Geom -- p3d geometry """ if not isinstance(vertices, np.ndarray): vertices = np.asarray(vertices, dtype=np.float32) if colors is not None: if not isinstance(colors, np.ndarray): colors = np.asarray(colors) if colors.dtype != np.uint8: colors = np.uint8(colors * 255) vertices = np.column_stack(( vertices.view(dtype=np.uint32).reshape(-1, 3), colors.view(dtype=np.uint32))) if texture_coords is not None: if not isinstance(texture_coords, np.ndarray): texture_coords = np.asarray(texture_coords) vertices = np.column_stack(( vertices.view(dtype=np.uint32).reshape(-1, 3), texture_coords.view(dtype=np.uint32).reshape(-1, 2))) data = vertices.tostring() if geom is None: if vertices.strides[0] == 12: vformat = GeomVertexFormat.get_v3() elif vertices.strides[0] == 16: vformat = GeomVertexFormat.get_v3c4() elif vertices.strides[0] == 20: vformat = GeomVertexFormat.get_v3t2() else: raise ViewerError('Incompatible point clout format: {},{}'.format( vertices.dtype, vertices.shape)) vdata = GeomVertexData('vdata', vformat, Geom.UHDynamic) vdata.unclean_set_num_rows(len(vertices)) vdata.modify_array_handle(0).set_subdata(0, len(data), data) prim = GeomPoints(Geom.UHDynamic) prim.clear_vertices() prim.add_consecutive_vertices(0, len(vertices)) prim.close_primitive() geom = Geom(vdata) geom.add_primitive(prim) else: vdata = geom.modify_vertex_data() vdata.unclean_set_num_rows(len(vertices)) vdata.modify_array_handle(0).set_subdata(0, len(data), data) prim = geom.modify_primitive(0) prim.clear_vertices() prim.add_consecutive_vertices(0, len(vertices)) prim.close_primitive() return geom
def _generate_mesh(points: List[Point]) -> Geom: """Generate mesh for a Path.""" def calc_color(param): return interpolate_rgb(START_COLOR, END_COLOR, param) if len(points) < 2: return Geom() vertex_data = GeomVertexData('path', VERTEX_FORMAT, Geom.UH_static) vertex_data.set_num_rows(2 * len(points) + 1) vertex_writer = GeomVertexWriter(vertex_data, 'vertex') normal_writer = GeomVertexWriter(vertex_data, 'normal') color_writer = GeomVertexWriter(vertex_data, 'color') length = sum(p1.distance(p2) for p1, p2 in window_iter(points)) vector = points[1] - points[0] distance = vector.norm() position = distance / length vector = vector.normalized() width_vector = LANE_WIDTH * 0.5 * vector.rotated_left() for vertex in (points[0] + width_vector, points[0] - width_vector): vertex_writer.add_data3f(vertex.x, vertex.y, HEIGHT) normal_writer.add_data3f(0.0, 0.0, 1.0) color_writer.add_data4f(*START_COLOR) last_vector = vector for point, next_ in zip(islice(points, 1, None), islice(points, 2, None)): vector = next_ - point distance = vector.norm() vector = vector.normalized() try: bisector = (last_vector + vector).normalized() width_vector = (sec(bisector, vector) * 0.5 * LANE_WIDTH * bisector.rotated_left()) except ZeroDivisionError: width_vector = vector.rotated_right() * 0.5 * LANE_WIDTH color = calc_color(position) for vertex in (point + width_vector, point - width_vector): vertex_writer.add_data3f(vertex.x, vertex.y, HEIGHT) normal_writer.add_data3f(0.0, 0.0, 1.0) color_writer.add_data4f(*color) position = position + distance / length last_vector = vector point = points[-1] width_vector = 0.5 * LANE_WIDTH * last_vector.rotated_left() distance = LANE_WIDTH if distance > LANE_WIDTH else distance / 2 vector = -last_vector * distance for vertex in (point + width_vector + vector, point - width_vector + vector, point): vertex_writer.add_data3f(vertex.x, vertex.y, HEIGHT) normal_writer.add_data3f(0.0, 0.0, 1.0) color_writer.add_data4f(*END_COLOR) primitive = GeomTristrips(Geom.UH_static) primitive.add_consecutive_vertices(0, 2 * len(points) + 1) primitive.close_primitive() geom = Geom(vertex_data) geom.add_primitive(primitive) return geom
def gen_geom(self, mesh_json): # Create vertex format geom_array = GeomVertexArrayFormat() geom_array.add_column("vertex", 3, Geom.NTFloat32, Geom.CPoint) has_normals = False has_texcoords = False has_weights = False if "normals" in mesh_json: geom_array.add_column("normal", 3, Geom.NTFloat32, Geom.CNormal) has_normals = True if "texcoords" in mesh_json: geom_array.add_column("texcoord", 3, Geom.NTFloat32, Geom.CTexcoord) has_texcoords = True if "weights" in mesh_json: geom_array.add_column("joint", 4, Geom.NTUint8, Geom.CIndex) geom_array.add_column("weight", 4, Geom.NTFloat32, Geom.COther) has_weights = True geom_format = GeomVertexFormat() geom_format.add_array(geom_array) geom_format = GeomVertexFormat.register_format(geom_format) # Set up vertex data vdata = GeomVertexData( str(random.randint(0, 255)) + "_vdata", geom_format, Geom.UHStatic) vcount = len(mesh_json["vertices"]) // 3 vdata.setNumRows(vcount) vertex = GeomVertexWriter(vdata, "vertex") for i in range(vcount): vertex.addData3(mesh_json["vertices"][3 * i], mesh_json["vertices"][3 * i + 1], mesh_json["vertices"][3 * i + 2]) if has_normals: normal = GeomVertexWriter(vdata, "normal") for i in range(vcount): normal.addData3(mesh_json["normals"][3 * i], mesh_json["normals"][3 * i + 1], mesh_json["normals"][3 * i + 2]) if has_texcoords: texcoord = GeomVertexWriter(vdata, "texcoord") for i in range(vcount): texcoord.addData2(mesh_json["texcoords"][2 * i], mesh_json["texcoords"][2 * i + 1]) if has_weights: joint = GeomVertexWriter(vdata, "joint") weight = GeomVertexWriter(vdata, "weight") for i in range(vcount): joint_count = len(mesh_json["joints"][i]) joint.addData4( 0 if joint_count < 1 else mesh_json["joints"][i][0], 0 if joint_count < 2 else mesh_json["joints"][i][1], 0 if joint_count < 3 else mesh_json["joints"][i][2], 0 if joint_count < 4 else mesh_json["joints"][i][3]) weight.addData4( 0 if joint_count < 1 else mesh_json["weights"][i][0], 0 if joint_count < 2 else mesh_json["weights"][i][1], 0 if joint_count < 3 else mesh_json["weights"][i][2], 0 if joint_count < 4 else mesh_json["weights"][i][3]) # Create primitive prim = GeomTriangles(Geom.UHStatic) for i in range(vcount // 3): prim.addVertices(3 * i, 3 * i + 1, 3 * i + 2) geom = Geom(vdata) geom.add_primitive(prim) # Load texture tex = None if "texture" in mesh_json: tex = Loader(EComponent.base).loadTexture( (Path("resources") / mesh_json["texture"]).absolute()) tex.setMagfilter(SamplerState.FT_nearest) tex.setMinfilter(SamplerState.FT_nearest) # Create new geometry node geom_node = GeomNode(str(random.randint(0, 255)) + "_node") if tex is None: geom_node.addGeom(geom) else: attrib = TextureAttrib.make(tex) state = RenderState.make(attrib) geom_node.addGeom(geom, state) if EComponent.panda_root_node is not None: self.geom_path = EComponent.panda_root_node.attach_new_node( geom_node) self.geom_path.set_shader_input("object_id", self.object_id) # Set shader if has_weights and self.geom_path is not None: self.geom_path.setTag("shader type", "skinned") bone_mats = PTA_LMatrix4f() for _ in range(100): bone_mats.push_back(helper.np_mat4_to_panda(np.identity(4))) self.geom_path.set_shader_input(f"boneMats", bone_mats) # Disable culling self.geom_path.node().setBounds(OmniBoundingVolume()) self.geom_path.node().setFinal(True)
def get_geom(self): geom = Geom(self.vdata) geom.add_primitive(self.tris) return geom
def __make_points(vertices, colours=None, geom: Geom = None) -> Geom: """ This function is largely inspired by panda3d_viewer's implementation. Copyright (c) 2020, Igor Kalevatykh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ if not isinstance(vertices, np.ndarray): vertices = np.asarray(vertices, dtype=np.float32) if colours is not None: if not isinstance(colours, np.ndarray): colours = np.asarray(colours) if colours.dtype != np.uint8: colours = np.uint8(colours * 255) vertices = np.column_stack((vertices.view(dtype=np.uint32).reshape(-1, 3), colours.view(dtype=np.uint32))) data = vertices.tostring() if geom is None: if vertices.strides[0] == 12: vformat = GeomVertexFormat.get_v3() elif vertices.strides[0] == 16: vformat = GeomVertexFormat.get_v3c4() else: raise ValueError('Incompatible point clout format: {},{}'.format(vertices.dtype, vertices.shape)) vdata = GeomVertexData('vdata', vformat, Geom.UHDynamic) vdata.unclean_set_num_rows(len(vertices)) vdata.modify_array_handle(0).set_subdata(0, len(data), data) prim = GeomPoints(Geom.UHDynamic) prim.clear_vertices() prim.add_consecutive_vertices(0, len(vertices)) prim.close_primitive() geom = Geom(vdata) geom.add_primitive(prim) else: vdata = geom.modify_vertex_data() vdata.unclean_set_num_rows(len(vertices)) vdata.modify_array_handle(0).set_subdata(0, len(data), data) prim = geom.modify_primitive(0) prim.clear_vertices() prim.add_consecutive_vertices(0, len(vertices)) prim.close_primitive() return geom
class CubeMesh(): name: str geom: Geom __face_count: int __vertex_data_format: GeomVertexFormat __vertex_data: GeomVertexData __triangles: GeomTriangles __triangle_data: GeomVertexArrayData __vertex: GeomVertexWriter __normal: GeomVertexWriter __wireframe_node: GeomNode def __init__(self, name: str = 'cube_mesh', wireframe_thickness: float = 5) -> None: self.name = name self.__vertex_data_format = GeomVertexFormat.getV3n3() self.__vertex_data = GeomVertexData(name, self.__vertex_data_format, Geom.UHStatic) self.geom = Geom(self.__vertex_data) self.__triangles = GeomTriangles(Geom.UHStatic) self.__triangle_data = self.__triangles.modifyVertices() self.__vertex = GeomVertexWriter(self.__vertex_data, 'vertex') self.__normal = GeomVertexWriter(self.__vertex_data, 'normal') self.__face_count = 0 def add_face(face: Face) -> None: self.__make_face(face) self.__make_face(Face.LEFT) self.__make_face(Face.RIGHT) self.__make_face(Face.BACK) self.__make_face(Face.FRONT) self.__make_face(Face.BOTTOM) self.__make_face(Face.TOP) self.__triangles.close_primitive() self.geom.add_primitive(self.__triangles) def is_connected(x, y, z, x1, y1, z1): return (abs(x - x1) == 1 and abs(y - y1) != 1 and abs(z - z1) != 1) or \ (abs(x - x1) != 1 and abs(y - y1) == 1 and abs(z - z1) != 1) or \ (abs(x - x1) != 1 and abs(y - y1) != 1 and abs(z - z1) == 1) ls = LineSegs() ls.set_thickness(wireframe_thickness) arr_x = [0, 0, 0, 0, 1, 1, 1, 1] arr_y = [0, 0, 1, 1, 1, 1, 0, 0] arr_z = [0, -1, -1, 0, 0, -1, -1, 0] for pos1 in range(len(arr_x) - 1): for pos2 in range(pos1, len(arr_x)): x = arr_x[pos1] y = arr_y[pos1] z = arr_z[pos1] x1 = arr_x[pos2] y1 = arr_y[pos2] z1 = arr_z[pos2] if (is_connected(x, y, z, x1, y1, z1)): ls.move_to(x, y, z) ls.draw_to(x1, y1, z1) self.__wireframe_node = ls.create() def __make_face(self, face: Face, pos: Point = Point(0, 0, 0)) -> None: def make(x1, y1, z1, x2, y2, z2) -> None: if x1 == x2: self.__vertex.add_data3f(x1, y1, z1) self.__vertex.add_data3f(x2, y2, z1) self.__vertex.add_data3f(x2, y2, z2) self.__vertex.add_data3f(x1, y1, z2) self.__normal.add_data3( normalise(2 * x1 - 1, 2 * y1 - 1, 2 * z1 - 1)) self.__normal.add_data3( normalise(2 * x2 - 1, 2 * y2 - 1, 2 * z1 - 1)) self.__normal.add_data3( normalise(2 * x2 - 1, 2 * y2 - 1, 2 * z2 - 1)) self.__normal.add_data3( normalise(2 * x1 - 1, 2 * y1 - 1, 2 * z2 - 1)) else: self.__vertex.add_data3f(x1, y1, z1) self.__vertex.add_data3f(x2, y1, z1) self.__vertex.add_data3f(x2, y2, z2) self.__vertex.add_data3f(x1, y2, z2) self.__normal.add_data3( normalise(2 * x1 - 1, 2 * y1 - 1, 2 * z1 - 1)) self.__normal.add_data3( normalise(2 * x2 - 1, 2 * y1 - 1, 2 * z1 - 1)) self.__normal.add_data3( normalise(2 * x2 - 1, 2 * y2 - 1, 2 * z2 - 1)) self.__normal.add_data3( normalise(2 * x1 - 1, 2 * y2 - 1, 2 * z2 - 1)) vertex_id = self.__face_count * 4 self.__triangles.addVertices(vertex_id, vertex_id + 1, vertex_id + 3) self.__triangles.addVertices(vertex_id + 1, vertex_id + 2, vertex_id + 3) self.__face_count += 1 x, y, z = pos if face == Face.FRONT: make(x + 1, y + 1, z - 1, x, y + 1, z) elif face == Face.BACK: make(x, y, z - 1, x + 1, y, z) elif face == Face.RIGHT: make(x + 1, y, z - 1, x + 1, y + 1, z) elif face == Face.LEFT: make(x, y + 1, z - 1, x, y, z) elif face == Face.TOP: make(x + 1, y + 1, z, x, y, z) elif face == Face.BOTTOM: make(x, y + 1, z - 1, x + 1, y, z - 1) else: raise Exception("unknown face") @property def artificial_lighting(self) -> str: return 'artificial_lighting' @artificial_lighting.getter def artificial_lighting(self) -> bool: return self.__artificial_lighting @property def body_node(self) -> GeomNode: node = GeomNode(self.name) node.addGeom(self.geom) return node @property def wireframe_node(self) -> GeomNode: return self.__wireframe_node