Help with normals...

Blitz3D Forums/Blitz3D Programming/Help with normals...

Vertigo(Posted 2008) [#1]
Hello all. The below code is modified from the code archives(I believe terabit did it originally). Im trying to get the .obj importer to take normals into consideration when loading. And so far its proving to be a headache. Also the x appended to the front of each function is for use with the XORS 3D Wrapper but it should apply to normal blitz as well. I think it has something to do with the ordering of the normal data.. Im not sure... any mesh guru's care to help?


Type OBJ_VN
	
	Field index%
	Field x#, y#, z#
	
End Type

Type OBJ_VNF
	
	Field v_index%
	Field n_index%
	
End Type

Type OBJ_V
	
	Field index%
	Field x#, y#, z#
	
End Type

Function OBJ_New_VNF(vtx%, vn%)

	newVN.OBJ_VNF = New OBJ_VNF
	newVN\v_index% = vtx%
	newVN\n_index% = vn%
	Return
	
End Function

Function LoadObj(file$, OBJ_USE_TEX=False, Do_centermesh = False)

	Local infile, intex$, cmd$, themesh, blanksurf, ek, its
	Local P1$, P2$, P3$, P4$, vtx1#, vtx2#, vtx3#, vtx4#
	Local tx1#, tx2#, tx3#, tx4#, retmesh, v, uvo 
	Local vtx = 0
	Local vtxn = 0
	Local tmp_vn1%, tmp_vn2%, tmp_vn3%, tmp_vn4%
	Local OBJ_USING_NORMALS = False
	
	If FileType(file$)=0 Then Return -1

	infile = ReadFile(file$)
 
	themesh = xCreateMesh()
	tempvert = xCreateMesh()
	retmesh = xCreateMesh()
 
	TempVertSurf = xCreateSurface(tempvert)
	blanksurf = xCreateSurface(themesh)
 
	While Not Eof(infile)
		intex$ = ReadLine$(infile)
		cmd$ = ParseEntry(intex$,0)
		its = CountIt(intex$," ")
 
		If its>1 Then P1$ = ParseEntry(intex$,1) Else P1$=""
		If its>2 Then P2$ = ParseEntry(intex$,2) Else P2$=""
		If its>3 Then P3$ = ParseEntry(intex$,3) Else P3$=""
		If its>4 Then P4$ = ParseEntry(intex$,4) Else P4$=""
 
 
		Select cmd$
			Case "V"
				; Adds vertex to new mesh.
				xAddVertex blanksurf,Float(P1$),Float(P2$),Float(P3$)*-1

			Case "VT"
				; Vertex texture coords.
				xAddVertex TempVertSurf,Rand(10),Rand(10),Rand(10)
				xVertexTexCoords TempVertSurf,vtx,Float(P1$),1-Float(P2$)
				vtx = vtx + 1
 
			Case "VN"
				; Get vertex normal from obj
				OBJ_USING_NORMALS = True
				VN.OBJ_VN = New OBJ_VN
				VN\index% = vtxn%
				VN\x# = Float(P1$)
				VN\y# = Float(P2$)
				VN\z# = Float(P3$)
				vtxn% = vtxn% + 1

			; Case "USEMTL"

			Case "F"
				If currentsurf = 0 Then 
					currentsurf = xCreateSurface(retmesh)
				EndIf
 
				vtx1# = -65535 : tx1# = -65535 
				vtx2# = -65535 : tx2# = -65535 
				vtx3# = -65535 : tx3# = -65535 
				vtx4# = -65535 : tx4# = -65535 
				   
				If its>1 Then
					ug = CountIt(P1$,"/")
					If ug>0 Then
						vtx1#=Float(ParseEntry(P1$,0,"/"))-1
					EndIf
 
					If ug>1 Then
						tx1# = Float(ParseEntry(P1$,1,"/"))-1
					EndIf

					If ug>2 Then
						tmp_vn1% = Int(ParseEntry(P1$,2,"/"));-1
						OBJ_New_VNF(Int(vtx1#), tmp_vn1%)
					EndIf
				EndIf

				If its>2 Then
					ug = CountIt(P2$,"/")
					If ug>0 Then
						vtx2#=Float(ParseEntry(P2$,0,"/"))-1
					EndIf
 
	   				If ug>1 Then
   						tx2# = Float(ParseEntry(P2$,1,"/"))-1
				   	EndIf

					If ug>2 Then
						tmp_vn2% = Int(ParseEntry(P2$,2,"/"));-1
						OBJ_New_VNF(Int(vtx2#), tmp_vn2%)
					EndIf
  				EndIf

				If its>3 Then
					ug = CountIt(P3$,"/")
					If ug>0 Then
						vtx3#=Float(ParseEntry(P3$,0,"/"))-1
					EndIf
 
		 			If ug>1 Then
						tx3# = Float(ParseEntry(P3$,1,"/"))-1
					EndIf

					If ug>2 Then
						tmp_vn3% = Int(ParseEntry(P3$,2,"/"));-1
						OBJ_New_VNF(Int(vtx3#), tmp_vn3%)
					EndIf
				EndIf
  
  
				If its>4 Then
					ug = CountIt(P4$,"/")
					If ug>0 Then
						vtx4#=Float(ParseEntry(P4$,0,"/"))-1
					EndIf
 
					If ug>1 Then
						tx4# = Float(ParseEntry(P4$,1,"/"))-1
					EndIf

					If ug>2 Then
						tmp_vn4% = Int(ParseEntry(P4$,2,"/"));-1
						OBJ_New_VNF(Int(vtx4#), tmp_vn4%)
					EndIf
				EndIf

				If vtx1<0 Then vtx1 = 0
				If vtx2<0 Then vtx2 = 0
				If vtx3<0 Then vtx3 = 0
				If vtx4<0 Then vtx4 = 0
  
				If vtx1>xCountVertices(blanksurf)-1 Then vtx1 = xCountVertices(blanksurf)-1
				If vtx2>xCountVertices(blanksurf)-1 Then vtx2 = xCountVertices(blanksurf)-1
				If vtx3>xCountVertices(blanksurf)-1 Then vtx3 = xCountVertices(blanksurf)-1
				If vtx4>xCountVertices(blanksurf)-1 Then vtx4 = xCountVertices(blanksurf)-1
  
				If tx1>xCountVertices(tempvertsurf)-1 Then tx1 = xCountVertices(tempvertsurf)-1
				If tx2>xCountVertices(tempvertsurf)-1 Then tx2 = xCountVertices(tempvertsurf)-1
				If tx3>xCountVertices(tempvertsurf)-1 Then tx3 = xCountVertices(tempvertsurf)-1
				If tx4>xCountVertices(tempvertsurf)-1 Then tx4 = xCountVertices(tempvertsurf)-1
  
				v = xCountVertices(currentsurf)
  
				If its>1 Then
					If tx1<0 Then tx1 = tx1 + vtx+1 
					uvo = tx1
				
					If xCountVertices(TempVertSurf)=0 Then
						xAddVertex currentsurf,xVertexX(blanksurf,vtx1),xVertexY(blanksurf,vtx1),xVertexZ(blanksurf,vtx1)
					Else
						xAddVertex currentsurf,xVertexX(blanksurf,vtx1),xVertexY(blanksurf,vtx1),xVertexZ(blanksurf,vtx1),xVertexU(TempVertSurf,uvo),xVertexV(TempVertSurf,uvo)
					EndIf
				EndIf
			
				If its>2 Then
					If tx2<0 Then tx2 = tx2 + vtx+1     
					uvo = tx2

					If xCountVertices(TempVertSurf)=0 Then
						xAddVertex currentsurf,xVertexX(blanksurf,vtx2),xVertexY(blanksurf,vtx2),xVertexZ(blanksurf,vtx2)
					Else
						xAddVertex currentsurf,xVertexX(blanksurf,vtx2),xVertexY(blanksurf,vtx2),xVertexZ(blanksurf,vtx2),xVertexU(TempVertSurf,uvo),xVertexV(TempVertSurf,uvo)
					EndIf
				EndIf

				If its>3 Then
					If tx3<0 Then tx3 = tx3 + vtx+1
					uvo = tx3
					If xCountVertices(TempVertSurf)=0 Then
						xAddVertex currentsurf,xVertexX(blanksurf,vtx3),xVertexY(blanksurf,vtx3),xVertexZ(blanksurf,vtx3)
					Else
						xAddVertex currentsurf,xVertexX(blanksurf,vtx3),xVertexY(blanksurf,vtx3),xVertexZ(blanksurf,vtx3),xVertexU(TempVertSurf,uvo),xVertexV(TempVertSurf,uvo)
					EndIf
				EndIf
			
				If its>4 Then
					If tx4<0 Then tx4 = tx4 + vtx+1    
					uvo = tx4
					If xCountVertices(TempVertSurf)=0 Then
						xAddVertex currentsurf,xVertexX(blanksurf,vtx4),xVertexY(blanksurf,vtx4),xVertexZ(blanksurf,vtx4)
					Else
						xAddVertex currentsurf,xVertexX(blanksurf,vtx4),xVertexY(blanksurf,vtx4),xVertexZ(blanksurf,vtx4),xVertexU(TempVertSurf,uvo),xVertexV(TempVertSurf,uvo)
					EndIf
				EndIf
  
				xAddTriangle currentsurf,v,v+1,v+2
  
				If its>4 Then
					xAddTriangle currentsurf,v+2,v+3,v
				EndIf
    
 		End Select
 
	Wend

	CloseFile infile
	xFlipMesh retmesh

	If OBJ_USING_NORMALS = True Then
		OBJ_Apply_Normals(retmesh)
	Else
		xUpdateNormals retmesh
	End If

	;xUpdateNormals retmesh	; Dont use Update Normals if VN command above made changes to VertexNormal.

	Delete Each OBJ_VNF
	Delete Each OBJ_VN
		
	xFreeEntity tempvert
	xFreeEntity themesh

	Return retmesh
End Function

Function OBJ_Apply_Normals(mesh)
	on_surf = xCountSurfaces(mesh)
	For cur_surf = 0 To on_surf -1
		final_surf = xGetSurface(mesh,cur_surf)

		For this.OBJ_VNF = Each OBJ_VNF
		
			For VN.OBJ_VN = Each OBJ_VN
				
				If VN\index% = this\n_index% Then
					DebugLog "mine!!! " + this\n_index + "\" + VN\x# + ", " + VN\y# + ", " + VN\z#
					xVertexNormal(final_surf, this\v_index%, VN\x#, VN\y#, VN\z#)
				End If
			Next
		
		Next
	
	Next
	Return
	
End Function

Function ParseEntry$( Message$, Item, Sep$ = " ")
 Local fas, count, spos, epos, num#, epon#,pos
 
 Repeat
  fas = Instr(message$,sep$,fas+1)
  count = count + 1 
 Until fas = 0 Or count = item
 
 spos = fas+1
 epos = Instr(message$+sep$,sep$,fas+1)
 grub$ = Upper$(Trim$(Mid$(message$,spos,(epos-spos))))
 If Instr(grub$,"E-") Then 
  pos = Instr(grub$,"E-")
  ;1.41e-02 = 1.41 * (10 ^ -2)
  num# = Left$(grub$,pos-1)
  epon# = Mid$(grub$,pos+1,Len(grub$)-(pos))
  ;'DebugLog "Total: "+grub$
  ;'DebugLog "Num: "+num#
  ;'DebugLog "etex: "+Mid$(grub$,pos+1,Len(grub$)-(pos))
  ;'DebugLog "Exp: "+epon#
  num# = num# * (10 ^ epon#)
  Return num#
  Return "0.0"
 Else 
  Return grub$
 EndIf
End Function

Function CountIt( Message$, Sep$=" ")
 message$=Trim$(message$)
 Local fas, count
 Repeat
 fas = Instr(message$,sep$,fas+1)
  If fas<>0 Then count = count + 1 
 Until fas = 0
 
 Return count+1
End Function



Ross C(Posted 2008) [#2]
Is this causing polgons to be flipped? The normals shouldn't matter otherwise, as you can recalculate the normals based on the way the triangles are created.

sswift has updatenormals code that does a better job than blitz's built in command.


Vertigo(Posted 2008) [#3]
.OBJ files are saved using a left hand coord system I believe. Im not sure what blitz uses... but I do believe that terabit's obj loaded loads then backwards and inside out etc due to the flip mesh command. I need to have access to the actual normals that are saved with the object though. Calculating them based on whatever method besides using the normal data is not sufficient.

I am curious as to what the ordeal is anyways. I can change that stupid indexing offset about -2 and it still works and messed up just the same without any vertex index out of range errors or anything. So I think I might seriously have something screwed up in those counters. Also this looks like it creates multiple surfaces and joins them etc... if that is the case am I simply losing the vertex normal info when everything is slammed into one object? Ie. Does blitz re-order the vertices when you muck with the surfaces?

There were two more testing methods I was going to try but I didnt want it to have to go that far in order to figure this out. The first was to apply the vertex normal data at the time the vertex is created, and before it is used in the addtriangle command. The second method involved loading the mesh as is, then creating a type for each of the vertices x,y,z locations, then to do a distance check across all of the verticies on the surface and if they were close then apply the vertex normal data saved in the OBJ_VN type to the vertex at that location... I figured the first would eliminate the surface issue, and the second would eliminate whether or not the vertices are being re-indexed.

Any suggestions?


srcoder(Posted 2008) [#4]
I think you need the -1 in this bit of code to parse out the index of the normal to be used by this vertex.

If ug>2 Then
   tmp_vn4% = Int(ParseEntry(P4$,2,"/"));-1
   OBJ_New_VNF(Int(vtx4#), tmp_vn4%)
EndIf


remove the semi-colon and test it.


Vertigo(Posted 2008) [#5]
Thanks, but the reason I had it commented out is because it didnt work as thats what I tried originally, hince my asking about the indexing order. Using the -1 makes nearly every triangle pitched black.


srcoder(Posted 2008) [#6]
Tried multiplying the normals that you get from the file by -1.0 in the OBJ_ApplyNormals function?

Could you post your code so far??