Normals & Tangents visualization

Everything related to 3D programming
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Normals & Tangents visualization

Post by applePi »

if the mesh have info for normals and tangents, we get that info by:
GetMeshData(#Mesh,0, MeshData(), #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Tangent , 0, MeshVertexCount(#Mesh)-1)
which direct the results to the structured array MeshData.
also we can use :
NormalizeMesh(#Mesh)
BuildMeshTangents(#Mesh)

to create normals and tangents info for the mesh.

to plot a normal line from a vertex on the object surface we use:
plot line [from vertex0 to (vertex0 + its normal)]
imagine the normal as a shift applied to vertex0 to get a new position, then we draw a line from vertex0 to the new virtual position in which vertex0 is looking at or directed its eye to. (the line should be perpendicular to the surface) . we can multiply the normal by a number so to make the line bigger or smaller as needed.

the PB sphere have intrinsic normal and tangents so we don't need
NormalizeMesh(#Mesh)
BuildMeshTangents(#Mesh)
but if we apply NormalizeMesh(#Mesh) (uncomment line 66) we see some lines are going inside in addition to the outside, is this a bug in NormalizeMesh(#Mesh): visit the sphere interior to see these internal lines along the dark vertical line of wood texture .
but this "may be bug" does not happened with "sphere.mesh" i have found in ogre package (OgreSDK_vc9_v1-7-4), that sphere is very strange, it seems designed manually, and does not have tangents and can't be created with BuildMeshTangents(#Mesh). just enjoy that strange sphere and try to texture it.
if you want download this "sphere.mesh" from here: http://www.2shared.com/file/hJwV3Con/sphere.html click the smaller download button and not the big one.

Image
i have used this code also with a terrain mesh generated by Basic Terrain Generator by Samuel here http://forum.purebasic.com/english/view ... 36&t=59954 and gives good results

Code: Select all

#CameraSpeed = 1
#Mesh      = 50
#Normals  = 55
#Tangents = 60

Global Dim MeshData.PB_MeshVertex(0)

Global xx.f, yy.f
Global ArrSize

Define.f KeyX, KeyY, MouseX, MouseY

Enumeration
  #Window
  #Plane
  #Camera
  #Light1
  #Light2
  #cyl
EndEnumeration

If InitEngine3D()
  
  Add3DArchive(".", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
  ;Add3DArchive("C:\OgreSDK\OgreSDK_vc9_v1-7-4\media\models",#PB_3DArchive_FileSystem)
    
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
ExamineDesktops()
DesktopW = DesktopWidth(0)
DesktopH = DesktopHeight(0)
Total=50

If OpenWindow(#Window, 0, 0, DesktopW, DesktopH, "spikey , W toggle wireFrame ... arrow keys and mouse to move and rotate")
  If OpenWindowedScreen(WindowID(#Window), 0, 0, DesktopW, DesktopH, 0, 0, 0)
    
    CreateCamera(#Camera, 0, 0, 100, 100)
    MoveCamera(#Camera, 0, 10, 40, #PB_Absolute)
    CameraLookAt(#Camera,0,0,0)
    CameraBackColor(#Camera, RGB(250,250,250))


    CreateLight(#Light1, RGB(0, 0, 0), -20, 40, 20)
    SetLightColor(#Light1, #PB_Light_DiffuseColor, RGB(255,255,255))
        
    AmbientColor(RGB(255, 255, 255))
    
    CreateMaterial(5, LoadTexture(5, "wood.jpg"))
    MaterialCullingMode(5, #PB_Material_NoCulling)
    ;MaterialShadingMode(5, #PB_Material_Wireframe)
        
     
    CreateSphere(#Mesh,10,16,16)
    ;LoadMesh(#Mesh, "terrain0.mesh")  
    ;LoadMesh(#Mesh, "sphere.mesh")  
        
    CreateEntity(#Mesh,MeshID(#Mesh), MaterialID(5),0,0,0 )
    
    ;NormalizeMesh(#Mesh)
    ;BuildMeshTangents(#Mesh)
            
    GetMeshData(#Mesh,0, MeshData(), #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Tangent , 0, MeshVertexCount(#Mesh)-1)
    ArrSize = ArraySize(MeshData())
    ;Debug ArrSize
        
    ;creating Normals and Tangents lines
    CreateMesh(#Normals, #PB_Mesh_LineList , #PB_Mesh_Dynamic)
    
    For c=0 To ArrSize
      
      ; the vertex on the object surface 
      x.f = MeshData(c)\x 
      y.f = MeshData(c)\y
      z.f = MeshData(c)\z
        
      nx.f = MeshData(c)\NormalX
      ny.f = MeshData(c)\NormalY
      nz.f = MeshData(c)\NormalZ
      
      tx.f = MeshData(c)\TangentX
      ty.f = MeshData(c)\TangentY
      tz.f = MeshData(c)\TangentZ
                 
      ; for normals; find the next vertex to draw line with vertex on the object surface
      x2.f = x+nx*3 : y2.f = y+ny*3: z2.f = z+nz*3   
      ; for tangents; find the next vertex to draw line with vertex on the object surface
      x3.f = x+tx*1 : y3.f = y+ty*1: z3.f = z+tz*1
            
      MeshVertexPosition(x, y, z)    ;vertex on the object surface
      MeshVertexColor(RGB(255,0,0))
      MeshVertexPosition(x2, y2, z2) ; for normals
      MeshVertexColor(RGB(255,0,0))
      
      
      MeshVertexPosition(x, y, z)    ;vertex on the object surface
      MeshVertexColor(RGB(0,255,0))      
      MeshVertexPosition(x3, y3, z3) ; for tangents
      MeshVertexColor(RGB(0,255,0))
      
    Next c
       
    FinishMesh(#True)
    CreateMaterial(0, LoadTexture(0, "White.jpg"))
    DisableMaterialLighting(0, #True)
    SetMeshMaterial(#Normals, MaterialID(0))
    CreateEntity(#Normals,MeshID(#Normals),MaterialID(0))
    AttachEntityObject(#mesh,"",EntityID(#Normals))

  EndIf
EndIf
;HideEntity(#Mesh,#True)

RotateEntity(#mesh, 0,20,0)
wireFrame = 1

    Repeat
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/20 
        MouseY = -MouseDeltaY()/20
      EndIf
      
          
      If ExamineKeyboard()
      
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -0.2
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = 0.2
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -0.2
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = 0.2
        Else
          KeyY = 0
        EndIf
        
        If KeyboardReleased(#PB_Key_W)
          If wireFrame
          MaterialShadingMode(5, #PB_Material_Wireframe)
          wireFrame ! 1
        Else 
          MaterialShadingMode(5, #PB_Material_Solid)
          wireFrame ! 1
        EndIf
        EndIf
            
      EndIf
  
      RotateCamera(#Camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera(#Camera, KeyX, 0, KeyY)
      
      RotateEntity(#mesh, 0.0,0.1,0.0,#PB_Relative)
      
      RenderWorld()
      
            
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
    
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
  
End

the same above code but added tubes over the Normals lines, the function TubeXYZ :

Code: Select all

TubeXYZ (tube, x.f, y.f,z.f, x2.f, y2.f,z2.f, Radius.f, TubeShape, Material)
draw a tube between position x,y,z to other position x2,y2,z2 with a desired radius and shape (triangular, square, pentagonal,..., 16 edges, etc) and material, in the design of TubeXYZ i depends on these sources
http://www.dbfinteractive.com/forum/ind ... pic=5993.0
http://www.blackpawn.com/texts/pqtorus/
now i forgot the interior of the function completely (100%), but i use it comfortably, (should be added to PB native functions or something like it, your kids will enjoy designing buildings using tubes in different shapes and orientation.
Image
still there is a problem: to align a cube correctly with the normal line, i see "FetchOrientation.pb" in the official examples ... :cry: or we may need to read some multivariables calculus pages as i saw in some pages a plane aligned to a surface.... later

Code: Select all

#CameraSpeed = 1
#Mesh      = 50
#Normals  = 55
#Tangents = 60

Declare TubeXYZ (Line3D, x.f, y.f, z.f, x2.f, y2.f, z2.f, Radius.f, TubeShape, Material)

Global Dim MeshData.PB_MeshVertex(0)

Structure vector3d
  x.f
  y.f
  z.f
EndStructure

Structure vertex
  x.f
  y.f
  z.f
EndStructure

Dim vertx.vertex(32)
    
Define.f KeyX, KeyY, MouseX, MouseY

Enumeration
  #Window
  #Plane
  #Camera
  #Light1
  #Light2
  #cyl
EndEnumeration

If InitEngine3D()
  
  Add3DArchive(".", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
  ;Add3DArchive("C:\OgreSDK\OgreSDK_vc9_v1-7-4\media\models",#PB_3DArchive_FileSystem)
    
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
ExamineDesktops()
DesktopW = DesktopWidth(0)
DesktopH = DesktopHeight(0)
Total=50

If OpenWindow(#Window, 0, 0, DesktopW, DesktopH, "Normals & Tangents, ....W toggle wire/solid Frame ... arrow keys/ mouse to move/ rotate Camera")
  If OpenWindowedScreen(WindowID(#Window), 0, 0, DesktopW, DesktopH, 0, 0, 0)
  
    CreateCamera(#Camera, 0, 0, 100, 100)
    MoveCamera(#Camera, 0, 20, 30, #PB_Absolute)
    CameraLookAt(#Camera,0,0,0)
    CameraBackColor(#Camera, RGB(250,250,250))

    CreateLight(#Light1, RGB(0, 0, 0), -20, 40, 20)
    SetLightColor(#Light1, #PB_Light_DiffuseColor, RGB(255,255,255))
    
    
    AmbientColor(RGB(255, 255, 255))
    

    CreateMaterial(2, LoadTexture(2, "clouds.jpg"))
    MaterialCullingMode(2, #PB_Material_NoCulling)
    CreateMaterial(5, LoadTexture(5, "wood.jpg"))
    MaterialCullingMode(5, #PB_Material_NoCulling)
    ;MaterialShadingMode(5, #PB_Material_Wireframe)
        
     
    CreateSphere(#Mesh,10,16,16)
    ;LoadMesh(#Mesh, "terrain0.mesh")  
    ;LoadMesh(#Mesh, "sphere.mesh")  
    ;LoadMesh(#Mesh, "terr.mesh") 
        
    CreateEntity(#Mesh,MeshID(#Mesh), MaterialID(5),0,0,0 )
    
    ;NormalizeMesh(#Mesh)
    ;BuildMeshTangents(#Mesh)
            
    GetMeshData(#Mesh,0, MeshData(), #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Tangent , 0, MeshVertexCount(#Mesh)-1)
    ArrSize = ArraySize(MeshData())
    ;Debug ArrSize
        
    ;creating Normals and tangents lines
    CreateMesh(#Normals, #PB_Mesh_LineList , #PB_Mesh_Dynamic)
    
    For c=0 To ArrSize
      
      x.f = MeshData(c)\x  
      y.f = MeshData(c)\y
      z.f = MeshData(c)\z
       
      nx.f = MeshData(c)\NormalX
      ny.f = MeshData(c)\NormalY
      nz.f = MeshData(c)\NormalZ
      
      tx.f = MeshData(c)\TangentX
      ty.f = MeshData(c)\TangentY
      tz.f = MeshData(c)\TangentZ
         
      x2.f = x+nx*3 : y2.f = y+ny*3: z2.f = z+nz*3 ; for normals
      x3.f = x+tx*1 : y3.f = y+ty*1: z3.f = z+tz*1 ; for tangents
      
      MeshVertexPosition(x, y, z)    ; vertex on the surface
      MeshVertexColor(RGB(255,0,0))
      MeshVertexPosition(x2, y2, z2) ; for normals, find the next vertex to draw line with vertex on the object surface
      MeshVertexColor(RGB(255,0,0))
      
      
      MeshVertexPosition(x, y, z)    ;  vertex on the surface
      MeshVertexColor(RGB(0,255,0))      
      MeshVertexPosition(x3, y3, z3) ; for tangents
      MeshVertexColor(RGB(0,255,0))
      
            
    Next c
       
    FinishMesh(#True)
    CreateMaterial(0, LoadTexture(0, "White.jpg"))
    DisableMaterialLighting(0, #True)
    SetMeshMaterial(#Normals, MaterialID(0))
    CreateEntity(#Normals,MeshID(#Normals),MaterialID(0))
    AttachEntityObject(#mesh,"",EntityID(#Normals))
    ;;ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    
    ; again but for the purpose to draw tube between vertex 1 and vertex 2
    For c=0 To ArrSize
      
      x.f = MeshData(c)\x  
      y.f = MeshData(c)\y
      z.f = MeshData(c)\z
      
      
      nx.f = MeshData(c)\NormalX
      ny.f = MeshData(c)\NormalY
      nz.f = MeshData(c)\NormalZ
    
     x2 = x+nx*3 : y2 = y+ny*3: z2 = z+nz*3
     TubeXYZ(c+100,  x,y,z,   x2,y2,z2,  0.2, 8, 2)
     AttachEntityObject(#mesh,"",EntityID(c+100))
     
   Next
      
   ;;oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo


  EndIf
EndIf
;HideEntity(#Mesh,#True)

RotateEntity(#mesh, 0,20,0)
wireFrame = 1

    Repeat
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/20 
        MouseY = -MouseDeltaY()/20
      EndIf
      
          
      If ExamineKeyboard()
      
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -0.2
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = 0.2
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -0.2
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = 0.2
        Else
          KeyY = 0
        EndIf
        
        If KeyboardReleased(#PB_Key_W)
          If wireFrame
          MaterialShadingMode(5, #PB_Material_Wireframe)
          wireFrame ! 1
        Else 
          MaterialShadingMode(5, #PB_Material_Solid)
          wireFrame ! 1
        EndIf
        EndIf
            
      EndIf
  
      RotateCamera(#Camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera(#Camera, KeyX, 0, KeyY)
      
      RotateEntity(#mesh, 0.0,0.1,0.0,#PB_Relative)
      
      RenderWorld()
      
            
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
    
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
  
End


;oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
;oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
;oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
;oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo

;the beginning of the Tubes construction code, from here to the end of this page

#Rings = 2 ;number of Rings over all the Line (always 2, start ring and end ring)

Procedure vector_cross(*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = (*v1\y * *v2\z) - (*v2\y * *v1\z)
    *vout\y = (*v1\z * *v2\x) - (*v2\z * *v1\x)
    *vout\z = (*v1\x * *v2\y) - (*v2\x * *v1\y)
EndProcedure

Procedure.f vector_magnitude(*v.vector3d)
    mag.f
    mag = Sqr(*v\x * *v\x + *v\y * *v\y + *v\z * *v\z)
    If mag = 0:mag = 1:EndIf
    ProcedureReturn mag
EndProcedure

Procedure vector_normalize (*v.vector3d)
    mag.f
    mag = vector_magnitude(*v)
    *v\x = *v\x / mag
    *v\y = *v\y / mag
    *v\z = *v\z / mag
EndProcedure


Procedure vector_add (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x + *v2\x
    *vout\y = *v1\y + *v2\y
    *vout\z = *v1\z + *v2\z
EndProcedure

Procedure vector_sub (*v1.vector3d, *v2.vector3d, *vout.vector3d)
    *vout\x = *v1\x - *v2\x
    *vout\y = *v1\y - *v2\y
    *vout\z = *v1\z - *v2\z
EndProcedure



  
  Procedure TubeXYZ (tube, x.f, y.f,z.f, x2.f, y2.f,z2.f, Radius.f, TubeShape, Material)
  ;TubeXYZ(#mesh, x,y,z, x2,y2,z2, Radius.f, TubeShape, Material)  
    x.f+0.00001 : y.f+0.00001 : z.f+0.00001 ; i don't know why 0.00001 is necessary
    x2.f+0.00001 : y2.f+0.00001 : z2.f+0.00001 ; if x,y,z or x2,y2,z2 are zero !!!
    
    CreateMesh(tube , #PB_Mesh_TriangleList, #PB_Mesh_Dynamic )
    
    ;; 0.00001 : necessary if all x,t,z are zero
    Dim vertx.vertex(10)
  lineVec.vector3d

   u.f: r.f
      
  txu.f : txv.f
   
  x1.f = x
  y1.f = y
  z1.f = z
  
  bands = TubeShape
    
  ;vector of the line between start vertex and the end vertex
  lineVec\x = x2 - x1
  lineVec\y = y2 - y1
  lineVec\z = z2 - z1
  
  
   ;Dist.f = Sqr(lineVec\x*lineVec\x + lineVec\y*lineVec\y + lineVec\z*lineVec\z)
  ;Debug Dist
  tt.f = 0
  
  For i=0 To #Rings
        
       x = x1 + lineVec\x * tt 
      y = y1 + lineVec\y * tt 
      z = z1 + lineVec\z * tt
      tt + 1
      
       vertx(i)\x = x
       vertx(i)\y = y
       vertx(i)\z = z
       
   Next 
        
     current_point.vector3d
        next_point.vector3d
        T.vector3d
        B.vector3d
        N.vector3d
        p.f
     For i = 0 To #Rings-1
     
        ;center point
                
        current_point\x = vertx(i)\x
        current_point\y = vertx(i)\y
        current_point\z = vertx(i)\z
        ;next point For Frenet square
        
        next_point\x = vertx(i+1)\x
        next_point\y = vertx(i+1)\y
        next_point\z = vertx(i+1)\z

        ;T  = P' - P
        vector_sub(next_point, current_point, T)

        ;N = P' + P
        vector_add(next_point, current_point, N)

        ;B = T x N
        vector_cross(T, N, B)

        ;N = B x T
        vector_cross(B, T, N)

        ;Normalize vectors Or Else it won't work
        vector_normalize(B)
        vector_normalize(N)
        
        For j = 0 To bands
              new_point_x.f
              new_point_y.f
              
              ;rotate around the current point using normal rotation makes bands
            new_point_x = Sin(j * (#PI*2) / bands) * Radius
            new_point_y = Cos(j * (#PI*2) / bands) * Radius
            
                ;this is the coordinates of our point along the curve
            x = N\x * new_point_x + B\x * new_point_y + current_point\x
            y = N\y * new_point_x + B\y * new_point_y + current_point\y
            z = N\z * new_point_x + B\z * new_point_y + current_point\z
            
            MeshVertexPosition(x, y, z)
            MeshVertexTextureCoordinate(txu, txv)
            MeshVertexNormal(1, 1, 1)
            
            xv=xv+x+0.1
            
            txt+1
            
            txv = txv + 1/#Rings
                         
         Next 
         txv = 0
         txu = txu + 1/bands
         
      Next 

      v.l
      
      For j = 0 To bands -1
          MeshFace(v,v + bands+1, v+1)
          MeshFace(v + bands+1, v + bands+2, v+1 )
          
          v + 1   
          
      Next 
 
    NormalizeMesh(tube)
    BuildMeshTangents(tube)
    FinishMesh(tube)
    ;NormalizeMesh(tube)
    ;BuildMeshTangents(tube)
    CreateEntity(tube,MeshID(tube),MaterialID(Material))
      
    
  EndProcedure
  
 
 
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: Normals & Tangents visualization

Post by applePi »

this is what i was seeking for, to position a cube or a cylinder perpendicular to the surface, and it was solved before in "Meridians and Parallels"
http://purebasic.fr/english/viewtopic.php?f=12&t=48641
so we only do this:
EntityFixedYawAxis(spike , #True)
EntityLookAt(spike , x2,y2,z2)

the entity look at the end point of the normal line or its extension
to appreciate what EntityFixedYawAxis does : comment it in the example 2 at the end.
in example 1 i have used models which have normals by design from the http://www.ogre3d.org/download/sdk
or for your convenience i have uploaded a few models to these links:
http://wikisend.com/download/968076/Normals.rar
or
http://www.2shared.com/file/KczmR1eA/Normals.html
only OgreHead.mesh does not show normals even after normalization, may be because it is a Demon :shock:
Image
the usage at the title bar:

Code: Select all

#CameraSpeed = 1

Global Dim MeshData.PB_MeshVertex(0)

Global xx.f, yy.f
Global ArrSize

Define.f KeyX, KeyY, MouseX, MouseY

Enumeration
  #Mesh
  #Camera
  
EndEnumeration

If InitEngine3D()
  
  Add3DArchive(".", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
      
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
ExamineDesktops()
DesktopW = DesktopWidth(0)
DesktopH = DesktopHeight(0)

If OpenWindow(0, 0, 0, DesktopW, DesktopH, "Normals , ....W toggle wire/solid Frame ... arrow keys/ mouse to move/ rotate Camera")
  If OpenWindowedScreen(WindowID(0), 0, 0, DesktopW, DesktopH, 0, 0, 0)
    
    Global monitor=CreateSprite(#PB_Any,120,40)
    
    CreateCamera(#Camera, 0, 0, 100, 100)
    MoveCamera(#Camera, 0, 10, 40, #PB_Absolute)
    CameraLookAt(#Camera,0,0,0)
    CameraBackColor(#Camera, RGB(250,250,250))


    CreateLight(0, RGB(0, 0, 0), -20, 40, 20)
    SetLightColor(0, #PB_Light_DiffuseColor, RGB(255,255,255))
        
    AmbientColor(RGB(255, 255, 255))
    
    CreateMaterial(5, LoadTexture(5, "wood.jpg"))
    MaterialCullingMode(5, #PB_Material_NoCulling)
    CreateMaterial(6, LoadTexture(6, "Geebee2.bmp"))
     
    ;CreateSphere(#Mesh,10,16,16)
    ;LoadMesh(#Mesh, "sphere.mesh") 
    LoadMesh(#mesh, "knot.mesh")
    ;BuildMeshTangents(#mesh)
    ;NormalizeMesh(#mesh)    
    CreateEntity(#Mesh,MeshID(#Mesh), MaterialID(5),0,0,0 )
            
    GetMeshData(#Mesh,0, MeshData(), #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Tangent , 0, MeshVertexCount(#Mesh)-1)
    ArrSize = ArraySize(MeshData())
    ;Debug ArrSize
        
    ;find Normals lines end points
      
    For c=0 To ArrSize
      
      ;the vertex on the object surface 
      x.f = MeshData(c)\x 
      y.f = MeshData(c)\y
      z.f = MeshData(c)\z
        
      nx.f = MeshData(c)\NormalX
      ny.f = MeshData(c)\NormalY
      nz.f = MeshData(c)\NormalZ
                       
      ;for normals; find the next vertex to draw line along the normal vector begins from the vertex on the object surface
      x2.f = x+nx*7 : y2.f = y+ny*7: z2.f = z+nz*7   
                             
      spike = c + 10 ; begins numbering spikes from number 10 and up
      ;CreateCube(spike, 1)
      CreateCylinder(spike, 1, 7)
      TransformMesh(spike, 0,0,0, 1,1,1, 90,0,0)
      ;TransformMesh(spike + c, 0,0,0, 0.3,1,0.3, 90,0,0)
      UpdateMeshBoundingBox(spike)
      CreateEntity(spike , MeshID(spike), MaterialID(6), x,y,z)
      EntityFixedYawAxis(spike , #True)
      EntityLookAt(spike , x2,y2,z2)
      AttachEntityObject(#mesh,"",EntityID(spike ))
      
    Next c
       
    CreateMaterial(0, LoadTexture(0, "White.jpg"))
    DisableMaterialLighting(0, #True)
    
  EndIf
EndIf
;HideEntity(#Mesh,#True)

RotateEntity(#mesh, 0,20,0)
wireFrame = 1
triangles = MeshIndexCount(#mesh)/3
    Repeat
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/20 
        MouseY = -MouseDeltaY()/20
      EndIf
      
          
      If ExamineKeyboard()
      
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = #CameraSpeed
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = #CameraSpeed
        Else
          KeyY = 0
        EndIf
        
        If KeyboardReleased(#PB_Key_W)
          If wireFrame
          MaterialShadingMode(5, #PB_Material_Wireframe)
          wireFrame ! 1
        Else 
          MaterialShadingMode(5, #PB_Material_Solid)
          wireFrame ! 1
        EndIf
        EndIf
            
      EndIf
  
      RotateCamera(#Camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera(#Camera, KeyX, 0, KeyY)
      
      RotateEntity(#mesh, 0.0,0.1,0.0,#PB_Relative)
      
      RenderWorld()
      
      StartDrawing(SpriteOutput(monitor))
      DrawText(5,5,"FPS : "+Str(Engine3DStatus(#PB_Engine3D_CurrentFPS )))
      ;DrawText(5,20,"Tris : "+StrF(Engine3DStatus(#PB_Engine3D_NbRenderedTriangles))) 
      DrawText(5,20,"Triangles=" +Str(triangles))
      
      StopDrawing()
      DisplaySprite(monitor,0,0)
  
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
    
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
  
End
example 2 does not need any downloads

Code: Select all

#CameraSpeed = 1

Global Dim MeshData.PB_MeshVertex(0)

Global xx.f, yy.f
Global ArrSize

Define.f KeyX, KeyY, MouseX, MouseY

Enumeration
  #Mesh
  #Camera
  
EndEnumeration

If InitEngine3D()
  
  Add3DArchive(".", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Models", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "Examples/3D/Data/Scripts",#PB_3DArchive_FileSystem)
      
  Parse3DScripts()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
ExamineDesktops()
DesktopW = DesktopWidth(0)
DesktopH = DesktopHeight(0)

If OpenWindow(0, 0, 0, DesktopW, DesktopH, "Normals , ....W toggle wire/solid Frame ... arrow keys/ mouse to move/ rotate Camera")
  If OpenWindowedScreen(WindowID(0), 0, 0, DesktopW, DesktopH, 0, 0, 0)
    
    Global monitor=CreateSprite(#PB_Any,120,40)
    
    CreateCamera(#Camera, 0, 0, 100, 100)
    MoveCamera(#Camera, 0, 10, 40, #PB_Absolute)
    CameraLookAt(#Camera,0,0,0)
    CameraBackColor(#Camera, RGB(250,250,250))


    CreateLight(0, RGB(0, 0, 0), -20, 40, 20)
    SetLightColor(0, #PB_Light_DiffuseColor, RGB(255,255,255))
        
    AmbientColor(RGB(255, 255, 255))
    
    CreateMaterial(5, LoadTexture(5, "wood.jpg"))
    MaterialCullingMode(5, #PB_Material_NoCulling)
    CreateMaterial(6, LoadTexture(6, "Geebee2.bmp"))
     
    CreateSphere(#Mesh,10,16,16)
    ;LoadMesh(#Mesh, "sphere.mesh") 
    ;LoadMesh(#mesh, "knot.mesh")
    ;BuildMeshTangents(#mesh)
    ;NormalizeMesh(#mesh)    
    CreateEntity(#Mesh,MeshID(#Mesh), MaterialID(5),0,0,0 )
            
    GetMeshData(#Mesh,0, MeshData(), #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Tangent , 0, MeshVertexCount(#Mesh)-1)
    ArrSize = ArraySize(MeshData())
    ;Debug ArrSize
        
    ;find Normals lines end points
      
    For c=0 To ArrSize
      
      ;the vertex on the object surface 
      x.f = MeshData(c)\x 
      y.f = MeshData(c)\y
      z.f = MeshData(c)\z
        
      nx.f = MeshData(c)\NormalX
      ny.f = MeshData(c)\NormalY
      nz.f = MeshData(c)\NormalZ
                       
      ;for normals; find the next vertex to draw line along the normal vector begins from the vertex on the object surface
      x2.f = x+nx*7 : y2.f = y+ny*7: z2.f = z+nz*7   
                             
      spike = c + 10 ; begins numbering spikes from number 10 and up
      CreateCube(spike, 1)
      ;CreateCylinder(spike, 1, 7)
      ;TransformMesh(spike, 0,0,0, 1,1,1, 90,0,0)
      TransformMesh(spike, 0,0,0, 1,2,1, 90,0,0)
      UpdateMeshBoundingBox(spike)
      CreateEntity(spike , MeshID(spike), MaterialID(6), x,y,z)
      EntityFixedYawAxis(spike , #True)
      EntityLookAt(spike , x2,y2,z2)
      AttachEntityObject(#mesh,"",EntityID(spike ))
      
    Next c
       
    CreateMaterial(0, LoadTexture(0, "White.jpg"))
    DisableMaterialLighting(0, #True)
    
  EndIf
EndIf
;HideEntity(#Mesh,#True)

RotateEntity(#mesh, 0,20,0)
wireFrame = 1
triangles = MeshIndexCount(#mesh)/3
    Repeat
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/20 
        MouseY = -MouseDeltaY()/20
      EndIf
      
          
      If ExamineKeyboard()
      
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = #CameraSpeed
        Else
          KeyX = 0
        EndIf
        
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = #CameraSpeed
        Else
          KeyY = 0
        EndIf
        
        If KeyboardReleased(#PB_Key_W)
          If wireFrame
          MaterialShadingMode(5, #PB_Material_Wireframe)
          wireFrame ! 1
        Else 
          MaterialShadingMode(5, #PB_Material_Solid)
          wireFrame ! 1
        EndIf
        EndIf
            
      EndIf
  
      RotateCamera(#Camera, MouseY, MouseX, 0, #PB_Relative)
      MoveCamera(#Camera, KeyX, 0, KeyY)
      
      RotateEntity(#mesh, 0.0,0.1,0.0,#PB_Relative)
      
      RenderWorld()
      
      StartDrawing(SpriteOutput(monitor))
      DrawText(5,5,"FPS : "+Str(Engine3DStatus(#PB_Engine3D_CurrentFPS )))
      ;DrawText(5,20,"Tris : "+StrF(Engine3DStatus(#PB_Engine3D_NbRenderedTriangles))) 
      DrawText(5,20,"Triangles=" +Str(triangles))
      
      StopDrawing()
      DisplaySprite(monitor,0,0)
  
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
    
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
  
End
Note:
add this :
MoveEntity(spike, 0,0,-1, #PB_Local )
after line 88 in example 2
EntityLookAt(spike , x2,y2,z2)
and compare
Last edited by applePi on Sat Jan 02, 2016 11:08 am, edited 1 time in total.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5524
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Normals & Tangents visualization

Post by Kwai chang caine »

Really great...works fine on W7
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Normals & Tangents visualization

Post by IdeasVacuum »

Really huge work applePi, very useful 8)
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Post Reply