1

Bonjour,
Voila mon problème : je crée un model 3D à partir d'une image 2D. Plusieurs images 2D en fait, mais ce n'est pas le sujet de ce post.
Apparement, (car je ne peux les compter, il y en a plusieurs milliers), je n'ai que 1 triangle sur deux qui s'affiche.

Je dois avouer que comme je découvre D3D, je n'en comprend pas tout.
Par exemple, pour afficher un triangle :
- J'ai besoin de 3 points. Mais avec D3D j'envois tout mes points, et il doit trouver tous seul quels sont les triangles? Comment fait-il?

- J'ai besoin d'un "sens", je veux dire que le triangle ABC et le triangle CBA sont différents car orientés différement. Avec D3D je ne vois pas cette notion. (sauf peut-être dans PerspectiveFovLH mais je n'y entend rien)
D'ailleurs puisque mon model n'affiche qu'un triangle sur deux, je dois dire que le resultat visuel ressemble un problème de ce type.

2

Juste comme ça je te conseillerais de commencer par lire la documentation de Direct3D qui répond précisément à toutes les questions que tu pose...
D'ailleurs au niveau de ce que tu demandes le fonctionnement est exactement le même pour OpenGL.

Sinon, tu balance des points à D3D, mais tu lui dis également comment les interpréter, c'est toi qui choisit.
Globalement triangle list (ok mais pas le plus efficace en général (plus souvent rentable lors d'utilisation d'indices)), triangle strip (rox) ou triangle fan (sux). Comme c'est disponible dans la documentation je te laisse aller voir ça.

Le sens c'est simple, c'est sens direct (CBA), ou sens indirect (ABC). Tu choisis quelles faces afficher, et quelles faces masquer avec le paramètre de culling. Mais le sens c'est avant tout toi qui le donne à tes triangles, D3D n'a pas grand chose à voir là dedans (enfin éventuellement au niveau du repère utilisé, mais c'est le bout du monde) et il ne fait qu'utiliser les données que tu lui fournis.

Et oui, si ton modèle n'affiche qu'un triangle sur deux tu as certainement un problème de culling. Je dirais donc que tu utilises des triangle list, et que tu as simplement mal généré ton modèle (le backface culling permet de gagner pas mal de performances dans bon nombre de cas) vu que les triangle strip n'ont pas ce problème. Tu peux désactiver le backface culling si nécessaire, mais c'est le mal. Et le mal c'est pas bien !

avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

3

Effectivement, je n'ai pas lu la doc, juste des tuto. Je suis un peu fainéant.

Je vais tenter de désactiver le backface culling (temporairement) afin de voir si mon problème est bien le culling.
Merci.

4

Aïe, il était déja desactivé. (device.RenderState.CullMode = Cull.Nonewink
Ce doit être un problème de géometrie donc...

5

Tu utilises quoi pour afficher ton modèle ? Triangle lists ou triangle strips ?
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

6

Triangle list.
Et ma routine de rendu est archi-classique, je suis quasi certain qu'il n'y a pas de d'erreur :
public void Render()
{
if (device != null)
{
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);

device.BeginScene();

device.SetStreamSource(0, VBuffer, 0);

device.VertexFormat = CustomVertex.PositionTextured.Format;

setTexture(myTexture);

device.DrawPrimitives(PrimitiveType.TriangleList, 0, nb_vertice/3);

// No geometric transformation
device.Transform.World = Matrix.Identity;

Rotate();

Scale();

setViewPoint();

// Perspective adjust
device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 0.0f, 800.0f);

device.EndScene();

device.Present();
} }

7

Et à quoi correspond ta variable nb_triangle ? C'est le nombre de points ou le nombre de triangles ?
Sinon juste une petite astuce, tu n'es pas obligé de recréer puis réassigner la matrice de projection à chaque frame...
D'ailleurs les matrices devraient plutôt être assignées en début de rendu, sinon elles n'auront d'influence qu'à la frame suivante tongue
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

8

Je m'attendais à cette question, c'est le nombre de points, je viens de le modifier dans mon code.
Merci pour les astuces, je vais modifier ça aussi.

9

Puisque tu sembles connaitre D3D, tu peux me donner une autre astuce, stp?
Je passe par 2 tableaux pour créer mon VertexBuffer, car pour le créer j'ai besoin de sa taille, et je n'ai pas trouvé comment faire.
Voila le morceau de code, c'est justement celui ou je crée le model, tu trouvera peut-être pour mon problème d'affichage.
Désolé de balancer du code comme ça, (surtout sans l'indentation) mais je cherche depuis un moment.
private void createBox()
{
//myTexture = Texture.FromBitmap(device, TextureImage, 0, Pool.SystemMemory); // the good texture, but not working yet

myTexture = TextureLoader.FromFile(device, @"white.png"); // Application.StartupPath + "\texture.bmp");

ArrayList VertexBuffer = new ArrayList();

int step = 1;
for (int y = step; y < YRES; y += step)
{
for (int x = step; x < XRES; x += step)
{
float planephase = 0.5f - (y - besty) / avgd;
if (_var[y][x] == -1)
{
VertexBuffer.Add(createVertex1(x - bestx, y - besty, (_wrapphase[y][x] - planephase) * zscale, x, y));
}

planephase = 0.5f - (y - step - besty) / avgd;

if (_var[y - step][x - step] == -1)
{
VertexBuffer.Add(createVertex1(x - step - bestx, y - step - besty, (_wrapphase[y - step][x - step] - planephase) * zscale, x, y));
}
}
}
nb_vertice = VertexBuffer.Count;
VBuffer = new VertexBuffer(typeof(CustomVertex.PositionTextured),
VertexBuffer.Count,
device,
Usage.WriteOnly,
CustomVertex.PositionTextured.Format,
Pool.Default);

CustomVertex.PositionTextured[] arrayVertices = (CustomVertex.PositionTextured[])VBuffer.Lock(0, 0);

for (int i = 0; i < VertexBuffer.Count; i++)
{
arrayVertices[i] = (CustomVertex.PositionTextured)VertexBuffer[i];
}
VBuffer.Unlock(); }

10

Donc en regardant le code j'en déduis que tu utilises Managed DirectX en C# tongue
Déjà pour le ArrayList: c'est une limitation volontaire au C# 1.0 (.NET 1.0 -> .NET 1.1) ? Car un List<CustomVertex.PositionTextured> (en C# 2.0 / .NET 2.0) serait largement plus efficace.
Pour la taille d'un vertex buffer ensuite c'est simple, c'est taille d'un point en octets * nombe de points.
Et le nombre de points ben c'est à toi de le calculer tongue
A priori dans ton code c'est un truc incalculable ? (Bon je ne sais pas ce qu'est sensé faire ton code non plus)
Enfin par calculable, je veux dire avec une formule toute bete, pas une boucle for wink

Bon après si tu as un problème de génération des triangles ça peut venir de cette fonction, de ta variable _var (trifus) ou de ta fonction createVertex1 (mais peu de chances même si je n'ai pas vu le code à l'intérieur) mais je ne saurais t'en dire plus grin

Sinon [code]Application.StartupPath + "\texture.bmp"[/code] c'est le mal [code]System.IO.Path.Combine(Application.StartupPath, "texture.bmp")[/code] c'est le bien !
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

11

Son code n'est de toute façon pas portable s'il utilise Direct X, donc ça sert à quoi de passer par System.IO.Path.Combine?
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

12

Parce que en plus de la portabilité, ça gère automatiquement le fait de rajouter \ (ou /) si il y a besoin, et de ne pas le rajouter s'il n'y a pas besoin ?
Parce que la fonction vérifie que tu utilises des noms de répertoires / fichiers à peu près valide ?
Parce qu'il n'y a aucun intérêt à produire un code sale là où une alternative propre existe à un cout moindre ?

De plus je te signale qu'il n'est pas impossible (je n'ai pas dit facile) de produire un assembly Managed DirectX, ou un assembly XNA, se basant sur OpenGL à l'intérieur, ce qui rend ton argument de non portabilité tout pourri, hmmm... tout pourri en fait.
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

13

Ok, thx.
Ca ne peux pas venir de fonction createVertex1 car c'est ça :
private CustomVertex.PositionTextured createVertex1(int x, int y, float z, int tu, int tv)
{
return new CustomVertex.PositionTextured(new Vector3(x, y, z), tu, tv); }

Ca peut paraitre étrange de faire une fonction pour ça, mais je risque d'utiliser PositionNormalTextured à la place de PositionTextured, et cela sera plus simple.

Je vais vérifier la création de _var[][] car je suis un peu à cours d'idées.

Pour Application.StartupPath + "\texture.bmp" rassure toi, je ne compte pas l'utiliser, ma texture est normalement generée par le code.
Je n'arrive pas encore à l'utiliser sans la sauver et utiliser fromFile. J'ai fais un essais avec fromStream, sans succès, et sans chercher car je mets ça de côté, en attendant de resoudre mon problème de géométrie.

14

Pas de problème de portabilité de toute façon, ce code marche très bien en C++ et JAVA. wink

15

Tant que c'est du DirectX, ce n'est pas portable. Il n'y a pas qu'un seul système d'exploitation au monde.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

16

avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

17

J'ai trouvé mon problème : je devais utiliser triangle.Strips plutôt que triangle.Lists.
J'avais essayé et je n'obtenais que le haut du modèle, mais ça marche si j'enlève le " /3 " de device.DrawPrimitives(PrimitiveType.TriangleList, 0, nb_vertice/3);

J'ai un doute sur le fait que j'ai un triangle pour 3 points avec triangle.strips. Apparement je peux avoir 2 triangles avec 4 points, c'est ça?

18

C'est 3 points pour le premier triangle et un seul pour les suivants, c'est à dire nombre de points - 2. Mais tu devrais vraiment regarder la documentation, c'est expliqué tongue
(Par contre si tu enlèves le /3 tu as un bug, tu lui dis de dessiner deux triangles de plus que ce que tu as réellement, le matériel/les driver ont tendance à laisser passer ce genre de choses sans broncher mais ça provoque assez souvent des bugs sournois plus tard)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

19

Effectivement avec nb_vertice-2 j'ai un bug en moins (un triangle où il ne faut pas).
Merci !

20

Je profite de ce topic pour poser une question bête :
Je voudrais effectuer une rotation en X et Y, mais seulement lorsque je fait un click gauche + déplacement de la souris. Donc un fonctionnement comme dans les logiciels de modelisation 3D. Je fais :
private void Rotate()
{
MouseState mouseStateData = mouseInputDevice.CurrentMouseState;
Byte[] MouseButtons = mouseStateData.GetMouseButtons();
oldX = X;
oldY = Y;
if (MouseButtons[0 ] != 0 && MouseIn) // MouseIn = true si la souris est dans le picturebox
{
X = ScreenPictureBox.PointToClient(MousePosition).X - oldX; // PointToClient pour récuperer la position relative dans le control picturebox
Y = ScreenPictureBox.PointToClient(MousePosition).Y - oldY;

rotX = (float)(-HALFPI + (Y / (float)ScreenPictureBox.Height) * Math.PI);
rotY = (float)(-HALFPI + (X / (float)ScreenPictureBox.Width) * Math.PI);
}
device.Transform.World = Matrix.RotationX(rotX) * Matrix.RotationY(rotY) * Matrix.RotationZ(0); }
Mais ça ne marche pas : soit l'image se dédouble (cas avec ce code), soit l'image se remet dans une position calculée par rapport à l'endroit ou je clique dans l'image.
J'ai beau chercher, c'est pourtant un problème logique, mais je sèche.

21

Bah ici c'est simple, ton image se "dédouble" parce que tu confonds coordonnée absolue et relative.
Vu le code je dirais que tu appelles cette fonction à chaque image, du coup tu passes d'une coordonnée absolue (relative à 0) à une coordonnée relative (par rapport à l'ancien X, donc 0 la plupart du temps).
Tu utilises oldX comme une coordonnée absolue (ligne 10), mais X comme une coordonnée relative (ligne 10), pourtant tu commences (ligne 5) par oldX = X, il y a incohérence wink
En réalité ce que tu peux faire (il n'y a pas qu'une manière de faire), c'est de sauvegarder en dehors de la fonction les coordonnées absolues et utiliser pour le calcul les coordonnées relatives.
De même tu ne dois pas calculer un angle de rotation "absolu" mais une valeur relative que tu ajoutes à l'ancienne, afin que la position du modèle ne soit pas déterminée par le pixel sur lequel tu clique tongue (Je sais pas si je suis clair)

oldX = mouseX; oldY = mouseY;
A priori donc un truc de ce genreint deltaX, deltaY, mouseX, mouseY;
float deltaRotX, deltaRotY;

// Lire position souris dans mouseX, mouseY

deltaX = mouseX -  oldX;
deltaY = mouseY -  oldY;

// Calculer deltaRotX, deltaRotY en fonction de deltaX, deltaY

rotX += deltaRotX;
rotY += deltaRotY;
Avec un truc comme ça tout est relatif au dernier point survolé par la souris, mais c'est aussi possible de faire par rapport au clic d'origine.

Après, question optimisation, essaye de ne pas apeller deux fois de suite PointToClient et plutôt de sauvegarder le résultat du premier appel tongue

Sinon ce que tu essayes de faire s'apparente à un arcball, même si le principe n'est pas le même (je te laisse te documenter via google), ça t'intéressera peut être d'y jeter un oeil happy
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

22

Je ne vois pas comment calculer deltaRotX et deltaRotY , tout ce que je fais me donne le même resultat : l'image saute à une autre position lorsque je clique.
J'ai essayé ça, et d'autres variantes :
deltaRotX = (deltaX - rotX) / ScreenPictureBox.Width;
deltaRotY = (deltaY - rotY) / ScreenPictureBox.Height;

Je vais y réflechir, avec tes explications je vais bien finir par trouver.
Merci de ton aide.

23

ça ne fonctionnait pas avec la formule de ton algo de départ ?
En tout cas celle que tu as là est complètement fausse: tu mélanges une coordonnée (relative) avec un angle (absolu) grin

En théorie, tu définis un angle sur la largeur de ta fenêtre (ce que tu avais fait au départ) et tu fais une bête proportionnalité:
Donc ici un simple deltaRotX = (float)(Math.PI * deltaX / ScreenPictureBox.Width); devrait fonctionner.
Si la souris bouge vers la gauche tu as un écart négatif, et vers la droite un écart positif, ce qui entraine soit une augmentation de l'angle de rotation total, soit une diminution, ça ne peut pas rater ^^
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

24

Hello,
J'ai repris ce projet, et je bloque à nouveau:

Je calcule un nouveau modèle et une nouvelle texture pour quasi-chaque frame.
Ce calcul est un peu long, et est donc appelé dans un autre thread.

Une fois que mon nouveau modèle est crée, j'appelle "render()", cf. mon post ./6 (Il a peu évolué depuis).
Mais ça clignote, je pense que j'en fais trop.

Que dois-je rappeler une fois que mon nouveau modèle est crée?

Merci d'avance.

Edit : c'est bon j'ai résolu mon problème.