Josh Posted December 24, 2009 Posted December 24, 2009 To edit the terrain heightmap on the GPU, I create a small buffer and copy part of the heightmap to this. Then I enable the terrain editor shader and draw this small buffer back onto the same spot on the heightmap buffer: Strict Import leadwerks.ENGINE Import "terrain.bmx" Import "Globals.bmx" Global oldTerrainToolPosition:TVec3=Vec3(-1000) Global terrainfilter:TShader[10] Global terrainchanged:Int Global editterrainaabb:TAABB TTerrain.highresheightmap=1 Function UpdateTerrain(terrain:TTerrain) Local x:Int,z:Int,size:Int If terrainchanged 'terrain.generatecolormap() If terrainchanged=2 terrain.getheightmap() If TerrainSectorAABBUpdate size=Int(Sqr(TerrainSectorAABBUpdate.length)+0.5) For x=0 To size-1 For z=0 To size-1 If TerrainSectorAABBUpdate[x,z] terrain.sector[x,z].UpdateAABB() TerrainSectorAABBUpdate[x,z]=0 EndIf Next Next EndIf If editterrainaabb ForEachEntityInAABBDo(editterrainaabb,callback,terrain,ENTITY_MODEL) terrain.quadtree.root.ForEachLeafInAABBDo(editterrainaabb,func,Null) terrain.quadtree.root.UpdateAABB() EndIf EndIf editterrainaabb=Null terrainchanged=False EndIf Function func(leaf:TQuadTreeLeaf,o:Object) leaf.UpdateInstanceHeights(terrain) EndFunction Function Callback:Int(entity:TEntity,extra:Object) If Int(entity.GetKey("aligntoground")) entity.AlignToTerrain(TTerrain(extra)) EndIf Return 1 EndFunction EndFunction Global TerrainSectorAABBUpdate:Byte[,] Function AddVegetationInstance(terrain:TTerrain,x:Float,z:Float,layer:Int,density:Float,randrotation:Int,randscale:Float,aligntonormal:Int,tilt:Float) Local pitch#,yaw#,dist# Local dir:TVec3 Local roll:Float=0.0 Local mat:TMat4 Local scale:Float Local alignmat:TMat4 If terrain.quadtree.layers[layer]=Null Return If terrain.quadtree.layers[layer].model=Null Return If randrotation mat=TMat4.FromYawPitchRoll(Rnd(0.0,360.0),Rnd(-tilt,tilt),Rnd(-tilt,tilt)) Else 'SeedRnd (mat.ix+mat.iy+mat.iz+mat.jx+mat.jy+mat.jz+mat.kx+mat.ky+mat.kz+mat.tx+mat.ty+mat.tz)*1000.0 mat=TMat4.FromYawPitchRoll(0.0,Rnd(-tilt,tilt),Rnd(-tilt,tilt)) EndIf 'SeedRnd (mat.ix+mat.iy+mat.iz+mat.jx+mat.jy+mat.jz+mat.kx+mat.ky+mat.kz+mat.tx+mat.ty+mat.tz)*1000.0 scale=Rnd(1.0-randscale,1.0+randscale) mat.ix:*scale mat.iy:*scale mat.iz:*scale mat.jx:*scale mat.jy:*scale mat.jz:*scale mat.kx:*scale mat.ky:*scale mat.kz:*scale mat.tx=x'x+x0*density+Rnd(-density*0.5,density*0.5) mat.tz=z'z+z0*density+Rnd(-density*0.5,density*0.5) mat.ty=terrain.GetElevation(mat.tx,mat.tz) If aligntonormal dir=terrain.CalcNormal(x,z) dist#=Sqr(dir.x#*dir.x#+dir.z#*dir.z#) pitch#=ATan2(-dir.y#,dist#) yaw#=ATan2(-dir.x#,dir.z#) If randrotation 'SeedRnd (mat.ix+mat.iy+mat.iz+mat.jx+mat.jy+mat.jz+mat.kx+mat.ky+mat.kz+mat.tx+mat.ty+mat.tz)*1000.0 roll=Rnd(0.0,360.0) EndIf alignmat=TMat4.FromYawPitchRoll(yaw,pitch,roll) alignmat.tx=mat.tx alignmat.ty=mat.ty alignmat.tz=mat.tz mat.ix=-alignmat.ix*scale mat.iy=-alignmat.iy*scale mat.iz=-alignmat.iz*scale mat.jx=alignmat.kx*scale mat.jy=alignmat.ky*scale mat.jz=alignmat.kz*scale mat.kx=alignmat.jx*scale mat.ky=alignmat.jy*scale mat.kz=alignmat.jz*scale If randrotation 'SeedRnd (mat.ix+mat.iy+mat.iz+mat.jx+mat.jy+mat.jz+mat.kx+mat.ky+mat.kz+mat.tx+mat.ty+mat.tz)*1000.0 mat=mat.times(TMat4.FromYawPitchRoll(0.0,Rnd(-tilt,tilt),Rnd(-tilt,tilt))) EndIf EndIf terrain.quadtree.addinstance(mat,layer,density) EndFunction Global toolimage:TTexture Function EditTerrain(terrain:TTerrain,x:Float,z:Float,outerradius:Float,innerradius:Float,editmode:Int=0,strength:Float=1.0,channel:Int=0,flattenheight:Float,toolfloor#=0.0,toolceiling#=1.0) Global toolimagebuffer:TBuffer Global channelmask:Float[4] Local x0:Float,z0:Float,x1:Float,z1:Float Local w:Int,h:Int Local tw:Int,th:Int Local cx:Float,cy:Float Local terrainsize:Float Local buffer:TBuffer Local format:Int Local terrbuffer:TBuffer Local texture:TTexture Local constraints:Float[2] Local i:Int Local scale:Float Local ix:Float=x Local iz:Float=z scenechanged=1 If editmode=4 Local gx0:Int,gy0:Int Local gx1:Int,gy1:Int x=Round(x/terrain.scale.x+0.5)+terrain.resolution/2-1 z=Round(z/terrain.scale.z+0.5)+terrain.resolution/2-1 gx0=x-outerradius gx1=x+outerradius gy0=z-outerradius gy1=z+outerradius gx0=Max(0,gx0) gx0=Min(gx0,terrain.resolution-1) gy0=Max(0,gy0) gy0=Min(gy0,terrain.resolution-1) gx1=Max(0,gx1) gx1=Min(gx1,terrain.resolution-1) gy1=Max(0,gy1) gy1=Min(gy1,terrain.resolution-1) w=(gx1-gx0)/2 For x0=gx0 To gx1 For z0=gy0 To gy1 If strength>0 terrain.SetTileVisibility(x0,z0,0,0) Else terrain.SetTileVisibility(x0,z0,1,0) EndIf Next Next terrain.UpdateVisibilityTexture(gx0,gy0,gx1-gx0+1,gy1-gy0+1) Return EndIf If editmode=5 If Not CurrentVegetationLayer Return 'If Not terrain.quadtree.layers[TerrainVegetationLayer] Return 'If Not terrain.quadtree.layers[TerrainVegetationLayer].model Return 'If SelectedGadgetItem(Gadget_VegetationList)=-1 Return If strength>0.0 'Add instances Local tilt:Float=CurrentVegetationLayer.randomtilt'VegetationTilt[TerrainVegetationLayer] Local density:Float=CurrentVegetationLayer.density'VegetationDensity[TerrainVegetationLayer]'Float(GadgetText(Gadget_VegetationDensity)) For x0=-outerradius/density To outerradius/density For z0=-outerradius/density To outerradius/density If Sqr(x0*density*x0*density+z0*density*z0*density)>outerradius Continue 'SeedRnd x+x0*density+z+z0*density cx=x+x0*density+Rnd(-density*0.5,density*0.5) cy=z+z0*density+Rnd(-density*0.5,density*0.5) AddVegetationInstance(terrain,cx,cy,CurrentVegetationLayer.index,CurrentVegetationLayer.density,CurrentVegetationLayer.randomrotation,CurrentVegetationLayer.randomscale,CurrentVegetationLayer.aligntoterrain,CurrentVegetationLayer.randomtilt) Next GCCollect() Next Else 'Remove instances Local aabb:TAABB=New TAABB aabb.x0=x-outerradius aabb.x1=x+outerradius aabb.y0=-infinity aabb.y1=infinity aabb.z0=z-outerradius aabb.z1=z+outerradius aabb.update() terrain.quadtree.root.ForEachLeafInAABBDo(aabb,func,vec3(x,outerradius,z)) Function func(leaf:TQuadTreeLeaf,o:Object) Local n:Int Local dx:Float,dz:Float Local t:TVec3 Local count:Int t=TVec3(o) count=leaf.instance_count[CurrentVegetationLayer.index] n=0 If count Repeat dx=Abs(leaf.instances[CurrentVegetationLayer.index][n*16+12]-t.x) dz=Abs(leaf.instances[CurrentVegetationLayer.index][n*16+14]-t.z) If Sqr(dx*dx+dz*dz)<t.y leaf.DeleteInstance(n,CurrentVegetationLayer.index) n:-1 count:-1 EndIf If n>=count-1 Exit If count<1 Exit n:+1 Forever EndIf EndFunction EndIf Return EndIf If editmode=1 terrainchanged=1 Else terrainchanged=2 EndIf If Not TerrainSectorAABBUpdate Or TerrainSectorAABBUpdate.length<>terrain.sectors*terrain.sectors TerrainSectorAABBUpdate=New Byte[terrain.sectors,terrain.sectors] EndIf If editmode<>1 terrbuffer=terrain.heightbuffer texture=terrain.heightmap Else terrbuffer=terrain.alphabuffer texture=terrain.alphatexture EndIf x0=Floor((0.5+(x-outerradius+0.5*terrain.scale.x)/(Float(terrain.resolution)*terrain.meterspertile))*(terrain.resolution-1)) x1=Ceil((0.5+(x+outerradius+0.5*terrain.scale.x)/(Float(terrain.resolution)*terrain.meterspertile))*(terrain.resolution-1)) z0=Floor((0.5+(z-outerradius+0.5*terrain.scale.x)/(Float(terrain.resolution)*terrain.meterspertile))*(terrain.resolution-1)) z1=Ceil((0.5+(z+outerradius+0.5*terrain.scale.x)/(Float(terrain.resolution)*terrain.meterspertile))*(terrain.resolution-1)) 'Figure out which sectors are affected and need their AABBs updated (skip for paint edit mode) If editmode<>1 And editmode<>4 And editmode<>5 Local sx0:Int,sx1:Int,sz0:Int,sz1:Int sx0=Floor(x0/Float(terrain.sectorresolution)) sx1=Ceil(x1/Float(terrain.sectorresolution))-1 sz0=Floor(z0/Float(terrain.sectorresolution)) sz1=Ceil(z1/Float(terrain.sectorresolution))-1 If sx0<0 sx0=0 If sz0<0 sz0=0 If sx1>terrain.sectors-1 sx1=terrain.sectors-1 If sz1>terrain.sectors-1 sz1=terrain.sectors-1 For x=sx0 To sx1 For z=sz0 To sz1 TerrainSectorAABBUpdate[x,z]=1 Next Next EndIf 'Create small image If editmode=1 format=TEXTURE_RGBA8 Else If GetGraphicsVendor()=VENDOR_NVIDIA If GetShaderModel()=4 format=TEXTURE_FLOAT32 Else format=TEXTURE_FLOAT Print 1 EndIf Else format=TEXTURE_FLOAT32 EndIf EndIf w=x1-x0+1+1+1 h=z1-z0+1+1+1 tw=Pow2(w,1) th=Pow2(h,1) If tw<2 tw=2 If th<2 th=2 'If tw<64 tw=64 'If th<64 th=64 If toolimage If toolimage.width()<>tw Or toolimage.height()<>th toolimage=Null EndIf EndIf If toolimage If TextureFormat(toolimage)<>format toolimage=Null EndIf If Not toolimage toolimage=CreateTexture(tw,th,format) 'If TextureFormat(toolimage)<>format Notify 1 toolimagebuffer=CreateBuffer(tw,th,BUFFER_COLOR) toolimage.setfilter(TEXFILTER_PIXEL) toolimage.bind() SetColorBuffer(toolimagebuffer,toolimage) EndIf If editmode=1 Select channel Case 0 If strength>0.0 channelmask[0]=-1.0 channelmask[1]=-1.0 channelmask[2]=-1.0 channelmask[3]=-1.0 Else channelmask[0]=0.0 channelmask[1]=0.0 channelmask[2]=0.0 channelmask[3]=0.0 EndIf Case 1 If strength>0.0 channelmask[0]=1.0 channelmask[1]=-1.0 channelmask[2]=-1.0 channelmask[3]=-1.0 Else channelmask[0]=1.0 channelmask[1]=0.0 channelmask[2]=0.0 channelmask[3]=0.0 EndIf Case 2 If strength>0.0 channelmask[0]=0.0 channelmask[1]=1.0 channelmask[2]=-1.0 channelmask[3]=-1.0 Else channelmask[0]=0.0 channelmask[1]=1.0 channelmask[2]=0.0 channelmask[3]=0.0 EndIf Case 3 If strength>0.0 channelmask[0]=0.0 channelmask[1]=0.0 channelmask[2]=1.0 channelmask[3]=-1.0 Else channelmask[0]=0.0 channelmask[1]=0.0 channelmask[2]=1.0 channelmask[3]=0.0 EndIf Case 4 If strength>0.0 channelmask[0]=0.0 channelmask[1]=0.0 channelmask[2]=0.0 channelmask[3]=1.0 Else channelmask[0]=0.0 channelmask[1]=0.0 channelmask[2]=0.0 channelmask[3]=1.0 EndIf EndSelect Else channelmask[0]=1.0 channelmask[1]=1.0 channelmask[2]=1.0 channelmask[3]=1.0 If Not editterrainaabb editterrainaabb=New TAABB editterrainaabb.x0=-infinity editterrainaabb.y0=-infinity editterrainaabb.z0=-infinity editterrainaabb.x1=infinity editterrainaabb.y1=infinity editterrainaabb.z1=infinity EndIf editterrainaabb.x0=Min(editterrainaabb.x0,x-outerradius) editterrainaabb.z0=Min(editterrainaabb.z0,z-outerradius) editterrainaabb.x1=Max(editterrainaabb.x1,x+outerradius) editterrainaabb.z1=Max(editterrainaabb.z1,z+outerradius) EndIf 'Disable heightmap linear filter glActiveTextureARB GL_TEXTURE15 glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST glActiveTextureARB GL_TEXTURE0 'Draw heightmap onto small image SetBuffer(toolimagebuffer) SetShader Null 'Global Texture_Contour:TTexture 'If Not Texture_Contour Texture_Contour=LoadTexture("abstract::crysisocean_DISP.dds") 'BindTexture Texture_Contour,1 SetColor vec4(1) FlipImage(texture,-x0+1.0,-z0+1.0) SetColor vec4(1) SetBuffer(BackBuffer()) terrainsize=(Float(terrain.resolution)*Terrain.meterspertile) ix:-terrain.scale.x*0.5 iz:-1 cx=((ix/terrain.scale.x+0.5*Float(terrain.resolution))/Float(terrain.resolution))+0.5/Float(terrain.resolution) cy=((iz/terrain.scale.z+0.5*Float(terrain.resolution))/Float(terrain.resolution))+0.5/Float(terrain.resolution) 'Load terrain edit shader If Not terrainfilter[editmode] terrainfilter[editmode]=LoadShader("abstract::generic.vert","abstract::terraintool.frag","#define TOOLMODE "+editmode+"~n") EndIf 'Set shader uniforms toolceiling=Min(1.0,toolceiling) toolfloor=Max(0.0,toolfloor) constraints[0]=toolfloor'0'Float(SliderValue(Gadget_TerrainToolFloor)-1)/29.0 constraints[1]=toolceiling'1'Float(SliderValue(Gadget_TerrainToolCeiling)-1)/29.0 If strength>0.0 constraints[0]=0.0 If strength<0.0 constraints[1]=1.0 If editmode>1 constraints[0]=0.0 constraints[1]=1.0 EndIf SetShaderVec2 terrainfilter[editmode],"toolposition",[cx,cy] SetShaderVec2 terrainfilter[editmode],"toolradius",[outerradius/terrain.size,innerradius/terrain.size] SetShaderFloat terrainfilter[editmode],"toolstrength",strength SetShaderFloat terrainfilter[editmode],"flattenheight",flattenheight SetShaderVec2 terrainfilter[editmode],"heightmapsize",[Float(terrain.resolution),Float(terrain.resolution)] SetShaderVec2 terrainfilter[editmode],"imagesize",[Float(tw),Float(th)] SetShaderVec4 terrainfilter[editmode],"channelmask",channelmask SetShaderVec2 terrainfilter[editmode],"constraints",constraints 'Draw the small image onto the heightmap buffer=GetBuffer() SetBuffer(terrbuffer) SetShader terrainfilter[editmode] glCheckError() flipImage(toolimage,x0-1,z0-1) glCheckError() SetBuffer buffer SetShader(Null) 'Update the normals of the edited area If editmode<>1 terrain.UpdateNormals(x0-1,z0-1,w,h) EndIf 'Restore heightmap linear filter glActiveTextureARB GL_TEXTURE15 glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR glActiveTextureARB GL_TEXTURE0 terrain.generatecolormap() EndFunction Function FlipImage(image:TTexture,x,y) image.bind(0) glcolor4f 1,1,1,1 glEnable image.target() gldisable GL_CULL_FACE DrawRect x,BufferHeight(GetBuffer())-y,image.width(),-image.height() glDisable image.target() Function DrawRect(x,y,width,height) glBegin GL_QUADS glTexCoord2f 0.0,0.0 glVertex2i x,y glTexCoord2f 0.0,1.0 glVertex2i x,y+height glTexCoord2f 1.0,1.0 glVertex2i x+width,y+height glTexCoord2f 1.0,0.0 glVertex2i x+width,y glEnd EndFunction EndFunction Quote Let's build cool stuff and have fun.
Masterxilo Posted December 24, 2009 Posted December 24, 2009 [...] Quote Hurricane-Eye Entertainment - Site, blog.
Paul Thomas Posted December 24, 2009 Posted December 24, 2009 Just got it working, thanks a lot Josh, greatly appreciated. Quote
Gardowyr Posted December 28, 2009 Posted December 28, 2009 Thank you very much! That's exactly what I need at the moment =) Quote
Paul Thomas Posted January 6, 2010 Posted January 6, 2010 Anyone know what to pass for the flatten uniform? Everything I've tried just flattens the terrain to 0 eventually. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.