Code archives/3D Graphics - Misc/Alpha Zorder

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

Download source code

Alpha Zorder by Beaker2003
Unlike normal and masked ones, Blitz doesn't sort alpha'd triangles, which leads
to far away objects appearing in front of near ones. 'Alpha Zorder' rectifies this
by sorting triangles, but only when needed. This makes it incredibly fast.

It's great for large numbers of trees and grass that contain some alpha mesh/textures.

Setup is slow at first, but it is possible to save the sorted data (code not included), so it is only calculated once.

There is a demo of the system here:
http://www.blitzbasic.com/codearcs/codearcs.php?code=807

One day I hope that programs like the excellent Gile[s] will calculate the
data when you render lightmaps etc. and save it to the exported file.
; code by Beaker 2002 - please credit prominently (or arrange otherwise)



Function setup_example(mesh)
	zo.zorder = Zorderize(mesh)
End Function

Function mainloop_example(cam)
	For zo.zorder = Each zorder
		SortAlpha(zo,cam)
	Next
End Function



Type zorder
	Field hiddenmesh
	Field hiddensurf
	Field screenmesh
	Field screensurf
	Field x,y,z		;banks: size = tricnt * 2bytes(short)
	Field tricnt	;counttriangles(surf)-1
	Field incy		;use the y axis
End Type


Function Zorderize.zorder(mesh, incy = False)
	zo.zorder = New zorder
	zo\hiddenmesh = mesh
	zo\incy = incy

	zo\hiddensurf = GetSurface(zo\hiddenmesh,1)

	zo\tricnt = CountTriangles(zo\hiddensurf)-1
	zo\x = CreateBank(zo\tricnt*2+8)
	DebugLog BankSize(zo\x)
	If incy
		zo\y = CreateBank(zo\tricnt*2+8)
	EndIf
	zo\z = CreateBank(zo\tricnt*2+8)

	For f = 0 To zo\tricnt
		PokeShort zo\x, f*2, f
		If incy
			PokeShort zo\y, f*2, f
		EndIf
		PokeShort zo\z, f*2, f
	Next

	zo\screenmesh = CopyMesh(zo\hiddenmesh)
;	zo\screenmesh = CopyMesh(zo\hiddenmesh,getparent(zo\hiddenmesh))
	HideEntity zo\hiddenmesh
