Given a U and V value, transform that to 3D coordinates

Blitz3D Forums/Blitz3D Programming/Given a U and V value, transform that to 3D coordinates

JoshK(Posted 2003) [#1]
Can someone post a TFormTextureCoords(u#,v#) routine? This is for a free lightmapper for making quick lightmapped meshes. The idea is to use Unwrap3D or something first, so that the model is "skinned" and a UV coordinate only appears on one triangle of the model. This will light polygons WITHOUT splitting them up to 3 vertices per triangle, and I don't believe a tool exists yet that does that.

I can write the lightmapper in a couple of minutes if someone else can do this...I'm a little short on time, and I thought someone with more experience with this kind of thing might be interested.


JoshK(Posted 2003) [#2]
It mostly comes down to a pointintriangle() function. Something like this...

Function TFormTextureCoords(u#,v#,mesh)
For s=1 To CountSurfaces(mesh)
	surf=GetSurface(mesh,1)
	For t=0 To CountTriangles(surf)-1
		a=TriangleVertex(surf,t,0)
		b=TriangleVertex(surf,t,1)
		c=TriangleVertex(surf,t,2)
		au#=VertexU(surf,a)
		av#=VertexV(surf,a)
		bu#=VertexU(surf,b)
		bv#=VertexV(surf,b)
		cu#=VertexU(surf,c)
		cv#=VertexV(surf,c)
		If PointInTriangle(u,v,au,av,bu,bv,cu,cv)
			TFormPoint x#,y#,z#,0,0
			Return True
			EndIf
		Next
	Next
Return False
End Function

Function PointInTriangle(x#,y#,Ax#,Ay#,Bx#,By#,Cx#,Cy#)

End Function



BlitzSupport(Posted 2003) [#3]
I can't tell if it's any use, but there's a point-in-triangle algorithm near the bottom of this page:

http://homepages.borland.com/efg2lab/Library/Delphi/Graphics/Math.htm

And another:

http://www.blackpawn.com/texts/pointinpoly/default.html


fredborg(Posted 2003) [#4]
Make an opposite version of my PickedU, PickedV and PickedW commands in the code archives, it couldn't be simpler.

Fredborg


JoshK(Posted 2003) [#5]
I might as well write one from scratch rather than try to understand someone else's routines. I'm posting this because if I have to do it, I won't have time for another two weeks.

Thanks.


Birdie(Posted 2003) [#6]
Hi,

Something like this ?? its not a good example but the method works.. I needs a better mapped model to work with so that each triangle has a unique texture position.

Global LM_red=0,LM_grn=0,LM_blu=0
Global DEBUG=True
Graphics3D 640,480,0,2
SetBuffer BackBuffer()
cam=CreateCamera()
PositionEntity cam,0,3,-10
;l=CreateLight()

Addlight -6,0,0	,6	,255,0,0
Addlight 0,10,6	,6	,0,255,0
Addlight 6,0,0	,6	,0,0,255
tex2=LoadTexture("nskinwh.jpg")
mesh=LoadMesh("ninja.b3d")
tex=VMapp(mesh,tex2)
EntityTexture mesh,tex2

While Not KeyDown(1)
	TurnEntity mesh,0,1,0
	If KeyHit(32) Then Debug=1-debug
	RenderWorld
	If DEBUG
		CopyRect 0,0,TextureWidth(tex2),TextureHeight(tex2),0,0,TextureBuffer(tex2),BackBuffer()
	EndIf
	Flip
Wend

Function Max3Vect(a#,b#,c#)
	If a<0 Then a=-a
	If b<0 Then b=-b
	If c<0 Then c=-c
	If a>b And a>c Then Return 1
	If b>a And b>c Then Return 2
	If c>a And c>b Then Return 3
	If a=b Then a=a+0.00001
	If b=c Then b=b+0.00002
	If c=a Then c=c+0.00003
	Return 0
End Function

Function VMapp(ent,	Tex)
	; TexFinal# = this to match the scale of the texture on the entity
	this_tex=tex
	texfinal#=TextureWidth(tex)
	buff=GraphicsBuffer()
	SetBuffer TextureBuffer(this_tex)
	LockBuffer TextureBuffer(this_tex)
	Local vx#[2],vy#[2],vz#[2],vu#[2],vv#[2]
	Local x#,y#,z#,nx#,ny#,nz#,nd#
	surf=GetSurface(ent,1)
	For t=0 To CountTriangles(surf)-1
		minu#=9999:maxu#=-9999
		minv#=9999:maxv#=-9999

		;Convert to World Scale
		For b=0 To 2
			x=VertexX(surf,TriangleVertex(surf,t,b))
			y=VertexY(surf,TriangleVertex(surf,t,b))
			z=VertexZ(surf,TriangleVertex(surf,t,b))
			TFormPoint x,y,z,ent,0
			vx[b]=x:vy[b]=y:vz[b]=z
			vu[b]=VertexU(surf,TriangleVertex(surf,t,b))
			vv[b]=VertexV(surf,TriangleVertex(surf,t,b))
			If vu[b]<minu Then minu=vu[b]
			If vu[b]>maxu Then maxu=vu[b]
			If vv[b]<minv Then minv=vv[b]
			If vv[b]>maxv Then maxv=vv[b]
		Next
		uvwid#=maxu-minu
		uvhgt#=maxv-minv
		tex_x#=TexFinal*uvwid
		tex_y#=TexFinal*uvhgt
		tx#=minu#*TexFinal
		ty#=minv#*TexFinal
		
		;Calc the normal
		x1#=vx[1]-vx[2]
		y1#=vy[1]-vy[2]
		z1#=vz[1]-vz[2]
		x2#=vx[1]-vx[0]
		y2#=vy[1]-vy[0]
		z2#=vz[1]-vz[0]
		nx=(y1*z2)-(z1*y2)
		ny=(z1*x2)-(x1*z2)
		nz=(x1*y2)-(y1*x2)
		nd=-((nx*vx[0])+(ny*vy[0])+(nz*vz[0]))
		Select Max3Vect(nx,ny,nz)
			Case 1; YZ Plane
				PX#=-((nz*MinU)+(ny*MinV)+nd)/nx
				VectorX#=PX:VectorY#=MinV:VectorZ#=MinU
				PX#=-((nz*MaxU)+(ny*MinV)+nd)/nx
				Vect1X#=PX : Vect1Y#=MinV : Vect1Z#=MaxU
				PX#=-((nz*MinU)+(ny*MaxV)+nd)/nx
				Vect2X#=PX : Vect2y#=MaxV : Vect2Z#=MinU
			Case 2; XZ Plane
				PY#=-((nx*MinU)+(nz*MinV)+nd)/ny
				VectorX#=MinU:VectorY#=PY:VectorZ#=MinV
				PY#=-((nx*MaxU)+(nz*MinV)+nd)/ny
				Vect1X#=MaxU : Vect1Y#=PY : Vect1Z#=MinV
				PY#=-((nx*MinU)+(nz*MaxV)+nd)/ny
				Vect2X#=MinU : Vect2Y#=PY : Vect2Z#=MaxV
			Case 3; XY Plane
				PZ#=-((nx*MinU)+(ny*MinV)+nd)/nz
				VectorX#=MinU:VectorY#=MinV:VectorZ#=PZ
				PZ#=-((nx*MaxU)+(ny*MinV)+nd)/nz
				Vect1X#=MaxU : Vect1Y#=MinV : Vect1Z#=PZ
				PZ#=-((nx*MinU)+(ny*MaxV)+nd)/nz
				Vect2X#=MinU : Vect2Y#=MaxV : Vect2Z#=PZ
		End Select
		e1X# =Vect1X-VectorX
		e1Y# =Vect1Y-VectorY
		e1Z# =Vect1Z-VectorZ
		e2X# =Vect2X-VectorX
		e2Y# =Vect2Y-VectorY
		e2Z# =Vect2Z-VectorZ
		For  iX# = 0 To Int(tex_x)-1
			For iY# = 0 To  Int(tex_y)-1
				ufactor#= Float(ix)/Float(tex_x)
				vfactor#= Float(iy)/Float(tex_y)
				ne1X#= e1X*ufactor
				ne1Y#= e1Y*ufactor
				ne1Z#= e1Z*ufactor
				ne2X#= e2X*vfactor
				ne2Y#= e2Y*vfactor
				ne2Z#= e2Z*vfactor
				lx#=VectorX+ne2X+ne1X
				ly#=VectorY+ne2Y+ne1Y
				lz#=VectorZ+ne2Z+ne1Z
				;check if point is in triangle
				If InsideTriangle(ix+tx,iy+ty,vu[0]*texfinal,vv[0]*texfinal,vu[1]*texfinal,vv[1]*texfinal,vu[2]*texfinal,vv[2]*texfinal)
					col=ReadPixelFast(tx+ix,ty+iy,TextureBuffer(this_tex)) And $ffffff
					fcr#=(col And $ff0000) Shr 16
					fcg#=(col And $ff00) Shr 8
					fcb#=col And $ff
					LM_Red=0
					LM_grn=0
					LM_blu=0
					;point is in triangle
					;so check it against all the lights in the scene
					For l.Light=Each light
						dx#=lx-l\x
						dy#=ly-l\y
						dz#=lz-l\z
						trange#=Sqr(dx*dx+dy*dy+dz*dz)
						lvx#=dx/trange
						lvy#=dy/trange
						lvz#=dz/trange
						lightatpoint l\r,l\g,l\b,lvx,lvy,lvz,l\range,trange,nx,ny,nz
					Next
					lm_red=(lm_red+fcr)/2
					lm_grn=(lm_grn+fcg)/2
					lm_blu=(lm_blu+fcb)/2
					col=(LM_red Shl 16) Or (LM_grn Shl 8) Or (LM_blu)
					WritePixelFast tx+ix,ty+iy,col,TextureBuffer(this_tex)
				EndIf
			Next
		Next
		For b=0 To 2
			VertexTexCoords surf,TriangleVertex(surf,t,b),vu[b],vv[b],0,1
		Next
		If DEBUG
			Color 255,255,255
			Line vu[0]*texfinal,vv[0]*texfinal,vu[1]*texfinal,vv[1]*texfinal
			Line vu[1]*texfinal,vv[1]*texfinal,vu[2]*texfinal,vv[2]*texfinal
			Line vu[2]*texfinal,vv[2]*texfinal,vu[0]*texfinal,vv[0]*texfinal
		EndIf
	Next
	UnlockBuffer TextureBuffer(this_tex)
	SetBuffer buff
End Function

Function CapVal_float#(val#,min#,max#)
	If val>min And val<max Then Return val
	If val<min Then Return min
	If val>max Then Return max
	Return val
End Function

Function dot(x0#,y0#,x1#,y1#,x2#,y2#)
	Return (x1#-x0#)*(y2#-y1#)-(x2#-x1#)*(y1#-y0#)
End Function

Function InsideTriangle(px#,py#,x0#,y0#,x1#,y1#,x2#,y2#)
	If dot(x0,y0,x1,y1,px,py)>=0
		If dot(x1,y1,x2,y2,px,py)>=0
			If dot(x2,y2,x0,y0,px,py)>=0
				Return True
			EndIf
		EndIf
	EndIf
End Function

Type light
	Field r#,g#,b#
	Field x#,y#,z#
	Field range#
End Type

;Light 

Function LightatPoint(lr#,lg#,lb#,lvx#,lvy#,lvz#,lrange#,range#,nx#,ny#,nz#)
	CosAng#=((lvx*nx)+(lvy*ny)+(lvz*nz))
	att0#=.63
	att1#=.025
	att2#=.055
	If cosang<0 Then Return False
	Att# = 1 / (Att0 + (Att1 * range) + (Att2 * range * range))
	Intensity# = (lrange*.75 ) *att * cosAng
	LM_Red=capval_Float((lr * intensity) + LM_Red,0,255)
	LM_Grn=capval_Float((lg * intensity) + LM_Grn,0,255)
	LM_Blu=capval_Float((lb * intensity) + LM_Blu,0,255)
	Return True
End Function

Function AddLight.light(x#,y#,z#,rng#,r#=255,g#=255,b#=255)
	l.Light=New Light
	l\x=x
	l\y=y
	l\z=z
	l\r=r
	l\g=g
	l\b=b
	l\range=rng
	Return l
End Function



JoshK(Posted 2003) [#7]
Use the Rallycar model to test with, or unwrap something with Unwrap3D.

Thanks, I'll test it this afternoon. Assuming this works okay, I can post a quick-and-dirty lightmapper this afternoon.


DJWoodgate(Posted 2003) [#8]
Great bit of code. Don't understand half of it, but it seems some pixels can get lit twice due perhaps to floating point innacuracies at the point in triangle test? Maybe one way round that is to have a check array to flag when a pixel has already been dealt with? Sometimes pixels are not lit at all, maybe that can be improved by adding epsilon to the triangle test. The lighting seems a little off to me, not sure what to do about that, is it due to the planar mapping? The Max3Vect function looks like it needs some attention as well, seems to me perhaps the last three lines before return 0 should perhaps be a bit further up?


Birdie(Posted 2003) [#9]
Hi,

Yeah the Max3Vect was an oldy function which didn't check for = cases or NAN etc, so I decided to check it another way, but that code should ok

Function Max3Vect(a#,b#,c#)
	If a<0 Then a=-a
	If b<0 Then b=-b
	If c<0 Then c=-c
	If a>b And a>c Then Return 1
	If b>a And b>c Then Return 2
	If c>a And c>b Then Return 3
	If a=b Then a=a+0.00001
	If b=c Then b=b+0.00002
	If c=a Then c=c+0.00003
	Return Max3Vect(a,b,c);eww
End Function


If some of the pixels are not getting lit then its probably the dot check on the point in triangle test.


JoshK(Posted 2003) [#10]
Whoops, this is a whole program. It'll take a little bit longer to pick it apart.