Code archives/3D Graphics - Effects/Instant Cliffs

This code has been declared by its author to be Public Domain code.

Download source code

Instant Cliffs by Mr Snidesmin2004
This function applies textures to a mesh's triangles based on the gradient of the triangles slope.

This way you can easily apply a cliff texture to cliffs etc without having to do it manually.

Up to 5 'grades' of texture can be applied with the function as it is, but it can be modified for more or less with ease.

Example is included. You just need to create the textures and terrain mesh. An easier way to create a terrain that you might want to use is here: http://blitzbasic.com/codearcs/codearcs.php?code=1081
Function GradePaintTerrainMesh%(m%, g1#, g2#, g3#, g4#, bGrad0%, bGrad1%, bGrad2%, bGrad3%, bGrad4%)	
	m2% = CreateMesh()
	
	s_g0% = CreateSurface(m2)
	s_g1% = CreateSurface(m2)
	s_g2% = CreateSurface(m2)
	s_g3% = CreateSurface(m2)
	s_g4% = CreateSurface(m2)
	
	For i% = 1 To CountSurfaces(m)
		s% = GetSurface(m, i)
		For it% = 0 To CountTriangles(s)-1
			v0% = TriangleVertex(s, it, 0)
			v1% = TriangleVertex(s, it, 1)
			v2% = TriangleVertex(s, it, 2)
			
			v0x# = VertexX(s, v0)
			v0y# = VertexY(s, v0)
			v0z# = VertexZ(s, v0)
			v0u# = VertexU(s, v0)
			v0v# = VertexV(s, v0)
			v0w# = VertexW(s, v0)
			v0nx# = VertexNX(s, v0)
			v0ny# = VertexNY(s, v0)
			v0nz# = VertexNZ(s, v0)
			v0red# = VertexRed(s, v0)
			v0green# = VertexRed(s, v0)
			v0blue# = VertexRed(s, v0)
			v0alpha# = VertexAlpha(s, v0)
			
			v1x# = VertexX(s, v1)
			v1y# = VertexY(s, v1)
			v1z# = VertexZ(s, v1)
			v1u# = VertexU(s, v1)
			v1v# = VertexV(s, v1)
			v1w# = VertexW(s, v1)
			v1nx# = VertexNX(s, v1)
			v1ny# = VertexNY(s, v1)
			v1nz# = VertexNZ(s, v1)
			v1red# = VertexRed(s, v1)
			v1green# = VertexRed(s, v1)
			v1blue# = VertexRed(s, v1)
			v1alpha# = VertexAlpha(s, v1)
			
			v2x# = VertexX(s, v2)
			v2y# = VertexY(s, v2)
			v2z# = VertexZ(s, v2)
			v2u# = VertexU(s, v2)
			v2v# = VertexV(s, v2)
			v2w# = VertexW(s, v2)
			v2nx# = VertexNX(s, v2)
			v2ny# = VertexNY(s, v2)
			v2nz# = VertexNZ(s, v2)
			v2red# = VertexRed(s, v2)
			v2green# = VertexRed(s, v2)
			v2blue# = VertexRed(s, v2)
			v2alpha# = VertexAlpha(s, v2)
						
			
			grad# = TriGradient(s, it)
			If grad < g1 Then 
				s2 = s_g0
			ElseIf grad < g2 Then 
				s2 = s_g1
			ElseIf grad < g3 Then 
				s2 = s_g2
			ElseIf grad < g4 Then 
				s2 = s_g3				
			Else
				s2 = s_g4
			End If

			v0% = AddVertex(s2, v0x, v0y, v0z, v0u, v0v, v0w)
			v1% = AddVertex(s2, v1x, v1y, v1z, v1u, v1v, v1w)
			v2% = AddVertex(s2, v2x, v2y, v2z, v2u, v2v, v2w)
			VertexNormal s2, v0, v0nx, v0ny, v0nz
			VertexNormal s2, v1, v1nx, v1ny, v1nz
			VertexNormal s2, v2, v2nx, v2ny, v2nz
			VertexColor s2, v0, v0red, v0green, v0blue, v0alpha
			VertexColor s2, v1, v1red, v1green, v1blue, v1alpha
			VertexColor s2, v2, v2red, v2green, v2blue, v2alpha
			AddTriangle s2, v0, v1, v2
		Next
	Next

	PaintSurface s_g0, bGrad0
	PaintSurface s_g1, bGrad1
	PaintSurface s_g2, bGrad2
	PaintSurface s_g3, bGrad3
	PaintSurface s_g4, bGrad4
	
	FreeEntity m
	Return m2
End Function


Function TriGradient#(surface%, triangle%)
	Local v0%,v1%,v2%
	Local v0x#, v0y#, v0z#
	Local v1x#, v1y#, v1z#
	Local v2x#, v2y#, v2z#
	Local tx#, ty#, tz#
	Local m1#, m2#, c1#, c2#
	Local ax#, ay#, az#
	Local theta#, argument#, modulus#
	Local i%
	
	;Special case 1: Is the whole triangle parallel to xz-plane?
	v0x = VertexX(surface, TriangleVertex(surface, triangle, 0))
	v0y = VertexY(surface, TriangleVertex(surface, triangle, 0))
	v0z = VertexZ(surface, TriangleVertex(surface, triangle, 0))
	v1x = VertexX(surface, TriangleVertex(surface, triangle, 1))
	v1y = VertexY(surface, TriangleVertex(surface, triangle, 1))
	v1z = VertexZ(surface, TriangleVertex(surface, triangle, 1))
	v2x = VertexX(surface, TriangleVertex(surface, triangle, 2))
	v2y = VertexY(surface, TriangleVertex(surface, triangle, 2))
	v2z = VertexZ(surface, TriangleVertex(surface, triangle, 2))
	If v0y = v1y And v1y = v2y Then
		;Yes, so gradient is 0
		Return 0
	End If
	
	;Step 1:
	;Sort out vertices in order of height (y-axis), v0=bottom, v1=middle, v2=top
	For i=0 To 2
        v% = TriangleVertex(surface, triangle, i)
  		If v0=0 Then v0 = v
		If v2=0 Then v2 = v
		
		If VertexY(surface,v) > VertexY(surface,v2) Then v2 = v
		If VertexY(surface,v) < VertexY(surface,v0) Then v0 = v
    Next
	For i=0 To 2
        v% = TriangleVertex(surface, triangle, i)
  		If v0<>v And v2<>v Then v1 = v
    Next
	v0x = VertexX(surface, v0)
	v0y = VertexY(surface, v0)
	v0z = VertexZ(surface, v0)
	v1x = VertexX(surface, v1)
	v1y = VertexY(surface, v1)
	v1z = VertexZ(surface, v1)
	v2x = VertexX(surface, v2)
	v2y = VertexY(surface, v2)
	v2z = VertexZ(surface, v2)
		
	;Step 2: Translate lowest point To 0,0,0
	tx = v0x
	ty = v0y
	tz = v0z
	v0x = v0x - tx
	v0y = v0y - ty
	v0z = v0z - tz
	v1x = v1x - tx
	v1y = v1y - ty
	v1z = v1z - tz
	v2x = v2x - tx
	v2y = v2y - ty
	v2z = v2z - tz
	
	;Special case 2: Is the line (v1,v2) is parallel to xz-plane?
	If v1y = v2y Then
		;Yes, so invert the triangle in the y-axis
		v0y = v1y
		v1y = 0
		v2y = 0
		;Lowest point is now v2, highest is v0, so swap them:
		tx# = v2x
		ty# = v2y
		tz# = v2z
		v2x = v0x
		v2y = v0y
		v2z = v0z
		v0x = tx
		v0y = ty
		v0z = tz
		;Re-do translation:
		v0x = v0x - tx
		v0y = v0y - ty
		v0z = v0z - tz
		v1x = v1x - tx
		v1y = v1y - ty
		v1z = v1z - tz
		v2x = v2x - tx
		v2y = v2y - ty
		v2z = v2z - tz
	End If
	
	
	;Step 3: Find Point a, such that y(a) = 0 and y is on the line (v2, v1)
	;Line Equations:
	;y=m1x+c1
	;y=m2z+c2
	m1 = (v2y-v1y) / (v2x-v1x)
	m2 = (v2y-v1y) / (v2z-v1z)
	c1 = v1y - m1 * v1x
	c2 = v1y - m1 * v1z
	ay = 0
	ax = -c1/m1
	az = -c2/m2
	
	;Special case 3: is v1 at y=0
	If v1y = 0 Then
		;Yes, therefore a = v1
		ax = v1x
		ay = v1y
		az = v1z
	End If
	
	;Step 4. Rotate all points v0,v1,v2, a about y-axis so that point a is at x=0
	theta# = -ATan2(az, ax)	;Angle to rotate
	;NOTE: Actually only v2's z-component will be used, so let's be lazy and only calculate v2z.
	;;Rotate v0
	;argument# = ATan2(v0z, v0x)
	;modulus# = Sqr(v0x^2 + v0z^2)
	;v0x = modulus * Cos(theta+argument)
	;v0z = modulus * Sin(theta+argument)
	;;Rotate v1
	;argument# = ATan2(v1z, v1x)
	;modulus# = Sqr(v1x^2 + v1z^2)
	;v1x = modulus * Cos(theta+argument)
	;v1z = modulus * Sin(theta+argument)
	;;Rotate v2
	argument# = ATan2(v2z, v2x)
	modulus# = Sqr(v2x^2 + v2z^2)
	;v2x = modulus * Cos(theta+argument)
	v2z = modulus * Sin(theta+argument)
	;;Rotate a
	;argument# = ATan2(az, ax)
	;modulus# = Sqr(ax^2 + az^2)
	;ax = modulus * Cos(theta+argument)
	;az = modulus * Sin(theta+argument)
	
	
	;Step 5. Calculate the gradient, and return the value.
	Return Abs(v2y / v2z)
End Function


;Example:
Graphics3D 800, 600, 0, 2

b0 =  LoadBrush("grass_flat.bmp",1+8)
b1 =  LoadBrush("grass_slope.bmp",1+8)
b2 =  LoadBrush("grass+rocks.bmp",1+8)
b3 =  LoadBrush("rocks.bmp",1+8)
b4 =  LoadBrush("cliff.bmp",1+8)

terrain = LoadMesh("terrain.3ds")
terrain = GradePaintTerrainMesh(terrain, 0.1, 0.3, 0.8, 1.2, b0, b1, b2, b3, b4)

cam = CreateCamera()

PositionEntity cam, 100, 100, 100
PointEntity cam, terrain

AmbientLight 200, 200, 200

MoveMouse GraphicsWidth()/2, GraphicsHeight()/2
FlushMouse

While Not KeyHit(1)
	SetBuffer BackBuffer()
	UpdateWorld
	RenderWorld
	VWait
	Flip

	dY# = EntityPitch(Cam)+MouseYSpeed()/2*0.5
	If dY > 89 Then dY = 89
	If dY < -89 Then dY = -89
	RotateEntity Cam, dY, EntityYaw(Cam)-(MouseXSpeed()/2)*0.5, 0
	MoveEntity Cam, 0, 0, (MouseDown(1)-MouseDown(2))*3
	MoveMouse GraphicsWidth()/2, GraphicsHeight()/2
Wend
End

Comments

Ziltch2004
Great job.
Now I will have to make some texture to suit!


aab2004
Very effective


Code Archives Forum