Josh Posted December 24, 2009 Share 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 My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Paul Thomas Posted December 24, 2009 Share Posted December 24, 2009 Wow, lmao. Quote Link to comment Share on other sites More sharing options...
Masterxilo Posted December 24, 2009 Share Posted December 24, 2009 [...] Quote Hurricane-Eye Entertainment - Site, blog. Link to comment Share on other sites More sharing options...
Paul Thomas Posted December 24, 2009 Share Posted December 24, 2009 Just got it working, thanks a lot Josh, greatly appreciated. Quote Link to comment Share on other sites More sharing options...
Gardowyr Posted December 28, 2009 Share Posted December 28, 2009 Thank you very much! That's exactly what I need at the moment =) Quote Link to comment Share on other sites More sharing options...
Paul Thomas Posted January 6, 2010 Share 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 Link to comment Share on other sites More sharing options...
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.