Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Andreas

Frischling

  • »Andreas« ist der Autor dieses Themas

Beiträge: 77

Beruf: Schüler

  • Private Nachricht senden

1

12.07.2007, 12:32

Picking auf große Distanz

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Kapitel 3

// Beispielprogramm 01

// ===================



#include <TriBase.h>
#include "Resource.h"

#define Geschwindigkeit 15

// ******************************************************************

// Struktur für einen Vertex der Wasseroberfläche

struct SWaterVertex
{
    tbVector3           vPosition;  // Position

    tbVector3           vNormal;    // Normalenvektor

    tbVector2           vTexture;   // 2D-Texturkoordinaten

    static const DWORD  dwFVF;      // Vertexformat

};

const DWORD SWaterVertex::dwFVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

// Globale Variablen

const int               g_iResolution = 2;          // Die Auflösung der Wasseroberfläche

float                   g_fTime = 0.0f;             // Globaler Zeitzähler

tbVector3               g_vCameraPos;                   // Kameraposition

float                   g_fCameraRot;                   // Rotation der Kamera

float                   g_fCameraUpDown;                // Schaut die Kamera hoch oder runter?

float                   g_fFOV = TB_DEG_TO_RAD(90.0f);  // Sichtfeld

                
tbMatrix                mProjection;
tbMatrix                mCamera;    
tbVector3               vCameraDir;     
tbFont*                 m_pFont1;
tbModel*                kleines_Feld;
tbPlane Ebene(tbPlaneFromPointNormal(tbVector3(0.0f, 0.0f, 0.0f), tbVector3(0.0f, 1.0f, 0.0f)));

bool Intersects(const tbPlane &plane, bool bCull, 
                        float *t, tbVector3 *vcHit, tbVector3 Richtung, tbVector3 Ursprung);


// ******************************************************************

void DeviceToDatabase(const POINT Punkt,  tbVector3* Ursprung, tbVector3* Richtung) 
{ 
    DWORD x = (DWORD) Punkt.x; 
    DWORD y = (DWORD) Punkt.y;
    


        //Länge/Breite des Client-Fensters 

    DWORD dWidth = (DWORD) 1024.0; 
    DWORD dHeight = (DWORD) 1024.0; 

    tbMatrix proj, view, InvView; 
        //Projektions- und Weltmatrix 

   // m_gi->GetProjection(proj); 

   // m_gi->GetWorld(view); 


    proj = mProjection;
    view = mCamera;
    InvView = tbMatrixInvert(mCamera);
    tbVector3 v;
    

    v.x = (((2 * (float)x) / (float)dWidth ) - 1) / (float)proj.m11; 
    v.y = (((2 * (float)y) / (float)dHeight) - 1) / (float)-proj.m22; 
    //v.y = -v.y;

    v.z = 1; 

    //InvView = view.Inverse(); 

    tbVector3 dir, origin; 
    dir.x = v.x * InvView.m11 + v.y * InvView.m21 + v.z * InvView.m31; 
    dir.y = v.x * InvView.m12 + v.y * InvView.m22 + v.z * InvView.m32; 
    dir.z = v.x * InvView.m13 + v.y * InvView.m23 + v.z * InvView.m33; 
    
    dir = tbVector3Normalize(dir); 

    origin.x = InvView.m41; 
    origin.y = InvView.m42; 
    origin.z = InvView.m43; 
    

    *Richtung = dir;
    *Ursprung = origin;
    


} 
    
    
// ******************************************************************

// Die Render-Funktion

