Bonjour
Je vous propose un outil implémentant OGRE et NEWTON sous VB 2008. Pour ce faire, j'ai utilisé les wrappers correspondants Mogre et MogreNewt.
C'est un outil permettant de visualiser une scène exportée depuis 3DS Max avec l'outil oFusion. Il présente sous une interface simple, une fenêtre de rendu 3D incorporée à une forme (Embeded Ogre Window), la gestion des collisions de la caméra (FPS like) ou pas, la possibilité de sélecionner des objets et de jouer avec, de modifier les lumières, leurs couleurs, de jouer avec les ombres...
C'est un premier projet que j'ai réalisé pour prendre en main tous ses outils. Il n'est pas encore parfait, mais est quand même bien avancé, et toutes les fonctions de bases semblent fonctionner (en tout cas chez moi).
Je le met à votre disposition, car je n'ai trouvé aucun exemple en VB quant à l'utilisation de OGRE et Newton, ce qui est bien dommage car se sont vraiment des outils puissants.
J'inclut une scène exemple, pour faire mumuse avec.
Bien sur, si vous voulez aller plus loin, il vous faudra les différents SDK, on peut les trouver sur www.ogre3D.org,
http://www.newtondynamics.com/, les wiki :
http://www.ogre3d.org/wiki/index.php/Main_Page, http://www.ogre3d.org/wiki/index.php/Mogre_Tutorials...et bien sur, google est mon ami ;o)
Alors voilà, dites moi ce que vous en pensez.
Edit : je viens de commencer à transposer le code dans une classe pour pouvoir le réutiliser de manière simple, j'ai réimplémenté toute la partie chargement affichage et déplacement, il ne reste plus qu'à réimplémenter la gestion de la physique. Quand elle sera terminée, je la déposerais ici, ce qui permettra d'utiliser un moteur 3D puissant en .Net de manière simplissime. (bon, il faudra avoir 3DS MAx quand même...sinon, il faudra voir pour adapter la partie chargement avec les fichiers générés par l'exporter de blender).
Edit 2 : comme promis, la classe est online :
http://www.vbfrance.com/codes/CLASSE-UTILISATION-OGRE-NEWTON_47581.aspx
Source / Exemple :
Imports Mogre
Imports MOIS
Imports MogreNewt
Imports OFusion
Imports System.Runtime.InteropServices
Public Class frmMain
#Region "Déclarations"
Private myRoot As Root 'La racine OGRE
Private mySceneManager As SceneManager 'Le SceneManager OGRE
Private myCamera As Camera 'La caméra
Private MyWindow As RenderWindow 'La fenêtre de rendu (ici ce sera une picturebox)
Private init As Boolean = True 'Permettra de savoir si on est en cours d'initialisation de l'application
Private EnCoursDeSelection = False 'Permettra de savoir si un objet est en cours de sélection
Private EnCoursDeTranslation As Boolean = False 'Permettra de savoir si un objet est en cours de translation
Private ShowAxes As Boolean = False 'Axe du monde visible ou pas
Private TrackObjet As Boolean = False 'Autotracking de la caméra actif ou pas
Private RenduEnCours As Boolean = True 'Sert à savoir si on à quitter l'appli pour stopper le rendu
Private Scene As OSMScene 'La variable pour le chargement de la scene oFusion
Private MyShadowTechnique As Mogre.ShadowTechnique 'Continedra le choix du type d'affichage des ombres
'Variables pour la sélectiond dans la TreeView
Private SceneNodeSelected As Mogre.SceneNode 'Contiendra le noeud sélectionné dans le treeview
Private MObjectSelected As Mogre.MovableObject 'Contiendra l'objet sélectionnée
Private LightSelected As Mogre.Light 'Contiendra la lumière sélectionnée
Private NodeAxe As Mogre.SceneNode 'L'axe des objets
Private NodeAxeMonde As Mogre.SceneNode 'L'axe du monde
'Déclarations pour Newton
Private myWorld As World = Nothing 'Le monde physique
Private Gravity As Single = -9.8 'Et oui, on aura un poid...(Sur terre = 9.81m/s²
'La taille du body représentant le corp physique de la caméra
'Ajuster cette valeur en fonction de la scène. A priori, 70 représente un humain d'à peu près 1m80, si mes
'estimations sont juste.
Private CamSize As Mogre.Vector3 = New Mogre.Vector3(10, 70, 10)
Private CamNode As SceneNode 'Le node de la caméra
Private CamViewNode As SceneNode
Private CamBody As Body 'Le corps physique de la caméra
Private CamColl As CollisionPrimitives.Ellipsoid 'Le type de collision
Private NoMovement As Boolean = True
Private camera_rotation_x As Single
Private camera_rotation_xx As Single
Private camera_rotation_y As Mogre.Degree
Private y_rotation_cont As Degree
Private y_limit_a As Single = 90
Private y_limit_b As Single = -90
Private InitialCamBodyPos As Mogre.Vector3
Private InitialCamBodyOrient As Mogre.Quaternion
'Déclaration pour MOIS
Private inputManager As MOIS.InputManager
Private inputKeyboard As MOIS.Keyboard = Nothing
Private inputMouse As MOIS.Mouse = Nothing
'Translate & rotate scalars
Private moving As Boolean
#End Region
#Region "CONSTANTES"
'Changer ces constantes pour avoir des vitesses de déplacement et/ou de rotation différentes (mode détection de collisions inactif)
Const TRANSLATE As Single = 600
Const ROTATE As Single = 1
#End Region
#Region "Procédures & Fonctions"
Private Function get_body_position(ByVal bod As Body) As Mogre.Vector3 'retourne la position du body
Dim orient As Quaternion
Dim pos As Mogre.Vector3
bod.GetPositionOrientation(pos, orient)
Return pos
End Function
Private Function get_body_orientation(ByVal bod As Body) As Quaternion ' retourne l'orientation du body
Dim orient As Quaternion
Dim pos As Mogre.Vector3
bod.GetPositionOrientation(pos, orient)
Return orient
End Function
Private Sub camera_force_callback(ByVal Corps As Body)
'Cette procédure est appelée à chaque update du monde physique.
'On y applique la gravité ainsi que la rotation sur l'axe des X
If mnuGravite.Checked Then
Dim masse As Single
Dim inertie As Mogre.Vector3
Dim Force As Mogre.Vector3
'on récupère la position et l'orientation du corp passé en paramètre
Dim posBody As Mogre.Vector3 = CamBody.Position
Dim OrientBody As Quaternion = CamBody.Orientation
Corps.GetMassMatrix(masse, inertie) 'on récupère sa masse et son inertie
Force = New Mogre.Vector3(0, Gravity * 2000, 0) 'on y applique la gravité, le facteur de multiplication est là pour ajusté la valeur.
'Curieusement, si je ne multiplie pas, on se croirait sur la Lune. Si quelqu'un sait pourquoi, merci de me le dire.
Force *= masse
Corps.AddForce(Force) 'on applique la force de gravité
End If
Corps.Omega = New Mogre.Vector3(0, camera_rotation_x, 0) 'pour le déplacement sur X
End Sub
Private Sub InitOgre()
'Création de la racine OGRE et du SceneManager. Appeler dans le load de la form, le menu Ouvrir et le menu recharger
myRoot = New Root("Plugins.cfg", "ogre.cfg", "ogre.log")
mySceneManager = myRoot.CreateSceneManager(SceneType.ST_GENERIC)
End Sub
Private Sub InitTree(ByVal SceneNode As Mogre.SceneNode, ByVal sceneTreeNode As TreeNode)
'Remplissage de la TreeView de sélection des objets
'c'est une fonction récursive
'TODO : classement en ordre alphabétique dans les 3 noeuds principaux
Dim NumChildNodes As UShort 'le nombre d'enfants du scenenode passé en paramètre
Dim NewNode As TreeNode = New TreeNode 'on crèe un nouveau node dans le treeview qui va recevoir les paramètres à ajouter au treeview
Try
NumChildNodes = SceneNode.NumChildren 'on récupère le nombre d'enfants du scenenode
NewNode.Name = SceneNode.Name 'Son nom
NewNode.Text = SceneNode.Name + " (" + NumChildNodes.ToString + " enfants)" 'on concatène le nombre d'enfants au nom pour l'affichage dans le treeview
NewNode.Tag = SceneNode 'on met le scenenode dans le tag du noeud de la treeview pour s'en servir lors de la sélection du noeud dans la treeview (cf Treeview_AfterSelect)
If SceneNode.Name.ToUpper.Contains("AXE") Then 'si on est sur un scenenode axe, on sort de la procédure car on ne veut pas le faire appraitre dans la treeview
Exit Sub
End If
If SceneNode.Name.ToUpper.Contains("ROOT") Then 'si on est sur root du scenemanager, on ne fait rien, on se contante de lancer le premier niveau de récursivité
treeScene.Nodes.Item(0).Text = "Root (" + NumChildNodes.ToString + " enfants)"
For i As UShort = 0 To NumChildNodes - 1
InitTree(SceneNode.GetChild(i), treeScene.SelectedNode)
Next
Else 'sinon, on teste le type d'objet et suvant le cas on l'ajoute au noeud du treeview adéquate
If SceneNode.GetAttachedObject(SceneNode.Name).MovableType = "Camera" Then
'Cette ligne permet de sélectionner le bon neoud auquel ajouté l'objet
treeScene.SelectedNode = treeScene.Nodes.Item(0).Nodes.Item(1)
ElseIf SceneNode.GetAttachedObject(SceneNode.Name).MovableType = "Light" Then
treeScene.SelectedNode = treeScene.Nodes.Item(0).Nodes.Item(3)
ElseIf SceneNode.GetAttachedObject(SceneNode.Name).MovableType = "Entity" Then
treeScene.SelectedNode = treeScene.Nodes.Item(0).Nodes.Item(2)
End If
'on ajoute le noeud
treeScene.SelectedNode.Nodes.Add(NewNode)
'treeScene.SelectedNode = treeScene.Nodes(treeScene.Nodes.Count - 1)
If NumChildNodes > 0 Then 'si il y a des nodes enfants, on desend dans le scenenode
For i As UShort = 0 To NumChildNodes - 1
InitTree(SceneNode.GetChild(i), treeScene.SelectedNode)
Next
End If
End If
Catch ex As System.Runtime.InteropServices.SEHException
'en cas d'erreur....on ne fait rien, sinon, des messages apparaissent lors de la création du treeview, on se contente d'un gestionnaire générique pour ne pas planter le programme
treeScene.SelectedNode = treeScene.Nodes.Item(0).Nodes.Item(0)
'on ajoute le noeud
treeScene.SelectedNode.Nodes.Add(NewNode)
If NumChildNodes > 0 Then 'si il y a des nodes enfants, on desend dans le scenenode
For i As UShort = 0 To NumChildNodes - 1
InitTree(SceneNode.GetChild(i), treeScene.SelectedNode)
Next
End If
End Try
End Sub
Private Sub InitScene()
Try
'On initialise la racine OGRE
myRoot.Initialise(False)
'On crè la fenêtre, ici ce sera dans le contrôle picMogre, une picturebox
Dim misc As NameValuePairList = New NameValuePairList
misc("externalWindowHandle") = picMogre.Handle.ToString
Dim const_list As Const_NameValuePairList = misc.ReadOnlyInstance
MyWindow = myRoot.CreateRenderWindow("OgreWieport", 0, 0, False, const_list)
'On ajoute un handler qui permettre de récupérer la variable timeSinceLastFrame pour la gestion des déplacements
'AddHandler myRoot.FrameStarted, AddressOf FrameStarted
'On crés le ressource manager avec les ressources choisie dans la boîte de chargement.
'Par défaut, on prend le chemin de la scène
ResourceGroupManager.Singleton.AddResourceLocation(System.IO.Path.GetDirectoryName(txtNomScene.Text), "FileSystem", "General")
'On ajoute le répertoires OBJETS de l'application qui contient, entre autre, les axes
ResourceGroupManager.Singleton.AddResourceLocation(Application.StartupPath + "\Objets", "FileSystem", "General")
'et on parcourt la listbox de la fenêtre de choix pour ajouter les ressources supplémentaires (répertoires ou fichiers zip)
If lstRessources.Items.Count > 0 Then
For i As Integer = 0 To lstRessources.Items.Count - 1
'lstTypeRessources contient le type de ressource de la ressource considérée dans lstRessources
ResourceGroupManager.Singleton.AddResourceLocation(lstRessources.Items(i), lstTypeRessources.Items(i), "General")
Next
End If
'Fini, on initialise toutes les ressources
ResourceGroupManager.Singleton.InitialiseAllResourceGroups()
'On charge la scène OSM grâce à la dll oFusion
Scene = New OSMScene(mySceneManager, MyWindow)
Scene.Initialize(txtNomScene.Text)
Scene.CreateScene(mySceneManager.RootSceneNode)
'création de la caméra
If Scene.CameraList.Count > 0 Then
'Si la scene contient au moins une caméra, on sélectionne la première
myCamera = Scene.CameraList(0)
Else
'sinon, on en crè une par défaut
myCamera = Scene.SceneMgr.CreateCamera("CameraDefaut")
myCamera.SetPosition(0, 0, 0)
myCamera.SetDirection(0, 0, 0)
myCamera.FOVy = CType(1, Mogre.Radian)
Dim camNode As SceneNode = mySceneManager.CreateSceneNode("CameraDefaut")
camNode.AttachObject(myCamera)
Dim CameraTarget As Mogre.SceneNode = mySceneManager.CreateSceneNode("CameraDefaut.target")
CameraTarget.SetPosition(1000, 1000, 1000)
CameraTarget.SetDirection(0, 0, 0)
CameraTarget.SetScale(1, 1, 1)
'On crè le viewport
Dim ViewPort As Mogre.Viewport = MyWindow.AddViewport(myCamera)
myCamera.AspectRatio = ViewPort.ActualWidth / ViewPort.ActualHeight
End If
txtFOV.Text = myCamera.FOVy.ValueRadians
myCamera.NearClipDistance = 5
InitialCamBodyOrient = myCamera.Orientation
InitialCamBodyPos = myCamera.Position
'si on a décidé d'activer la gestion des collisions, on initialise Newton
If mnuDetectionDeCollision.Checked Then
InitNewton()
End If
'initialisation de l'inputmanager MOIS
InitInputHandler()
Catch ex As System.Runtime.InteropServices.SEHException
'en cas d'erreur....
If OgreException.IsThrown Then
MsgBox(OgreException.LastException.FullDescription, MsgBoxStyle.Critical, _
"Exeption OGRE!")
Else
MsgBox(ex.ToString, "Erreur")
End If
End Try
End Sub
Private Sub InitNewton()
'Initialisation de Newton pour la gestion des collision caméras, je n'y suis pas arrivé avec les RayScenQuery...
If myWorld Is Nothing Then
myWorld = New World 'le monde physique
'et initialisation de sa taille, par défaut elle est de 100 sur chaque axes.
myWorld.SetWorldSize(New Mogre.Vector3(-100000, -100000, -100000), New Mogre.Vector3(100000, 100000, 100000))
End If
Dim cam_mass As Single = 90 'la masse de la caméra
'Création du monde physique pour Newton
Dim stat_col As MogreNewt.CollisionPrimitives.TreeCollisionSceneParser = New MogreNewt.CollisionPrimitives.TreeCollisionSceneParser(myWorld)
stat_col.ParseScene(mySceneManager.RootSceneNode, False) 'Utilisation du parser de scène Newton, attention, à ce jour (juillet 2008), le parmètre true, au mieux, ne fonctionne pas et au pire plante le programme.
'Création et paramétrage du body pour le monde
Dim bod As MogreNewt.Body = New MogreNewt.Body(myWorld, stat_col)
stat_col.Dispose()
bod.AttachToNode(mySceneManager.RootSceneNode)
bod.SetPositionOrientation(New Mogre.Vector3(0.0, 0.0, 0.0), Quaternion.IDENTITY)
'Collision de la caméra
Dim PosCam As Mogre.Vector3 = mySceneManager.GetSceneNode(myCamera.Name).Position 'on récupère la position de la caméra
Dim OrientCam As Quaternion = mySceneManager.GetSceneNode(myCamera.Name).Orientation 'on récupère l'orientation de la caméra
CamNode = mySceneManager.RootSceneNode.CreateChildSceneNode("CamNode") 'on crè un Scennode
Me.CamNode.SetScale(Me.CamSize) 'on le met à la taille de la caméra
Me.CamColl = New CollisionPrimitives.Ellipsoid(myWorld, Me.CamSize) 'on crè le système de collision
Me.CamBody = New Body(myWorld, Me.CamColl) 'on l'applique au body représentant la caméra
Me.CamColl.Dispose() 'on libère la collision
Me.CamBody.AttachToNode(Me.CamNode) 'et on l'attache au noeud créé précédement
'calcul de l'inertie de la caméra
Dim cam_inertia As Mogre.Vector3 = MomentOfInertia.CalcEllipsoidSolid(cam_mass, Me.CamSize)
Me.CamBody.SetMassMatrix(cam_mass, cam_inertia)
AddHandler Me.CamBody.ForceCallback, AddressOf camera_force_callback 'la fonction appelée lors de l'update du monde physique
Me.CamBody.AutoFreeze = False 'Important, sinon, iompossible de déplacer le body...
'Création d'un "UP Vector" pour empécher le body de tourner sur Y
Dim uv2 As BasicJoints.UpVector = New BasicJoints.UpVector(myWorld, Me.CamBody, Mogre.Vector3.UNIT_Y)
'Création d'un scenenode 1 unités au dessus du camnode pour y mettre la caméra
'Ca nécessite un peu d'explications :
'Si on met 0 comme valeur sur Y, la caméra est positionnée au centre du body.
'Comme le but est de représenter un être humain, ça ne le fait pas.
'Par contre, la valeur 1 positionne la caméra juste au dessus du body, mais, à contrarion, dans une pièce
'au plafond trop bas, la caméra va passer au dessus du plafond....Pour le moment, je n'ai pas trouvé mieux.
Me.CamViewNode = Me.CamNode.CreateChildSceneNode("CamViewNode", New Mogre.Vector3(0, 1, 0)) 'création du scenenode
mySceneManager.RootSceneNode.DetachObject(myCamera) 'on détache la caméra du rootscenenode (créé par OSMLoader)
Me.CamViewNode.AttachObject(myCamera) 'et on attache la caméra au viewnode
CamBody.SetPositionOrientation(PosCam, OrientCam) 'Sert à récupérer la position et orientation initiale de la caméra pour positionner son corp.
InitialCamBodyOrient = get_body_orientation(CamBody)
InitialCamBodyPos = get_body_position(CamBody)
'CamBody.MaterialGroupID = New MogreNewt.MaterialID(myWorld)
MogreNewt.Debugger.Instance.Init(mySceneManager) 'et on initialise le debugger newton.
End Sub
Private Sub InitInputHandler()
'Définition du mode d'accès de la souris et du handle de fenêtre à gérer. ATTENTION : ce n'est pas le handle du contrôle qui affichera le rendu mais celui de la fenêtre qui le contient
Dim param As MOIS.ParamList = New MOIS.ParamList()
'Les 4 premiers paramètres servent à signaler que MOIS ne sera pas le seul à être capable de gérer le clavier et la souris
'ceci permet de disposer du curseur de la souris pour faire autre chose pendant que Ogre rend ses frames
param.Insert("w32_mouse", "DISCL_NONEXCLUSIVE")
param.Insert("w32_mouse", "DISCL_FOREGROUND")
param.Insert("w32_keyboard", "DISCL_NONEXCLUSIVE")
param.Insert("w32_keyboard", "DISCL_FOREGROUND")
param.Insert("WINDOW", Me.Handle.ToString) 'ici, on passe le handle de notre "top level window" (cf. DirectX et DirectInput)
'Hook de l'input manager à la fenêtre
inputManager = MOIS.InputManager.CreateInputSystem(param)
If Not inputManager Is Nothing Then
'Creation des device de capture MOIS
Try
'Le clavier
inputKeyboard = CType(inputManager.CreateInputObject(MOIS.Type.OISKeyboard, False), MOIS.Keyboard)
Catch ex As System.Runtime.InteropServices.SEHException
'en cas d'erreur....
If OISException.IsThrown Then
MsgBox(OISException.LastException.eText, MsgBoxStyle.Critical, _
"Exeption OIS!")
Else
MsgBox(ex.ToString, "Erreur")
End If
End Try
Try
'La souris
inputMouse = CType(inputManager.CreateInputObject(MOIS.Type.OISMouse, False), MOIS.Mouse)
Catch ex As System.Runtime.InteropServices.SEHException
'en cas d'erreur....
If OISException.IsThrown Then
MsgBox(OISException.LastException.eText, MsgBoxStyle.Critical, _
"Exeption OIS!")
Else
MsgBox(ex.ToString, "Erreur")
End If
End Try
'A répéter pour d'autre input, joystick par exemple :
'' ''Try
'' '' inputJoy = CType(inputManager.CreateInputObject(MOIS.Type.OISJoyStick, False), MOIS.JoyStick)
'' ''Catch ex As System.Runtime.InteropServices.SEHException
'' '' 'en cas d'erreur....
'' '' If OISException.IsThrown Then
'' '' MsgBox(OISException.LastException.eText, MsgBoxStyle.Critical, _
'' '' "Exeption OIS!")
'' '' Else
'' '' MsgBox(ex.ToString, "Erreur")
'' '' End If
'' ''End Try
End If
' Et l'évènement qui sera attaché au FrameStarted
AddHandler myRoot.FrameStarted, AddressOf FrameStarted
End Sub
Private Sub DisposeOgre()
'Pemet de nettoyer les instances OGRES en cas de rechargement de la scène ou de l'ouverture d'une nouvelle
'en gros, on réinitialise toutes les instances Ogre
SceneNodeSelected = Nothing
MObjectSelected = Nothing
myCamera = Nothing
Scene = Nothing
ResourceGroupManager.Singleton.DestroyResourceGroup("General")
MyWindow.RemoveAllViewports()
MyWindow.Dispose()
myRoot.DestroySceneManager(mySceneManager)
myRoot.DetachRenderTarget(MyWindow)
myRoot.Dispose()
MyWindow = Nothing
mySceneManager = Nothing
End Sub
Private Sub DisposeNewton()
'Permet de liberer les instances Newton, mais ça ne marche pas top, à paufiner....
'Ainsi, si on recharge la scène ou si on en charge une autre, tout marche sauf que l'on a pas de mouvement sur X.
'A l'heure qu'il est, je ne sais pas pourquoi
RemoveHandler Me.CamBody.ForceCallback, AddressOf camera_force_callback
myWorld.DestroyAllBodies()
myWorld.Dispose()
myWorld = Nothing
End Sub
Private Sub LoadAxe()
'Permet de charger l'objet Axe et de l'ajouter à la scene
Dim Axe01 As Entity 'Sera l'axe afficher sdur les objets
Dim AxeMonde As Entity 'Comme son nom l'indique
Try
Axe01 = mySceneManager.CreateEntity("Axe01", "Axe.mesh") 'on charge l'objet
AxeMonde = Axe01.Clone("AxeMonde") 'on le clone pour avoir deux axes séparés
'On crè le node qui contioendra l'axe du monde
NodeAxeMonde = mySceneManager.RootSceneNode.CreateChild("AxeMonde")
NodeAxeMonde.AttachObject(AxeMonde)
NodeAxeMonde.SetPosition(0, 0, 0)
NodeAxeMonde.SetScale(1, 1, 1)
NodeAxeMonde.SetVisible(False)
NodeAxeMonde.ResetToInitialState()
'on fait pareil pour l'axe des objets
NodeAxe = mySceneManager.RootSceneNode.CreateChild("Axe01")
NodeAxe.AttachObject(Axe01)
NodeAxe.SetPosition(0, 0, 0)
NodeAxe.SetScale(1, 1, 1)
NodeAxe.InheritOrientation = False 'si on ne fait pas ça, l'axe se comporte étrangement lorsque l'objet tourne
NodeAxe.InheritScale = False 'Pareil, le scale de l'objet s'ajoute au scale de l'axe
NodeAxe.SetVisible(False)
Catch ex As System.Runtime.InteropServices.SEHException
'en cas d'erreur....
If OgreException.IsThrown Then
MsgBox(OgreException.LastException.FullDescription, MsgBoxStyle.Critical, _
"Exeption OGRE!")
Else
MsgBox(ex.ToString, "Erreur")
End If
End Try
End Sub
Public Function FrameStarted(ByVal evt As FrameEvent) As Boolean
'Gère les évènements clavier et souris
'le test pour annuler le mouvement de la caméra est mis en externe par rapport
'au test de detection de collision car si on relache la souris avant les touches
'la caméra continue à se déplacer, donc, on annule sa vélocité et sa rotation à la fin de la fonction
Dim PasdeMouvement As Boolean = True
If moving Then 'Si on a cliqué sur le bouton gauche de la souris, on se déplace dans le monde
CaptureFunction() 'on lance la capture clavier/souris par MOIS
'Il y a 2 systèmes de mouvement, avec ou sans détection de collisions
If mnuDetectionDeCollision.Checked Then
'Avec
'Le principe est de récupérer l'orientation du corps de la caméra sur l'axe de déplacement choisi
'et de lui affecter une vitesse de déplacement sur cette axe.
'Lorsque l'on arrête le déplacement, on annule la vitesse.
Dim direction As Mogre.Vector3
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_UP) Then
direction = get_body_orientation(CamBody) * Mogre.Vector3.NEGATIVE_UNIT_Z
CamBody.Velocity = CamBody.Velocity * New Mogre.Vector3(0, 1, 0) + direction * 200 * 2
PasdeMouvement = False
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_DOWN) Then
direction = get_body_orientation(CamBody) * Mogre.Vector3.UNIT_Z
CamBody.Velocity = CamBody.Velocity * New Mogre.Vector3(0, 1, 0) + direction * 200 * 2
PasdeMouvement = False
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_LEFT) Then
direction = get_body_orientation(CamBody) * Mogre.Vector3.NEGATIVE_UNIT_X
CamBody.Velocity = CamBody.Velocity * New Mogre.Vector3(0, 1, 0) + direction * 200 * 2
PasdeMouvement = False
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_RIGHT) Then
direction = get_body_orientation(CamBody) * Mogre.Vector3.UNIT_X
CamBody.Velocity = CamBody.Velocity * New Mogre.Vector3(0, 1, 0) + direction * 200 * 2
PasdeMouvement = False
End If
'Pour le déplacement sur Y (vertical) on se déplace sur le Y du monde et pas de la caméra
'Donc, pas besoin de récupérer la direction de la caméra
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_PGUP) Then
CamBody.Velocity = New Mogre.Vector3(0, 1000, 0)
PasdeMouvement = False
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_PGDOWN) Then
CamBody.Velocity = New Mogre.Vector3(0, -1000, 0)
PasdeMouvement = False
End If
'Pour la rotation de la caméra, on récupère le déplacement de la souris sur X et Y
Dim mouseState As MOIS.MouseState_NativePtr = inputMouse.MouseState
camera_rotation_x = -mouseState.X.rel * 0.5F
If camera_rotation_x <> 0 Then
PasdeMouvement = False
End If
camera_rotation_y = -mouseState.Y.rel * 0.5F
'On travaille sur le camviewnode pour que l'axe de la caméra soit orienté correctement
CamViewNode.Pitch(camera_rotation_y)
'Si on atteint un angle de rotation maximale vers le haut ou le bas, on annule la rotation
y_rotation_cont += camera_rotation_y
If y_rotation_cont > y_limit_a Or y_rotation_cont < y_limit_b Then
CamViewNode.Pitch(-camera_rotation_y)
y_rotation_cont -= camera_rotation_y
End If
Else
'Sans
'On applique simplement une translation ou une rotation à la caméra
Dim myTranslation As Mogre.Vector3 = Mogre.Vector3.ZERO 'Pour le déplacement de la caméra sur ces axes sans détection de collision
myTranslation.z = 0
myTranslation.x = 0
myTranslation.y = 0
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_UP) Then
myTranslation.z += -TRANSLATE
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_DOWN) Then
myTranslation.z += TRANSLATE
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_LEFT) Then
myTranslation.x += -TRANSLATE
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_RIGHT) Then
myTranslation.x += TRANSLATE
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_PGUP) Then
myTranslation.y += TRANSLATE
End If
If inputKeyboard.IsKeyDown(MOIS.KeyCode.KC_PGDOWN) Then
myTranslation.y += -TRANSLATE
End If
Dim mouseState As MOIS.MouseState_NativePtr = inputMouse.MouseState
camera_rotation_x = mouseState.X.rel * -ROTATE
camera_rotation_y = mouseState.Y.rel * -ROTATE
'Et on déplace la caméra
myCamera.Position += myCamera.Orientation * myTranslation * evt.timeSinceLastFrame
myCamera.Yaw(camera_rotation_x * evt.timeSinceLastFrame)
myCamera.Pitch(camera_rotation_y) 'si on multiplie par timesincelastframe, le résultat est plus qu'étrange...A voir.
End If
End If
'C'est ici que l'on annule la vélocité et la rotation de la caméra.
If PasdeMouvement And mnuDetectionDeCollision.Checked Then
CamBody.Velocity = New Mogre.Vector3(0, 0, 0)
camera_rotation_x = 0
End If
Return RenduEnCours 'tant que l'on ne quitte pas l'appli, on renvoi True.
End Function
Private Sub CaptureFunction()
'Lance la capture du clavier et de la souris
inputKeyboard.Capture()
inputMouse.Capture()
End Sub
Private Sub RemplitGrille()
'Permet de remplir la grille d'infos une fois qu'un objet est sélectionné
Dim tab(1) As String
Try
'On efface le contenu de la grille
grdDetail.Rows.Clear()
'Et on remplit
'La position
tab(0) = "Position X"
tab(1) = SceneNodeSelected.Position.x.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Position Y"
tab(1) = SceneNodeSelected.Position.y.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Position Z"
tab(1) = SceneNodeSelected.Position.z.ToString
grdDetail.Rows.Add(tab)
'L'Orientation
tab(0) = "Orientation X"
tab(1) = SceneNodeSelected.Orientation.x.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Orientation Y"
tab(1) = SceneNodeSelected.Orientation.y.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Orientation Z"
tab(1) = SceneNodeSelected.Orientation.z.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Orientation W"
tab(1) = SceneNodeSelected.Orientation.w.ToString
grdDetail.Rows.Add(tab)
'L'échelle
tab(0) = "Echelle X"
tab(1) = SceneNodeSelected.GetScale.x.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Echelle Y"
tab(1) = SceneNodeSelected.GetScale.y.ToString
grdDetail.Rows.Add(tab)
tab(0) = "Echelle Z"
tab(1) = SceneNodeSelected.GetScale.z.ToString
grdDetail.Rows.Add(tab)
'Les ombres
tab(0) = "CastShadows"
tab(1) = IIf(MObjectSelected.CastShadows, "Oui", "Non")
grdDetail.Rows.Add(tab)
'La visibilité
tab(0) = "Visible"
tab(1) = IIf(MObjectSelected.Visible, "Oui", "Non")
grdDetail.Rows.Add(tab)
'La Bounding box
tab(0) = "ShowBoundingBox"
tab(1) = IIf(SceneNodeSelected.ShowBoundingBox, "Oui", "Non")
grdDetail.Rows.Add(tab)
GetPosition()
GetOrientation()
GetEchelle()
Catch ex As Exception
End Try
End Sub
Private Sub GetOrientation()
'Récupère l'orientation de l'objet sélectionné pour l'afficher dans les paramètres de le'objet
Try
txtOrientationX.Value = SceneNodeSelected.Orientation.x
txtOrientationY.Value = SceneNodeSelected.Orientation.y
txtOrientationZ.Value = SceneNodeSelected.Orientation.z
txtOrientationW.Value = SceneNodeSelected.Orientation.w
Catch ex As Exception
End Try
End Sub
Private Sub GetPosition()
'Récupère la position de l'objet sélectionné pour l'afficher dans les paramètres de le'objet
Try
txtPositionX.Value = SceneNodeSelected.Position.x
txtPositionY.Value = SceneNodeSelected.Position.y
txtPositionZ.Value = SceneNodeSelected.Position.z
Catch ex As Exception
End Try
End Sub
Private Sub GetEchelle()
'Récupère l'échelle de l'objet sélectionné pour l'afficher dans les paramètres de le'objet
txtScaleX.Value = SceneNodeSelected.GetScale.x
txtScaleY.Value = SceneNodeSelected.GetScale.y
txtScaleZ.Value = SceneNodeSelected.GetScale.z
End Sub
#End Region
#Region "Evènements"
#Region "Form"
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Hide() 'Cache la fenêtre principale
treeScene.Sort() 'trie la treeview, une fois triée, elle le reste même si on la recharge avec de nouvelles données.
InitOgre()
'Affichage de la fenêtre de choix de la scène à charger
frmViewerload.ShowDialog()
If frmViewerload.bValide Then
'Si on a valider le choix.....
'On affiche la form d'attente
Cursor = Cursors.WaitCursor 'juste pour la beauté
If frmViewerload.chkPhysique.Checked Then
mnuDetectionDeCollision.Checked = True
mnuGravite.Enabled = True
mnuDebugActif.Enabled = True
End If
'Affichage de la fenêtre de paramètres OGRES, le cas échéant
If frmViewerload.chkOgre.Checked Then
If Not myRoot.ShowConfigDialog Then
Exit Sub
End If
Else
If Not myRoot.RestoreConfig() Then
If Not myRoot.ShowConfigDialog Then
Exit Sub
End If
End If
End If
frmInfoLoad.Show()
frmInfoLoad.Refresh() 'nécessair pour afficher son contenu
'Cette partie permet de remplir les listes locales de la form pour le rechargement de la scène
Me.lstRessources.Items.Clear()
Me.lstTypeRessources.Items.Clear()
Me.txtNomScene = frmViewerload.txtNomscene
For i As Integer = 0 To frmViewerload.lstRessources.Items.Count - 1
Me.lstRessources.Items.Add(frmViewerload.lstRessources.Items(i))
Next
For i As Integer = 0 To frmViewerload.lstTypeRessources.Items.Count - 1
Me.lstTypeRessources.Items.Add(frmViewerload.lstTypeRessources.Items(i))
Next
'Et on initialise la scène
Me.InitScene()
LoadAxe() 'On ajoute les axes
Me.InitTree(mySceneManager.RootSceneNode, Nothing) 'On remplit la treeview
frmViewerload.Dispose() 'et on détruit la form de chargement
'On ajoutes la gestion des évèbements aux champs texte
AddHandler txtPositionY.ValueChanged, AddressOf Position
AddHandler txtPositionZ.ValueChanged, AddressOf Position
AddHandler txtScaleY.ValueChanged, AddressOf Echelle
AddHandler txtScaleZ.ValueChanged, AddressOf Echelle
'On détruit la form d'attente
frmInfoLoad.Hide()
frmInfoLoad.Dispose()
Cursor = Cursors.Default
'On démarre le timer pour le rendu et la gestion des touches
'timerRendu.Enabled = True
init = False 'L'initialisation est terminé, la variable init passe à false
Me.Show() 'Tout est fini, on affiche la fenêtre
'myRoot.StartRendering()
While RenduEnCours
My.Application.DoEvents()
'Affichage des infos de rendu
Try
lblAvg.Text = "FPS moyennes: " & Mogre.StringConverter.ToString(MyWindow.AverageFPS, 3)
lblCurr.Text = "FPS courantes: " & Mogre.StringConverter.ToString(MyWindow.LastFPS, 3)
lblBest.Text = "Meilleures FPS: " & Mogre.StringConverter.ToString(MyWindow.BestFPS, 3)
lblWorst.Text = "Pires FPS: " & Mogre.StringConverter.ToString(MyWindow.WorstFPS, 3)
lblNumTris.Text = "Triangles: " & Mogre.StringConverter.ToString(MyWindow.TriangleCount)
lblNumBatches.Text = "Nombre de Batch: " & Mogre.StringConverter.ToString(MyWindow.BatchCount)
Catch ex As Exception
End Try
'et on rend une frame
myRoot.RenderOneFrame()
'Update du monde physique
If mnuDetectionDeCollision.Checked Then
Dim stepPhysics As Single = 0.1
myWorld.Update(stepPhysics)
End If
If SceneNodeSelected Is Nothing Then
'si un objet est sélectionné ou pas, on active ou désactive le panneau de paramètre
grpParamObjet.Enabled = False
cmdResetEtat.Enabled = False
Else
grpParamObjet.Enabled = True
cmdResetEtat.Enabled = True
End If
End While
'Sur des machines rapide, le nombre trop élevé de FPS rend la rotation sur X des plus étrange si la détection de collisions est activée.
'Le renderOneFrame rendant moins de FPS, je l'utilise dans le timer.
'C'est surement une histoire de facteur de multiplication lors de la récupération de camera_rotation_x, mais je n'ai pas trouvé la formule magique.
DisposeNewton()
If mnuDetectionDeCollision.Checked Then
DisposeOgre()
End If
Else
'Sinon on s'en va
Me.Dispose()
End If
End Sub
Private Sub frmMain_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
'On se contente d'arrêter le timer et à positionner la vaiable permettant de stopper le rendu Ogre, le reste des ressources ser libéré par le garbage collector (en tout cas on l'espère ;o) )
'timerRendu.Enabled = False
RenduEnCours = False
End Sub
#End Region
#Region "Timer"
Private Sub timerRendu_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerRendu.Tick
''Affichage des infos de rendu
'Try
' lblAvg.Text = "FPS moyennes: " & Mogre.StringConverter.ToString(MyWindow.AverageFPS, 3)
' lblCurr.Text = "FPS courantes: " & Mogre.StringConverter.ToString(MyWindow.LastFPS, 3)
' lblBest.Text = "Meilleures FPS: " & Mogre.StringConverter.ToString(MyWindow.BestFPS, 3)
' lblWorst.Text = "Pires FPS: " & Mogre.StringConverter.ToString(MyWindow.WorstFPS, 3)
' lblNumTris.Text = "Triangles: " & Mogre.StringConverter.ToString(MyWindow.TriangleCount)
' lblNumBatches.Text = "Nombre de Batch: " & Mogre.StringConverter.ToString(MyWindow.BatchCount)
'Catch ex As Exception
'End Try
''et on rend une frame
''myRoot.RenderOneFrame()
''Update du monde physique
'If mnuDetectionDeCollision.Checked Then
' Dim stepPhysics As Single = 0.1
' myWorld.Update(stepPhysics)
'End If
'If SceneNodeSelected Is Nothing Then
' 'si un objet est sélectionné ou pas, on active ou désactive le panneau de paramètre
' grpParamObjet.Enabled = False
' cmdResetEtat.Enabled = False
'Else
' grpParamObjet.Enabled = True
' cmdResetEtat.Enabled = True
'End If
End Sub
#End Region
#Region "Picture Box (Pour le rendu Ogre et le choix des couleurs de la lumière)"
Private Sub picMogre_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picMogre.MouseDown
'Quand on clique dans la picture box, on active le déplacement si c'est avec le bouton gauche
If e.Button = Windows.Forms.MouseButtons.Left Then
moving = True
Cursor.Hide()
End If
End Sub
Private Sub picMogre_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picMogre.MouseUp
'Et on désactive le déplacement quand on relache le bouton gauche
If e.Button = Windows.Forms.MouseButtons.Left Then
moving = False
Cursor.Show()
End If
End Sub
Private Sub picSpecular_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles picSpecular.DoubleClick
'On passe les paramètres à la form de sélection des couleurs (la lumière sélectionner et l'action à effectuer)
frmColorDialogue.myLight = LightSelected
frmColorDialogue.Provenance = "Specular"
'On ouvre la form
frmColorDialogue.ShowDialog()
'on la libère
frmColorDialogue.Dispose()
End Sub
Private Sub picDiffuse_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles picDiffuse.DoubleClick
'On passe les paramètres à la form de sélection des couleurs (la lumière sélectionner et l'action à effectuer)
frmColorDialogue.myLight = LightSelected
frmColorDialogue.Provenance = "Diffuse"
'On ouvre la form
frmColorDialogue.ShowDialog()
'on la libère
frmColorDialogue.Dispose()
End Sub
Private Sub picMogre_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles picMogre.SizeChanged
'Pour redimensionner le vieport de manière correcte quant on redimmensionne la picturebox (du à un resize de la form ou un déplacement des splitter)
If Not init Then 'on ne le fait qu'une fois l'initalisation terminée.
timerRendu.Enabled = False 'on arrête le timer (on ne va pas rendre pendant que le vieport n'existe plus...)
Try
'on récupère le viewport
Dim myViewport As Mogre.Viewport = MyWindow.GetViewport(0)
'on récupère la couleur du vieport car elle est perdu à sa destruction
Dim CouleurVieport As Mogre.ColourValue = myViewport.BackgroundColour
'On le supprime de la fenêtre de rendu
MyWindow.RemoveViewport(myViewport.ZOrder)
'Et on efface la feneêtre de rendu
myRoot.DetachRenderTarget(MyWindow)
MyWindow.Dispose()
MyWindow = Nothing
'On recrè la fenêtre, qui prendra comme dimension la nouvelle taille du contrôle
Dim misc As NameValuePairList = New NameValuePairList
misc("externalWindowHandle") = picMogre.Handle.ToString
Dim const_list As Const_NameValuePairList = misc.ReadOnlyInstance
MyWindow = myRoot.CreateRenderWindow("OgreWieport", 0, 0, False, const_list)
'On recrè un viewport avec les nouveaux paramètrex
myViewport = MyWindow.AddViewport(myCamera)
'on réaffecte la couleur précédemment sauvegardée
myViewport.BackgroundColour = CouleurVieport
'on fixe l'aspect ratio de la caméra
myCamera.AspectRatio = myViewport.ActualWidth / myViewport.ActualHeight
Catch ex As Exception
'en cas d'erreur....
If OgreException.IsThrown Then
Try 'parfois ça plante ici car OgreException.LastException n'est pas défini, donc je réimbrique un try
MsgBox(OgreException.LastException.FullDescription, MsgBoxStyle.Critical, _
"Exeption OGRE!")
Catch ex2 As Exception
End Try
Else
MsgBox(ex.ToString, "Erreur")
End If
End Try
timerRendu.Enabled = True 'on redémarre le timer
End If
End Sub
#End Region
#Region "Champs texte"
Private Sub txtFOV_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtFOV.TextChanged
'Permet de changer l'angle du champ de vision
If txtFOV.Text <> "" Then
Try
myCamera.FOVy = CType(txtFOV.Text, Mogre.Radian)
Catch ex As Exception
End Try
End If
End Sub
Private Sub Echelle(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtScaleX.ValueChanged
'Appeller par les 3 txtScale, permet de changer le facteur d'échelle de l'objet sélectionné
If Not EnCoursDeSelection Then 'nécessaire car si on est en cours de sélection d'un objet, de mauvais paramètres sont appliqués
SceneNodeSelected.SetScale(txtScaleX.Value, txtScaleY.Value, txtScaleZ.Value) 'et on applique l'échelle
End If
End Sub
Private Sub Position(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtPositionX.ValueChanged, txtPositionX.Scroll
'Appeller par les 3 txtPosition, permet de changer la position de l'objet sélectionné
If Not EnCoursDeSelection And Not EnCoursDeTranslation Then 'nécessaire car si on est en cours de sélection d'un objet, de mauvais paramètres sont appliqués
SceneNodeSelected.SetPosition(txtPositionX.Value, txtPositionY.Value, txtPositionZ.Value) 'et on applique la position
End If
End Sub
#End Region
#Region "Les menus"
Private Sub mnuParamOgre_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuParamOgre.Click
'Montre la fenêtre de configuration OGRE
myRoot.ShowConfigDialog()
'Une fois les paramètres modifiés, on recharge la scène
mnuRecharger_Click(sender, e)
End Sub
Private Sub mnuOuvrir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuOuvrir.Click
Me.Hide() 'On cache la fenêtre principale
'Affichage de la fenêtre de choix de la scène à charger
frmViewerload.ShowDialog()
If frmViewerload.bValide Then
'Si on a valider le choix.....
'On affiche la form d'attente
frmInfoLoad.Show()
frmInfoLoad.Refresh() 'nécessair pour afficher son contenu
Cursor = Cursors.WaitCursor 'juste pour la beauté
'timerRendu.Enabled = False 'on arrête le timer
DisposeNewton()
DisposeOgre() 'on libère les ressources Ogre
'on reinitialise les checkboxs
chkTracking.Checked = False
chkAxe.Checked = False
'on vide le treeview et on recrè les 3 noeuds de base
treeScene.Nodes.Clear()
treeScene.Nodes.Add("Root")
treeScene.Nodes.Item(0).Nodes.Add("Autres")
treeScene.Nodes.Item(0).Nodes.Add("Cameras")
treeScene.Nodes.Item(0).Nodes.Add("Lights")
treeScene.Nodes.Item(0).Nodes.Add("Entities")
'on vide les listes héritées de la forme de chargement pour le menu recharger
Me.lstRessources.Items.Clear()
Me.lstTypeRessources.Items.Clear()
Me.txtNomScene = frmViewerload.txtNomscene
'et on les remplit avec les nouvelles valeur
For i As Integer = 0 To frmViewerload.lstRessources.Items.Count - 1
Me.lstRessources.Items.Add(frmViewerload.lstRessources.Items(i))
Next
For i As Integer = 0 To frmViewerload.lstTypeRessources.Items.Count - 1
Me.lstTypeRessources.Items.Add(frmViewerload.lstTypeRessources.Items(i))
Next
'On recrè le scène manager
mySceneManager = myRoot.CreateSceneManager(SceneType.ST_GENERIC)
If frmViewerload.chkPhysique.Checked Then
mnuDetectionDeCollision.Checked = True
mnuGravite.Enabled = True
mnuDebugActif.Enabled = True
End If
'Affichage de la fenêtre de paramètres OGRES, le cas échéant
If frmViewerload.chkOgre.Checked Then
If Not myRoot.ShowConfigDialog Then
Exit Sub
End If
Else
If Not myRoot.RestoreConfig() Then
If Not myRoot.ShowConfigDialog Then
Exit Sub
End If
End If
End If
'Et on initialise la scène
Me.InitScene()
LoadAxe() 'On charge les axes
Me.InitTree(mySceneManager.RootSceneNode, Nothing) 'on remplit la treeview
'On détruit la form d'attente
frmInfoLoad.Hide()
frmInfoLoad.Dispose()
Cursor = Cursors.Default
Me.Show() 'et on réaffiche la fenêtre
'on libère la form de chargement
frmViewerload.Dispose()
'On démarre le timer pour le rendu et la gestion des touches
'timerRendu.Enabled = True
End If
End Sub
Private Sub mnuCouleurDuViewport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuCouleurDuViewport.Click
'on récupère le vieport
Dim myViewport As Mogre.Viewport = MyWindow.GetViewport(0)
'pour le passer en paramètre à la fenêtre de choix des couleurs
frmColorDialogue.myViewPort = myViewport
frmColorDialogue.Provenance = "Viewport"
'on l'affiche
frmColorDialogue.ShowDialog()
'et on la libère
frmColorDialogue.Dispose()
End Sub
Private Sub mnuRecharger_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuRecharger.Click
'Permet de recharger la scène en cours
Cursor = Cursors.WaitCursor
Me.Hide()
'On affiche la form d'attente
frmInfoLoad.Show()
frmInfoLoad.Refresh() 'nécessair pour afficher son contenu
'on arrête le timer
'timerRendu.Enabled = False
'on détruit nos différentes interfaces
DisposeNewton()
DisposeOgre()
treeScene.Nodes.Clear()
treeScene.Nodes.Add("Root")
'on recrè les noeuds de base du treeview
treeScene.Nodes.Item(0).Nodes.Add("Autres")
treeScene.Nodes.Item(0).Nodes.Add("Cameras")
treeScene.Nodes.Item(0).Nodes.Add("Lights")
treeScene.Nodes.Item(0).Nodes.Add("Entities")
'on initialise le scenemanager
mySceneManager = myRoot.CreateSceneManager(SceneType.ST_GENERIC)
'Et on initialise la scène
Me.InitScene()
LoadAxe() 'on charge les axes
Me.InitTree(mySceneManager.RootSceneNode, Nothing) 'on initialise le treeview
'On détruit la form d'attente
frmInfoLoad.Hide()
frmInfoLoad.Dispose()
Me.Show()
Cursor = Cursors.Default
'On démarre le timer pour le rendu et la gestion des touches
'timerRendu.Enabled = True
End Sub
Private Sub mnuAxeDuMonde_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuAxeDuMonde.Click
'permet de montrer/cacher l'axe du monde
If mnuAxeDuMonde.Checked Then
NodeAxeMonde.SetVisible(True)
Else
NodeAxeMonde.SetVisible(False)
End If
End Sub
Private Sub mnuOmbres_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuOmbres.Click
'Permet d'afficher ou pas les ombres on fonction de la technique choisie
If mnuOmbres.Checked Then
mySceneManager.ShadowTechnique = MyShadowTechnique
Else
mySceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_NONE
End If
End Sub
Private Sub mnuShadowType_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuShadowType.SelectedIndexChanged
'C'est un menu combbox pour la simple raison que le traitement du choix est simplifié (pas à se paluche les évènements de 6 menu, juste une sélection dans une combo)
Select Case mnuShadowType.SelectedIndex
Case 0
MyShadowTechnique = ShadowTechnique.SHADOWTYPE_STENCIL_MODULATIVE
Case 1
MyShadowTechnique = ShadowTechnique.SHADOWTYPE_STENCIL_ADDITIVE
Case 2
MyShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_MODULATIVE
Case 3
MyShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_ADDITIVE
Case 4
MyShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED
Case 5
MyShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED
End Select
'si le menu d'affichage des ombres est coché, on applique directe
If mnuOmbres.Checked Then
mySceneManager.ShadowTechnique = MyShadowTechnique
End If
End Sub
Private Sub mnuCouleurOmbres_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuCouleurOmbres.Click
'On passe les paramètre à la forme de choix des couleurs
frmColorDialogue.mySceneManager = mySceneManager
frmColorDialogue.Provenance = "Ombres"
'on l'affiche
frmColorDialogue.ShowDialog()
'et on la libère
frmColorDialogue.Dispose()
End Sub
Private Sub mnuLumireAmbiante_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuLumireAmbiante.Click
'On passe les paramètre à la forme de choix des couleurs
frmColorDialogue.mySceneManager = mySceneManager
frmColorDialogue.Provenance = "Ambiante"
'on l'affiche
frmColorDialogue.ShowDialog()
'et on la libère
frmColorDialogue.Dispose()
End Sub
Private Sub mnuDetectionDeCollision_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuDetectionDeCollision.Click
mnuOptions.HideDropDown()
If mnuDetectionDeCollision.Checked Then
mnuGravite.Enabled = True
'mnuGravite.Checked = True
mnuDebugActif.Enabled = True
mnuRecharger_Click(sender, e)
Else
mnuGravite.Enabled = False
mnuGravite.Checked = False
mnuDebugActif.Enabled = False
mnuRecharger_Click(sender, e)
End If
End Sub
Private Sub mnuDebugActif_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuDebugActif.Click
If mnuDebugActif.Checked Then
MogreNewt.Debugger.Instance.ShowLines(myWorld)
Else
MogreNewt.Debugger.Instance.HideLines()
End If
End Sub
Private Sub mnuHauteurCamera_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuHauteurCamera.TextChanged
'Permet de changer la hauteur de la caméra en temps réel
Try
If Not init Then
Me.CamSize.y = mnuHauteurCamera.Text
Me.CamNode.SetScale(Me.CamSize)
End If
Catch ex As Exception
End Try
End Sub
#End Region
#Region "Le treeview"
Private Sub treeScene_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles treeScene.AfterSelect
'si on est pas en cours de chargement de la scène initiale, on traite la sélection du treeview
If Not init Then
'on cache le groupe pour la gestion de la lumière
grpLumiere.Visible = False
'on est en cours de sélection d'un objet donc :
EnCoursDeSelection = True
'chkAxe.Checked = False
If Not SceneNodeSelected Is Nothing Then 'si le scenenodeselected précédent n'est pas vide, on cache sa bounding box
SceneNodeSelected.ShowBoundingBox = False
End If
Try
Dim tree As TreeView = sender 'on récupère le sender dans un objet typé (plus pratique pour coder
SceneNodeSelected = tree.SelectedNode.Tag 'on récupère le scenenode dans le tag du treenode
Dim ObjectType As String 'pour le test du type d'objet sélectionné
Try
MObjectSelected = SceneNodeSelected.GetAttachedObject(tree.SelectedNode.Name) 'on récupère l'objet contenu dans le scenenode
Catch
End Try
If Not e.Node.Text.ToUpper.Contains("ROOT") Then 'si on est pas sur root, alors :
Try
ObjectType = MObjectSelected.MovableType 'on récupère le type de l'objet
Select Case ObjectType
Case "Entity" 'si c'est une entity
chkTracking.Checked = False
chkTracking.Enabled = True
grpParamObjet.Enabled = True
Case "Camera" 'si c'est une caméra
grpParamObjet.Enabled = False
myCamera = mySceneManager.GetCamera(MObjectSelected.Name) 'on récupère son nom
Dim ViewPort As Mogre.Viewport = MyWindow.GetViewport(0) 'on récupère le premier viewport
ViewPort.Camera = myCamera 'et on change de caméra
Case "Light" 'si c'est une lumière
grpLumiere.Visible = True
grpParamObjet.Enabled = True
chkTracking.Checked = False
chkTracking.Enabled = True
LightSelected = MObjectSelected
'on paramètre les picturesbox représentant la couleur de la lumière avec ses couleurs, justement
picDiffuse.BackColor = Color.FromArgb(LightSelected.DiffuseColour.GetAsARGB())
picSpecular.BackColor = Color.FromArgb(LightSelected.SpecularColour.GetAsARGB())
'et les trackbar pour régler l'atténuation
trkRange.Value = LightSelected.AttenuationRange * 100
trkConstant.Value = LightSelected.AttenuationConstant * 100
trkLinear.Value = LightSelected.AttenuationLinear * 100
trkQuadratic.Value = LightSelected.AttenuationQuadric * 100
End Select
grpParamObjet.Text = "Modifications objet : " + SceneNodeSelected.Name
Catch ex As Exception
'si on est en erreur, on désactive tout
chkTracking.Checked = False
chkTracking.Enabled = True
grpLumiere.Visible = False
grpParamObjet.Enabled = False
End Try
Try
'on montre la bounding box de l'objet sélectionné
SceneNodeSelected.ShowBoundingBox = True
Catch ex As Exception
End Try
RemplitGrille() 'on remplit la grille de paramètres de l'objet
EnCoursDeSelection = False 'la sélection est terminée
If ShowAxes Then
chkAxe.Checked = True 'si on doit montrer l'axe de l'objet, on le fait
End If
If TrackObjet Then
chkTracking.Checked = True 'si l'autotrackin est actif, alors on le remet
End If
End If
Catch ex As System.Runtime.InteropServices.SEHException
'en cas d'erreur....on ne fait rien de spécial
End Try
End If
End Sub
Private Sub treeScene_BeforeSelect(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles treeScene.BeforeSelect
'Si l'axe de l'objet est affiché
If ShowAxes Then
chkAxe.Checked = False 'on va déclencher l'évènement changed de la checkbox
End If
If TrackObjet Then ' on fait pareil pour l'autotracking
chkTracking.Checked = False
End If
End Sub
#End Region
#Region "Les check box"
Private Sub chkTracking_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkTracking.CheckedChanged
'Permet d'activer/désactiver l'autotracking de l'objet sélectionné par la caméra
Try
myCamera.SetAutoTracking(False)
If chkTracking.Checked Then
myCamera.SetAutoTracking(True, SceneNodeSelected)
End If
Catch ex As Exception
End Try
End Sub
Private Sub chkAxe_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkAxe.CheckedChanged
'Permet de montrer/cacher l'axe de l'objet sélectionné
If Not EnCoursDeSelection Then 'si on est pas en cours de sélection de l'objet
Try
If chkAxe.Checked Then
'Lorsque la case est cochée
mySceneManager.RootSceneNode.RemoveChild(NodeAxe) 'on détache l'axe de la racine
SceneNodeSelected.AddChild(NodeAxe) 'on l'attache à l'objet sélectionnée
NodeAxe.SetPosition(0, 0, 0) 'au centre de ce dernier
NodeAxe.SetOrientation(SceneNodeSelected.Orientation.w, SceneNodeSelected.Orientation.x, SceneNodeSelected.Orientation.y, SceneNodeSelected.Orientation.z) 'et avec l'orientation de ce dernier
NodeAxe.SetVisible(True) 'et on le montre
Else
'lorsque la case est décochée, on cache le Node de l'axe
NodeAxe.SetVisible(False)
SceneNodeSelected.RemoveChild(NodeAxe) 'on l'enlève de l'objet sélectionné
mySceneManager.RootSceneNode.AddChild(NodeAxe) 'et on l'attache à la racine
End If
Catch
'Juste au cas ou...
End Try
End If
End Sub
Private Sub chkAxe_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkAxe.Click
'On inverse simplement la variable permettant de savoir si on affiche ou pas l'axe des objets
ShowAxes = Not ShowAxes
End Sub
Private Sub chkTracking_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles chkTracking.Click
'On inverse simplement la variable permettant de savoir si on est en autotracking des objets
TrackObjet = Not TrackObjet
End Sub
#End Region
#Region "La grille"
Private Sub grdDetail_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles grdDetail.CellDoubleClick
'Lors d'un double clique sur les cellules de la grille, on permet le choix sur boundingbox et visible (les autres valeurs sont modifiée par les champs en entête de la form
Dim rectangle As New System.Drawing.Rectangle 'le rectangle correspondant à la cellule sélectionnée
Dim Cell As DataGridViewCell = sender.currentcell 'on récupère la cellule sélectionnée
Dim Row As DataGridViewRow = sender.rows(Cell.RowIndex) 'la ligne sélectionnée
Dim FirstCell As DataGridViewCell = Row.Cells(0) 'La première cellule
rectangle = Me.grdDetail.GetCellDisplayRectangle(Cell.ColumnIndex, Cell.RowIndex, True) 'on paramètre le rectangle
If Cell.Value = "Oui" Then 'suivant la valeur de la cellule, on paramètre la combobox
Me.cboBoolean.SelectedIndex = 0
Else
Me.cboBoolean.SelectedIndex = 1
End If
'on positionne et dimmensionne la combobox pour l'afficher dans la cellule
Me.cboBoolean.Top = rectangle.Top
Me.cboBoolean.Left = rectangle.Left
Me.cboBoolean.Width = rectangle.Width
Me.cboBoolean.Height = rectangle.Height
Me.cboBoolean.Tag = FirstCell.Value 'pour savoir sur quel paramètre de la grille on travail (cf. cboBoolean.SelectedIndexChanged)
'et on la montre
Me.cboBoolean.Visible = True
End Sub
#End Region
#Region "Les Command Buttons"
Private Sub cmdSetDirection_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSetDirection.Click
'Permet de fixer la direction de l'objet en fonction des 3 champs textes
SceneNodeSelected.SetDirection(txtDirectionX.Value, txtDirectionY.Value, txtDirectionZ.Value)
GetOrientation() 'pour afficher les nouvelles valeurs
End Sub
Private Sub cmdPitch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPitch.Click
'On tourne sur X
SceneNodeSelected.Pitch(txtRotationX.Value)
'Si l'axe est affiché, même punition. Réaction bizarre si la vaiable inheritorientation est mise à true.
If ShowAxes Then
NodeAxe.Pitch(txtRotationX.Value)
End If
GetOrientation() 'on affiche la nouvelle orientation
End Sub
Private Sub cmdYAw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdYAw.Click
'cf. cmdPich_Click sauf que c'est sur Y
SceneNodeSelected.Yaw(txtRotationY.Value)
If ShowAxes Then
NodeAxe.Yaw(txtRotationY.Value)
End If
GetOrientation()
End Sub
Private Sub cmdRoll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRoll.Click
'cf. cmdPich_Click sauf que c'est sur Z
SceneNodeSelected.Roll(txtRotationZ.Value)
If ShowAxes Then
NodeAxe.Roll(txtRotationZ.Value)
End If
GetOrientation()
End Sub
Private Sub cmdResetOrientation_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdResetOrientation.Click
'Permet de mettre l'objet dans sa direction de création, avant toute rotation
SceneNodeSelected.ResetOrientation()
GetOrientation()
End Sub
Private Sub cmdSetorientation_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSetorientation.Click
'Permet de ficer l'orientation de l'objet en fonction des 4 paramètre choisis
SceneNodeSelected.SetOrientation(txtOrientationW.Value, txtOrientationX.Value, txtOrientationY.Value, txtOrientationZ.Value)
End Sub
Private Sub cmdResetEtat_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdResetEtat.Click
'Permet de réinitialiser l'objet à ses conditions d'origine
EnCoursDeSelection = True
SceneNodeSelected.ResetToInitialState()
'on récupère les nouvelles valeurs pour les afficher
GetPosition()
GetOrientation()
GetEchelle()
EnCoursDeSelection = False
End Sub
Private Sub cmdSetTranslation_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSetTranslation.Click
'Permet de déplacer l'objet en fonction de l'axe choisi
Dim Axe As Mogre.Node.TransformSpace
EnCoursDeTranslation = True 'on commence la translation
'On récupère l'axe choisi dans la combobox
Select Case cboTransAxe.SelectedIndex
Case 0
Axe = Node.TransformSpace.TS_LOCAL
Case 1
Axe = Node.TransformSpace.TS_PARENT
Case 2
Axe = Node.TransformSpace.TS_WORLD
End Select
'et on translate en fonction des paramètres sélectionés
SceneNodeSelected.Translate(txtTransX.Value, txtTransY.Value, txtTransZ.Value, Axe)
GetPosition() 'on récupère la nouvelle position
EnCoursDeTranslation = False 'la translation est terminée
End Sub
Private Sub cmdReinitCamera_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdReinitCamera.Click
'Pour réinitialiser la caméra à sa position d'origine
If mnuDetectionDeCollision.Checked Then
CamBody.SetPositionOrientation(InitialCamBodyPos, InitialCamBodyOrient)
Else
myCamera.SetPosition(InitialCamBodyPos.x, InitialCamBodyPos.y, InitialCamBodyPos.z)
myCamera.Orientation = InitialCamBodyOrient
End If
End Sub
#End Region
#Region "Les ComboBox"
Private Sub cboBoolean_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboBoolean.SelectedIndexChanged
'Si la combobox est visible, alors on est en tains de choisir l'option
If cboBoolean.Visible Then
If cboBoolean.Tag = "Visible" Then 'si ça porte sur la visibilité de l'objet
If cboBoolean.SelectedIndex = 0 Then
MObjectSelected.Visible = True
Else
MObjectSelected.Visible = False
End If
ElseIf cboBoolean.Tag = "CastShadows" Then 'sur sa faculté à projeter une ombre
If cboBoolean.SelectedIndex = 0 Then
MObjectSelected.CastShadows = True
Else
MObjectSelected.CastShadows = False
End If
Else 'alors c'est la boundingbox
If cboBoolean.SelectedIndex = 0 Then
SceneNodeSelected.ShowBoundingBox = True
Else
SceneNodeSelected.ShowBoundingBox = False
End If
End If
cboBoolean.Visible = False 'on cache la combobox
RemplitGrille() 'et on reremplit la grille
End If
End Sub
#End Region
#Region "Les trackbars"
Private Sub trkRange_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles trkRange.ValueChanged
'Modification de la portée de la lumière
lblRange.Text = trkRange.Value
LightSelected.SetAttenuation(trkRange.Value, trkConstant.Value / 100, System.Math.Round(trkLinear.Value / 10000, 5), System.Math.Round(trkQuadratic.Value / 10000, 5))
'Les valeurs sont divisée pour s'accorder au range des paramètres. A affiner, pour voir plus ou moins d'effets
End Sub
Private Sub trkConstant_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles trkConstant.ValueChanged
'La constante d'atténuation
lblConstant.Text = trkConstant.Value / 100
LightSelected.SetAttenuation(trkRange.Value, trkConstant.Value / 100, System.Math.Round(trkLinear.Value / 10000, 5), System.Math.Round(trkQuadratic.Value / 10000, 5))
'Les valeurs sont divisée pour s'accorder au range des paramètres. A affiner, pour voir plus ou moins d'effets
End Sub
Private Sub trkLinear_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles trkLinear.ValueChanged
'La linéarité de l'atténuation
lblLinear.Text = System.Math.Round(trkLinear.Value / 10000, 5)
LightSelected.SetAttenuation(trkRange.Value, trkConstant.Value / 100, System.Math.Round(trkLinear.Value / 10000, 5), System.Math.Round(trkQuadratic.Value / 10000, 5))
'Les valeurs sont divisée pour s'accorder au range des paramètres. A affiner, pour voir plus ou moins d'effets
End Sub
Private Sub trkQuadratic_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles trkQuadratic.ValueChanged
'La valeur Quadratic (Pas tout compris là...)
lblQuadratic.Text = System.Math.Round(trkQuadratic.Value / 10000, 5)
LightSelected.SetAttenuation(trkRange.Value, trkConstant.Value / 100, System.Math.Round(trkLinear.Value / 10000, 5), System.Math.Round(trkQuadratic.Value / 10000, 5))
'Les valeurs sont divisée pour s'accorder au range des paramètres. A affiner, pour voir plus ou moins d'effets
End Sub
#End Region
#End Region
End Class
Conclusion :
Attention, la source ci-dessus n'est pas utilisable tel quel, vous devez télécharger le projet pour celà.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.