;	EntityFX zo\screenmesh,16

	zo\screensurf = GetSurface(zo\screenmesh,1)

	surf = zo\hiddensurf	;GetSurface(fullmesh,1)
	If Not surf Then RuntimeError "No surface found"
	ordered = False
	While ordered = False
		ordered = True
		For f = 1 To zo\tricnt
	;		If f > 0
				v0 = TriangleVertex ( surf,PeekShort(zo\x,f*2),0 )
				v1 = TriangleVertex ( surf,PeekShort(zo\x,f*2),1 )
				v2 = TriangleVertex ( surf,PeekShort(zo\x,f*2),2 )
				medx# = (VertexX(surf,v0)+VertexX(surf,v1)+VertexX(surf,v2)) / 3.0

				v0b = TriangleVertex ( surf,PeekShort(zo\x,(f-1)*2),0 )
				v1b = TriangleVertex ( surf,PeekShort(zo\x,(f-1)*2),1 )
				v2b = TriangleVertex ( surf,PeekShort(zo\x,(f-1)*2),2 )
				medxb# = (VertexX(surf,v0b)+VertexX(surf,v1b)+VertexX(surf,v2b)) / 3.0

				If (medx) > (medxb)
					temp = PeekShort(zo\x,f*2)
					PokeShort zo\x,f*2, PeekShort(zo\x,(f-1)*2)
					PokeShort zo\x, (f-1)*2, temp
					ordered = False
				EndIf


				v0 = TriangleVertex ( surf,PeekShort(zo\z,f*2),0 )
				v1 = TriangleVertex ( surf,PeekShort(zo\z,f*2),1 )
				v2 = TriangleVertex ( surf,PeekShort(zo\z,f*2),2 )

				medz# = (VertexZ(surf,v0)+VertexZ(surf,v1)+VertexZ(surf,v2)) / 3.0

				v0b = TriangleVertex ( surf,PeekShort(zo\z,(f-1)*2),0 )
				v1b = TriangleVertex ( surf,PeekShort(zo\z,(f-1)*2),1 )
				v2b = TriangleVertex ( surf,PeekShort(zo\z,(f-1)*2),2 )
				medzb# = (VertexZ(surf,v0b)+VertexZ(surf,v1b)+VertexZ(surf,v2b)) / 3.0

				If (medz) > (medzb)
					temp = PeekShort(zo\z,f*2)
					PokeShort zo\z,f*2, PeekShort(zo\z,(f-1)*2)
					PokeShort zo\z,(f-1)*2, temp
					ordered = False
				EndIf
	;		EndIf
		Next

		If incy
			For f = 1 To zo\tricnt
				v0 = TriangleVertex ( surf,PeekShort(zo\y,f*2),0 )
				v1 = TriangleVertex ( surf,PeekShort(zo\y,f*2),1 )
				v2 = TriangleVertex ( surf,PeekShort(zo\y,f*2),2 )
				medy# = (VertexX(surf,v0)+VertexX(surf,v1)+VertexX(surf,v2)) / 3.0

				v0b = TriangleVertex ( surf,PeekShort(zo\y,(f-1)*2),0 )
				v1b = TriangleVertex ( surf,PeekShort(zo\y,(f-1)*2),1 )
				v2b = TriangleVertex ( surf,PeekShort(zo\y,(f-1)*2),2 )
				medyb# = (VertexX(surf,v0b)+VertexX(surf,v1b)+VertexX(surf,v2b)) / 3.0

				If (medy) > (medyb)
					temp = PeekShort(zo\y,f*2)
					PokeShort zo\y,f*2, PeekShort(zo\y,(f-1)*2)
					PokeShort zo\y, (f-1)*2, temp
					ordered = False
				EndIf
			Next
		EndIf

		If KeyDown(1) Then End
	Wend

	Return zo
End Function


Function SortAlpha(zo.zorder,cam)
	Local origsurf = zo\hiddensurf
	Local newsurf = zo\screensurf
	Local xf,yf,zf,f
	TFormVector 0,0,1, cam,0
	If (Abs(TFormedX()) > Abs(TFormedZ())) And (Abs(TFormedX()) > Abs(TFormedY()))
		If prev <> 1
			prev = 1
			ClearSurface newsurf,0,1
			If TFormedX() > 0
				For f = 0 To zo\tricnt
					xf = PeekShort(zo\x,f*2)
					AddTriangle ( newsurf,TriangleVertex ( origsurf,xf,0 ),TriangleVertex ( origsurf,xf,1 ),TriangleVertex ( origsurf,xf,2 ) )
				Next
			Else
				For f = zo\tricnt To 0 Step -1
					xf = PeekShort(zo\x,f*2)
					AddTriangle ( newsurf,TriangleVertex ( origsurf,xf,0 ),TriangleVertex ( origsurf,xf,1 ),TriangleVertex ( origsurf,xf,2 ) )
				Next
			EndIf
		EndIf
	Else
		If (Abs(TFormedY()) > Abs(TFormedZ()))
			If (prev <> 2) And zo\incy
				prev = 2
				ClearSurface newsurf,0,1
				If TFormedY() > 0
					For f = 0 To zo\tricnt
						yf = PeekShort(zo\y,f*2)
						AddTriangle ( newsurf,TriangleVertex ( origsurf,yf,0 ),TriangleVertex ( origsurf,yf,1 ),TriangleVertex ( origsurf,yf,2 ) )
					Next
				Else
					For f = zo\tricnt To 0 Step -1
						yf = PeekShort(zo\y,f*2)
						AddTriangle ( newsurf,TriangleVertex ( origsurf,yf,0 ),TriangleVertex ( origsurf,yf,1 ),TriangleVertex ( origsurf,yf,2 ) )
					Next
				EndIf
			EndIf
		Else
			If prev <> 3
				prev = 3
				ClearSurface newsurf,0,1
				If TFormedZ() > 0
					For f = 0 To zo\tricnt
						zf = PeekShort(zo\z,f*2)
						AddTriangle ( newsurf,TriangleVertex ( origsurf,zf,0 ),TriangleVertex ( origsurf,zf,1 ),TriangleVertex ( origsurf,zf,2 ) )
					Next
				Else
					For f = zo\tricnt To 0 Step - 1
						zf = PeekShort(zo\z,f*2)
						AddTriangle ( newsurf,TriangleVertex ( origsurf,zf,0 ),TriangleVertex ( origsurf,zf,1 ),TriangleVertex ( origsurf,zf,2 ) )
					Next
				EndIf
			EndIf
		EndIf
	EndIf
