GDI+D: Scène 3D interactive

Soyez le premier à donner votre avis sur cette source.

Vue 1 293 fois - Téléchargée 205 fois

Description

[Version avec image de capture qui remplace celle du 21.01.2018]

Bonjour,

Sous Windows, on peut programmer une représentation graphique non triviale en utilisant "que" GDI (Graphics Device Interface).
Il est bien entendu que le plus souvent, il vaut mieux étudier, installer et utiliser des librairies graphiques plus évoluées telles que OpenGL, DirectX, etc.

La scène 3D interactive construite ici devrait permettre de:
- Tourner un objet librement autour de son axe 3D vertical Z.
- Basculer (incliner) l'objet en bas ou en haut (par rapport à l'écran).
- Déplacer l'œil (perpendiculairement à l'écran) pour modifier l'effet de perspective.
- Agrandir ou rétrécir l'image 2D projetée (zoom 2D intelligent) avec la roulette.
- Déplacer l'image 2d obtenue (move 2D) avec bouton gauche de la souris.
- Modifier interactivement un paramètre de l'objet représenté (Damier).
- Obtenir une séquence de dessins sans scintillement.
- Modifier les dimensions de la fenêtre.

Elle est basés principalement sur "GDI+C: Dessin sans scintillement" et sur l'édification de la perspective qui suit.

Transformation (perspective) en notation matricielle

Projection 3D->2D:
       Basculement (rotX)         (rotZ)
(x')   (1   0       0   )   (cos(a) -sin(a) 0)   (x)
(y') = (0 cos(b) -sin(b)) * (sin(a)  cos(a) 0) * (y)
(z')   (0 sin(b)  cos(b))   (  0       0    1)   (z)

       (       cos(a)       -sin(a)       0)   (x)   (XX XY  0)   (x)
     = (cos(b)*sin(a) cos(b)*cos(a) -sin(b)) * (y) = (YX YY YZ) * (y)
       (sin(b)*sin(a) sin(b)*cos(a)  cos(b))   (z)   (ZX ZY ZZ)   (z)

Perspective: q = d/(d+y');  U = q*x';  V = q*z'; // W = q*y';

Avec la transformation 2D->2D (layout, mise en page):
       u = U0 + Dil*U; v = V0 + Dil*V;

struct Persp {
  const float DegToRad=0.01745329f;
  float D,XX,XY,YX,YY,YZ,ZX,ZY,ZZ; // XZ=0: vertical reste vertical

  void Def(float d,float az,float ab) {// az,ab: en degrés (°)
    float rz=az*DegToRad,rx=-ab*DegToRad; // en rad
    float sa=sinf(rz),ca=cosf(rz),sb=sinf(rx),cb=cosf(rx);
    D=d; XX=ca; XY=-sa;
    YX=cb*sa; YY=cb*ca; YZ=-sb;
    ZX=sb*sa; ZY=sb*ca; ZZ=cb;
  }
};

Nous choisissons ici un objet simple et "plat", adapté aux différentes étapes du programme:
struct Damier {
  int N=0,NN;
  float *C,*U,*V; // *W pas utilisé

  void Def(int n) { // Damier carré n*n centré à l'origine (n>0)
    if ((n<=0)||(n==N)) return;
    if (N>0) {free(C); free(U); free(V);}
    N=n; NN=(n+1)*(n+1);
    int m=NN*sizeof(float);
    C=(float*)malloc((n+1)*sizeof(float));
    U=(float*)malloc(m); V=(float*)malloc(m); // W=(float*)malloc(m);
    float d=200.0f/n,c=-100.0f;
    for (int i=0; i<n; ++i,c+=d) C[i]=c;
    C[n]=100.0f;
  }
  void Transf(Persp* psp) {
    for (int j=0,k=0; j<=N; ++j) {float y=C[j];
      for (int i=0; i<=N; ++i,++k) {
        float x=C[i],q=psp->D/(psp->D+psp->YX*x+psp->YY*y);
        U[k]=q*(psp->XX*x+psp->XY*y); V[k]=q*(psp->ZX*x+psp->ZY*y);
      }
    }
  }
  void Draw(HDC hdc,int u0,int v0,float dil) {
    const HBRUSH b1=CreateSolidBrush(0X22FF00),b2=CreateSolidBrush(0X0022FF);
    SelectObject(hdc,GetStockObject(NULL_PEN));
    int n1=N+1,n11=n1+1;
    for (int j=0,k=0; j<N; ++j,++k)
      for (int i=0; i<N; ++i,++k) {POINT fc[4];
        fc[0]={u0+(int)(dil*U[k])    ,v0+(int)(dil*V[k])};
        fc[1]={u0+(int)(dil*U[k+1])  ,v0+(int)(dil*V[k+1])};
        fc[2]={u0+(int)(dil*U[k+n11]),v0+(int)(dil*V[k+n11])};
        fc[3]={u0+(int)(dil*U[k+n1]) ,v0+(int)(dil*V[k+n1])};
        SelectObject(hdc,((i&1)==(j&1))?b1:b2); Polygon(hdc,fc,4);
    }
  }
};



Bonne lecture ...

Liens

WikipédiA: Graphics Device Interface
CodeS-SourceS: GDI+A: Déplacement avec la souris
CodeS-SourceS: GDI+B: Move et Zoom avec la souris
CodeS-SourceS: GDI+C: Dessin sans scintillement
CodeS-SourceS/Javascript Retro-A: Scène et perspective

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Commenter la réponse de William VOIROL

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.