hello, everyone. i’ve done a little job to render EarthSculptor terrain in panda. EarthSculptor is a nice terrain editor, you can also export terrain texture, but just a final combined texture, terrain doesn’t look good using only single texture. we can find the original textures and using multitexture to get the same appearence as in EarthSculptor. i implement this with GeoMipTerrain and cg shader.
Screen shots:
here i take EarthSculptor’s default map for example, the same way when you have made your own terrain.
At first let’s check “EarthSculptor\Maps\defaultMap” folder. it contains output files. there are 4 png images:
default.png - the heightmap of the map
default_l.png - the lightmap of the map
default_c.png - the colormap of the map
default_d.png - the alphamap of the map, each channel represents one of the four detail textures that make up the detail textures.
and a .map file:
default.map - this is an ascii file containing all the parameters, colors, texture names used in the map. open it with a texteditor we can find the deatail textures. this map use 4 detail textures, you can find them in “EarthSculptor\Textures” folder:
detailtexture1 “[HOME]Textures\grayRock.png”
detailtexture2 “[HOME]Textures\hardDirt.png”
detailtexture3 “[HOME]Textures\bigRockFace.png”
detailtexture4 “[HOME]Textures\shortGrass.png”
now we have all textures we need. i copied them to a “data” folder.
one problem i didn’t get through is the detail texture scale. we cann’t used the scale factor directly from file “default.map”, the terrain will look different with in EarthSculptor. i did some test it seems EarthSculptor’s scale is opposite to our normal way and is not linear, i couldn’t find a formular to convert a EarthSculptor’s scale to a normal scale. i had to count how many times each detail repeats to get the approximate scale factor. Waiting for someone to figure it out.
here is my script and shader. it’s plain simple. Big thanks to pro-rsoft for GeoMipTerrain and guiding me in texture and shader.
# rendering Earthsculptor terrain with panda
# Author:weihuan, Email:kutawei@yahoo.cn, 2008/06/29
import direct.directbase.DirectStart
from pandac.PandaModules import GeoMipTerrain
from pandac.PandaModules import TextureStage
from pandac.PandaModules import TextNode
from pandac.PandaModules import Texture
from pandac.PandaModules import Filename
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText
import sys
class World(DirectObject):
def __init__(self):
self.title = OnscreenText(text = "Rendering Earthsculptor terrain",
style = 1, fg = (1,1,1,1), pos = (.4,-.95),
align = TextNode.ALeft, scale = .08)
base.camLens.setFar(2000)
base.setFrameRateMeter(True)
base.setBackgroundColor(0.4, 0.5, 0.7)
#terrain setting
self.terrain = GeoMipTerrain("myTerrain")
self.terrain.setHeightfield(Filename("data/default.png"))
self.terrain.getRoot().setSz(400)
self.terrain.setBlockSize(32)
self.terrain.setFactor(400)
self.terrain.setMinLevel(3)
self.terrain.getRoot().reparentTo(render)
self.terrain.getRoot().setPos(-256/2, -256/2, 0)
self.terrain.generate()
#load textures
tex0 = loader.loadTexture("data/default_d.png")
tex0.setMinfilter(Texture.FTLinearMipmapLinear)
tex1 = loader.loadTexture("data/grayRock.png")
tex1.setMinfilter(Texture.FTLinearMipmapLinear)
tex2 = loader.loadTexture("data/hardDirt.png")
tex2.setMinfilter(Texture.FTLinearMipmapLinear)
tex3 = loader.loadTexture("data/bigRockFace.png")
tex3.setMinfilter(Texture.FTLinearMipmapLinear)
tex4 = loader.loadTexture("data/shortGrass.png")
tex4.setMinfilter(Texture.FTLinearMipmapLinear)
tex5 = loader.loadTexture("data/default_c.png")
tex5.setMinfilter(Texture.FTLinearMipmapLinear)
tex6 = loader.loadTexture("data/default_l.png")
tex6.setMinfilter(Texture.FTLinearMipmapLinear)
#set mutiltextures
self.terrain.getRoot().setTexture( TextureStage('tex0'),tex0 )
self.terrain.getRoot().setTexture( TextureStage('tex1'),tex1 )
self.terrain.getRoot().setTexture( TextureStage('tex2'),tex2 )
self.terrain.getRoot().setTexture( TextureStage('tex3'),tex3 )
self.terrain.getRoot().setTexture( TextureStage('tex4'),tex4 )
self.terrain.getRoot().setTexture( TextureStage('tex5'),tex5 )
self.terrain.getRoot().setTexture( TextureStage('tex6'),tex6 )
#load shader
self.terrain.getRoot().setShader(loader.loadShader('terraintexture.sha'))
self.accept('escape', sys.exit)
taskMgr.add(self.update,"updateTerrain")
def update(self, task):
self.terrain.setFocalPoint(base.camera.getX(),base.camera.getY())
self.terrain.update()
return task.cont
if __name__ == '__main__':
myworld = World()
run( )
terraintexture.sha
//Cg
//
//Cg profile arbvp1 arbfp1
void vshader( in float4 vtx_position : POSITION,
in float2 vtx_texcoord0 : TEXCOORD0,
in uniform float4x4 mat_modelproj,
out float4 l_position : POSITION,
out float2 l_texcoord0 : TEXCOORD0,
out float2 l_detail1 : TEXCOORD1,
out float2 l_detail2 : TEXCOORD2,
out float2 l_detail3 : TEXCOORD3,
out float2 l_detail4 : TEXCOORD4 )
{
l_position = mul(mat_modelproj,vtx_position);
l_texcoord0 = vtx_texcoord0;
//detail texture coordinates scaled, we must get the correct scale fator to make terrain look like in EarthSculptor
l_detail1 = vtx_texcoord0 * 9.3; //27.365000 in EarthSculptor
l_detail2 = vtx_texcoord0 * 12.8; //20.000000 in EarthSculptor
l_detail2 = vtx_texcoord0 * 7.9; //32.340000 in EarthSculptor
l_detail4 = vtx_texcoord0 * 11.5; //22.389999 in EarthSculptor
}
void fshader( in float4 l_position : POSITION,
in float2 l_texcoord0 : TEXCOORD0,
in float2 l_detail1 : TEXCOORD1,
in float2 l_detail2 : TEXCOORD2,
in float2 l_detail3 : TEXCOORD3,
in float2 l_detail4 : TEXCOORD4,
in uniform sampler2D tex_0 : TEXUNIT0,
in uniform sampler2D tex_1 : TEXUNIT1,
in uniform sampler2D tex_2 : TEXUNIT2,
in uniform sampler2D tex_3 : TEXUNIT3,
in uniform sampler2D tex_4 : TEXUNIT4,
in uniform sampler2D tex_5 : TEXUNIT5,
in uniform sampler2D tex_6 : TEXUNIT6,
out float4 o_color : COLOR )
{
//add 4 detail colors
float4 alpha = tex2D(tex_0, l_texcoord0.xy);
o_color = tex2D(tex_1, l_detail1.xy) * alpha.x
+ tex2D(tex_2, l_detail2.xy) * alpha.y
+ tex2D(tex_3, l_detail3.xy) * alpha.z
+ tex2D(tex_4, l_detail4.xy) * alpha.w;
//color map, there are 3 Color Modes in EarthSculptor
o_color = o_color + tex2D(tex_5, l_texcoord0.xy) - 0.5;
//o_color = o_color + tex2D(tex_5, l_texcoord0.xy);
//o_color = o_color * tex2D(tex_5, l_texcoord0.xy);
//light map
o_color = o_color * tex2D(tex_6, l_texcoord0.xy);
o_color.a = 1.0;
}