2012-05-12 5 views
2

J'essaie de faire un jeu 3D WP7 dans XNA en dessinant des modèles constitués de lignes, en utilisant DrawUserIndexedPrimitives Tout cela fonctionne très bien, mais maintenant je veux donner à chaque modèle sa propre rotation. Actuellement j'utilise un BasicEffect pour dessiner tous les modèles. Je peux définir sa rotation, mais tous les objets auront la même rotation. Est-il possible de définir une rotation différente pour chaque objet? Je suis venu en avec quelques solutions que je pourrais utiliser, mais je ne suis pas satisfait de l'un d'eux:XNA pour WP7 jeu: DrawUserIndexedPrimitives

  • Créer une nouvelle BasicEffect pour chaque objet, avec son propre monde, puis boucle sur tous les objets pour obtenir leur effet de base et le dessiner - je suppose que tous ces BasicEffects créeraient beaucoup de surcharge, et je veux séparer l'effet des modèles.
  • Faire le calcul des points moi-même (c'est-à-dire calcluler la rotation et passer ces valeurs à la méthode DrawUserIndexedPrimitives) - C'est un calcul assez coûteux, qui fait beaucoup baisser la performance.

Y a-t-il une voie suggérée à prendre ici?

Je ne sais pas si DrawUserIndexedPrimitives est la meilleure méthode à utiliser, je veux juste pouvoir dessiner des lignes et leur donner une rotation. S'il y a une meilleure façon de le faire, s'il vous plaît me dire :)

Ma solution actuelle:

protected override void Draw(GameTime gameTime) 
{ 
    GraphicsDevice.Clear(Color.Black); 

    foreach (var model in _models) 
    { 

     foreach (var pass in model.Effect.CurrentTechnique.Passes) 
     { 
      pass.Apply(); 
      model.Effect.World = _model.GetWorld(); 

      var points = model.GetPoints(); 
      GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.LineList, points, 0, points.Length, model.Lines, 0, model.Lines.Length/2); 

      _models[0].Draw(GraphicsDevice); 
     } 
    } 

    base.Draw(gameTime); 
} 

model.GetWorld() retourne une matrice avec la rotation, la translation et à l'échelle de l'objet, le modèle. GetPoints() une liste avec les points et model.Lines est une liste avec les indices des points connectés

Répondre

2

Vous avez généralement besoin d'un type d'effet quelconque (tel que BasicEffect). La raison en est que les effets se composent de deux choses principales: le code écrit pour le GPU (éclairage, etc) et les paramètres qu'il expose (comme Effect.World, la matrice du monde). Il ne serait pas très utile de compiler le code GPU plus d'une fois car il sera le même à chaque fois, donc la seule autre chose que nous devons considérer est les paramètres.

Notez l'appel à passer.Appliquer(). Ce que cela fait réellement est de télécharger tous les paramètres que vous avez définis sur l'effet à la GPU chaque fois avant de dessiner. Ce que nous devrions vous dire, c'est que vous devriez pouvoir régler la rotation sur un seul effet juste avant chaque tirage et appeler Appliquer, au lieu de créer un tas d'effets avec des rotations réglées individuellement. De plus, la définition de Effect.World devrait en fait précéder la pass.Apply().

Pour répondre au deuxième point, vous avez totalement raison. Le GPU est fait pour effectuer des transformations sur des points avec un parallélisme massif, il est donc préférable de ne pas l'essayer vous-même car il sera lent. Comme pour DrawUserIndexedPrimitives, je ne suis pas un buffeur graphique, mais généralement cet appel est réservé aux situations où vos sommets changent constamment (comme un blob ou un chiffon doux), essentiellement où vous ne pouvez pas décrire le maillage par juste des traductions, des rotations et des échelles. Le GPU expose des primitives spéciales appelées VertexBuffer, dont le but entier est de stocker un tas de points dans la mémoire GPU (ce qui les rend très rapidement accessibles). De là, si vous voulez le déplacer, le GPU transformera chaque point (mais notez que tout ce dont vous avez besoin pour le passer est la translation, la rotation, et l'échelle et c'est bon à faire). Utiliser DrawUserIndexedPrimitives doit envoyer tous les points au GPU à chaque frame, ce qui est plus lent (de combien, qui sait sans tester ces jours-ci).Par chance, la carte graphique implémente en fait un mode de dessin spécial appelé «Wireframe» qui, au lieu de tracer des triangles, dessine simplement les bords des triangles comme des lignes. Pour régler le mode wireframe, faites ceci avant d'appeler Draw:

this.GraphicsDevice.RasterizerState.FillMode = FillMode.WireFrame; 

Maintenant, en termes d'application de votre propre rotation, tout ce que vous avez réellement besoin de faire est de multiplier la matrice du monde par une matrice de rotation (utiliser quelque chose comme Matrix.CreateRotationX (yourAngle)).

0

Votre solution actuelle est très bien, mais je le ferais monde THW assigner avant la pass.Apply()

Si vous avez quelques modèles que vous pouvez passer au shader et tableau avec les transforme, et ajoutez à votre sommet structure un index pour ce tableau.

De cette façon, vous pouvez dessiner tout votre modèle en une seule passe.