Transform Texture Space To World Space?

Miscellaneous Forums/General Discussion/Transform Texture Space To World Space?

Still playing around with my idea for a simple lightmapper, and I think I've got most of the texture mapping, and lighting sorted, but I'm struggling to figure out how to convert from Texture Space to World Space.

Does anyone have code, pseudo code or an explanation on how to do this? Language not particularly important, but the more I can avoid mathematical notation and matrices, the better.

I had a look at YAL in the code archives, but can't really make head or tail of what's going on.

http://www.gamasutra.com/view/feature/1515/messing_with_tangent_space.php

Thanks for that. I had a read of it, along with a couple of similar pages people suggested, and I came up with what I thought was good code, but it's not working properly. Perhaps someone with a better mathematical mind than me could take a look and spot where I've gone wrong.

It has a dash of TV and a dash of BMax but it should all be pretty readable whatever language/API you use. I've included all the important related functions and left out a couple of functions which I know are working perfectly and aren't related to this particular calculation anyway. ( For instance, PointInTri is definitely working and bears no correlation to the transformation from texture spsace to world space anyway.


' MAIN CODE - THIS IS THE ESSENCE OF THE LIGHTMAPPER. IT CHECKS IF EACH POINT IS IN A TRI
' AND IF IT IS, IT FINDS THE WORLD COORDINATES WITHIN THAT TRI THAT THE PIXEL COORDINATES MAP TO

	PrecalculateTriangles(Mesh,TexWidth,TexHeight,UVChannel)

	For Local TX:Int=0 To TexWidth-1
		For Local TY:Int=0 To TexHeight-1
			
			For Local T:LightmapTriangle=EachIn LightmapTriangle.List
				
				SearchU=(TX+0.5)/Float(TexWidth) ' TURN PIXEL COORDINATES INTO UV COORDINATES
				SearchV=(TY+0.5)/Float(TexHeight)
				
				Local PIT:Int=False
				
				Select UVChannel
				
					Case 0
						If PointInTriangle(SearchU,SearchV,T.TA1.X,T.TA1.Y,T.TA2.X,T.TA2.Y,T.TA3.X,T.TA3.Y)
							PIT=True
						End If
						
					Case 1
						If PointInTriangle(SearchU,SearchV,T.TB1.X,T.TB1.Y,T.TB2.X,T.TB2.Y,T.TB3.X,T.TB3.Y)
							PIT=True
						End If
						
				End Select
				
				If PIT=True
										
					Local DeltaUAdd:cTV_3DVECTOR=TVMathLibrary.VMultiply(T.DeltaU,SearchU)
					Local DeltaVAdd:cTV_3DVECTOR=TVMathLibrary.VMultiply(T.DeltaV,SearchV)
										
					TVMathLibrary.TVVec3Add(PointOut1,T.OriginWS3,DeltaUAdd)
					TVMathLibrary.TVVec3Add(PointOut2,PointOut1,DeltaVAdd)
					
					' WORLD COORDINATES SHOULD NOW BE IN POINT OUT 2!!

					' LIGHTING CALCULATION AND SETPIXEL'ING GOES HERE
				End If
				
			Next
			
		Next
	Next

' END OF LIGHTMAPPING CODE

' FUNCTIONS USED BY THE MAIN CODE

Function PrecalculateTriangles(Mesh:cTVMesh,TexWidth:Int,TexHeight:Int,UVChannel:Int)
	
	For Local TCount:Int=0 To Mesh.GetTriangleCount()-1
		
		Local T:LightmapTriangle=New LightmapTriangle
		
		T.Face=TCount
		
		Mesh.GetTriangleInfo(TCount,T.V1,T.V2,T.V3,T.Group)
		
		Mesh.GetVertex(T.V1,T.P1.x,T.P1.y,T.P1.z,T.N1.x,T.N1.y,T.N1.z,T.TA1.X,T.TA1.Y,T.TB1.X,T.TB1.Y,T.Col1)
		Mesh.GetVertex(T.V2,T.P2.x,T.P2.y,T.P2.z,T.N2.x,T.N2.y,T.N2.z,T.TA2.X,T.TA2.Y,T.TB2.X,T.TB2.Y,T.Col2)
		Mesh.GetVertex(T.V3,T.P3.x,T.P3.y,T.P3.z,T.N3.x,T.N3.y,T.N3.z,T.TA3.X,T.TA3.Y,T.TB3.X,T.TB3.Y,T.Col3)
			
		Select UVChannel
			Case 0
				ComputeTangentBasis(T.P1,T.P2,T.P3,T.TA1,T.TA2,T.TA3,T.Tangent,T.BiTangent)
			Case 1
				ComputeTangentBasis(T.P1,T.P2,T.P3,T.TB1,T.TB2,T.TB3,T.Tangent,T.BiTangent)
		End Select
		
		T.DeltaU=TVMathLibrary.VMultiply(T.Tangent,1/Float(TexWidth))
		T.DeltaV=TVMathLibrary.VMultiply(T.BiTangent,1/Float(TexHeight))
		
		T.OriginWS=cTV_3DVECTOR.create(T.P1.x,T.P1.y,T.P1.z)
		
		Select UVChannel
			Case 0
				T.XMult=T.TA1.X*TexWidth-0.5
				T.YMult=T.TA1.Y*TexHeight-0.5
			Case 1
				T.XMult=T.TB1.X*TexWidth-0.5
				T.YMult=T.TB1.Y*TexHeight-0.5
		End Select
		
		T.DeltaUSubtract=TVMathLibrary.VMultiply(T.DeltaU,T.XMult)
		T.DeltaVSubtract=TVMathLibrary.VMultiply(T.DeltaV,T.YMult)
		
		TVMathLibrary.TVVec3Subtract(T.OriginWS2,T.OriginWS,T.DeltaUSubtract)
		TVMathLibrary.TVVec3Subtract(T.OriginWS3,T.OriginWS2,T.DeltaVSubtract)
		
		' CALCULATE THE SURFACE NORMAL
		TVMathLibrary.TVVec3Subtract(T.P1P2,T.P2,T.P1)
		TVMathLibrary.TVVec3Subtract(T.P1P3,T.P3,T.P1)
		TVMathLibrary.TVVec3Cross(T.SurfaceNormal,T.P1P2,T.P1P3)
		T.SurfaceNormal.Normalize()
		
	Next
	
End Function

Function ComputeTangentBasis(P1:cTV_3DVECTOR,P2:cTV_3DVECTOR,P3:cTV_3DVECTOR,UV1:cTV_2DVECTOR,UV2:cTV_2DVECTOR,UV3:cTV_2DVECTOR,Tangent:cTV_3DVECTOR,Bitangent:cTV_3DVECTOR)
	
	Local Edge1:cTV_3DVECTOR=cTV_3DVECTOR.create(0,0,0)
	TVMathLibrary.TVVec3Subtract(Edge1,P2,P1)
	Local Edge2:cTV_3DVECTOR=cTV_3DVECTOR.create(0,0,0)
	TVMathLibrary.TVVec3Subtract(Edge2,P3,P1)
	Local Edge1UV:cTV_2DVECTOR=cTV_2DVECTOR.create(0,0)
	TVMathLibrary.TVVec2Subtract(Edge1UV,UV2,UV1)
	Local Edge2UV:cTV_2DVECTOR=cTV_2DVECTOR.create(0,0)
	TVMathLibrary.TVVec2Subtract(Edge2UV,UV3,UV1)
	
	Local CP:Float=(Edge1UV.Y*Edge2UV.X)-(Edge1UV.X*Edge2UV.Y)
	
	If CP<>0
		
		Local Mul:Float=1.0/CP
		
		Local TangentEdgeMult1:cTV_3DVECTOR=TVMathLibrary.VMultiply(Edge1,-Edge2UV.Y)
		Local TangentEdgeMult2:cTV_3DVECTOR=TVMathLibrary.VMultiply(Edge2,Edge1UV.Y)
		Local BiTangentEdgeMult1:cTV_3DVECTOR=TVMathLibrary.VMultiply(Edge1,-Edge2UV.X)
		Local BiTangentEdgeMult2:cTV_3DVECTOR=TVMathLibrary.VMultiply(Edge2,Edge1UV.X)
		
		Local TangentTotal:cTV_3DVECTOR=cTV_3DVECTOR.create(0,0,0)
		TVMathLibrary.TVVec3Add(TangentTotal,TangentEdgeMult1,TangentEdgeMult2)
		Local BiTangentTotal:cTV_3DVECTOR=cTV_3DVECTOR.create(0,0,0)
		TVMathLibrary.TVVec3Add(BiTangentTotal,BiTangentEdgeMult1,BiTangentEdgeMult2)
		
		Local VTangent:cTV_3DVECTOR=TVMathLibrary.VMultiply(TangentTotal,Mul)
		Local VBiTangent:cTV_3DVECTOR=TVMathLibrary.VMultiply(BiTangentTotal,Mul)
				
		Tangent.x=VTangent.x
		Tangent.y=VTangent.y
		Tangent.z=VTangent.z
		
		BiTangent.x=VBiTangent.x
		BiTangent.y=VBiTangent.y
		BiTangent.z=VBiTangent.z
		
	End If
	
	
	
End Function