tbResult RenderProc(float fNumSecsPassed)
{

    tbMatrix    mWorld;
    tbVector3   vCamera;
    int         iNumPasses;
    char        acText[256];
    char        acText3[256];
    BOOL getroffen = false;
    tbVector3 Ursprung;
    tbVector3 Richtung;
    tbVector3 Punkt2;
    


    // Die Szene beginnen

    tbDirect3D& D3D = tbDirect3D::Instance();
    D3D->BeginScene();
    D3D->Clear(0, 
                           NULL, 
                           D3DCLEAR_TARGET, 
                           D3DCOLOR_XRGB(0,0,0), 
                           1.0f, 
                           0);
    D3D->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
    // Projektionsmatrix erstellen und einsetzen

    mProjection = tbMatrixProjection(g_fFOV, D3D.GetAspect(), 0.1f, 300.0f);
    D3D.SetTransform(D3DTS_PROJECTION, mProjection);

    // Kameramatrix erstellen und einsetzen

    vCameraDir = tbVector3(sinf(g_fCameraRot) * cosf(g_fCameraUpDown),
                           sinf(g_fCameraUpDown),
                           cosf(g_fCameraRot) * cosf(g_fCameraUpDown));
    mCamera = tbMatrixCamera(g_vCameraPos, g_vCameraPos + vCameraDir);
    D3D.SetTransform(D3DTS_VIEW, mCamera);
    // ------------------------------------------------------------------

    
    
    // ------------------------------------------------------------------

        POINT Cursor;
    GetCursorPos(&Cursor);
    DeviceToDatabase(Cursor, &Ursprung,  &Richtung);
    Punkt2 = Ursprung+Richtung*10000;

    D3D.SetTransform(D3DTS_WORLD, tbMatrixIdentity());

    getroffen = tbLineHitsModel(Ursprung, Punkt2, kleines_Feld, tbMatrixIdentity(), tbMatrixInvert(tbMatrixIdentity()), 0, NULL, NULL, NULL);
    

    if(!getroffen) {
        kleines_Feld->Render(-1, -1, TRUE, FALSE);
        kleines_Feld->Render(-1, -1, FALSE, TRUE);
    }
    else {
        kleines_Feld->Render(-1, -1, TRUE, FALSE,1);
        kleines_Feld->Render(-1, -1, FALSE, TRUE,1);
    }
        // ------------------------------------------------------------------

    
    // Weltmatrix zurücksetzen

    D3D.SetTransform(D3DTS_WORLD, tbMatrixIdentity());

    // Texturen setzen

    D3D.SetTexture(0, g_pWaterTexture);
    D3D.SetTexture(1, g_pEnvMap);

    
    // Datenquellen und Vertexformat setzen

    D3D->SetStreamSource(0, g_pWaterVB->GetVB(), 0, sizeof(SWaterVertex));
    D3D->SetIndices(g_pWaterIB->GetIB());
    D3D.SetFVF(SWaterVertex::dwFVF);
        // Zeichnen!

    iNumPasses = g_pWaterEffect->Begin();
    for(iPass = 0; iPass < iNumPasses; iPass++)
    {
        g_pWaterEffect->Pass(iPass);
        D3D->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0,
                                  g_iResolution * g_iResolution, 0,
                                  (g_iResolution - 1) * (g_iResolution - 1) * 2);
    }

    g_pWaterEffect->End();

    
        
    char acText2[256];

    sprintf(acText2, "X:%f  Y:%f  Z:%f", g_vCameraPos.x, g_vCameraPos.y, g_vCameraPos.z);
    sprintf(acText, "FPS: %.2f", 1.0f / fNumSecsPassed);
    tbVector3 Kollisionspunkt;
    
    Intersects(Ebene, true, NULL, &Kollisionspunkt, Richtung, Ursprung);
    if(Kollisionspunkt) sprintf(acText3, "X:%f, Y:%f, Z:%f", Kollisionspunkt.x, Kollisionspunkt.y, Kollisionspunkt.z);
    m_pFont1->Begin();



    // Framerate anzeigen

    
    m_pFont1->DrawText(tbVector2(10.0f, 30.0f), acText);
    m_pFont1->DrawText(tbVector2(10.0f, 50.0f), acText2);
    
    if(Kollisionspunkt) m_pFont1->DrawText(tbVector2((float)(Cursor.x), (float)(Cursor.y+20)),
                       acText3, TB_FF_ALIGN_HCENTER | TB_FF_ALIGN_VCENTER, -1,
                       tbColor(1.0f, 0.75f, 0.75f), tbColor(0.0f, 1.0f, 1.0f),
                       tbVector2(1.5f, 1.5f),
                       0.0f, 0.0f,
                       0.0f, 50.0f, 0.0f);
      else m_pFont1->DrawText(tbVector2((float)(Cursor.x), (float)(Cursor.y+20)),
                       "FALSE", TB_FF_ALIGN_HCENTER | TB_FF_ALIGN_VCENTER, -1,
                       tbColor(1.0f, 0.75f, 0.75f), tbColor(0.0f, 1.0f, 1.0f),
                       tbVector2(1.5f, 1.5f),
                       0.0f, 0.0f,
                       0.0f, 50.0f, 0.0f);
    
    
    
    
    m_pFont1->End();
    // Szene beenden

    D3D->EndScene();

    return TB_OK;
}

