Page 1 of 1

Normals & Tangents visualization

Posted: Mon May 18, 2015 11:14 am
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
  
 
 

Re: Normals & Tangents visualization

Posted: Thu Jul 30, 2015 4:46 pm
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

Re: Normals & Tangents visualization

Posted: Mon Aug 03, 2015 10:21 am
by Kwai chang caine
Really great...works fine on W7
Thanks for sharing 8)

Re: Normals & Tangents visualization

Posted: Mon Aug 03, 2015 11:22 am
by IdeasVacuum
Really huge work applePi, very useful 8)