End Function

Function FreeZorder()
	For zo.zorder = Each zorder
		FreeEntity zo\screenmesh 
		FreeBank zo\x 
		FreeBank zo\y 
		FreeBank zo\z 
	Next
	Delete Each zorder
End Function

Comments

fredborg2005
Here's another take on the same thing, based on Beakers code, but speeded up quite a bit. It also uses less memory :)




Filax2005
Maybe can you post an example freborg ?


fredborg2005
Sure, here is a small one:



DH2005
Bare in mind, that this system (Fredborg's) won't work if you modify the mesh after you have inited the system (tried it on my cloud system, after modifying the position of some of the 'sprites' it wont work).

Although, a very nice system fredborg !


Beaker2006
This is true. My system only works on static meshes (or mostly static, for example: animated grass, trees etc).


t3K|Mac2006
i get a surface index out of range when using this code on a loadanimmesh() mesh. any hints?


Beaker2006
Probably because your base entity isn't a mesh (probly a pivot). You can check it with something like:
If EntityClass(myEntity) <> "Mesh" Then Print "No mesh here"


t3K|Mac2006
i have several meshes and pivots mixed in this loadanimmesh()-mesh. do i have to delete all the pivots to get zorder to work? or do i have to make sure that the base entity is a mesh?


Beaker2006
Neither. It expects to recieve a single mesh. And can only sort one mesh to be visually correct (AFAIR). For example: a lot of grass, a lot of leaves, but not both.

There is a way to get it to work on both grass and leaves, but it involves combining the grass and leaf textures into one, and also combining the meshes.


t3K|Mac2006
ohmygod - i have 260 meshes (in one loadanimmesh)... ok i see i have a problem.... hmmmmm


Beaker2006
Actually, regarding the grass/leaves example I give above, you wouldn't need to combine them as long as they never visually overlap each other. But, you would need to pass them both seperately to the Zorder.


Beaker2006
[EDIT: discussion here:
http://www.blitzbasic.com/Community/posts.php?topic=59416 ]

Here is a new version that (a) works better with animated meshes (rotation) and (b) you can optionally
just supply a particular surface to zorderize, using this syntax:
ZOrder_Init(mesh, surf=0, y_include=False)

Here is the new library:


And here is new example code:



jfk EO-111102006
isn't the random z-order problem only affecting triangles of one mesh, so does it actualy make sense to add several meshes together?

And to t3k: there is a command in blitz that tells you if an entity is a mesh, a pivot or whatever:

http://www.blitzbasic.com/b3ddocs/command.php?name=entityclass&ref=goto

So you maybe have to parse the animmesh recursively and make a list of all children that are meshes.


Mikorians2014
I've been faked out with animmeshes that have "meshes" with no polygons in 'em


Code Archives Forum