Code archives/3D Graphics - Mesh/Texture Splatting on Meshterrain
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This function creates a mesh terrain layer using a heightmap, a colormap and a alphamap for transparency (up to 128x128 vertices/pixel). All black pixels (0,0,0) of the alphamap are ignored. The trick is to create a full nontransparent base layer with FX2 and add the transparent FX2+32 mesh layers on top of it which results in nice faded transitions between two textures. Here is a running demo showing the effect. With Keys 1-5 you can show/hide the base layer and the 4 transparent layers. Moving with arrows and Mouse, LMB/RMB = 2x faster, SPACE = Wireframe: Download Code of the demo (all images are 128x128 pixel except the textures): | |||||
Type triangle Field v%[2] Field alpha# End Type Global alphavertex#[65536] ; create Meshterrain Function LoadMeshTerrain(hmap%,vscale#=16.0,cmap%,cscale#=1.0,amap%,r1%=False,g1%=False,b1%=False,base%=False) Local rgb%,r%,g%,b%,a# Local h#,x%,y%,vertex% Local vx#,vz#,u#,v# Local v0%,v1%,v2%,v3% ; Heightmap If hmap Then Local hbuf%=ImageBuffer(hmap) Local size%=ImageWidth(hmap)-1 Local verts%=size+1 EndIf ; Colormap If cmap Then Local cbuf%=ImageBuffer(cmap) Local cwidth%=ImageWidth(cmap) Local cfactor#=cwidth*1.0/verts EndIf ; Alphamap If amap Then Local abuf%=ImageBuffer(amap) ; create the Mesh Local mesh%=CreateMesh() Local surf%=CreateSurface(mesh) ; lock buffers LockBuffer hbuf If cmap Then LockBuffer cbuf If amap Then LockBuffer abuf For y=0 To size For x=0 To size ; read height (only red channel) and normalize it h=Normalize((ReadPixelFast(x,size-y,hbuf) And $ff0000)/$10000,0,255,0.0,vscale) ; read vertexcolor from colormap (R,G,B) If cmap Then rgb=ReadPixelFast(x*cfactor,(size-y)*cfactor,cbuf) r=Int(((rgb And $ff0000)/$10000)*cscale) g=Int(((rgb And $ff00)/$100)*cscale) b=Int((rgb And $ff)*cscale) Else r=128 g=128 b=128 EndIf ; read alpha value from alphamap (only red channel) If amap Then a=Normalize((ReadPixelFast(x,size-y,abuf) And $ff0000)/$10000,0,255,0,1) Else a=1.0 EndIf ; use forced colors if used If r1 Then r=r1 If g1 Then g=g1 If b1 Then b=b1 ; calculate vertex coordinates / texture coordinates vx=x-(size/2.0) vz=y-(size/2.0) u=x*1.0/size v=(size-y)*1.0/size ; place vertex vertex=AddVertex(surf,vx,h,vz,u,v) ; set vertex color and texture coordinates VertexColor surf,vertex,r,g,b,a ; build alpha blitzarray for alpha check later alphavertex[vertex]=a ; set triangles If y<size And x<size Then v0=x+((size+1)*y) v1=x+((size+1)*y)+(size+1) v2=(x+1)+((size+1)*y) v3=(x+1)+((size+1)*y)+(size+1) ; add first triangle t.triangle = New triangle t\v[0]=v0 t\v[1]=v1 t\v[2]=v2 ; add second triangle t.triangle = New triangle t\v[0]=v2 t\v[1]=v1 t\v[2]=v3 EndIf Next Next ; flag all 100% transparent triangles (just add transparency values, higher than 0 = not transparent :-) For t.triangle = Each triangle t\alpha=alphavertex[t\v[0]]+alphavertex[t\v[1]]+alphavertex[t\v[2]] Next ; create triangles For t.triangle = Each triangle ; base layer = draw ALL triangles If base=True Then AddTriangle surf,t\v[0],t\v[1],t\v[2] Else ; if they are not transparent If t\alpha>0 Then AddTriangle surf,t\v[0],t\v[1],t\v[2] EndIf EndIf ; delete triangle from to do list Delete t.triangle Next ; unlock buffers If amap Then UnlockBuffer abuf If cmap Then UnlockBuffer cbuf UnlockBuffer hbuf UpdateNormals mesh Return mesh End Function ; Normalize a value Function Normalize#(value#=128.0,value_min#=0.0,value_max#=255.0,norm_min#=0.0,norm_max#=1.0) Return ((value-value_min)/(value_max-value_min))*(norm_max-norm_min)+norm_min End Function |
Comments
| ||
Brilliant, thanks for sharing. |
| ||
Nice, works well here. |
| ||
My Samsung NC10 has a problem. At certain angles and distances the grass layer pops in and out of existence showing the background color. |
| ||
Beaker, try it this way: I revised it and it works with only one mesh now, gaining 10% speed. Just replace the texture_splatting.bb with this one and run demo2.bb (or download the whole package again). Download Singlemesh-Version demo2.bb texture_splatting.bb |
| ||
Unfortunately, still the same problem. |
| ||
This is really very useful, thanks Krishan! Compared to many other examples of multi-textured terrains this is the easiest to use, whilst still giving great results! |
| ||
Beaker: I dunno, perhaps the Intel GMA950 doesn't allow meshes displayed in this way - you could experiment with the order the meshes/surfaces are drawn. Here on my nVidia 9600M GT it works fine. To top it - I experimented with normal maps to dramatically increase the detail level of the poor 128x128 vertex resolution and here is my solution, again texture splatted. I got it to work only using two meshes - one multitextured and one with the normalmap put on top of it. Lighting is a combination of vertex light and dot3 lighting. You can change the sunlight angle (Y axis, 0...360°) with the Keys Q/W and the sun inclination angle with A/S (-90 to 90°). With the keys 1/2 you can show/hide the multitextured mesh and the normal map mesh to see the difference! Beware: i am using a very hires 2048x2048 normal map texture here, so resize it if it doesn't work! Download demo_normals.bb (the include is the same file like in my single-mesh-version) |
| ||
I like the method, but is this texturesplatting? since you are still using vertex alpha for the transparency and not really a blendmode of textures. |
Code Archives Forum