Code archives/3D Graphics - Effects/Instant Cliffs
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| 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
| ||
| Great job. Now I will have to make some texture to suit! |
| ||
| Very effective |
Code Archives Forum