// ******************************************************************

******************************************************************

// Intersection with Plane from origin till infinity. 

bool Intersects(const tbPlane &plane, bool bCull, 
                        float *t, tbVector3 *vcHit, tbVector3 Richtung, tbVector3 Ursprung) {
   
    float Vd = tbVector3Dot(plane.n, Richtung);//  plane.n * Richtung;


   // ray parallel to plane

   if (fabs(Vd) < 0.00001f)
      return false;

   // normal pointing away from ray dir

   // => intersection backface if any

   if (bCull && (Vd > 0.0f))
      return false;

   float Vo = -( (tbVector3Dot(plane.n , Ursprung)) + plane.d);

   float _t = Vo / Vd;

   // intersection behind ray origin

   if (_t < 0.0f)
      return false;

   if (vcHit) {
      (*vcHit) = Ursprung + (Richtung * _t);
      }

   if (t)
      (*t) = _t;

   return true;
   } // Intersects(Plane)







// ******************************************************************


Hallo, tut mir leid, das der Quellcode etwas länger ist.
Das Programm ist eine Abwandlung von dem ersten Beispielprogramm aus Kapitel 3. Es handelt sich dabei um eine große Ebene, die mit einer Dreiecksliste aufgespannt wird. Dazu gibt es dann auch noch die mathematische Ebene (Variable Ebene)!
Über dieser große Ebene liegt noch eine kleinere Ebene, die mit tbModel geladen und auch auf Kollision mit dem Strahl aus der Maustaste geprüft wird. Liegt eine Kollision vor (also wenn der Cursor darüber liegt, dann wird sie in Gelb gerendert (die rendermethode wurde umgeschrieben)

Das Problem ist jetzt, je weiter ich mich mit der Kamera entferne, desto ungenauer ist die Kollisionserkennung. Die kleine Ebene wird nicht als makiert angezeigt wenn man drüber fährt sondern man muss sich ein ganzes stück weiter in z-Richtung bewegen, damit sie gelb wird.
Auch die Koordinaten, die den Schnittpunkt der Ebene liefern werden immer ungenauer je weiter man sich entfernt.

Da diese große Toleranz nicht akzeptabel ist (Sie geht in Wertebereiche von bis zu 15), habe ich ne Frage: Liegt das daran, dass die DeviceToDatabase-Methode, die den Strahl aus dem Mausklick berechnet falsch ist (Oder eine andere Methode), oder liegt das einfach an der Ungenauigkeit des floats? Weiß jemand, wie man das Problem beheben kann, oder muss man alle Methoden auch die Inverseberechnung der Matrix auf double umschreiben?

Vielen Dank für eine Antwort

Andreas

Black-Panther

Alter Hase

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

2

12.07.2007, 12:58

ALso mir geht in deiner Strahl-berechnungs-Funktion die Weltmatrix ab... Weiß nicht obs sonst stimmt (habs mir jetzt nicht sooo genau angeschaut)... Hier mal meine Ray-Extraction-Function:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Liefert den Mousecoord-Strahl in 3D für eine 2D-ScreenCoord

OMEGA_API ogResult ogUtilsGet3DMouseRay(og2DVector& vMousePosition,
                                        og3DVector* pvPickOrigin, og3DVector* pvPickDirection)
{
    if(!pvPickOrigin || !pvPickDirection) OG_ERROR_NULL_POINTER(L"pvPickOrigin || pvPickDirection", OG_ERROR);

    ogDirect3D& D3D = ogDirect3D::Instance();
    //Projektionsmatrix holen

    const ogMatrix mProjection = D3D.GetTransform(D3DTS_PROJECTION);

    //Compute the vector of the pick ray in screen space

    og3DVector v;
    v.x =  (((2.f * vMousePosition.x) / D3D.GetScreenSize().x) - 1.f) / mProjection.m11;
    v.y = -(((2.f * vMousePosition.y) / D3D.GetScreenSize().y) - 1.f) / mProjection.m22;
    v.z =  1.0f;

    //Get the inverse view matrix

    const ogMatrix mWorld           = D3D.GetTransform(D3DTS_WORLD);
    const ogMatrix mView            = D3D.GetTransform(D3DTS_VIEW);
    const ogMatrix mWorldView       = mWorld * mView;   
    const ogMatrix mWorldViewInv    = ogMatrixInvert(mWorldView);

    //Transform the screen space pick ray into 3D space

    (*pvPickDirection).x    = v.x * mWorldViewInv.m11 + v.y * mWorldViewInv.m21 + v.z * mWorldViewInv.m31;
    (*pvPickDirection).y    = v.x * mWorldViewInv.m12 + v.y * mWorldViewInv.m22 + v.z * mWorldViewInv.m32;
    (*pvPickDirection).z    = v.x * mWorldViewInv.m13 + v.y * mWorldViewInv.m23 + v.z * mWorldViewInv.m33;
    (*pvPickOrigin).x       = mWorldViewInv.m41;
    (*pvPickOrigin).y       = mWorldViewInv.m42;
    (*pvPickOrigin).z       = mWorldViewInv.m43;

    return OG_OK;
}
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

Andreas

Frischling

  • »Andreas« ist der Autor dieses Themas

Beiträge: 77

Beruf: Schüler

  • Private Nachricht senden

3

12.07.2007, 13:06

Hallo, vielen Dank für die Antwort.
Das habe ich in dem DirectX SDK auch mit der Weltmatrix gelesen.
Allerdings konnte ich nicht verstehen, wofür der die Weltmatrix braucht.
Die Weltmatrix ist doch für jedes Objekt anders.
Und wenn ich in dem Raum ein Mathematisches Gebilde wie eine Ebene habe, was soll ich denn da für eine andere Matrix als die Einheitsmatrix nehmen? (Und die verändert ja eigentlich nix)

Wenn ich sozusagen 6 Objekte auf dem Screen sehe und alle an einer anderen Position, also eine andere Weltmatrix, und ich möchte herausfinden, welches anglickt worden ist, dann muss ich 6mal diese Strahlmethode aufrufen, um den Strahl zu erhalten und 6mal um dann tbLineHitsModel um herauszufinden, ob es wirklich getroffen wurde?

Kommt mir ein bischen komisch vor, kann mir das einer erläutern?

Vielen Dank und viele Grüße
Andreas

Andreas

Frischling

  • »Andreas« ist der Autor dieses Themas

Beiträge: 77

Beruf: Schüler

  • Private Nachricht senden

4

13.07.2007, 11:14

Hallo,
ich hab den Fehler gefunden, war ein echt dummer :(

Naja, viele Grüße
Andreas

Werbeanzeige