@tungsten
If you want the proper method, serega-kkz answer is the way to go. But since I wanted to try out the procedurally generated section of the manual I’m doing something like this (translated on the fly so be nice to my var name) :
from panda3d.core import GeomVertexFormat, GeomVertexData, Geom, GeomVertexWriter, GeomLinestrips, GeomNode
from direct.showbase.ShowBase import ShowBase
import math
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
hexGrid = self.drawGrid()
hexagon_nodepath = self.render.attachNewNode(hexGrid)
#You can twist the surface to draw Hexagon on and their size here
def drawGrid(self, start=(0, 0), end=(10, 10), HexSize=1):
self.HexList = self.getGridData(start, end, HexSize)
indexation = self.indexList(self.HexList)
self.verticesList = indexation[0]
self.HexsIndex = indexation[1]
array = self.create_array(self.verticesList, 'Hexagon')
geom = Geom(array)
for hex in self.HexsIndex:
prim = self.create_lineStrips_prim(hex)
geom.add_primitive(prim)
gridNode = GeomNode('Hex Grid')
gridNode.addGeom(geom)
return gridNode
def getGridData(self, start, end, size):
#This function calculate every vertices per hex that we need to have a grid
firstx = start[0]
firsty = start[1]
actualy = firsty
endx = end[0]
endy = end[1]
from_x_to_x = math.sqrt(3) * size
from_y_to_y = (2 * size) * (3 / 4)
x_offset = from_x_to_x / 2
poly_grid = []
row = 1
while actualy < endy:
if row % 2 == 0:
actual_x = firstx + x_offset
else:
actual_x = firstx
while actual_x < endx:
poly = []
for i in range(6):
angle_deg = 60 * i - 30
angle_rad = math.pi / 180 * angle_deg
x = actual_x + size * math.cos(angle_rad)
y = actualy + size * math.sin(angle_rad)
# If you don't round here, there is no optimisation done in a later step
poly.append((round(x, 4), round(y, 4)))
poly.append(poly[0])
poly_grid.append(poly)
actual_x += from_x_to_x
actualy += from_y_to_y
row += 1
return poly_grid
def indexList(self, HexList):
#Here we're doing 2 things : Firts we create a new list of vertices with no double; and at the same time we're collecting the indexes to create our lineStrip later
new_list = []
hexIndex = []
for hexagon in HexList:
actual_hex = []
for vertices in hexagon:
if vertices in new_list:
# If we haven't round earlier, this won't work, we'll just gonna copy the list.
actual_hex.append(new_list.index(vertices))
else :
new_list.append(vertices)
actual_hex.append(new_list.index(vertices))
hexIndex.append(actual_hex)
return new_list, hexIndex
def create_array(self, list_of_points, array_name='unknown'):
#Here we're creating the GeomVertexData and Writer, then we feed them our vertices
type_of_array = array_name
number_of_row = len(list_of_points)
array_format = GeomVertexFormat.get_v3()
vdata = GeomVertexData(type_of_array, array_format, Geom.UHStatic)
vdata.setNumRows(number_of_row)
vertex = GeomVertexWriter(vdata, 'vertex')
for point in list_of_points:
vertex.addData3(point[0], 0, point[1])
return vdata
#Here you can twist this function to have it draw TriStrip if that's what you want by picking the indexes [2, 3, 1, 4, 0, 5] instead of the order we send them in
def create_lineStrips_prim(self, HexIndex):
prim = GeomLinestrips(Geom.UHStatic)
for point in HexIndex:
prim.add_vertex(point)
prim.close_primitive()
return prim
app = MyApp()
app.run()
I then save the node with node.writeBamFile, since i’m not really interested on saving the model, but serega-kkz answer is safer to store your model long terme
I’ve try my best to be easy to understand, feel free to ask if something isn’t clear of if you have trouble with the sample code.
@rdb
That does imply that if you call modifyGeom on one of the GeomNodes, it will create a unique copy of the Geom.
Thanks for your answer ! This is working in the sense that it create a new GeomNode with the same Geom, but since I’m creating à copy of my first Geom I actually end with two of them (each new Hex increase my Geom counter by one on the scene graph analyzer). I’m wondering if it’s possible to add a new GeomNode without increasing my Geom count at all.