def fillTextureStages(self, nodePath): """ Prepares all materials of a given nodepath to have at least the 4 default textures in the correct order: [diffuse, normal, specular, roughness] """ emptyDiffuseTex = loader.loadTexture("Data/Textures/EmptyDiffuseTexture.png") emptyNormalTex = loader.loadTexture("Data/Textures/EmptyNormalTexture.png") emptySpecularTex = loader.loadTexture("Data/Textures/EmptySpecularTexture.png") emptyRoughnessTex = loader.loadTexture("Data/Textures/EmptyRoughnessTexture.png") textureOrder = [emptyDiffuseTex, emptyNormalTex, emptySpecularTex, emptyRoughnessTex] textureSorts = [0, 10, 20, 30] # Prepare the textures for tex in textureOrder: tex.setMinfilter(SamplerState.FTLinear) tex.setMagfilter(SamplerState.FTLinear) tex.setFormat(Texture.FRgba) # Iterate over all geom nodes for np in nodePath.findAllMatches("**/+GeomNode"): # Check how many texture stages the nodepath already has stages = np.findAllTextureStages() numStages = len(stages) # Fill the texture stages up for i in xrange(numStages, 4): stage = TextureStage("DefaultTexStage" + str(i)) stage.setSort(textureSorts[i]) stage.setMode(TextureStage.CMModulate) stage.setColor(Vec4(0, 0, 0, 1)) np.setTexture(stage, textureOrder[i])
def makeTextureMap(self): '''Citymania function that generates and sets the 4 channel texture map''' self.colorTextures = [] for terrain in self.terrains: terrain.getRoot().clearTexture() heightmap = terrain.heightfield() colormap = PNMImage(heightmap.getXSize()-1, heightmap.getYSize()-1) colormap.addAlpha() slopemap = terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x,y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) colorTexture = Texture() colorTexture.load(colormap) colorTS = TextureStage('color') colorTS.setSort(0) colorTS.setPriority(1) self.colorTextures.append((colorTexture, colorTS))
def makeTextureMap(self): '''Citymania function that generates and sets the 4 channel texture map''' self.colorTextures = [] for terrain in self.terrains: terrain.getRoot().clearTexture() heightmap = terrain.heightfield() colormap = PNMImage(heightmap.getXSize() - 1, heightmap.getYSize() - 1) colormap.addAlpha() slopemap = terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x, y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) colorTexture = Texture() colorTexture.load(colormap) colorTS = TextureStage('color') colorTS.setSort(0) colorTS.setPriority(1) self.colorTextures.append((colorTexture, colorTS))
def __apply_Textures(self, recipe, tex_dict): for i, ter_dict in enumerate(recipe['terrains']): tex_img = PNMImage() tex_img.read(Filename("{}/tex/{}".format(recipe['planet_path'], ter_dict['texture']))) tex = Texture() tex.load(tex_img) tex.setMinfilter(Texture.FTLinear) ts = TextureStage(str(i)) ts.setSort(i) self.NP.setTexture(ts, tex, i*10)
def addTexture(stage,path): tex=loader.loadTexture(path) tex.setWrapU(Texture.WMRepeat) tex.setWrapV(Texture.WMRepeat) s=str(stage) TS=model.findTextureStage(s) if not TS: TS=TextureStage(s) TS.setMode(TSmode[stage-2]) TS.setSort(stage-1) model.setTexture(TS,tex)
def setOwnerTextures(self): self.ownerview = True root = self.terrain.getRoot() root.clearShader() root.clearTexture() cityTexture = Texture() cityTexture.load(self.citymap) cityTS = TextureStage('citymap') cityTS.setSort(0) root.setTexture( self.gridTS, self.gridTexture ) root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks) root.setTexture(cityTS, cityTexture, 1)
def setOwnerTextures(self): self.ownerview = True root = self.terrain.getRoot() root.clearShader() root.clearTexture() cityTexture = Texture() cityTexture.load(self.citymap) cityTS = TextureStage('citymap') cityTS.setSort(0) root.setTexture(self.gridTS, self.gridTexture) root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks) root.setTexture(cityTS, cityTexture, 1)
def splatting(node, first, second, stencil, scale=None, offset=None): """Apply a texture splatting to the provided NodePath. """ # Apply the first texture. ts1 = TextureStage("stage-first") ts1.setSort(0) ts1.setMode(TextureStage.MReplace) ts1.setSavedResult(True) node.setTexture(ts1, first) # Apply the second texture. ts2 = TextureStage("stage-second") ts2.setSort(1) ts2.setMode(TextureStage.MReplace) node.setTexture(ts2, second) # Apply the stencil. ts3 = TextureStage("stage-stencil") ts3.setSort(2) ts3.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) node.setTexture(ts3, stencil) if scale: node.setTexScale(ts3, scale, scale) if offset is not None: node.setTexOffset(ts1, *offset) node.setTexOffset(ts2, *offset) node.setTexOffset(ts3, *offset)
def apply_splatted_textures(self, tile: NodePath, first_tex, second_tex, stencil_tex): # first = self.load("textures/sand_tex_1.png") # second = self.load("textures/grass_tex_1.png") # third = self.load("textures/water_tex_1.png") # stencil = self.load("textures/stencil_tex_1.png") # stencil_2 = self.load("textures/stencil_tex_2.png") # # normal = self.load("textures/sea-normal.jpg") # normal = self.loader.load_texture("textures/layingrock-n.jpg") # Apply the first texture. ts1 = TextureStage("stage-first") ts1.setSort(0) ts1.setMode(TextureStage.MReplace) ts1.setSavedResult(True) tile.setTexture(ts1, first_tex) # Apply the second texture. ts2 = TextureStage("stage-second") ts2.setSort(1) ts2.setMode(TextureStage.MReplace) tile.setTexture(ts2, second_tex) ts3 = TextureStage("stage-stencil") ts3.setSort(2) ts3.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) ts3.setSavedResult(True) tile.setTexture(ts3, stencil_tex)
def __create_terrain(self): terrain = GeoMipTerrain("Terrain") terrain.setHeightfield(self.__texture_path(self.__scene.get("scene", "heightmap"))) terrain.getRoot().reparentTo(self.render) terrain.generate() terrain.getRoot().setSx(1000.0 / 512) terrain.getRoot().setSy(1000.0 / 512) terrain.getRoot().setSz(74) terrain.getRoot().setPos(-500, -500, 0) black = self.loader.loadTexture(self.__texture_path(self.__scene.get("terrain", "black"))) black.setMinfilter(Texture.FTLinearMipmapNearest) ts = TextureStage("stage-first") ts.setSort(0) ts.setMode(TextureStage.MReplace) ts.setSavedResult(True) terrain.getRoot().setTexture(ts, black) terrain.getRoot().setTexScale(ts, 250, 250) white = self.loader.loadTexture(self.__texture_path(self.__scene.get("terrain", "white"))) white.setMinfilter(Texture.FTLinearMipmapNearest) ts = TextureStage("stage-second") ts.setSort(1) ts.setMode(TextureStage.MReplace) terrain.getRoot().setTexture(ts, white) terrain.getRoot().setTexScale(ts, 250, 250) stencil = self.loader.loadTexture(self.__texture_path(self.__scene.get("scene", "stencil"))) ts = TextureStage("stage-stencil") ts.setSort(2) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) terrain.getRoot().setTexture(ts, stencil) ts = TextureStage("stage-vertexcolour") ts.setSort(3) ts.setCombineRgb(TextureStage.CMModulate, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSPrimaryColor, TextureStage.COSrcColor) terrain.getRoot().setTexture(ts, "final")
class ShadowCaster(DirectObject): def __init__(self): DirectObject.__init__(self) self.shadowCamArm = None self.casterState = None self.shadowBuffer = None self.shadowColor = 0.5 self.shadowColorIndex = 0 self.shadowsEnabled = 0 self.clearColor = VBase4(1, 1, 1, 1) self.setupTask = None self.shadowsHidden = False def enable(self): camNode = Camera('shadowCam') camNode.setCameraMask(CIGlobals.ShadowCameraBitmask) self.shadowLens = OrthographicLens() self.shadowLens.setFilmSize(60 * 4, 60 * 4) camNode.setLens(self.shadowLens) self.shadowCamArm = camera.attachNewNode('shadowCamArm') self.shadowCam = self.shadowCamArm.attachNewNode(camNode) self.shadowCamArm.setPos(0, 40, 0) self.shadowCam.setPos(0, -40, 0) self.shadowTex = Texture('shadow') self.shadowTex.setBorderColor(self.clearColor) self.shadowTex.setWrapU(Texture.WMBorderColor) self.shadowTex.setWrapV(Texture.WMBorderColor) self.casterState = NodePath('temp') self.casterState.setColorScaleOff(10) self.casterState.setColor(self.shadowColor, self.shadowColor, self.shadowColor, 1, 10) self.casterState.setTextureOff(10) self.casterState.setLightOff(10) self.casterState.setFogOff(10) camNode.setInitialState(self.casterState.getState()) render.hide(CIGlobals.ShadowCameraBitmask) self.shadowStage = TextureStage('shadow') self.shadowStage.setSort(1000) self.turnOnShadows() def disable(self): if not self.shadowsEnabled: return None self.shadowsEnabled = 0 self.shadowCamArm.removeNode() self.shadowCam.removeNode() base.camNode.clearTagState('caster') self.turnOffShadows() self.shadowTex = None self.shadowStage = None def turnOnShadows(self): render.setTexProjector(self.shadowStage, NodePath(), self.shadowCam) def turnOffShadows(self): render.clearTexProjector(self.shadowStage) self.destroyBuffer() def createBuffer(self): if not base.win.getGsg(): return None self.shadowBuffer = base.win.makeTextureBuffer('shadow', 1024 * 4, 1024 * 4, tex=self.shadowTex) self.shadowBuffer.setSort(30) self.shadowBuffer.setClearColor(self.clearColor) dr = self.shadowBuffer.makeDisplayRegion() dr.setCamera(self.shadowCam) self.setupCamera() def setupCamera(self): groundState = NodePath('temp') groundState.setTexture(self.shadowStage, self.shadowTex) groundState.setTexGen(self.shadowStage, TexGenAttrib.MWorldPosition) base.camNode.setTagStateKey('cam') base.camNode.setTagState('shground', groundState.getState()) def destroyBuffer(self): if self.shadowBuffer: base.graphicsEngine.removeWindow(self.shadowBuffer) self.shadowBuffer = None
class Terrain: folder = os.path.dirname(os.path.abspath(__file__)) subfolder = "/Maps/" file = "simple.jpg" filepath = folder + subfolder + file def __init__(self): fn = Filename.fromOsSpecific(self.filepath) self.terrain = GeoMipTerrain("mySimpleTerrain") self.terrain.setHeightfield("Entities/Maps/heightmap.png") self.terrain.getRoot().setSz(40) #terrain.setBruteforce(True) self.terrain.getRoot().reparentTo(render) # Set terrain properties self.terrain.setBlockSize(16) self.terrain.setNear(500) self.terrain.setFar(100) self.terrain.setFocalPoint(base.camera) # Store the root NodePath for convenience root = self.terrain.getRoot() root.reparentTo(render) # some tinkering """ # tell renderer to repeat texture when reading over the edge. texGrass.setWrapU(Texture.WM_repeat) texGrass.setWrapV(Texture.WM_repeat) # apply mipmapping: tell renderer how to handle multiple texture pixels being rendered t a single screen pixel (makes textures 30% larger in GPU mem.) texGrass.setMinfilter(SamplerState.FT_linear_mipmap_linear) """ self.terrain.generate() """ new attempt to include blend mapping: """ # determine terrain size self.heightmap = self.terrain.heightfield() if self.heightmap.getXSize() > self.heightmap.getYSize(): self.size = self.heightmap.getXSize() - 1 else: self.size = self.heightmap.getYSize() - 1 self.xsize = self.heightmap.getXSize() - 1 self.ysize = self.heightmap.getYSize() - 1 # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 self.generateSurfaceTextures() # load a blend texture from file: self.blendTexture = loader.loadTexture("Entities/Maps/blendMap.png") self.blendTS = TextureStage('blend') self.blendTS.setSort(0) self.blendTS.setPriority(1) # apply textures to the terrain and connect custom shader for blend mapping: self.setSurfaceTextures() # Add a task to keep updating the terrain (for changing terrain, or synamic resolution) def updateTask(task): self.terrain.update() return task.cont taskMgr.add(updateTask, "update") # this is where we load the textures to be assigned to the terrain def generateSurfaceTextures(self): # Textureize self.grassTexture = loader.loadTexture("Entities/Maps/grassy2.png") self.grassTexture.setWrapU(Texture.WMRepeat) self.grassTexture.setWrapV(Texture.WMRepeat) self.grassTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear) self.grassTexture.setAnisotropicDegree(8) self.grassTS = TextureStage('grass') self.grassTS.setSort( 1) # sorting order is relevent for assigning textures to the four self.rockTexture = loader.loadTexture("Entities/Maps/simple.jpg") self.rockTexture.setWrapU(Texture.WMRepeat) self.rockTexture.setWrapV(Texture.WMRepeat) self.rockTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear) #self.grassTexture.setAnisotropicDegree(8) self.rockTS = TextureStage('rock') self.rockTS.setSort(2) # self.rockTS.setCombineRgb(TextureStage.CMAdd, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) self.sandTexture = loader.loadTexture("Entities/Maps/stars.png") self.sandTexture.setWrapU(Texture.WMRepeat) self.sandTexture.setWrapV(Texture.WMRepeat) self.sandTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear) #self.sandTexture.setAnisotropicDegree(8) self.sandTS = TextureStage('sand') self.sandTS.setSort(3) self.sandTS.setPriority(5) # TODO: figure out what this is for... self.snowTexture = loader.loadTexture("Entities/Maps/grass.png") self.snowTexture.setWrapU(Texture.WMRepeat) self.snowTexture.setWrapV(Texture.WMRepeat) self.snowTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear) #self.snowTexture.setAnisotropicDegree(8) self.snowTS = TextureStage('snow') self.snowTS.setSort(4) self.snowTS.setPriority(0) # a background (or rather freground?) texture that will be present independently from the blend map (consider removal) self.overlayTexture = loader.loadTexture("Entities/Maps/heightmap.png") self.overlayTexture.setWrapU(Texture.WMRepeat) self.overlayTexture.setWrapV(Texture.WMRepeat) self.overlayTexture.setMinfilter(SamplerState.FT_linear_mipmap_linear) #self.overlayTexture.setAnisotropicDegree(8) self.overlayTS = TextureStage('overlay') self.overlayTS.setSort(5) self.overlayTS.setPriority(10) # this is where we assign loaded textures to be blended in the shader. def setSurfaceTextures(self): self.ownerview = False root = self.terrain.getRoot() root.clearTexture() #self.terrain.setTextureMap() root.setTexture( self.blendTS, self.snowTexture ) # this texture determines where the other textures are visible root.setTexture(self.grassTS, self.snowTexture) #root.setTexScale(self.grassTS, self.size*5, self.size*5) # I try to make the texture 20 times smaller then the blend map... root.setTexture(self.rockTS, self.snowTexture) #rockTexture #root.setTexScale(self.rockTS, self.size*5, self.size*5) root.setTexture(self.sandTS, self.snowTexture) #sandTexture #root.setTexScale(self.sandTS, self.size*5, self.size*5) root.setTexture(self.snowTS, self.snowTexture) #snowTexture #root.setTexScale(self.snowTS, self.size*5, self.size*5) #(consider removal) root.setTexture(self.overlayTS, self.overlayTexture) #overlayTexture #root.setTexScale(self.overlayTS, self.xsize, self.ysize) root.setShaderInput('size', self.xsize, self.ysize, self.size, self.size) root.setShader(loader.loadShader('Entities/Maps/terrainblender.sha'))
def __init__(self, path, heightScale, shader=None, skipTextures=False): self.shader = shader meshManager.MeshFactory.__init__(self) self.dataIndex = {} self.heightScale = heightScale d = parseFile(path + "/texList.txt") self.mapTexStages = {} self.specialMaps = {} for m in d["Special"]: s = m.split("\t") self.specialMaps[s[1]] = s[0] # List of non map texture stages, and their sizes # (TexStage,Size) self.texList = [] if not skipTextures: if "Tex2D" in d: sort = 0 for m in d["Tex2D"]: sort += 1 s = m.split() name = s[0] texStage = TextureStage(name + "stage" + str(sort)) texStage.setSort(sort) source = s[1] # def setTexModes(modeText): # combineMode=[] # for t in modeText: # if t[:1]=='M': # texStage.setMode(getRenderMapType(t)) # elif t[:1]=='C': # combineMode.append(getCombineMode(t)) # elif t=='Save': # texStage.setSavedResult(True) # else: # print "Illegal mode info for "+name # if len(combineMode)>0: # texStage.setCombineRgb(*combineMode) # if len(modeText)==0: # texStage.setMode(TextureStage.MModulate) if source == "file": # setTexModes(s[3:]) tex = loadTex(path + "/textures/" + name) # self.terrainNode.setTexture(texStage,tex) # self.terrainNode.setShaderInput('tex2D_'+name,tex) self.texList.append((texStage, float(s[2]), tex, name)) elif source == "map": # setTexModes(s[2:]) self.mapTexStages[s[0]] = texStage # # else: # print 'Invalid source for '+name+' int Tex2D' self.LOD = meshManager.LOD(float("inf"), 0)
class GUnit(GEntity): def __init__(self,conf): GEntity.__init__(self,conf) self.p3dobject.reparentTo(self.gmap.units_node) self.p3dobject.setTransparency(TransparencyAttrib.MAlpha) #to be put under condition for non pickable units (bonuses npc for instance) self.p3dobject.setTag('GUnit-pickable','1') self.p3dobject.setPos(self.gmap.root.find('**/tile_'+str(conf['tileid'])),0,0,0) #supposedly already a float, but will screw up if not, so just making sure. self.move_speed=float(conf['move_speed']) self.path=[] self.popout_when_move_over=False self.pid=conf['pid'] #highlight self.ts_highlighted=TextureStage('ts_highlighted') self.ts_highlighted.setMode(TextureStage.MDecal) self.ts_highlighted.setSort(2) #highlight self.ts_selected=TextureStage('ts_selected') self.ts_selected.setMode(TextureStage.MDecal) self.ts_selected.setSort(3) @staticmethod def load_resources(): GUnit.textures={ 'highlighted':loader.loadTexture('data/models/highlighted.tex.png'), 'selected':loader.loadTexture('data/models/selected.tex.png'), } def dispose(self): '''del method''' GEntity.dispose(self) self.popout_sequence.finish() del self.popout_sequence def add_path(self,data): ''' adds tile to pass by. ''' #check for data completeness if not 'path' in data: out('WARNING in GUnit.add_path: incomplete data:\n'+str(data)) return elif not isinstance(data['path'],list): out('WARNING in GUnit.add_path: invalid data:\n'+str(data)) return #data considered valid self.path.extend([self.instances[eid] for eid in data['path']]) if not self.update_move in update_list: update_list.append(self.update_move) #out('GUnit.add_path:'+str(data)) def finish_move_to(self,data): '''triggered by server side unit, to indicate the need to popout at end of move.''' out('GUnit.finish_move_to()'+str(data)) if self.update_move in update_list: self.popout_when_move_over=True else: self.popout() def popout(self): '''sets up the popout animation at end of unit's mission''' scale=self.p3dobject.scaleInterval(.5,(.1,.1,.1)) finish=Func(lambda:dispose_list.append(self)) self.popout_sequence=Sequence(scale,finish) self.popout_sequence.start() def set_highlighted(self): self.p3dobject.setTexture(self.ts_highlighted,self.textures['highlighted']) def unset_highlighted(self): self.p3dobject.clearTexture(self.ts_highlighted) def set_selected(self): self.p3dobject.setTexture(self.ts_selected,self.textures['selected']) def unset_selected(self): self.p3dobject.clearTexture(self.ts_selected) def update_move(self): '''called every frame during while a move.''' if len(self.path)==0: out('WARNING in GUnit.update_move: path is empty, but method still called. removing it.') update_list.remove(self.update_move) return if not hasattr(self,'move_interval'): #start moving #first 3 args=model,duration,pos, the duration=1/... is relative to server side tile side size self.move_interval=LerpPosInterval(self.p3dobject, (1/(self.move_speed*ConfigVariableDouble('clock-frame-rate').getValue())), self.path[0].p3dobject.getPos(), name='interval_unit_move_'+str(self.eid) ) self.p3dobject.lookAt(self.path[0].p3dobject.getPos()) self.p3dobject.loop('run') self.move_interval.start() else: #is move ~over ? #t=self.move_interval.getT() #d=self.move_interval.getDuration() #d=d-t d=dist3(self.p3dobject,self.path[0].p3dobject) #out('client '+str(t*100./d)+'%') #arrived if d<self.move_speed: #out('client '+str(self.path[0].eid)+'@'+str(self.frame_no)) self.p3dobject.setPos(self.path[0].p3dobject,0,0,0) self.path.pop(0) if len(self.path)==0: self.p3dobject.stop() self.move_interval.finish() del self.move_interval update_list.remove(self.update_move) if self.popout_when_move_over: self.popout() else: #first 3 args=model,duration,pos self.move_interval.finish() self.move_interval=LerpPosInterval(self.p3dobject, (1/(self.move_speed*ConfigVariableDouble('clock-frame-rate').getValue())), self.path[0].p3dobject.getPos(), name='interval_unit_move_'+str(self.eid) ) self.p3dobject.lookAt(self.path[0].p3dobject.getPos()) self.move_interval.start()
class Water(AssetBase): def __init__(self, name, size=10000, resolution=1024): """Arguments: size -- Edge length of the water square. resolution -- Texture size of the rendered reflection buffer. """ # Uncomment to see the output of the refclection buffer. base.bufferViewer.toggleEnable() AssetBase.__init__(self) self.name = name self.cm = CardMaker("water surface") self.cm.setFrame(-0.5 * size, 0.5 * size, -0.5 * size, 0.5 * size) self.cm.setHasUvs(True) self.node = NodePath(self.cm.generate()) self.node.setP(self.node, -90) self.node.flattenLight() self.node.hide(BitMask32.bit(1)) #self.node.setTwoSided(True) self.node.setShaderOff() # size of one texture tile in meters self.tex_size = 100.0 diffuse = TexturePool.loadTexture("textures/water.diffuse.png") diffuse.setWrapU(Texture.WMRepeat) diffuse.setWrapV(Texture.WMRepeat) diffuse.setMinfilter(Texture.FTLinearMipmapLinear) diffuse.setMagfilter(Texture.FTLinearMipmapLinear) self.diffuse_stage = TextureStage("diffuse") self.diffuse_stage.setSort(2) self.node.setTexture(self.diffuse_stage, diffuse) self.node.setTexScale(self.diffuse_stage, size / self.tex_size, size / self.tex_size) # Reflection camera renders to 'buffer' which is projected onto the # water surface. buffer = base.win.makeTextureBuffer("water reflection", resolution, resolution) buffer.setClearColor(Vec4(0, 0, 0, 1)) self.refl_cam = base.makeCamera(buffer) self.refl_cam.reparentTo(self.node) self.refl_cam.node().setCameraMask(BitMask32.bit(1)) self.refl_cam.node().getLens().setFov(base.camLens.getFov()) self.refl_cam.node().getLens().setNearFar(1, 100000) plane = PlaneNode("water culling plane", Plane(Vec3(0, 0, 1), Point3(0, 0, 0))) cfa = CullFaceAttrib.makeReverse() cpa = ClipPlaneAttrib.make(PlaneNode.CEVisible, plane) rs = RenderState.make(cfa, cpa) self.refl_cam.node().setInitialState(rs) reflection = buffer.getTexture() reflection.setMinfilter(Texture.FTLinear) reflection.setMagfilter(Texture.FTLinear) self.refl_stage = TextureStage("reflection") self.refl_stage.setSort(1) self.node.projectTexture(self.refl_stage, reflection, base.cam) self.node.setTexture(self.refl_stage, reflection) # Blend between diffuse and reflection. self.diffuse_stage.setColor(VBase4(1, 1, 1, 0.2)) # opacity of 20% self.diffuse_stage.setCombineRgb( TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSConstant, TextureStage.COSrcAlpha) self.addTask(self.update, name="water update", sort=1, taskChain="world") def update(self, task): """Updates position of the reflection camera and the water plane.""" mc = base.cam.getMat(render) #mf = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)).getReflectionMat() mf = Mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1) self.refl_cam.setMat(mc * mf) self.node.setX(camera.getX(render)) self.node.setY(camera.getY(render)) self.node.setTexOffset(self.diffuse_stage, self.node.getX() / self.tex_size, self.node.getY() / self.tex_size) return task.cont def destroy(self): self.removeAllTasks() self.node.removeNode() self.refl_cam.removeNode()
class GTile(GEntity): def __init__(self,conf): self.p3dobject=self.gmap.tile_matrix_node.attachNewNode('tile_'+str(conf['eid'])) self.p3dobject.setTransparency(TransparencyAttrib.MAlpha) #self.test_sphere=loader.loadModel('data/models/test_sphere.egg') #self.test_sphere.reparentTo(self.p3dobject) GEntity.__init__(self,conf) self.x,self.y=x,y=conf['x'],conf['y'] self.p3dobject.setTag('x',str(x)) self.p3dobject.setTag('y',str(y)) self.p3dobject.setPythonTag('ref',self) #half of a tile side t=self.gmap.tile_matrix_node.getScale()[0]/2. self.p3dobject.setPos(self.gmap.tile_matrix_node,(-self.gmap.resx/2.+x+t)*2.,(y-self.gmap.resy/2.+t)*2.,0) #preload texture holder quad self.quad=GTile.resources['quad']() self.quad.setTransparency(TransparencyAttrib.MAlpha) #self.quad.reparentTo(self.p3dobject) self.quad.reparentTo(self.gmap.tiles_quads_node) self.quad.setPos(self.p3dobject.getPos()) self.quad.hide() #pid of the player that owns the tile self.pawner=None self.ts_pawn=TextureStage('ts_pawn') self.ts_pawn.setMode(TextureStage.MReplace) self.ts_pawn.setSort(2) #selection self.is_selected=False self.ts_selected=TextureStage('ts_selected') self.ts_selected.setMode(TextureStage.MReplace) self.ts_selected.setSort(3) #highlight self.is_highlighted=False self.ts_highlighted=TextureStage('ts_highlighted') self.ts_highlighted.setMode(TextureStage.MDecal) self.ts_highlighted.setSort(4) def __repr__(self): return 'GTile{eid:'+str(self.eid)+'\n\ x/y:'+str(self.x)+'/'+str(self.y)+'\n\ pawner:'+str(self.pawner)+'\n\ selected:'+str(self.is_selected)+'\n\ highlighted:'+str(self.is_highlighted)+'\n\ }' def __str__(self): return self.__repr__() @staticmethod def load_resources(): #dict of texture GTile.resources={ 'quad':lambda:loader.loadModel('data/models/tiles/tile.egg'), } GTile.textures={ 'highlighted':loader.loadTexture('data/models/tiles/tile.highlighted.tex.png'), 'selected':loader.loadTexture('data/models/tiles/tile.selected.tex.png'), 'pawn-0':loader.loadTexture('data/models/tiles/tile.pawned.black.tex.png'), 'pawn-1':loader.loadTexture('data/models/tiles/tile.pawned.white.tex.png'), } @property def left_tile(self): '''property getter''' if self.x>0:return self.gmap.tile_matrix[self.x-1][self.y] return None @property def lower_tile(self): '''property getter''' if self.y>0:return self.gmap.tile_matrix[self.x][self.y-1] return None @property def right_tile(self): '''property getter''' if self.x<self.gmap.resx-1:return self.gmap.tile_matrix[self.x+1][self.y] return None @property def upper_tile(self): '''property getter''' if self.y<self.gmap.resy-1:return self.gmap.tile_matrix[self.x][self.y+1] return None @property def neighbors(self): '''property getter''' return filter(lambda t:t!=None,[self.left_tile,self.lower_tile,self.right_tile,self.upper_tile]) @property def wall(self): ''' returns a list of all tiles that form a wall connected to this tile. a tile with no pawner doesn't belong to any wall. ''' if self.pawner==None: return [] wall=[] fringe=[self] visited={} while len(fringe): t=fringe.pop(0) if t.pawner==self.pawner: wall.append(t) visited[t]=1 fringe.extend([n for n in t.neighbors if n.pawner==self.pawner and n not in visited]) def change_pawner(self,data): #out('tile '+str(self.eid)+' set to '+str(data['owner'])) if self.pawner!=data['pawner']: self.pawner=data['pawner'] if self.pawner==None: self.quad.clearTexture(self.ts_pawn) if not (self.is_selected or self.is_highlighted): self.quad.hide() else: self.quad.setTexture(self.ts_pawn,self.textures['pawn-'+str(self.pawner)]) self.quad.show() def set_highlighted(self): #out('tile.eid='+str(self.eid)) self.is_highlighted=True self.quad.show() self.quad.setTexture(self.ts_highlighted,self.textures['highlighted']) def unset_highlighted(self): self.is_highlighted=False self.quad.clearTexture(self.ts_highlighted) if not (self.is_selected or self.pawner!=None): self.quad.hide() def set_selected(self): self.is_selected=True self.quad.show() self.quad.setTexture(self.ts_selected,self.textures['selected']) def unset_selected(self): self.is_selected=False self.quad.clearTexture(self.ts_selected) if not (self.is_highlighted or self.pawner!=None): self.quad.hide() @property def center_pos(self): return self.p3dobject.getPos()
"""base.camLens.setNearFar(1.0, 50.0) base.camLens.setFov(45.0)""" camera.setPos(0.0, -20.0, 10.0) camera.lookAt(0.0, 0.0, 0.0) root = render.attachNewNode("Root") root.setPos(0.0, 0.0, 0.0) textureArrow = loader.loadTexture("arrow.png") textureArrow.setWrapU(Texture.WMClamp) textureArrow.setWrapV(Texture.WMClamp) stageArrow = TextureStage("Arrow") stageArrow.setSort(1) textureCircle = loader.loadTexture("circle.png") textureCircle.setWrapU(Texture.WMClamp) textureCircle.setWrapV(Texture.WMClamp) stageCircle = TextureStage("Circle") stageCircle.setSort(2) modelCube = loader.loadModel("cube.egg") cubes = [] for x in [-3.0, 0.0, 3.0]: cube = modelCube.copyTo(root) cube.setPos(x, 0.0, 0.0) cubes += [ cube ]
def setupHeightmap(self, name): # Automatically generate a heightmap mesh from a monochrome image. self.hmHeight = 120 hmPath = "../maps/map" + name + "/map" + name + "-h.png" imPath = "../maps/map" + name + "/map" + name + "-i.png" smPath = "../maps/map" + name + "/map" + name + "-s.png" scmPath = "../maps/map" + name + "/map" + name + "-sc.png" print(hmPath) print(imPath) print(smPath) print(scmPath) hmImg = PNMImage(Filename(hmPath)) hmShape = BulletHeightfieldShape(hmImg, self.hmHeight, ZUp) hmNode = BulletRigidBodyNode('Terrain') hmNode.addShape(hmShape) hmNode.setMass(0) self.hmNP = render.attachNewNode(hmNode) self.worldBullet.attachRigidBody(hmNode) self.hmOffset = hmImg.getXSize() / 2.0 - 0.5 self.hmTerrain = GeoMipTerrain('gmTerrain') self.hmTerrain.setHeightfield(hmImg) # Optimizations and fixes self.hmTerrain.setBruteforce(True) # I don't think this is actually needed. self.hmTerrain.setMinLevel(3) # THIS is what triangulates the terrain. self.hmTerrain.setBlockSize(128) # This does a pretty good job of raising FPS. # Level-of-detail (not yet working) # self.hmTerrain.setNear(40) # self.hmTerrain.setFar(200) self.hmTerrain.generate() self.hmTerrainNP = self.hmTerrain.getRoot() self.hmTerrainNP.setSz(self.hmHeight) self.hmTerrainNP.setPos(-self.hmOffset, -self.hmOffset, -self.hmHeight / 2.0) self.hmTerrainNP.flattenStrong() # This only reduces the number of nodes; nothing to do with polys. self.hmTerrainNP.analyze() # Here begins the scenery mapping treeModel = loader.loadModel("../res/models/tree_1.egg") rockModel = loader.loadModel("../res/models/rock_1.egg") rock2Model = loader.loadModel("../res/models/rock_2.egg") rock3Model = loader.loadModel("../res/models/rock_3.egg") # caveModel = loader.loadModel("../res/models/cave_new.egg") # planeFrontModel = loader.loadModel("../res/models/plane_front.egg") # planeWingModel = loader.loadModel("../res/models/plane_wing.egg") texpk = loader.loadTexture(scmPath).peek() # GameObject nodepath for flattening self.objNP = render.attachNewNode("gameObjects") self.treeNP = self.objNP.attachNewNode("goTrees") self.rockNP = self.objNP.attachNewNode("goRocks") self.rock2NP = self.objNP.attachNewNode("goRocks2") self.rock3NP = self.objNP.attachNewNode("goRocks3") # self.caveNP = self.objNP.attachNewNode("goCave") # self.planeFrontNP = self.objNP.attachNewNode("goPlaneFront") # self.planeWingNP = self.objNP.attachNewNode("goPlaneWing") for i in range(0, texpk.getXSize()): for j in range(0, texpk.getYSize()): color = VBase4(0, 0, 0, 0) texpk.lookup(color, float(i) / texpk.getXSize(), float(j) / texpk.getYSize()) if(int(color.getX() * 255.0) == 255.0): newTree = self.treeNP.attachNewNode("treeNode") treeModel.instanceTo(newTree) newTree.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newTree.setScale(randint(0,4)) newTree.setScale(2) if(int(color.getX() * 255.0) == 128): newRock = self.rockNP.attachNewNode("newRock") newRock.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rockModel.instanceTo(newRock) if(int(color.getX() * 255.0) == 77): newRock2 = self.rock2NP.attachNewNode("newRock2") newRock2.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock2Model.instanceTo(newRock2) if(int(color.getX() * 255.0) == 102): newRock3 = self.rock3NP.attachNewNode("newRock3") newRock3.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock3Model.instanceTo(newRock3) # if(int(color.getX() * 255.0) == 64): # newCave = self.caveNP.attachNewNode("newCave") # newCave.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newCave.setScale(5) # newCave.setP(180) # caveModel.instanceTo(newCave) # if(int(color.getX() * 255.0) == 191): # newPlaneFront = self.planeFrontNP.attachNewNode("newPlaneFront") # newPlaneFront.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneFront.setScale(6) # planeFrontModel.instanceTo(newPlaneFront) # if(int(color.getX() * 255.0) == 179): # newPlaneWing = self.planeWingNP.attachNewNode("newPlaneWing") # newPlaneWing.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneWing.setScale(6) # newPlaneWing.setH(250) # newPlaneWing.setR(180) # newPlaneWing.setP(135) # planeWingModel.instanceTo(newPlaneWing) self.snowflakes = [] for i in xrange(0, self.snowflakeCount): print("Call " + str(i)) sf = SMCollect(self.worldBullet, self.worldObj, self.snowflakePositions[i]) self.snowflakes.append(sf) # render.flattenStrong() self.hmTerrainNP.reparentTo(render) # Here begins the attribute mapping ts = TextureStage("stage-alpha") ts.setSort(0) ts.setPriority(1) ts.setMode(TextureStage.MReplace) ts.setSavedResult(True) self.hmTerrainNP.setTexture(ts, loader.loadTexture(imPath, smPath)) ts = TextureStage("stage-stone") ts.setSort(1) ts.setPriority(1) ts.setMode(TextureStage.MReplace) self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/stone_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-ice") ts.setSort(2) ts.setPriority(1) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor) self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/ice_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-snow") ts.setSort(3) ts.setPriority(0) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcAlpha) self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/snow_tex_1.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) # print(self.snowflakes) return hmNode
class TerrainManager(DirectObject.DirectObject): def __init__(self): self.accept("mouse1", self.lclick) self.waterType = 2 self.water = None self.citycolors = {0: VBase3D(1, 1, 1)} self.accept('generateRegion', self.generateWorld) self.accept('regenerateRegion', self.regenerateWorld) self.accept("regionView_normal", self.setSurfaceTextures) self.accept("regionView_owners", self.setOwnerTextures) self.accept("regionView_foundNew", self.regionViewFound) self.accept("updateRegion", self.updateRegion) self.accept("enterCityView", self.enterCity) # View: 0, region, # cityid self.view = 0 self.ownerview = False def lclick(self): cell = picker.getMouseCell() print "Cell:", cell blockCoords = self.terrain.getBlockFromPos(cell[0], cell[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) print "Block coords:", blockCoords print "NodePath:", block print "Elevation:", self.terrain.getElevation(cell[0], cell[1]) if not self.view: messenger.send("clickForCity", [cell]) def switchWater(self): print "Switch Water" self.waterType += 1 if self.waterType > 2: self.waterType = 0 self.generateWater(self.waterType) def generateWorld(self, heightmap, tiles, cities, container): self.heightmap = heightmap self.terrain = PagedGeoMipTerrain("surface") #self.terrain = GeoMipTerrain("surface") self.terrain.setHeightfield(self.heightmap) #self.terrain.setFocalPoint(base.camera) self.terrain.setBruteforce(True) self.terrain.setBlockSize(64) self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) #root.setSz(100) self.terrain.setSz(100) messenger.send('makePickable', [root]) if self.heightmap.getXSize() > self.heightmap.getYSize(): self.size = self.heightmap.getXSize()-1 else: self.size = self.heightmap.getYSize()-1 self.xsize = self.heightmap.getXSize()-1 self.ysize = self.heightmap.getYSize()-1 # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 self.generateSurfaceTextures() self.generateWaterMap() self.generateOwnerTexture(tiles, cities) #self.terrain.makeTextureMap() colormap = PNMImage(heightmap.getXSize()-1, heightmap.getYSize()-1) colormap.addAlpha() slopemap = self.terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x,y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) self.colorTexture = Texture() self.colorTexture.load(colormap) self.colorTS = TextureStage('color') self.colorTS.setSort(0) self.colorTS.setPriority(1) self.setSurfaceTextures() self.generateWater(2) taskMgr.add(self.updateTerrain, "updateTerrain") print "Done with terrain generation" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) self.terrain.getRoot().analyze() self.accept("h", self.switchWater) def regenerateWorld(self): '''Regenerates world, often upon city exit.''' self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) self.terrain.setSz(100) messenger.send('makePickable', [root]) # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 #self.generateSurfaceTextures() self.generateWaterMap() self.setSurfaceTextures() self.generateWater(2) print "Done with terrain regeneration" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) def generateWaterMap(self): ''' Iterate through every pix of color map. This will be very slow so until faster method is developed, use sparingly getXSize returns pixels length starting with 1, subtract 1 for obvious reasons We also slip in checking for the water card size, which should only change when the color map does ''' print "GenerateWaterMap" self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax = -1,0,-1,0 for x in range(0, self.heightmap.getXSize()-1): for y in range(0, self.heightmap.getYSize()-1): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if self.heightmap.getGrayVal(x,y) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if self.waterXMin == -1 or x < self.waterXMin: self.waterXMin = x if not self.waterYMax: self.waterYMax = y if y < self.waterYMax: self.waterYMax = y if x > self.waterXMax: self.waterXMax = x if y > self.waterYMin: self.waterYMin = y # Transform y coords self.waterYMin = self.size-64 - self.waterYMin self.waterYMax = self.size-64 - self.waterYMax def generateOwnerTexture(self, tiles, cities): '''Generates a simple colored texture to be applied to the city info region overlay. Due to different coordinate systems (terrain org bottom left, texture top left) some conversions are needed, Also creates and sends a citylabels dict for the region view ''' self.citymap = PNMImage(self.xsize, self.ysize) citylabels = cities scratch = {} # Setup for city labels for ident in cities: scratch[ident] = [] # conversion for y axis ycon = [] s = self.ysize - 1 for y in range(self.ysize): ycon.append(s) s -= 1 for ident, city in cities.items(): if ident not in self.citycolors: self.citycolors[ident] = VBase3D(random.random(), random.random(), random.random()) for tile in tiles: self.citymap.setXel(tile.coords[0], ycon[tile.coords[1]], self.citycolors[tile.cityid]) # Scratch for labeling if tile.cityid: scratch[tile.cityid].append((tile.coords[0], tile.coords[1])) for ident, values in scratch.items(): xsum = 0 ysum = 0 n = 0 for coords in values: xsum += coords[0] ysum += coords[1] n += 1 xavg = xsum/n yavg = ysum/n print "Elevation:", self.terrain.getElevation(xavg, yavg) z = self.terrain.getElevation(xavg, yavg)*100 citylabels[ident]["position"] = (xavg, yavg, z+15) print "Citylabels:", citylabels messenger.send("updateCityLabels", [citylabels, self.terrain]) def generateSurfaceTextures(self): # Textureize self.grassTexture = loader.loadTexture("Textures/grass.png") self.grassTS = TextureStage('grass') self.grassTS.setSort(1) self.rockTexture = loader.loadTexture("Textures/rock.jpg") self.rockTS = TextureStage('rock') self.rockTS.setSort(2) self.rockTS.setCombineRgb(TextureStage.CMAdd, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) self.sandTexture = loader.loadTexture("Textures/sand.jpg") self.sandTS = TextureStage('sand') self.sandTS.setSort(3) self.sandTS.setPriority(5) self.snowTexture = loader.loadTexture("Textures/ice.png") self.snowTS = TextureStage('snow') self.snowTS.setSort(4) self.snowTS.setPriority(0) # Grid for city placement and guide and stuff self.gridTexture = loader.loadTexture("Textures/grid.png") self.gridTexture.setWrapU(Texture.WMRepeat) self.gridTexture.setWrapV(Texture.WMRepeat) self.gridTS = TextureStage('grid') self.gridTS.setSort(5) self.gridTS.setPriority(10) def enterCity(self, ident, city, position, tiles): '''Identifies which terrain blocks city belogs to and disables those that are not A lot of uneeded for loops in here. Will need to find a better way later.''' #root = self.terrain.getRoot() children = [] for terrain in self.terrain.terrains: root = terrain.getRoot() children += root.getChildren() keepBlocks = [] # Reset water dimentions self.waterXMin = 0 self.waterXMax = 0 self.waterYMin = 0 self.waterYMax = 0 for tile in tiles: blockCoords = self.terrain.getBlockFromPos(tile.coords[0], tile.coords[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) if block not in keepBlocks: keepBlocks.append(block) if self.heightmap.getGrayVal(tile.coords[0], self.size-tile.coords[1]) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if not self.waterXMin: self.waterXMin = tile.coords[0] if not self.waterYMin: self.waterYMin = tile.coords[1] if tile.coords[1] > self.waterYMax: self.waterYMax = tile.coords[1] if tile.coords[0] > self.waterXMax: self.waterXMax = tile.coords[0] if tile.coords[0] < self.waterXMin: self.waterXMin = tile.coords[0] if tile.coords[1] < self.waterYMin: self.waterYMin = tile.coords[1] for child in children: if child not in keepBlocks: child.detachNode() self.view = ident self.generateWater(2) def newTerrainOverlay(self, task): root = self.terrain.getRoot() position = picker.getMouseCell() if position: # Check to make sure we do not go out of bounds if position[0] < 32: position = (32, position[1]) elif position[0] > self.xsize-32: position = (self.xsize-32, position[1]) if position[1] < 32: position = (position[0], 32) elif position [1] > self.ysize-32: position = (position[0], self.size-32) root.setTexOffset(self.tileTS, -(position[0]-32)/64, -(position[1]-32)/64) return task.cont def regionViewFound(self): '''Gui for founding a new city!''' self.setOwnerTextures() root = self.terrain.getRoot() task = taskMgr.add(self.newTerrainOverlay, "newTerrainOverlay") tileTexture = loader.loadTexture("Textures/tile.png") tileTexture.setWrapU(Texture.WMClamp) tileTexture.setWrapV(Texture.WMClamp) self.tileTS = TextureStage('tile') self.tileTS.setSort(6) self.tileTS.setMode(TextureStage.MDecal) #self.tileTS.setColor(Vec4(1,0,1,1)) root.setTexture(self.tileTS, tileTexture) root.setTexScale(self.tileTS, self.terrain.xchunks, self.terrain.ychunks) self.acceptOnce("mouse1", self.regionViewFound2) self.acceptOnce("escape", self.cancelRegionViewFound) def regionViewFound2(self): '''Grabs cell location for founding. The texture coordinate is used as the mouse may enter an out of bounds area. ''' root = self.terrain.getRoot() root_position = root.getTexOffset(self.tileTS) # We offset the position of the texture, so we will now put the origin of the new city not on mouse cursor but the "bottom left" of it. Just need to add 32 to get other edge position = [int(abs(root_position[0]*64)), int(abs(root_position[1]*64))] self.cancelRegionViewFound() messenger.send("found_city_name", [position]) def cancelRegionViewFound(self): taskMgr.remove("newTerrainOverlay") root = self.terrain.getRoot() root.clearTexture(self.tileTS) # Restore original mouse function self.accept("mouse1", self.lclick) messenger.send("showRegionGUI") def setSurfaceTextures(self): self.ownerview = False root = self.terrain.getRoot() root.clearTexture() #self.terrain.setTextureMap() root.setTexture( self.colorTS, self.colorTexture ) root.setTexture( self.grassTS, self.grassTexture ) root.setTexScale(self.grassTS, self.size/8, self.size/8) root.setTexture( self.rockTS, self.rockTexture ) root.setTexScale(self.rockTS, self.size/8, self.size/8) root.setTexture( self.sandTS, self.sandTexture) root.setTexScale(self.sandTS, self.size/8, self.size/8) root.setTexture( self.snowTS, self.snowTexture ) root.setTexScale(self.snowTS, self.size/8, self.size/8) root.setTexture( self.gridTS, self.gridTexture ) root.setTexScale(self.gridTS, self.xsize, self.ysize) root.setShaderInput('size', self.xsize, self.ysize, self.size, self.size) root.setShader(loader.loadShader('Shaders/terraintexture.sha')) def setOwnerTextures(self): self.ownerview = True root = self.terrain.getRoot() root.clearShader() root.clearTexture() cityTexture = Texture() cityTexture.load(self.citymap) cityTS = TextureStage('citymap') cityTS.setSort(0) root.setTexture( self.gridTS, self.gridTexture ) root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks) root.setTexture(cityTS, cityTexture, 1) def updateRegion(self, heightmap, tiles, cities): self.generateOwnerTexture(tiles, cities) if self.ownerview: self.setOwnerTextures() def updateTerrain(self, task): '''Updates terrain and water''' self.terrain.update() # Water if self.waterType is 2: pos = base.camera.getPos() render.setShaderInput('time', task.time) mc = base.camera.getMat( ) self.water.changeCameraPos(pos,mc) self.water.changeCameraPos(pos,mc) #print "Render diagnostics" #render.analyze() #base.cTrav.showCollisions(render) return task.cont def generateWater(self, style): print "Generate Water:", self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax '''Generates water style 0: blue card style 1: reflective card style 2: reflective card with shaders ''' self.waterHeight = 22.0 if self.water: self.water.removeNode() if style is 0: cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) cm.setColor(0, 0, 1, 0.9) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) messenger.send('makePickable', [self.water]) elif style is 1: # From Prosoft's super awesome terrain demo cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax #self.water.setScale(size) self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) self.water.setShaderOff(1) self.water.setLightOff(1) self.water.setAlphaScale(0.5) self.water.setTransparency(TransparencyAttrib.MAlpha) wbuffer = base.win.makeTextureBuffer("water", 512, 512) wbuffer.setClearColorActive(True) wbuffer.setClearColor(base.win.getClearColor()) self.wcamera = base.makeCamera(wbuffer) self.wcamera.reparentTo(render) self.wcamera.node().setLens(base.camLens) self.wcamera.node().setCameraMask(BitMask32.bit(1)) self.water.hide(BitMask32.bit(1)) wtexture = wbuffer.getTexture() wtexture.setWrapU(Texture.WMClamp) wtexture.setWrapV(Texture.WMClamp) wtexture.setMinfilter(Texture.FTLinearMipmapLinear) self.wplane = Plane(Vec3(0, 0, 1), Point3(0, 0, self.water.getZ())) wplanenp = render.attachNewNode(PlaneNode("water", self.wplane)) tmpnp = NodePath("StateInitializer") tmpnp.setClipPlane(wplanenp) tmpnp.setAttrib(CullFaceAttrib.makeReverse()) self.wcamera.node().setInitialState(tmpnp.getState()) self.water.projectTexture(TextureStage("reflection"), wtexture, self.wcamera) messenger.send('makePickable', [self.water]) elif style is 2: # From Clcheung just as super awesome demomaster self.water_level = Vec4(0.0, 0.0, self.waterHeight, 1.0) self.water = water.WaterNode(self.waterXMin, self.waterYMin, self.waterXMax, self.waterYMax, self.water_level.getZ()) self.water.setStandardControl() self.water.changeParams(None) wl=self.water_level wl.setZ(wl.getZ()-0.05) #root.setShaderInput('waterlevel', self.water_level) render.setShaderInput('time', 0) messenger.send('makePickable', [self.water.waterNP])
base.disableMouse() """base.camLens.setNearFar(1.0, 50.0) base.camLens.setFov(45.0)""" camera.setPos(0.0, -20.0, 10.0) camera.lookAt(0.0, 0.0, 0.0) root = render.attachNewNode("Root") root.setPos(0.0, 0.0, 0.0) textureArrow = loader.loadTexture("arrow.png") textureArrow.setWrapU(Texture.WMClamp) textureArrow.setWrapV(Texture.WMClamp) stageArrow = TextureStage("Arrow") stageArrow.setSort(1) textureCircle = loader.loadTexture("circle.png") textureCircle.setWrapU(Texture.WMClamp) textureCircle.setWrapV(Texture.WMClamp) stageCircle = TextureStage("Circle") stageCircle.setSort(2) modelCube = loader.loadModel("cube.egg") cubes = [] for x in [-3.0, 0.0, 3.0]: cube = modelCube.copyTo(root) cube.setPos(x, 0.0, 0.0) cubes += [cube]
class TerrainManager(DirectObject.DirectObject): def __init__(self): self.accept("mouse1", self.lclick) self.waterType = 2 self.water = None self.citycolors = {0: VBase3D(1, 1, 1)} self.accept('generateRegion', self.generateWorld) self.accept('regenerateRegion', self.regenerateWorld) self.accept("regionView_normal", self.setSurfaceTextures) self.accept("regionView_owners", self.setOwnerTextures) self.accept("regionView_foundNew", self.regionViewFound) self.accept("updateRegion", self.updateRegion) self.accept("enterCityView", self.enterCity) # View: 0, region, # cityid self.view = 0 self.ownerview = False def lclick(self): cell = picker.getMouseCell() print "Cell:", cell blockCoords = self.terrain.getBlockFromPos(cell[0], cell[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) print "Block coords:", blockCoords print "NodePath:", block print "Elevation:", self.terrain.getElevation(cell[0], cell[1]) if not self.view: messenger.send("clickForCity", [cell]) def switchWater(self): print "Switch Water" self.waterType += 1 if self.waterType > 2: self.waterType = 0 self.generateWater(self.waterType) def generateWorld(self, heightmap, tiles, cities, container): self.heightmap = heightmap self.terrain = PagedGeoMipTerrain("surface") #self.terrain = GeoMipTerrain("surface") self.terrain.setHeightfield(self.heightmap) #self.terrain.setFocalPoint(base.camera) self.terrain.setBruteforce(True) self.terrain.setBlockSize(64) self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) #root.setSz(100) self.terrain.setSz(100) messenger.send('makePickable', [root]) if self.heightmap.getXSize() > self.heightmap.getYSize(): self.size = self.heightmap.getXSize() - 1 else: self.size = self.heightmap.getYSize() - 1 self.xsize = self.heightmap.getXSize() - 1 self.ysize = self.heightmap.getYSize() - 1 # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 self.generateSurfaceTextures() self.generateWaterMap() self.generateOwnerTexture(tiles, cities) #self.terrain.makeTextureMap() colormap = PNMImage(heightmap.getXSize() - 1, heightmap.getYSize() - 1) colormap.addAlpha() slopemap = self.terrain.makeSlopeImage() for x in range(0, colormap.getXSize()): for y in range(0, colormap.getYSize()): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if heightmap.getGrayVal(x, y) < 200: colormap.setAlpha(x, y, 0) else: colormap.setAlpha(x, y, 1) # Beach. Estimations from http://www.simtropolis.com/omnibus/index.cfm/Main.SimCity_4.Custom_Content.Custom_Terrains_and_Using_USGS_Data if heightmap.getGrayVal(x, y) < 62: colormap.setBlue(x, y, 1) # Rock elif slopemap.getGrayVal(x, y) > 170: colormap.setRed(x, y, 1) else: colormap.setGreen(x, y, 1) self.colorTexture = Texture() self.colorTexture.load(colormap) self.colorTS = TextureStage('color') self.colorTS.setSort(0) self.colorTS.setPriority(1) self.setSurfaceTextures() self.generateWater(2) taskMgr.add(self.updateTerrain, "updateTerrain") print "Done with terrain generation" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) self.terrain.getRoot().analyze() self.accept("h", self.switchWater) def regenerateWorld(self): '''Regenerates world, often upon city exit.''' self.terrain.generate() root = self.terrain.getRoot() root.reparentTo(render) self.terrain.setSz(100) messenger.send('makePickable', [root]) # Set multi texture # Source http://www.panda3d.org/phpbb2/viewtopic.php?t=4536 #self.generateSurfaceTextures() self.generateWaterMap() self.setSurfaceTextures() self.generateWater(2) print "Done with terrain regeneration" messenger.send("finishedTerrainGen", [[self.xsize, self.ysize]]) def generateWaterMap(self): ''' Iterate through every pix of color map. This will be very slow so until faster method is developed, use sparingly getXSize returns pixels length starting with 1, subtract 1 for obvious reasons We also slip in checking for the water card size, which should only change when the color map does ''' print "GenerateWaterMap" self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax = -1, 0, -1, 0 for x in range(0, self.heightmap.getXSize() - 1): for y in range(0, self.heightmap.getYSize() - 1): # Else if statements used to make sure one channel is used per pixel # Also for some optimization # Snow. We do things funky here as alpha will be 1 already. if self.heightmap.getGrayVal(x, y) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if self.waterXMin == -1 or x < self.waterXMin: self.waterXMin = x if not self.waterYMax: self.waterYMax = y if y < self.waterYMax: self.waterYMax = y if x > self.waterXMax: self.waterXMax = x if y > self.waterYMin: self.waterYMin = y # Transform y coords self.waterYMin = self.size - 64 - self.waterYMin self.waterYMax = self.size - 64 - self.waterYMax def generateOwnerTexture(self, tiles, cities): '''Generates a simple colored texture to be applied to the city info region overlay. Due to different coordinate systems (terrain org bottom left, texture top left) some conversions are needed, Also creates and sends a citylabels dict for the region view ''' self.citymap = PNMImage(self.xsize, self.ysize) citylabels = cities scratch = {} # Setup for city labels for ident in cities: scratch[ident] = [] # conversion for y axis ycon = [] s = self.ysize - 1 for y in range(self.ysize): ycon.append(s) s -= 1 for ident, city in cities.items(): if ident not in self.citycolors: self.citycolors[ident] = VBase3D(random.random(), random.random(), random.random()) for tile in tiles: self.citymap.setXel(tile.coords[0], ycon[tile.coords[1]], self.citycolors[tile.cityid]) # Scratch for labeling if tile.cityid: scratch[tile.cityid].append((tile.coords[0], tile.coords[1])) for ident, values in scratch.items(): xsum = 0 ysum = 0 n = 0 for coords in values: xsum += coords[0] ysum += coords[1] n += 1 xavg = xsum / n yavg = ysum / n print "Elevation:", self.terrain.getElevation(xavg, yavg) z = self.terrain.getElevation(xavg, yavg) * 100 citylabels[ident]["position"] = (xavg, yavg, z + 15) print "Citylabels:", citylabels messenger.send("updateCityLabels", [citylabels, self.terrain]) def generateSurfaceTextures(self): # Textureize self.grassTexture = loader.loadTexture("Textures/grass.png") self.grassTS = TextureStage('grass') self.grassTS.setSort(1) self.rockTexture = loader.loadTexture("Textures/rock.jpg") self.rockTS = TextureStage('rock') self.rockTS.setSort(2) self.rockTS.setCombineRgb(TextureStage.CMAdd, TextureStage.CSLastSavedResult, TextureStage.COSrcColor, TextureStage.CSTexture, TextureStage.COSrcColor) self.sandTexture = loader.loadTexture("Textures/sand.jpg") self.sandTS = TextureStage('sand') self.sandTS.setSort(3) self.sandTS.setPriority(5) self.snowTexture = loader.loadTexture("Textures/ice.png") self.snowTS = TextureStage('snow') self.snowTS.setSort(4) self.snowTS.setPriority(0) # Grid for city placement and guide and stuff self.gridTexture = loader.loadTexture("Textures/grid.png") self.gridTexture.setWrapU(Texture.WMRepeat) self.gridTexture.setWrapV(Texture.WMRepeat) self.gridTS = TextureStage('grid') self.gridTS.setSort(5) self.gridTS.setPriority(10) def enterCity(self, ident, city, position, tiles): '''Identifies which terrain blocks city belogs to and disables those that are not A lot of uneeded for loops in here. Will need to find a better way later.''' #root = self.terrain.getRoot() children = [] for terrain in self.terrain.terrains: root = terrain.getRoot() children += root.getChildren() keepBlocks = [] # Reset water dimentions self.waterXMin = 0 self.waterXMax = 0 self.waterYMin = 0 self.waterYMax = 0 for tile in tiles: blockCoords = self.terrain.getBlockFromPos(tile.coords[0], tile.coords[1]) block = self.terrain.getBlockNodePath(blockCoords[0], blockCoords[1]) if block not in keepBlocks: keepBlocks.append(block) if self.heightmap.getGrayVal(tile.coords[0], self.size - tile.coords[1]) < 62: # Water card dimensions here # Y axis flipped from texture space to world space if not self.waterXMin: self.waterXMin = tile.coords[0] if not self.waterYMin: self.waterYMin = tile.coords[1] if tile.coords[1] > self.waterYMax: self.waterYMax = tile.coords[1] if tile.coords[0] > self.waterXMax: self.waterXMax = tile.coords[0] if tile.coords[0] < self.waterXMin: self.waterXMin = tile.coords[0] if tile.coords[1] < self.waterYMin: self.waterYMin = tile.coords[1] for child in children: if child not in keepBlocks: child.detachNode() self.view = ident self.generateWater(2) def newTerrainOverlay(self, task): root = self.terrain.getRoot() position = picker.getMouseCell() if position: # Check to make sure we do not go out of bounds if position[0] < 32: position = (32, position[1]) elif position[0] > self.xsize - 32: position = (self.xsize - 32, position[1]) if position[1] < 32: position = (position[0], 32) elif position[1] > self.ysize - 32: position = (position[0], self.size - 32) root.setTexOffset(self.tileTS, -(position[0] - 32) / 64, -(position[1] - 32) / 64) return task.cont def regionViewFound(self): '''Gui for founding a new city!''' self.setOwnerTextures() root = self.terrain.getRoot() task = taskMgr.add(self.newTerrainOverlay, "newTerrainOverlay") tileTexture = loader.loadTexture("Textures/tile.png") tileTexture.setWrapU(Texture.WMClamp) tileTexture.setWrapV(Texture.WMClamp) self.tileTS = TextureStage('tile') self.tileTS.setSort(6) self.tileTS.setMode(TextureStage.MDecal) #self.tileTS.setColor(Vec4(1,0,1,1)) root.setTexture(self.tileTS, tileTexture) root.setTexScale(self.tileTS, self.terrain.xchunks, self.terrain.ychunks) self.acceptOnce("mouse1", self.regionViewFound2) self.acceptOnce("escape", self.cancelRegionViewFound) def regionViewFound2(self): '''Grabs cell location for founding. The texture coordinate is used as the mouse may enter an out of bounds area. ''' root = self.terrain.getRoot() root_position = root.getTexOffset(self.tileTS) # We offset the position of the texture, so we will now put the origin of the new city not on mouse cursor but the "bottom left" of it. Just need to add 32 to get other edge position = [ int(abs(root_position[0] * 64)), int(abs(root_position[1] * 64)) ] self.cancelRegionViewFound() messenger.send("found_city_name", [position]) def cancelRegionViewFound(self): taskMgr.remove("newTerrainOverlay") root = self.terrain.getRoot() root.clearTexture(self.tileTS) # Restore original mouse function self.accept("mouse1", self.lclick) messenger.send("showRegionGUI") def setSurfaceTextures(self): self.ownerview = False root = self.terrain.getRoot() root.clearTexture() #self.terrain.setTextureMap() root.setTexture(self.colorTS, self.colorTexture) root.setTexture(self.grassTS, self.grassTexture) root.setTexScale(self.grassTS, self.size / 8, self.size / 8) root.setTexture(self.rockTS, self.rockTexture) root.setTexScale(self.rockTS, self.size / 8, self.size / 8) root.setTexture(self.sandTS, self.sandTexture) root.setTexScale(self.sandTS, self.size / 8, self.size / 8) root.setTexture(self.snowTS, self.snowTexture) root.setTexScale(self.snowTS, self.size / 8, self.size / 8) root.setTexture(self.gridTS, self.gridTexture) root.setTexScale(self.gridTS, self.xsize, self.ysize) root.setShaderInput('size', self.xsize, self.ysize, self.size, self.size) root.setShader(loader.loadShader('Shaders/terraintexture.sha')) def setOwnerTextures(self): self.ownerview = True root = self.terrain.getRoot() root.clearShader() root.clearTexture() cityTexture = Texture() cityTexture.load(self.citymap) cityTS = TextureStage('citymap') cityTS.setSort(0) root.setTexture(self.gridTS, self.gridTexture) root.setTexScale(self.gridTS, self.terrain.xchunks, self.terrain.ychunks) root.setTexture(cityTS, cityTexture, 1) def updateRegion(self, heightmap, tiles, cities): self.generateOwnerTexture(tiles, cities) if self.ownerview: self.setOwnerTextures() def updateTerrain(self, task): '''Updates terrain and water''' self.terrain.update() # Water if self.waterType is 2: pos = base.camera.getPos() render.setShaderInput('time', task.time) mc = base.camera.getMat() self.water.changeCameraPos(pos, mc) self.water.changeCameraPos(pos, mc) #print "Render diagnostics" #render.analyze() #base.cTrav.showCollisions(render) return task.cont def generateWater(self, style): print "Generate Water:", self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax '''Generates water style 0: blue card style 1: reflective card style 2: reflective card with shaders ''' self.waterHeight = 22.0 if self.water: self.water.removeNode() if style is 0: cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) cm.setColor(0, 0, 1, 0.9) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) messenger.send('makePickable', [self.water]) elif style is 1: # From Prosoft's super awesome terrain demo cm = CardMaker("water") #cm.setFrame(-1, 1, -1, 1) cm.setFrame(self.waterXMin, self.waterXMax, self.waterYMin, self.waterYMax) self.water = render.attachNewNode(cm.generate()) if self.waterYMax > self.waterXMax: size = self.waterYMax else: size = self.waterXMax #self.water.setScale(size) self.water.lookAt(0, 0, -1) self.water.setZ(self.waterHeight) self.water.setShaderOff(1) self.water.setLightOff(1) self.water.setAlphaScale(0.5) self.water.setTransparency(TransparencyAttrib.MAlpha) wbuffer = base.win.makeTextureBuffer("water", 512, 512) wbuffer.setClearColorActive(True) wbuffer.setClearColor(base.win.getClearColor()) self.wcamera = base.makeCamera(wbuffer) self.wcamera.reparentTo(render) self.wcamera.node().setLens(base.camLens) self.wcamera.node().setCameraMask(BitMask32.bit(1)) self.water.hide(BitMask32.bit(1)) wtexture = wbuffer.getTexture() wtexture.setWrapU(Texture.WMClamp) wtexture.setWrapV(Texture.WMClamp) wtexture.setMinfilter(Texture.FTLinearMipmapLinear) self.wplane = Plane(Vec3(0, 0, 1), Point3(0, 0, self.water.getZ())) wplanenp = render.attachNewNode(PlaneNode("water", self.wplane)) tmpnp = NodePath("StateInitializer") tmpnp.setClipPlane(wplanenp) tmpnp.setAttrib(CullFaceAttrib.makeReverse()) self.wcamera.node().setInitialState(tmpnp.getState()) self.water.projectTexture(TextureStage("reflection"), wtexture, self.wcamera) messenger.send('makePickable', [self.water]) elif style is 2: # From Clcheung just as super awesome demomaster self.water_level = Vec4(0.0, 0.0, self.waterHeight, 1.0) self.water = water.WaterNode(self.waterXMin, self.waterYMin, self.waterXMax, self.waterYMax, self.water_level.getZ()) self.water.setStandardControl() self.water.changeParams(None) wl = self.water_level wl.setZ(wl.getZ() - 0.05) #root.setShaderInput('waterlevel', self.water_level) render.setShaderInput('time', 0) messenger.send('makePickable', [self.water.waterNP])
class PlayerBase(DirectObject): def __init__(self): # Player Model setup self.player = Actor("Player", {"Run":"Player-Run", "Sidestep":"Player-Sidestep", "Idle":"Player-Idle"}) self.player.setBlend(frameBlend = True) self.player.setPos(0, 0, 0) self.player.pose("Idle", 0) self.player.reparentTo(render) self.player.hide() self.footstep = base.audio3d.loadSfx('footstep.ogg') self.footstep.setLoop(True) base.audio3d.attachSoundToObject(self.footstep, self.player) # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) CamMask = BitMask32.bit(0) AvBufMask = BitMask32.bit(1) self.avbuf = None if base.win: self.avbufTex = Texture('avbuf') self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True) cam = Camera('avbuf') cam.setLens(base.camNode.getLens()) self.avbufCam = base.cam.attachNewNode(cam) dr = self.avbuf.makeDisplayRegion() dr.setCamera(self.avbufCam) self.avbuf.setActive(False) self.avbuf.setClearColor((1, 0, 0, 1)) cam.setCameraMask(AvBufMask) base.camNode.setCameraMask(CamMask) # avbuf renders everything it sees with the gradient texture. tex = loader.loadTexture('gradient.png') np = NodePath('np') np.setTexture(tex, 100) np.setColor((1, 1, 1, 1), 100) np.setColorScaleOff(100) np.setTransparency(TransparencyAttrib.MNone, 100) np.setLightOff(100) cam.setInitialState(np.getState()) #render.hide(AvBufMask) # Setup a texture stage to paint on the player self.paintTs = TextureStage('paintTs') self.paintTs.setMode(TextureStage.MDecal) self.paintTs.setSort(10) self.paintTs.setPriority(10) self.tex = Texture('paint_av_%s'%id(self)) # Setup a PNMImage that will hold the paintable texture of the player self.imageSizeX = 64 self.imageSizeY = 64 self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4) self.p.fill(1) self.p.alphaFill(0) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) # Apply the paintable texture to the avatar self.player.setTexture(self.paintTs, self.tex) # team self.playerTeam = "" # A lable that will display the players team self.lblTeam = DirectLabel( scale = 1, pos = (0, 0, 3), frameColor = (0, 0, 0, 0), text = "TEAM", text_align = TextNode.ACenter, text_fg = (0,0,0,1)) self.lblTeam.reparentTo(self.player) self.lblTeam.setBillboardPointEye() # basic player values self.maxHits = 3 self.currentHits = 0 self.isOut = False self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor") # setup the collision detection # wall and object collision self.playerSphere = CollisionSphere(0, 0, 1, 1) self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self))) self.playerCollision.node().addSolid(self.playerSphere) base.pusher.addCollider(self.playerCollision, self.player) base.cTrav.addCollider(self.playerCollision, base.pusher) # foot (walk) collision self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self))) self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1)) self.playerFootRay.node().setIntoCollideMask(0) self.lifter = CollisionHandlerFloor() self.lifter.addCollider(self.playerFootRay, self.player) base.cTrav.addCollider(self.playerFootRay, self.lifter) # Player weapon setup self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R") self.color = LPoint3f(1, 1, 1) self.gun = Gun(id(self)) self.gun.reparentTo(self.gunAttach) self.gun.hide() self.gun.setColor(self.color) self.hud = None # Player controls setup self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 self.mouseSpeedX = 0.1 self.mouseSpeedY = 0.1 # AI controllable variables self.AIP = 0.0 self.AIH = 0.0 self.movespeed = 5.0 self.userControlled = False self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit) self.accept("window-event", self.recalcAspectRatio) def runBase(self): self.player.show() self.gun.show() taskMgr.add(self.move, "moveTask%d"%id(self), priority=-4) def stopBase(self): taskMgr.remove("moveTask%d"%id(self)) self.ignoreAll() self.gun.remove() self.footstep.stop() base.audio3d.detachSound(self.footstep) self.player.delete() def setKey(self, key, value): self.keyMap[key] = value def setPos(self, pos): self.player.setPos(pos) def setColor(self, color=LPoint3f(0,0,0)): self.color = color self.gun.setColor(color) c = (color[0], color[1], color[2], 1.0) self.lblTeam["text_fg"] = c def setTeam(self, team): self.playerTeam = team self.lblTeam["text"] = team def shoot(self, shotVec=None): self.gun.shoot(shotVec) if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def reload(self): self.gun.reload() if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def recalcAspectRatio(self, window): self.winXhalf = window.getXSize() / 2 self.winYhalf = window.getYSize() / 2 def hit(self, entry, color): self.currentHits += 1 # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") splat = splat * LColorf(color[0], color[1], color[2], 1.0) self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) self.paintAvatar(entry) if self.currentHits >= self.maxHits: base.messenger.send("GameOver-player%d" % id(self)) self.isOut = True def __paint(self, s, t): """ Paints a point on the avatar at texture coordinates (s, t). """ x = (s * self.p.getXSize()) y = ((1.0 - t) * self.p.getYSize()) # Draw in color directly on the avatar p1 = PNMPainter(self.p) p1.setPen(self.colorBrush) p1.drawPoint(x, y) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) self.paintDirty = True def paintAvatar(self, entry): """ Paints onto an avatar. Returns true on success, false on failure (because there are no avatar pixels under the mouse, for instance). """ # First, we have to render the avatar in its false-color # image, to determine which part of its texture is under the # mouse. if not self.avbuf: return False #mpos = base.mouseWatcherNode.getMouse() mpos = entry.getSurfacePoint(self.player) ppos = entry.getSurfacePoint(render) self.player.showThrough(BitMask32.bit(1)) self.avbuf.setActive(True) base.graphicsEngine.renderFrame() self.player.show(BitMask32.bit(1)) self.avbuf.setActive(False) # Now we have the rendered image in self.avbufTex. if not self.avbufTex.hasRamImage(): print "Weird, no image in avbufTex." return False p = PNMImage() self.avbufTex.store(p) ix = int((1 + mpos.getX()) * p.getXSize() * 0.5) iy = int((1 - mpos.getY()) * p.getYSize() * 0.5) x = 1 if ix >= 0 and ix < p.getXSize() and iy >= 0 and iy < p.getYSize(): s = p.getBlue(ix, iy) t = p.getGreen(ix, iy) x = p.getRed(ix, iy) if x > 0.5: # Off the avatar. return False # At point (s, t) on the avatar's map. self.__paint(s, t) return True def move(self, task): if self is None: return task.done if self.userControlled: if not base.mouseWatcherNode.hasMouse(): return task.cont self.pointer = base.win.getPointer(0) mouseX = self.pointer.getX() mouseY = self.pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): p = self.TorsorControl.getP() + (mouseY - self.winYhalf) * self.mouseSpeedY if p <-80: p = -80 elif p > 90: p = 90 self.TorsorControl.setP(p) h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX if h <-360: h = 360 elif h > 360: h = -360 self.player.setH(h) else: self.TorsorControl.setP(self.AIP) self.player.setH(self.AIH) forward = self.keyMap["forward"] != 0 backward = self.keyMap["backward"] != 0 if self.keyMap["left"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, self.movespeed * globalClock.getDt()) elif self.keyMap["right"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, -self.movespeed * globalClock.getDt()) else: self.player.stop("Sidestep") if forward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(5, "Run") self.player.setY(self.player, -self.movespeed * globalClock.getDt()) elif backward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(-5, "Run") self.player.setY(self.player, self.movespeed * globalClock.getDt()) else: self.player.stop("Run") if not (self.keyMap["left"] or self.keyMap["right"] or self.keyMap["forward"] or self.keyMap["backward"] or self.player.getCurrentAnim() == "Idle"): self.player.loop("Idle") self.footstep.stop() else: self.footstep.play() return task.cont
class Water(AssetBase): def __init__(self, name, size=10000, resolution=1024): """Arguments: size -- Edge length of the water square. resolution -- Texture size of the rendered reflection buffer. """ # Uncomment to see the output of the refclection buffer. base.bufferViewer.toggleEnable() AssetBase.__init__(self) self.name = name self.cm = CardMaker("water surface") self.cm.setFrame(-0.5 * size, 0.5 * size, -0.5 * size, 0.5 * size) self.cm.setHasUvs(True) self.node = NodePath(self.cm.generate()) self.node.setP(self.node, -90) self.node.flattenLight() self.node.hide(BitMask32.bit(1)) # self.node.setTwoSided(True) self.node.setShaderOff() # size of one texture tile in meters self.tex_size = 100.0 diffuse = TexturePool.loadTexture("textures/water.diffuse.png") diffuse.setWrapU(Texture.WMRepeat) diffuse.setWrapV(Texture.WMRepeat) diffuse.setMinfilter(Texture.FTLinearMipmapLinear) diffuse.setMagfilter(Texture.FTLinearMipmapLinear) self.diffuse_stage = TextureStage("diffuse") self.diffuse_stage.setSort(2) self.node.setTexture(self.diffuse_stage, diffuse) self.node.setTexScale(self.diffuse_stage, size / self.tex_size, size / self.tex_size) # Reflection camera renders to 'buffer' which is projected onto the # water surface. buffer = base.win.makeTextureBuffer("water reflection", resolution, resolution) buffer.setClearColor(Vec4(0, 0, 0, 1)) self.refl_cam = base.makeCamera(buffer) self.refl_cam.reparentTo(self.node) self.refl_cam.node().setCameraMask(BitMask32.bit(1)) self.refl_cam.node().getLens().setFov(base.camLens.getFov()) self.refl_cam.node().getLens().setNearFar(1, 100000) plane = PlaneNode("water culling plane", Plane(Vec3(0, 0, 1), Point3(0, 0, 0))) cfa = CullFaceAttrib.makeReverse() cpa = ClipPlaneAttrib.make(PlaneNode.CEVisible, plane) rs = RenderState.make(cfa, cpa) self.refl_cam.node().setInitialState(rs) reflection = buffer.getTexture() reflection.setMinfilter(Texture.FTLinear) reflection.setMagfilter(Texture.FTLinear) self.refl_stage = TextureStage("reflection") self.refl_stage.setSort(1) self.node.projectTexture(self.refl_stage, reflection, base.cam) self.node.setTexture(self.refl_stage, reflection) # Blend between diffuse and reflection. self.diffuse_stage.setColor(VBase4(1, 1, 1, 0.2)) # opacity of 20% self.diffuse_stage.setCombineRgb( TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSConstant, TextureStage.COSrcAlpha, ) self.addTask(self.update, name="water update", sort=1, taskChain="world") def update(self, task): """Updates position of the reflection camera and the water plane.""" mc = base.cam.getMat(render) # mf = Plane(Vec3(0, 0, 1), Point3(0, 0, 0)).getReflectionMat() mf = Mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1) self.refl_cam.setMat(mc * mf) self.node.setX(camera.getX(render)) self.node.setY(camera.getY(render)) self.node.setTexOffset(self.diffuse_stage, self.node.getX() / self.tex_size, self.node.getY() / self.tex_size) return task.cont def destroy(self): self.removeAllTasks() self.node.removeNode() self.refl_cam.removeNode()
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) # Load the environment model. self.setup_environment() #self.scene = self.loader.loadModel("models/environment") # Reparent the model to render. #self.scene.reparentTo(self.render) # Apply scale and position transforms on the model. #self.scene.setScale(0.25, 0.25, 0.25) #self.scene.setPos(-8, 42, 0) # Needed for camera image self.dr = self.camNode.getDisplayRegion(0) # Needed for camera depth image winprops = WindowProperties.size(self.win.getXSize(), self.win.getYSize()) fbprops = FrameBufferProperties() fbprops.setDepthBits(1) self.depthBuffer = self.graphicsEngine.makeOutput( self.pipe, "depth buffer", -2, fbprops, winprops, GraphicsPipe.BFRefuseWindow, self.win.getGsg(), self.win) self.depthTex = Texture() self.depthTex.setFormat(Texture.FDepthComponent) self.depthBuffer.addRenderTexture(self.depthTex, GraphicsOutput.RTMCopyRam, GraphicsOutput.RTPDepth) lens = self.cam.node().getLens() lens.setFov(90.0, 90.0) # the near and far clipping distances can be changed if desired # lens.setNear(5.0) # lens.setFar(500.0) self.depthCam = self.makeCamera(self.depthBuffer, lens=lens, scene=self.render) self.depthCam.reparentTo(self.cam) # TODO: Scene is rendered twice: once for rgb and once for depth image. # How can both images be obtained in one rendering pass? self.render.setAntialias(AntialiasAttrib.MAuto) def setup_environment(self): # encapsulate some stuff # set up ambient lighting self.alight = AmbientLight('alight') self.alight.setColor(VBase4(0.1, 0.1, 0.1, 1)) self.alnp = self.render.attachNewNode(self.alight) self.render.setLight(self.alnp) # set up a point light self.plight = PointLight('plight') self.plight.setColor(VBase4(0.8, 0.8, 0.8, 1)) self.plnp = self.render.attachNewNode(self.plight) self.plnp.setPos(0, 0, 100) self.render.setLight(self.plnp) # set up terrain model self.terr_material = Material() self.terr_material.setShininess(1.0) self.terr_material.setAmbient(VBase4(0, 0, 0, 0)) self.terr_material.setDiffuse(VBase4(1, 1, 1, 1)) self.terr_material.setEmission(VBase4(0, 0, 0, 0)) self.terr_material.setSpecular(VBase4(0, 0, 0, 0)) # general scaling self.trrHorzSc = 4.0 self.trrVertSc = 4.0 # was 4.0 # Create sky #terrctr = self.trrHorzSc*65.0 #self.setup_skybox(terrctr,800.0,2.0,0.3) self.skysphere = self.loader.loadModel("sky-forest/SkySphere.bam") self.skysphere.setBin('background', 1) self.skysphere.setDepthWrite(0) self.skysphere.reparentTo(self.render) # Load some textures self.grsTxtSc = 5 self.numTreeTexts = 7 # ground texture self.txtGrass = self.loader.loadTexture('tex/ground005.png') self.txtGrass.setWrapU(Texture.WM_mirror) self.txtGrass.setWrapV(Texture.WM_mirror) self.txtGrass.setMagfilter(Texture.FTLinear) self.txtGrass.setMinfilter(Texture.FTLinearMipmapLinear) # set up terrain texture stages self.TS1 = TextureStage('terrtext') self.TS1.setSort(0) self.TS1.setMode(TextureStage.MReplace) # Set up the GeoMipTerrain self.terrain = GeoMipTerrain("myDynamicTerrain") img = PNMImage(Filename('tex/bowl_height_map.png')) self.terrain.setHeightfield(img) self.terrain.setBruteforce(0) self.terrain.setAutoFlatten(GeoMipTerrain.AFMMedium) # Set terrain properties self.terrain.setBlockSize(32) self.terrain.setNear(50) self.terrain.setFar(500) self.terrain.setFocalPoint(self.camera) # Store the root NodePath for convenience self.root = self.terrain.getRoot() self.root.clearTexture() self.root.setTwoSided(0) self.root.setCollideMask(BitMask32.bit(0)) self.root.setSz(self.trrVertSc) self.root.setSx(self.trrHorzSc) self.root.setSy(self.trrHorzSc) self.root.setMaterial(self.terr_material) self.root.setTexture(self.TS1, self.txtGrass) self.root.setTexScale(self.TS1, self.grsTxtSc, self.grsTxtSc) offset = 0.5 * img.getXSize() * self.trrHorzSc - 0.5 self.root.setPos(-offset, -offset, 0) self.terrain.generate() self.root.reparentTo(self.render) # load tree billboards self.txtTreeBillBoards = [] for a in range(self.numTreeTexts): fstr = 'trees/tree' + '%03d' % (a + 991) self.txtTreeBillBoards.append( \ self.loader.loadTexture(fstr + '-color.png', fstr + '-opacity.png')) self.txtTreeBillBoards[a].setMinfilter( Texture.FTLinearMipmapLinear) #self.placePlantOnTerrain('trees',300,0,20,20,self.trrHorzSc,self.trrVertSc, \ # self.numTreeTexts,self.txtTreeBillBoards,'scene-def/trees.txt') self.setup_house() self.setup_vehicle() self.taskMgr.add(self.skysphereTask, "SkySphere Task") def setup_house(self): # place farmhouse on terrain self.house = ModelNode('house1') self.loadModelOntoTerrain(self.render, self.terrain, self.house, 43.0, 0.275, 0.0, 0.0, self.trrHorzSc, self.trrVertSc, 'models/FarmHouse', Vec3(0, 0, 0), Point3(-12.0567, -29.1724, 0.0837742), Point3(12.2229, 21.1915, 21.3668)) def setup_vehicle(self): # place HMMWV on terrain self.hmmwv = ModelNode('hmmwv1') self.loadModelOntoTerrain(self.render, self.terrain, self.hmmwv, 33.0, 1.0, 20.0, 24.0, self.trrHorzSc, self.trrVertSc, 'models/hmmwv', Vec3(0, -90, 0), Point3(-1.21273, -2.49153, -1.10753), Point3(1.21273, 2.49153, 1.10753)) def setup_skybox(self, terrctr=645.0, boxsz=1000.0, aspect=1.0, uplift=0.0): vsz = boxsz / aspect self.bckgtx = [] self.bckgtx.append(self.loader.loadTexture('sky/Back2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Right2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Front2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Left2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Up.png')) for a in range(4): self.bckg = CardMaker('bkcard') lr = Point3(0.5 * boxsz, 0.5 * boxsz, -0.5 * vsz) ur = Point3(0.5 * boxsz, 0.5 * boxsz, 0.5 * vsz) ul = Point3(-0.5 * boxsz, 0.5 * boxsz, 0.5 * vsz) ll = Point3(-0.5 * boxsz, 0.5 * boxsz, -0.5 * vsz) self.bckg.setFrame(ll, lr, ur, ul) self.bckg.setHasNormals(0) self.bckg.setHasUvs(1) #self.bckg.setUvRange(self.bckgtx[a]) bkcrd = self.render.attachNewNode(self.bckg.generate()) bkcrd.setTexture(self.bckgtx[a]) self.bckgtx[a].setWrapU(Texture.WMClamp) self.bckgtx[a].setWrapV(Texture.WMClamp) bkcrd.setLightOff() bkcrd.setFogOff() bkcrd.setHpr(90.0 * a, 0, 0) cz = 0.5 * boxsz * uplift #print 'set card at:', terrctr,terrctr,cz, ' with points: ', lr,ur,ul,ll bkcrd.setPos(terrctr, terrctr, cz) self.top = CardMaker('bkcard') lr = Point3(0.5 * boxsz, -0.5 * boxsz, 0) ur = Point3(0.5 * boxsz, 0.5 * boxsz, 0) ul = Point3(-0.5 * boxsz, 0.5 * boxsz, 0) ll = Point3(-0.5 * boxsz, -0.5 * boxsz, 0) self.top.setFrame(ll, lr, ur, ul) self.top.setHasNormals(0) self.top.setHasUvs(1) #self.top.setUvRange(self.bckgtx[4]) bkcrd = self.render.attachNewNode(self.bckg.generate()) bkcrd.setTexture(self.bckgtx[4]) self.bckgtx[4].setWrapU(Texture.WMClamp) self.bckgtx[4].setWrapV(Texture.WMClamp) bkcrd.setLightOff() bkcrd.setFogOff() bkcrd.setHpr(0, 90, 90) bkcrd.setPos(terrctr, terrctr, 0.5 * vsz + 0.5 * boxsz * uplift) def placePlantOnTerrain(self, itemStr, itemCnt, Mode, typItemWidth, typItemHeight, trrHorzSc, trrVertSc, numTxtTypes, txtList, planFileName): # Billboarding plants crd = CardMaker('mycard') crd.setColor(0.5, 0.5, 0.5, 1) ll = Point3(-0.5 * typItemWidth, 0, 0) lr = Point3(0.5 * typItemWidth, 0, 0) ur = Point3(0.5 * typItemWidth, 0, typItemHeight) ul = Point3(-0.5 * typItemWidth, 0, typItemHeight) crd.setFrame(ll, lr, ur, ul) crd.setHasNormals(False) crd.setHasUvs(True) # generate/save/load locations try: plan_data_fp = open(planFileName, 'r') item_list = [] for line in plan_data_fp: toks = line.split(',') px = float(toks[0].strip(' ')) py = float(toks[1].strip(' ')) ang = float(toks[2].strip(' ')) dht = float(toks[3].strip(' ')) scl = float(toks[4].strip(' ')) idx = int(toks[5].strip(' ')) item_list.append((px, py, ang, dht, scl, idx)) plan_data_fp.close() print 'loaded ', itemStr, ' data file of size:', len(item_list) except IOError: # generate list and try to save item_list = [] for a in range(itemCnt): px = random.randrange(-self.trrHorzSc * 64, self.trrHorzSc * 64) py = random.randrange(-self.trrHorzSc * 64, self.trrHorzSc * 64) ang = 180 * random.random() dht = 0.0 scl = 0.75 + 0.25 * (random.random() + random.random()) idx = random.randrange(0, numTxtTypes) item_list.append([px, py, ang, dht, scl, idx]) try: plan_data_fp = open(planFileName, 'w') for c in item_list: print >> plan_data_fp, c[0], ',', c[1], ',', c[2], ',', c[ 3], ',', c[4], ',', c[5] plan_data_fp.close() print 'saved ', itemStr, ' data of size: ', len(item_list) except IOError: print 'unable to store ', itemStr, ' data of size: ', len( item_list) # define each plant for c in item_list: px = c[0] py = c[1] ang = c[2] dht = c[3] scl = c[4] idx = c[5] if idx >= numTxtTypes: idx = 0 if Mode > 0: for b in range(Mode): crdNP = self.render.attachNewNode(crd.generate()) crdNP.setTexture(txtList[idx]) crdNP.setScale(scl) crdNP.setTwoSided(True) ht = self.terrain.getElevation(px / trrHorzSc, py / trrHorzSc) crdNP.setPos(px, py, ht * trrVertSc + dht) crdNP.setHpr(ang + (180 / Mode) * b, 0, 0) crdNP.setTransparency(TransparencyAttrib.MAlpha) crdNP.setLightOff() else: # set up item as defined crd.setUvRange(txtList[idx]) crdNP = self.render.attachNewNode(crd.generate()) crdNP.setBillboardAxis() crdNP.setTexture(txtList[idx]) crdNP.setScale(scl) ht = self.terrain.getElevation(px / trrHorzSc, py / trrHorzSc) crdNP.setPos(px, py, ht * trrVertSc) crdNP.setTransparency(TransparencyAttrib.MAlpha) crdNP.setLightOff() def loadModelOntoTerrain(self, render_node, terr_obj, model_obj, hdg, scl, xctr, yctr, terr_horz_sc, terr_vert_sc, model_path, rotA, minP, maxP): # load model onto terrain hdg_rads = hdg * math.pi / 180.0 model_obj = self.loader.loadModel(model_path) rotAll = rotA rotAll.setX(rotAll.getX() + hdg) model_obj.setHpr(rotA) model_obj.setLightOff() # if model changes, these will have to be recomputed # minP = Point3(0,0,0) # maxP = Point3(0,0,0) # model_obj.calcTightBounds(minP,maxP) print minP print maxP htl = [] maxzofs = -1000.0 for xi in [minP[0], maxP[0]]: for yi in [minP[1], maxP[1]]: tx = xctr + scl * xi * math.cos(hdg_rads) ty = yctr + scl * yi * math.sin(hdg_rads) tht = self.terrain.getElevation(tx / terr_horz_sc, ty / terr_horz_sc) print 'tx=', tx, ', ty=', ty, ', tht=', tht htl.append(tht * terr_vert_sc - minP.getZ()) for hi in htl: if hi > maxzofs: maxzofs = hi print maxzofs model_obj.setPos(xctr, yctr, maxzofs) model_obj.setHpr(rotAll) model_obj.setScale(scl) model_obj.reparentTo(render_node) return maxzofs, minP, maxP def get_camera_image(self, requested_format=None): """ Returns the camera's image, which is of type uint8 and has values between 0 and 255. The 'requested_format' argument should specify in which order the components of the image must be. For example, valid format strings are "RGBA" and "BGRA". By default, Panda's internal format "BGRA" is used, in which case no data is copied over. """ tex = self.dr.getScreenshot() if requested_format is None: data = tex.getRamImage() else: data = tex.getRamImageAs(requested_format) image = np.frombuffer( data.get_data(), np.uint8) # use data.get_data() instead of data in python 2 image.shape = (tex.getYSize(), tex.getXSize(), tex.getNumComponents()) image = np.flipud(image) return image def get_camera_depth_image(self): """ Returns the camera's depth image, which is of type float32 and has values between 0.0 and 1.0. """ data = self.depthTex.getRamImage() depth_image = np.frombuffer(data.get_data(), np.float32) depth_image.shape = (self.depthTex.getYSize(), self.depthTex.getXSize(), self.depthTex.getNumComponents()) depth_image = np.flipud(depth_image) ''' Surface position can be inferred by calculating backward from the depth buffer. Each pixel on the screen represents a ray from the camera into the scene, and the depth value in the pixel indicates a distance along the ray. Because of this, it is not actually necessary to store surface position explicitly - it is only necessary to store depth values. Of course, OpenGL does that for free. So the framebuffer now needs to store surface normal, diffuse color, and depth value (to infer surface position). In practice, most ordinary framebuffers can only store color and depth - they don't have any place to store a third value. So we need to use a special offscreen buffer with an "auxiliary" bitplane. The auxiliary bitplane stores the surface normal. So then, there's the final postprocessing pass. This involves combining the diffuse color texture, the surface normal texture, the depth texture, and the light parameters into a final rendered output. The light parameters are passed into the postprocessing shader as constants, not as textures. If there are a lot of lights, things get interesting. You use one postprocessing pass per light. Each pass only needs to scan those framebuffer pixels that are actually in range of the light in question. To traverse only the pixels that are affected by the light, just render the illuminated area's convex bounding volume. The shader to store the diffuse color and surface normal is trivial. But the final postprocessing shader is a little complicated. What makes it tricky is that it needs to regenerate the original surface position from the screen position and depth value. The math for that deserves some explanation. We need to take a clip-space coordinate and depth-buffer value (ClipX,ClipY,ClipZ,ClipW) and unproject it back to a view-space (ViewX,ViewY,ViewZ) coordinate. Lighting is then done in view-space. Okay, so here's the math. Panda uses the projection matrix to transform view-space into clip-space. But in practice, the projection matrix for a perspective camera always contains four nonzero constants, and they're always in the same place: -- here are the non-zero elements of the projection matrix -- A 0 0 0 0 0 B 1 0 C 0 0 0 0 D 0 -- precompute these from above projection matrix -- ''' proj = self.cam.node().getLens().getProjectionMat() proj_x = 0.5 * proj.getCell(3, 2) / proj.getCell(0, 0) proj_y = 0.5 * proj.getCell(3, 2) proj_z = 0.5 * proj.getCell(3, 2) / proj.getCell(2, 1) proj_w = -0.5 - 0.5 * proj.getCell(1, 2) ''' -- now for each pixel compute viewpoint coordinates -- viewx = (screenx * projx) / (depth + projw) viewy = (1 * projy) / (depth + projw) viewz = (screeny * projz) / (depth + projw) ''' grid = np.mgrid[0:depth_image.shape[0], 0:depth_image.shape[1]] ygrid = np.float32(np.squeeze( grid[0, :, :])) / float(depth_image.shape[0] - 1) ygrid -= 0.5 xgrid = np.float32(np.squeeze( grid[1, :, :])) / float(depth_image.shape[1] - 1) xgrid -= 0.5 xview = 2.0 * xgrid * proj_x zview = 2.0 * ygrid * proj_z denom = np.squeeze(depth_image) + proj_w xview = xview / denom yview = proj_y / denom zview = zview / denom sqrng = xview**2 + yview**2 + zview**2 range_image = np.sqrt(sqrng) range_image_1 = np.expand_dims(range_image, axis=2) return depth_image, range_image_1 def compute_sample_pattern(self, limg_shape, res_factor): # assume velocity is XYZ and we are looking +X up and towards -Z pattern = [] lens = self.cam.node().getLens() sx = self.win.getXSize() sy = self.win.getYSize() ifov_vert = 2.0 * math.tan( 0.5 * math.radians(lens.getVfov())) / float(sy - 1) ifov_horz = 2.0 * math.tan( 0.5 * math.radians(lens.getHfov())) / float(sx - 1) #ifov_vert = lens.getVfov() / float(sy-1) #ifov_horz = lens.getHfov() / float(sy-1) for ldr_row in range(limg_shape[0]): theta = -10.0 - 41.33 * ( float(ldr_row) / float(limg_shape[0] - 1) - 0.5) for ldr_col in range(limg_shape[1]): psi = 60.0 * (float(ldr_col) / float(limg_shape[1] - 1) - 0.5) cpsi = math.cos(math.radians(psi)) vert_ang = theta / cpsi img_row_flt = (0.5 * float(sy - 1) - (math.tan(math.radians(vert_ang)) / ifov_vert)) #img_row_flt = 0.5*(sy-1) - (vert_ang / ifov_vert) if img_row_flt < 0: print('img_row_flt=%f' % img_row_flt) img_row_flt = 0.0 if img_row_flt >= sy: print('img_row_flt=%f' % img_row_flt) img_row_flt = float(sy - 1) img_col_flt = (0.5 * float(sx - 1) + (math.tan(math.radians(psi)) / ifov_horz)) #img_col_flt = 0.5*(sx-1) + (psi / ifov_horz) if img_col_flt < 0: print('img_col_flt=%f' % img_col_flt) img_col_flt = 0.0 if img_col_flt >= sx: print('img_col_flt=%f' % img_col_flt) img_col_flt = float(sx - 1) pattern.append((ldr_row, ldr_col, img_row_flt, img_col_flt)) return pattern def find_sorted_ladar_returns(self, rangearr, intensarr, ks_m): my_range = rangearr.copy() my_inten = intensarr.copy() ''' pixels data is organized by: [0] starting range of this return [1] ending range of this return [2] peak range of this return [3] total intensity of this return ''' int_mult = len(my_inten) pixels = map( list, zip(my_range.tolist(), my_range.tolist(), my_range.tolist(), my_inten.tolist())) spix = sorted(pixels, key=lambda x: x[0]) done = False while not done: mxpi = len(spix) if mxpi > 2: mindel = 1e20 mnidx = None for pidx in range(mxpi - 1): rdel = spix[pidx + 1][0] - spix[pidx][1] # must be within ks_m meters in range to merge if (rdel < ks_m) and (rdel < mindel): mindel = rdel mnidx = pidx # merge best two returns if mnidx is not None: # new range span for testing against neighbors spix[mnidx][1] = spix[mnidx + 1][1] # new peak range is range of max contributor if spix[mnidx + 1][3] > spix[mnidx][3]: spix[mnidx][2] = spix[mnidx + 1][2] # intensity of return is sum of contributors spix[mnidx][3] += spix[mnidx + 1][3] # remove one of the two merged del spix[mnidx + 1] else: done = True else: done = True # now eliminate all but max and last returns max_idx = None max_val = 0.0 for ci, pix in enumerate(spix): if pix[3] > max_val: max_val = pix[3] / int_mult max_idx = ci # if they are the same, return only one if spix[-1][3] >= spix[max_idx][3]: return [spix[-1]] else: return [spix[max_idx], spix[-1]] def sample_range_image(self, rng_img, int_img, limg_shape, vel_cam, pps, ldr_err, pattern): # depth image is set up as 512 x 512 and is 62.5 degrees vertical FOV # the center row is vertical, but we want to sample from the # region corresponding to HDL-32 FOV: from +10 to -30 degrees detailed_sensor_model = False fwd_vel = vel_cam[1] beam_div = 0.002 lens = self.cam.node().getLens() #sx = self.win.getXSize() sy = self.win.getYSize() ifov_vert = 2.0 * math.tan( 0.5 * math.radians(lens.getVfov())) / float(sy - 1) #ifov_horz = 2.0*math.tan(0.5*math.radians(lens.getHfov()))/float(sx-1) #ifov = math.radians(self.cam.node().getLens().getVfov() / self.win.getYSize()) sigma = beam_div / ifov_vert hs = int(2.0 * sigma + 1.0) gprof = gauss_kern(sigma, hs, normalize=False) rimg = np.zeros(limg_shape, dtype=np.float32) iimg = np.zeros(limg_shape, dtype=np.float32) margin = 10.0 for pidx, relation in enumerate(pattern): # get the usual scan pattern sample ldr_row, ldr_col, img_row_flt, img_col_flt = relation if ((img_row_flt > -margin) and (img_col_flt > -margin) and (img_row_flt < rng_img.shape[0] + margin) and (img_col_flt < rng_img.shape[1] + margin)): # within reasonable distance from image limits img_row = int(round(img_row_flt)) img_col = int(round(img_col_flt)) # motion compensation trng = np.float32(rng_img[img_row, img_col]) if trng > 0.0: # TODO: change this back to False done = True ic = 0 while not done: old_trng = trng del_row = pidx * fwd_vel / (ifov_vert * trng * pps) if (abs(del_row) > 1e-1) and (ic < 10): img_row_f = img_row_flt + del_row img_row = int(round(img_row_f)) trng = np.float32(rng_img[img_row, img_col]) ic += 1 if abs(trng - old_trng) < 0.5: done = True else: done = True # simple sensor processing: just sample from large images rimg[ldr_row, ldr_col] = np.float32(rng_img[img_row, img_col]) iimg[ldr_row, ldr_col] = np.float32(int_img[img_row, img_col]) if detailed_sensor_model: # detailed model subsamples whole beam width gpatch = copy_patch_centered((img_row, img_col), hs, int_img, 0.0) gpatch = np.float32(gpatch) gpatch *= gprof rpatch = copy_patch_centered((img_row, img_col), hs, rng_img, 0.0) rpatch = np.squeeze(rpatch) valid = rpatch > 1e-3 if np.count_nonzero(valid) > 0: rpatch_ts = rpatch[valid] gpatch_ts = gpatch[valid] returns = self.find_sorted_ladar_returns( rpatch_ts, gpatch_ts, 2.5) # for now we just take first return rimg[ldr_row, ldr_col] = returns[0][2] iimg[ldr_row, ldr_col] = returns[0][3] else: rimg[ldr_row, ldr_col] = 0.0 iimg[ldr_row, ldr_col] = np.float32(int_img[img_row, img_col]) rimg += ldr_err * np.random.standard_normal(rimg.shape) return rimg, iimg def skysphereTask(self, task): if self.base is not None: self.skysphere.setPos(self.base.camera, 0, 0, 0) self.terrain.generate() return task.cont
def setupHeightmap(self, name): # Automatically generate a heightmap mesh from a monochrome image. self.hmHeight = 120 hmPath = "../maps/map" + name + "/map" + name + "-h.png" imPath = "../maps/map" + name + "/map" + name + "-i.png" smPath = "../maps/map" + name + "/map" + name + "-s.png" scmPath = "../maps/map" + name + "/map" + name + "-sc.png" print(hmPath) print(imPath) print(smPath) print(scmPath) hmImg = PNMImage(Filename(hmPath)) hmShape = BulletHeightfieldShape(hmImg, self.hmHeight, ZUp) hmNode = BulletRigidBodyNode('Terrain') hmNode.addShape(hmShape) hmNode.setMass(0) self.hmNP = render.attachNewNode(hmNode) self.worldBullet.attachRigidBody(hmNode) self.hmOffset = hmImg.getXSize() / 2.0 - 0.5 self.hmTerrain = GeoMipTerrain('gmTerrain') self.hmTerrain.setHeightfield(hmImg) # Optimizations and fixes self.hmTerrain.setBruteforce( True) # I don't think this is actually needed. self.hmTerrain.setMinLevel(3) # THIS is what triangulates the terrain. self.hmTerrain.setBlockSize( 128) # This does a pretty good job of raising FPS. # Level-of-detail (not yet working) # self.hmTerrain.setNear(40) # self.hmTerrain.setFar(200) self.hmTerrain.generate() self.hmTerrainNP = self.hmTerrain.getRoot() self.hmTerrainNP.setSz(self.hmHeight) self.hmTerrainNP.setPos(-self.hmOffset, -self.hmOffset, -self.hmHeight / 2.0) self.hmTerrainNP.flattenStrong( ) # This only reduces the number of nodes; nothing to do with polys. self.hmTerrainNP.analyze() # Here begins the scenery mapping treeModel = loader.loadModel("../res/models/tree_1.egg") rockModel = loader.loadModel("../res/models/rock_1.egg") rock2Model = loader.loadModel("../res/models/rock_2.egg") rock3Model = loader.loadModel("../res/models/rock_3.egg") # caveModel = loader.loadModel("../res/models/cave_new.egg") # planeFrontModel = loader.loadModel("../res/models/plane_front.egg") # planeWingModel = loader.loadModel("../res/models/plane_wing.egg") texpk = loader.loadTexture(scmPath).peek() # GameObject nodepath for flattening self.objNP = render.attachNewNode("gameObjects") self.treeNP = self.objNP.attachNewNode("goTrees") self.rockNP = self.objNP.attachNewNode("goRocks") self.rock2NP = self.objNP.attachNewNode("goRocks2") self.rock3NP = self.objNP.attachNewNode("goRocks3") # self.caveNP = self.objNP.attachNewNode("goCave") # self.planeFrontNP = self.objNP.attachNewNode("goPlaneFront") # self.planeWingNP = self.objNP.attachNewNode("goPlaneWing") for i in range(0, texpk.getXSize()): for j in range(0, texpk.getYSize()): color = VBase4(0, 0, 0, 0) texpk.lookup(color, float(i) / texpk.getXSize(), float(j) / texpk.getYSize()) if (int(color.getX() * 255.0) == 255.0): newTree = self.treeNP.attachNewNode("treeNode") treeModel.instanceTo(newTree) newTree.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newTree.setScale(randint(0,4)) newTree.setScale(2) if (int(color.getX() * 255.0) == 128): newRock = self.rockNP.attachNewNode("newRock") newRock.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rockModel.instanceTo(newRock) if (int(color.getX() * 255.0) == 77): newRock2 = self.rock2NP.attachNewNode("newRock2") newRock2.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock2Model.instanceTo(newRock2) if (int(color.getX() * 255.0) == 102): newRock3 = self.rock3NP.attachNewNode("newRock3") newRock3.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock3Model.instanceTo(newRock3) # if(int(color.getX() * 255.0) == 64): # newCave = self.caveNP.attachNewNode("newCave") # newCave.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newCave.setScale(5) # newCave.setP(180) # caveModel.instanceTo(newCave) # if(int(color.getX() * 255.0) == 191): # newPlaneFront = self.planeFrontNP.attachNewNode("newPlaneFront") # newPlaneFront.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneFront.setScale(6) # planeFrontModel.instanceTo(newPlaneFront) # if(int(color.getX() * 255.0) == 179): # newPlaneWing = self.planeWingNP.attachNewNode("newPlaneWing") # newPlaneWing.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneWing.setScale(6) # newPlaneWing.setH(250) # newPlaneWing.setR(180) # newPlaneWing.setP(135) # planeWingModel.instanceTo(newPlaneWing) self.snowflakes = [] for i in xrange(0, self.snowflakeCount): print("Call " + str(i)) sf = SMCollect(self.worldBullet, self.worldObj, self.snowflakePositions[i]) self.snowflakes.append(sf) # render.flattenStrong() self.hmTerrainNP.reparentTo(render) # Here begins the attribute mapping ts = TextureStage("stage-alpha") ts.setSort(0) ts.setPriority(1) ts.setMode(TextureStage.MReplace) ts.setSavedResult(True) self.hmTerrainNP.setTexture(ts, loader.loadTexture(imPath, smPath)) ts = TextureStage("stage-stone") ts.setSort(1) ts.setPriority(1) ts.setMode(TextureStage.MReplace) self.hmTerrainNP.setTexture( ts, loader.loadTexture("../res/textures/stone_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-ice") ts.setSort(2) ts.setPriority(1) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor) self.hmTerrainNP.setTexture( ts, loader.loadTexture("../res/textures/ice_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-snow") ts.setSort(3) ts.setPriority(0) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcAlpha) self.hmTerrainNP.setTexture( ts, loader.loadTexture("../res/textures/snow_tex_1.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) # print(self.snowflakes) return hmNode
def __init__(self,path,heightScale,shader=None,skipTextures=False): self.shader=shader meshManager.MeshFactory.__init__(self) self.dataIndex={} self.heightScale=heightScale d=parseFile(path+'/texList.txt') self.mapTexStages={} self.specialMaps={} for m in d['Special']: s=m.split('\t') self.specialMaps[s[1]]=s[0] # List of non map texture stages, and their sizes # (TexStage,Size) self.texList=[] if not skipTextures: if "Tex2D" in d: sort=0; for m in d["Tex2D"]: sort+=1 s=m.split() name=s[0] texStage=TextureStage(name+'stage'+str(sort)) texStage.setSort(sort) source=s[1] # def setTexModes(modeText): # combineMode=[] # for t in modeText: # if t[:1]=='M': # texStage.setMode(getRenderMapType(t)) # elif t[:1]=='C': # combineMode.append(getCombineMode(t)) # elif t=='Save': # texStage.setSavedResult(True) # else: # print "Illegal mode info for "+name # if len(combineMode)>0: # texStage.setCombineRgb(*combineMode) # if len(modeText)==0: # texStage.setMode(TextureStage.MModulate) if source=='file': # setTexModes(s[3:]) tex=loadTex(path+"/textures/"+name) # self.terrainNode.setTexture(texStage,tex) # self.terrainNode.setShaderInput('tex2D_'+name,tex) self.texList.append((texStage,float(s[2]),tex,name)) elif source=='map': # setTexModes(s[2:]) self.mapTexStages[s[0]]=texStage # # else: # print 'Invalid source for '+name+' int Tex2D' self.LOD=meshManager.LOD(float('inf'),0)