def getWaterSurface(manager, polycount=50000, size=(512, 512)): # Get cache directory... cacheDir = manager.get("paths").getConfig().find("cache").get("path") # Check if the data required already exists... cachedWaterSurface = "%s/plane-%dx%d-%dk.bam" % (cacheDir, size[0], size[1], int(polycount / 1000)) try: return loader.loadModel(cachedWaterSurface) except: pass # Make cache directory if needed... if not os.path.isdir(cacheDir): os.mkdir(cacheDir) # Put in an image... img = PNMImage(*size) img.makeGrayscale() img.fill(0, 0, 0) img.write("%s/black-%dx%d.png" % (cacheDir, size[0], size[1])) # Put in a mesh... ht = HeightfieldTesselator("plane") assert ht.setHeightfield(Filename("%s/black-%dx%d.png" % (cacheDir, size[0], size[1]))) ht.setPolyCount(polycount) ht.setFocalPoint(size[0] * 0.5, size[1] * 0.5) node = ht.generate() node.setPos(-0.5 * size[0], 0.5 * size[1], 0) node.flattenLight() node.writeBamFile(cachedWaterSurface) return node
def export(self, file_name, texture_data): from pandac.PandaModules import PNMImage, VBase4D from pandac.PandaModules import Texture as P3DTexture pnm = PNMImage(256, 1024) self.texture2.store(pnm) pnm.write(file_name)
def get_heightmap_tex(self, size, filename = None): """Generate texture of map """ mod = self.world_size / size image = PNMImage(size, size) for x in xrange(size): for y in xrange(size): px = x * mod py = y * mod height = self[px, py] color = height / 50 r = 0 g = 0 b = 0 if color > 255: color = 255 if color < 0: color = abs(color) b = color else: g = color image.setPixel(x, y, (r, g, b)) if filename != None: image.write(filename) #for x in xrange(-1, 2): #for y in xrange(-1, 2): #image.setPixel(int(world.chunks_map.charX)+x, int(world.chunks_map.charY)+y, (255, 0, 0)) texture = Texture() texture.load(image) return texture
def getWaterSurface(manager, polycount=50000, size=(512, 512)): # Get cache directory... cacheDir = manager.get('paths').getConfig().find('cache').get('path') # Check if the data required already exists... cachedWaterSurface = "%s/plane-%dx%d-%dk.bam" % ( cacheDir, size[0], size[1], int(polycount / 1000)) try: return loader.loadModel(cachedWaterSurface) except: pass # Make cache directory if needed... if not os.path.isdir(cacheDir): os.mkdir(cacheDir) # Put in an image... img = PNMImage(*size) img.makeGrayscale() img.fill(0, 0, 0) img.write("%s/black-%dx%d.png" % (cacheDir, size[0], size[1])) # Put in a mesh... ht = HeightfieldTesselator("plane") assert ht.setHeightfield( Filename("%s/black-%dx%d.png" % (cacheDir, size[0], size[1]))) ht.setPolyCount(polycount) ht.setFocalPoint(size[0] * 0.5, size[1] * 0.5) node = ht.generate() node.setPos(-0.5 * size[0], 0.5 * size[1], 0) node.flattenLight() node.writeBamFile(cachedWaterSurface) return node
def get_heightmap_tex(self, size, filename=None): """Generate texture of map """ mod = self.world_size / size image = PNMImage(size, size) for x in xrange(size): for y in xrange(size): px = x * mod py = y * mod height = self[px, py] color = height / 50 r = 0 g = 0 b = 0 if color > 255: color = 255 if color < 0: color = abs(color) b = color else: g = color image.setPixel(x, y, (r, g, b)) if filename != None: image.write(filename) #for x in xrange(-1, 2): #for y in xrange(-1, 2): #image.setPixel(int(world.chunks_map.charX)+x, int(world.chunks_map.charY)+y, (255, 0, 0)) texture = Texture() texture.load(image) return texture
def paintEvent(self, event): screenData = StringStream() # Used to pass the data as a string screenImage = PNMImage() # Converts the texture data into a format usable with Qt if self.pandaTexture.hasRamImage(): print "Should draw yes?" self.pandaTexture.store(screenImage) screenImage.write(screenData, "test.ppm") self.paintPixmap.loadFromData(screenData.getData()) self.paintSurface.setPixmap(self.paintPixmap)
def get_map_3d_tex(self, size, filename=None, charPos=None): """Generate texture of map """ mod = self.world_size / size image = PNMImage(size, size) for x in xrange(size): for y in xrange(size): px = x * mod py = y * mod height = self[px, py] if height <= 0: color = (abs(height) / 50) + 50 if color > 255: color = 255 image.setPixel(x, y, (0, 0, 255 - color)) else: if height <= self.config.low_mount_level[1]: color = height / 20 r = 0 g = 50 + color b = 0 image.setPixel(x, y, (r, g, b)) elif height > self.config.low_mount_level[1]: color = height / 50 r = color g = color b = color if r > 255: r = 255 if g > 255: r = 255 if b > 255: b = 255 image.setPixel(x, y, (r, g, b)) if filename != None: image.write(filename) if charPos != None: charX, charY = charPos for x in xrange(-1, 2): for y in xrange(-1, 2): image.setPixel( int(charX / mod) + x, int(charY / mod) + y, (255, 0, 0)) texture = Texture() texture.load(image) return texture
def createPickingImage(size): ''' create a picking image with uniq colors for each point in the image ''' image = PNMImage(*size) for x in xrange(size[0]): for y in xrange(size[1]): r = x % 256 g = y % 256 b = (x // 256) + (y//256) * 16 image.setXelVal(x,y,r,g,b) # Reverse way is: # tx = r + ((b%16)*256) # ty = g + ((b//16)*256) imageFilename = 'data/textures/index-%i-%i.png' % (size[0], size[1]) image.write(Filename(imageFilename))
def createPickingImage(size): ''' create a picking image with uniq colors for each point in the image ''' image = PNMImage(*size) for x in xrange(size[0]): for y in xrange(size[1]): r = x % 256 g = y % 256 b = (x // 256) + (y // 256) * 16 image.setXelVal(x, y, r, g, b) # Reverse way is: # tx = r + ((b%16)*256) # ty = g + ((b//16)*256) imageFilename = 'data/textures/index-%i-%i.png' % (size[0], size[1]) image.write(Filename(imageFilename))
def get_map_3d_tex(self, size, filename = None, charPos = None): """Generate texture of map """ mod = self.world_size / size image = PNMImage(size, size) for x in xrange(size): for y in xrange(size): px = x * mod py = y * mod height = self[px, py] if height <= 0: color = (abs(height) / 50) + 50 if color > 255: color = 255 image.setPixel(x, y, (0, 0, 255-color)) else: if height <= self.config.low_mount_level[1]: color = height / 20 r = 0 g = 50+color b = 0 image.setPixel(x, y, (r, g, b)) elif height > self.config.low_mount_level[1]: color = height / 50 r = color g = color b = color if r > 255: r = 255 if g > 255: r = 255 if b > 255: b = 255 image.setPixel(x, y, (r, g, b)) if filename != None: image.write(filename) if charPos != None: charX, charY = charPos for x in xrange(-1, 2): for y in xrange(-1, 2): image.setPixel(int(charX/mod)+x, int(charY/mod)+y, (255, 0, 0)) texture = Texture() texture.load(image) return texture
def setupHeightfield( self ): # Prep terrain textures #coverTextureFile = "data/textures/ground/green.jpg" #self.mCoverTexture = loader.loadTexture(coverTextureFile) # Setup heightfield self.mHeightFieldTesselator = HeightfieldTesselator("Heightfield") #fName = "data/textures/ground/heightfield.png" #self.mHeightFieldTesselator.setPolyCount(10000) #fileObj = Filename(fName) self.mTerrainVScale = self.mTerrainUScale = 1.0/1024.0 myImage=PNMImage(256,256) myImage.makeGrayscale() p = Perlin(numberOfOctaves = 10, persistance = 0.65, smooth = False) for y in range(0,256): for x in range(0,256): i = p.noise2D(float(x)/256.0,float(y)/256.0) myImage.setGray(x, y, abs(i)) bigImage=PNMImage(1024, 1024) bigImage.gaussianFilterFrom(1.0, myImage) fileObj = Filename("data/textures/ground/myHeightfield.png") bigImage.write(fileObj) #myTexture = Texture() #myTexture.load(bigImage) self.mHeightFieldTesselator.setHeightfield(fileObj) self.mTerrainHeight = MAPSIZE/10 self.mHeightFieldTesselator.setVerticalScale(self.mTerrainHeight) self.mHorizontalScale = MAPSIZE/1024.0 self.mHeightFieldTesselator.setHorizontalScale(self.mHorizontalScale) self.mHeightFieldNode = None # self.tex0 = loader.loadTexture( 'models/textures/ground/schachbrett.png' ) self.tex0 = loader.loadTexture( 'data/textures/ground/mud-tile.png' ) #self.tex1 = loader.loadTexture( 'data/models/textures/ground/green.jpg' ) #self.tex2 = loader.loadTexture( 'data/models/textures/ground/grey-green-leaves.jpg' ) #self.ts0 = TextureStage( 'dirt' ) #self.ts1 = TextureStage( 'fungus' ) #self.ts2 = TextureStage( 'grass' ) self.updateHeightField()
class TerrainTile(GeoMipTerrain): """TerrainTiles are the building blocks of a terrain.""" def __init__(self, terrain, x, y): """Builds a Tile for the terrain at input coordinates. Important settings are used directly from the terrain. This allows for easier setting changes, and reduces memory overhead. x and y parameters give the appropriate world coordinates of this tile. """ self.terrain = terrain self.xOffset = x self.yOffset = y self.heightMapDetail = 1 # higher means greater detail self.name = "ID" + str(terrain.id) + "_X" + str(x) + "_Y" + str(y) GeoMipTerrain.__init__(self, name=self.name) self.image = PNMImage() #self.setAutoFlatten(GeoMipTerrain.AFMOff) self.setFocalPoint(self.terrain.focus) self.setAutoFlatten(GeoMipTerrain.AFMOff) self.getRoot().setPos(x, y, 0) if self.terrain.bruteForce: GeoMipTerrain.setBruteforce(self, True) GeoMipTerrain.setBlockSize( self, self.terrain.heightMapSize * self.heightMapDetail) else: GeoMipTerrain.setBlockSize(self, self.terrain.blockSize / 2) #self.setBorderStitching(1) self.setNear(self.terrain.near) self.setFar(self.terrain.far) def update(self): """Updates the GeoMip to use the correct LOD on each block.""" #logging.info("TerrainTile.update()") GeoMipTerrain.update(self) @pstat def updateTask(self, task): """Updates the GeoMip to use the correct LOD on each block.""" self.update() return task.again #@pstat def setHeightField(self, filename): """Set the GeoMip heightfield from a heightmap image.""" GeoMipTerrain.setHeightfield(self, filename) @pstat def generate(self): GeoMipTerrain.generate(self) @pstat def setHeight(self): """Sets the height field to match the height map image.""" self.setHeightField(self.image) @pstat def makeHeightMap(self): """Generate a new heightmap image. Panda3d GeoMipMaps require an image from which to build and update their height field. This function creates the correct image using the tile's position and the Terrain's getHeight() function. """ if SAVED_HEIGHT_MAPS: fileName = "maps/height/" + self.name + ".png" self.getRoot().setTag('EditableTerrain', '1') if self.image.read(Filename(fileName)): logging.info("read heightmap from " + fileName) return heightMapSize = self.terrain.tileSize * self.heightMapDetail + 1 self.image = PNMImage(heightMapSize, heightMapSize, 1, 65535) ySize = self.image.getYSize() - 1 getHeight = self.terrain.getHeight setGray = self.image.setGray xo = self.xOffset yo = self.yOffset d = self.heightMapDetail for x in range(self.image.getXSize()): for y in range(ySize + 1): height = getHeight(x / d + xo, y / d + yo) # feed pixel into image # why is it necessary to invert the y axis I wonder? setGray(x, ySize - y, height) #self.postProcessImage() if SAVED_HEIGHT_MAPS: fileName = "maps/height/" + self.name + ".png" logging.info("saving heightmap to " + fileName) self.image.write(Filename(fileName)) def postProcessImage(self): """Perform filters and manipulations on the heightmap image.""" #self.image.gaussianFilter() def setWireFrame(self, state): self.getRoot().setRenderModeWireframe() def makeSlopeMap(self): self.slopeMap = PNMImage() if SAVED_SLOPE_MAPS: fileName = "maps/slope/" + self.name + ".png" if self.slopeMap.read(Filename(fileName)): logging.info("read slopemap from " + fileName) return self.slopeMap = PNMImage(self.terrain.heightMapSize, self.terrain.heightMapSize) self.slopeMap.makeGrayscale() self.slopeMap.setMaxval(65535) size = self.slopeMap.getYSize() getNormal = self.getNormal setGray = self.slopeMap.setGray for x in range(size): for y in range(size): #note getNormal works at the same resolution as the heightmap normal = getNormal(x, y) # feed pixel into image # why is it necessary to invert the y axis I wonder? #logging.info( normal) normal.z /= self.terrain.getSz() normal.normalize() slope = 1.0 - normal.dot(Vec3(0, 0, 1)) setGray(x, y, slope) if SAVED_SLOPE_MAPS: fileName = "maps/slope/" + self.name + ".png" logging.info("saving slopemap to " + fileName) self.slopeMap.write(Filename(fileName)) def createGroups(self): self.statics = self.getRoot().attachNewNode(self.name + "_statics") self.statics.setSz(1.0 / self.terrain.getSz()) self.statics.setSx(1.0 / self.terrain.getSx()) self.statics.setSy(1.0 / self.terrain.getSy()) self.statics.setShaderAuto() @pstat def make(self): """Build a finished renderable heightMap.""" # apply shader #logging.info( "applying shader") self.terrain.texturer.apply(self.getRoot()) # detail settings #self.getRoot().setSx(1.0 / self.heightMapDetail) #self.getRoot().setSy(1.0 / self.heightMapDetail) #logging.info( "making height map") self.makeHeightMap() #logging.info( "setHeight()") self.setHeight() #self.getRoot().setSz(self.maxHeight) #http://www.panda3d.org/forums/viewtopic.php?t=12054 self.calcAmbientOcclusion() #logging.info( "generate()") self.generate() self.getRoot().setCollideMask(BitMask32.bit(1)) #self.makeSlopeMap() #logging.info( "createGroups()") self.createGroups() self.terrain.populator.populate(self)
class TerrainTile(GeoMipTerrain): """TerrainTiles are the building blocks of a terrain.""" def __init__(self, terrain, x, y): """Builds a Tile for the terrain at input coordinates. Important settings are used directly from the terrain. This allows for easier setting changes and reduces memory overhead. x and y parameters give the appropriate world coordinates of this tile. """ self.terrain = terrain self.xOffset = x self.yOffset = y self.heightMapDetail = 1 # higher means greater detail self.name = "ID" + str(terrain.id) + "_X" + str(x) + "_Y" + str(y) GeoMipTerrain.__init(self, name=self.name) self.image = PNImage() #self.setAutoFlatten(GeoMipTerrain.AFMOff self.setFocalPoint(self.terrain.focus) self.setAutoFlatten(GeoMipTerrain.AFMOff) self.getRoot().setPos(x, y, 0) if self.terrain.bruteForce: GeoMipTerrain.setBruteForce(self, True) GeoMipTerrain.setBlockSize(self, self.terrain.heightMapSize * self.heightMapDetail) else: GeoMipTerrain.setBlockSize(self, self.terrain.blockSize/2) #self.setBorderStitching(1) self.setNear(self.terrain.near) self.setFar(self.terrain.far) def update(self): """Updates the GeoMip to use the correct LOD on each block.""" #logging.info("TerrainTile.update()") GeoMipTerrain.update(self) @pstat def updateTask(self, task): """Updates the GeoMip to use the correct LOD on each block.""" self.update() return task.again #@pstat def setHeightField(self, filename): "Set the GeoMip heightfield from a heightmap image.""" GeoMipTerrain.setHeightfield(self, filename) @pstat def generate(self): GeoMipTerrain.generate(self) @pstat def setHeight(self): """Sets the height field to match the height map image.""" self.setHeightField(self.image) @pstat def makeHeightMap(self): """Generate a new heightmap image. Panda3d GeoMipMaps require an image from which to build and update their height field. This function creates the correct image using the tile's position and the Terrain's getHeight() function. """ if SAVED_HEIGHT_MAPS: fileName = "maps/height/" + self.name + ".png" self.getRoot().setTag('EditableTerrain', '1') if self.image.read(Filename(fileName)): logging.info( "read heightmap from " + fileName) return heightMapSize = self.terrain.tileSize * self.heightMapDetail + 1 self.image = PNMImage(heightMapSize, heightMapSize, 1, 65535) ySize = self.image.getYSize() - 1 getHeight = self.terrain.getHeight setGray = self.image.setGray xo = self.xOffset yo = self.yOffset d = self.heightMapDetail for x in range(self.image.getXSize()): for y in range(ySize + 1): height = getHeight(x / d + xo, y / d + yo) # feed pixel into image # why is it necessary to invert the y axis I wonder? setGray(x, ySize - y, height) #self.postProcessImage() if SAVED_HEIGHT_MAPS: fileName = "maps/height/" + self.name + ".png" logging.info( "saving heightmap to " + fileName) self.image.write(Filename(fileName)) def postProcessImage(self): """Perform filters and manipulations on the heightmap image.""" #self.image.gaussianFilter() def setWireFrame(self, state): self.getRoot().setRenderModeWireframe() def makeSlopeMap(self): self.slopeMap = PNMImage() if SAVED_SLOPE_MAPS: fileName = "maps/slope/" + self.name + ".png" if self.slopeMap.read(Filename(fileName)): logging.info( "read slopemap from " + fileName) return self.slopeMap = PNMImage(self.terrain.heightMapSize, self.terrain.heightMapSize) self.slopeMap.makeGrayscale() self.slopeMap.setMaxval(65535) size = self.slopeMap.getYSize() getNormal = self.getNormal setGray = self.slopeMap.setGray for x in range(size): for y in range(size): #note getNormal works at the same resolution as the heightmap normal = getNormal(x, y) # feed pixel into image # why is it necessary to invert the y axis I wonder? #logging.info( normal) normal.z /= self.terrain.getSz() normal.normalize() slope = 1.0 - normal.dot(Vec3(0, 0, 1)) setGray(x, y, slope) if SAVED_SLOPE_MAPS: fileName = "maps/slope/" + self.name + ".png" logging.info( "saving slopemap to " + fileName) self.slopeMap.write(Filename(fileName)) def createGroups(self): self.statics = self.getRoot().attachNewNode(self.name + "_statics") self.statics.setSz(1.0 / self.terrain.getSz()) self.statics.setSx(1.0 / self.terrain.getSz()) self.statics.setSy(1.0 / self.terrain.getSy()) self.statics.setShaderAuto() @pstat def make(self): """Build a finished renderable heightMap.""" # apply shader #logging.info( "applying shader") self.terrain.texturer.apply(self.getRoot()) # detail settings #self.getRoot().setSz(1.0 / self.heightMapDetail) #self.getRoot().setSy(1.0 / self.heightMapDetail) #logging.info( "making height map") self.makeHeightMap() #logging.info( "setHeight()") self.setHeight() #self.getRoot().setSz(self.maxHeight) #http://www.panda3d.org/forums/viewtopic.php?=t=12054 self.calcAmbientOcclusion() #loggin.info( "generate()") self.generate() self.getRoot().setCollideMask(BitMask32.bit(1)) #self.makeSlopeMap() #logging.info( "createGroups()") self.createGroups() self.terrain.populator.populate(self)