Utilizator:
Parola:
Am uitat parola... | Cont nou!


Articole Resurse Echipe Competiții Proiecte Forum DevBlogs Locuri de muncă GDROMag Issue#1 GDROCon 2007

 
Forum » Programare » Matematică » Camera




Pagina 1 din 2 [ 1 | 2 ]

Mesaj Info autor
    Postat la 20 Sep 2007 17:19:19    Subiect: Camera
Deliverance info:

Deliverance:

Am revenit la un proiect mai vechi, un .bsp loader(formatul folosit de quake 3) si m-am gandit sa-i adaug o clasa care sa simuleze o camera first person shooter. Informatiile pe care le retin pentru a reprezenta camera sunt cele 3 axe (X, Y si Z) si un vector de pozitie. Pentru a transforma obiectele in spatiul camerei construiesc inversa matricei determinata de aceste informatii in functia Look() astfel:
Cod sursă:

void CCamera::Look()
{                            
    CMatrix mat(xAxis.x, yAxis.x, zAxis.x, 0.0f,
                xAxis.y, yAxis.y, zAxis.y, 0.0f,
                xAxis.z, yAxis.z, zAxis.z, 0.0f,
                -Dot(eyePos,xAxis), -Dot(eyePos,yAxis),-Dot(eyePos,zAxis), 1.0f);
    
    glMultMatrixf(*mat);
}
 

Problema este ca in timp ce ma "plimb" prin interiorul nivelului, camera capata o rotatie ciudata pentru care nu gasesc explicatie. Incercati sa rotiti camera stanga-dreapta veti observa la ce ma refer, linkul este aici:
http://files-upload.com/files/514988/bspmd3.rar

Codul pentru camera este foarte mic si usor de inteles:

CCamera.h
Cod sursă:

#ifndef CCAMERA_H
#define CCAMERA_H

#include "CVector3D.h"
#include "CMatrix.h"
#include

namespace CAMERA
{    
    const unsigned int FPS_CAM = 0;
    const unsigned int TPS_CAM = 1;
}             

class CCamera
{
    private:
        unsigned int CameraType;
        bool FlyMode; // Used only with FPS_CAM
        float CameraSensitivity;    
        void RegenerateVectors();
    public:            
        CVector3D eyePos;
        CVector3D xAxis;
        CVector3D yAxis;
        CVector3D zAxis;

        float AngleXZ;       
        float AngleYZ;
        int *mx, *my, *w, *h;
        
        CCamera():CameraSensitivity(0.1f)
        {
            CameraType = CAMERA::FPS_CAM;
            FlyMode = true;

            eyePos = CVector3D(0.0f, 0.0f, 6.0f);
            xAxis = CVector3D(1.0f, 0.0f, 0.0f);
            yAxis = CVector3D(0.0f, 1.0f, 0.0f);
            zAxis = CVector3D(0.0f, 0.0f, 1.0f);
        };
        void Pitch(float angle);
        void Yaw(float angle);
        void Roll(float angle);
        void Look();        
        void Set(int *_mx, int *_my, int *_w, int *_h);
        void SetFly(bool FlyMode);
        void SetCameraType(unsigned int CameraType);
        void Move(float Amount);                 
        void Strafe(float Amount);
        void SetViewByMouse();
        void SetPosition(CVector3D Position);        
};

#endif
 


Camera.cpp
Cod sursă:

#include "CCamera.h"
#include

void CCamera::Set(int *_mx, int *_my, int *_w, int *_h)
{
    mx = _mx;
    my = _my;
    w  = _w;
    h  = _h;
}

void CCamera::Look()
{                            
    CMatrix mat(xAxis.x, yAxis.x, zAxis.x, 0.0f,
                xAxis.y, yAxis.y, zAxis.y, 0.0f,
                xAxis.z, yAxis.z, zAxis.z, 0.0f,
                -Dot(eyePos,xAxis), -Dot(eyePos,yAxis),-Dot(eyePos,zAxis), 1.0f);
    
    glMultMatrixf(*mat);
}                          

void CCamera::Move(float Amount)
{                          
    if (CameraType == CAMERA::FPS_CAM)
    {    
        if ( FlyMode )
        {
            eyePos = eyePos + -zAxis * Amount;
        }
        else                        
        {
            eyePos.x = eyePos.x - zAxis.x * Amount;
            eyePos.z = eyePos.z - zAxis.z * Amount;
        }
    }else
    {    
        // Camera type CAMERA::TPS_CAM --- Not implemented yet        
    }
}

void CCamera::Strafe(float Amount)
{                                                          
    eyePos += xAxis * Amount;    
}    

void CCamera::SetFly(bool FlyMode)
{    
    this->FlyMode = FlyMode;    
}

void CCamera::SetCameraType(unsigned int CameraType)
{    
    this->CameraType = CameraType;
}        

void CCamera::SetPosition(CVector3D Position)
{
    eyePos = Position;
}
        
void CCamera::Pitch(float angle)
{
    CMatrix mat;
    mat.Rotate(angle, xAxis, true);
    yAxis = yAxis.MatrixMultiply(mat);
    zAxis = zAxis.MatrixMultiply(mat);

    RegenerateVectors();
}

void CCamera::Yaw(float angle)
{
    CMatrix mat;
    mat.Rotate(angle, CVector3D(0.0f, 1.0f, 0.0f), true);
    xAxis = xAxis.MatrixMultiply(mat);
    zAxis = zAxis.MatrixMultiply(mat);

    RegenerateVectors();
}

void CCamera::Roll(float angle)
{
    CMatrix mat;
    mat.Rotate(angle, zAxis, true);
    xAxis = xAxis.MatrixMultiply(mat);
    yAxis = yAxis.MatrixMultiply(mat);

    RegenerateVectors();
}

void CCamera::RegenerateVectors()
{
    zAxis.Normalize();
    yAxis = Cross(zAxis, xAxis);
    yAxis.Normalize();
    xAxis = Cross(yAxis, zAxis);
    xAxis.Normalize();
}

void CCamera::SetViewByMouse()
{
    // Get current cursor position
        
    int MiddleX = (*w) >> 1;
    int MiddleY = (*h) >> 1;
        
    // Now move it back to the middle of the screen
    
    if (MiddleX==(*mx) && MiddleY==(*my))
        return;
    
    glutWarpPointer(MiddleX, MiddleY);
            
    int X = (*mx) - MiddleX;
    int Y = (*my) - MiddleY;    
    
    AngleXZ += X * CameraSensitivity;
    AngleYZ += Y * CameraSensitivity;
        
    Pitch(-Y * CameraSensitivity);
    Yaw(-X * CameraSensitivity);                    

    if (AngleYZ  90.0f)
    {    
        Pitch(Y * CameraSensitivity);
        AngleYZ = 90.0f;    
    }                                                                                                        
}
 


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 
    Postat la 20 Sep 2007 18:04:08    Subiect: < fara subiect >
Rimio info:

Rimio:

Incearca sa apelezi intai Yaw si dupaia Pitch.

If at first you don't succeed, you fail.



Status:
Înregistrat pe:
24 Mar 2007 21:50:44
Vârsta: 23 ani
Mesaje: 800
Locatie: Pitesti, Arges
Programator

 
    Postat la 20 Sep 2007 18:28:40    Subiect: < fara subiect >
Deliverance info:

Deliverance:

Nu. Nu-i asta.


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 
    Postat la 20 Sep 2007 18:36:09    Subiect: < fara subiect >
surreal info:

surreal:

Hmm... am impresia ca problema se datoreaza faptului ca recreezi xAxis tot pe baza lui xAxis. La fel pe y si z. Dupa un timp iti va aparea o mica marja de eroare din cauza ca float-ul (si double-ul) pastreaza numerele reale doar aproximativ. In timp eroarea asta se agraveaza exponential si de aia observi rotatia ciudata a camerei.

Iti recomand sa pastrezi in clasa doar 3 membrii:
- pozitia camerei
- unghiul in jurul lui OY (OY ramane fix adica (0,1,0)
- unghiul in jurul lui OX cel nou rezultat din rotatia in jurul lui OY

Din aceste trei variabile poti recrea precis matricea de rotatie fara pierderi de precizie de virgula mobila.

Ultima editare efectuată de surreal pe 20 Sep 2007 18:36:46; 1 editări în total

Reality is the single possibility I can't ignore


Status:
Înregistrat pe:
21 Jun 2007 16:41:32
Vârsta: 33 ani
Mesaje: 35
Locatie: Cluj
Programator

 
    Postat la 20 Sep 2007 18:51:32    Subiect: Re:
Deliverance info:

Deliverance:

surreal a scris:


Iti recomand sa pastrezi in clasa doar 3 membrii:
- pozitia camerei
- unghiul in jurul lui OY (OY ramane fix adica (0,1,0)
- unghiul in jurul lui OX cel nou rezultat din rotatia in jurul lui OY

Din aceste trei variabile poti recrea precis matricea de rotatie fara pierderi de precizie de virgula mobila.


As putea sa fac si asa, insa va fi mai dificil sa implementez apoi o camera cu sase grade de libertate.

Edit:
Cum adica regenerez xAxis tot pe baza lui xAxis? Si da, functia RegenerateVectors este problema.

Ultima editare efectuată de Deliverance pe 20 Sep 2007 19:02:51; 1 editări în total


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 
    Postat la 20 Sep 2007 19:00:56    Subiect: < fara subiect >
surreal info:

surreal:

ai putea sa ai si camera cu 6 grade de libertate... noile axe OX si OY le ai gata pe tava, mai trebuie sa calculezi noul OZ care-i produsul vectorial intre OX si OY, dupa care il normalizezi. daca ai noul OZ, poti crea matricea de rotatie in jurul lui, doar trebuie s-o concatenezi la matricea in in jurul lui OX si OY si ai gata inversul matricei camerei.
sper ca se intelege... acuma vad ca-i plin de OX OY... Smile

Ultima editare efectuată de surreal pe 20 Sep 2007 19:04:31; 3 editări în total

Reality is the single possibility I can't ignore


Status:
Înregistrat pe:
21 Jun 2007 16:41:32
Vârsta: 33 ani
Mesaje: 35
Locatie: Cluj
Programator

 
    Postat la 20 Sep 2007 19:14:15    Subiect: Re: Re:
surreal info:

surreal:

Deliverance a scris:


Cum adica regenerez xAxis tot pe baza lui xAxis?


la partea asta ma refeream: xAxis = xAxis.MatrixMultiply(mat);
poti sa incerci urmatorul test: creezi o matrice m1 cu rotatie de unghi=0.5 radiani in jurul lui OX si matricea m2 cu rotatie -0.5 radiani si rulezi urmatoarea bucata de cod de 100000 de ori.

xAxis = xAxis.MatrixMultiply(m1);
xAxis = xAxis.MatrixMultiply(m2);

teoretic xAxis n-ar trebui sa se schimbe, dar din cauza erorilor de calcul care se tot propaga vei observa ca de fapt se schimba subtil... cel putin asa ar trebui Very Happy

Ultima editare efectuată de surreal pe 20 Sep 2007 19:14:38; 1 editări în total

Reality is the single possibility I can't ignore


Status:
Înregistrat pe:
21 Jun 2007 16:41:32
Vârsta: 33 ani
Mesaje: 35
Locatie: Cluj
Programator

 
    Postat la 20 Sep 2007 19:16:59    Subiect: < fara subiect >
Deliverance info:

Deliverance:

Ai dreptate in privinta erorilor floating point, tocmai din cauza asta regenerez(se pare ca gresit) vectorii pentru ca tot timpul cele 3 axe sa fie ortonormale. In privinta bucatii respective de cod nu fac decat sa rotesc axa OX.


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 
    Postat la 20 Sep 2007 20:18:10    Subiect: < fara subiect >
Pintea info:

Pintea:

te complici extraordinar de mult, cum zicea si surreal , pastreaza starea ca origine + rotatiile cumulative in jurul celor 3 axe (cum sa nu poti implementa 6 grade de libertate ??)

la fiecare frame creezi doar o data matricea cu cele 3 rotatii, o salvezi, apoi ai acces si la cele 3 axe ptr implementarea miscarii.

sa nu mai spun ca la fiecare pitch/roll/yaw creezi o matrice de rotatie, aplici 2 inmultiri de matrici dupa care mai faci si o ortonormalizare...overkill

Ultima editare efectuată de Pintea pe 20 Sep 2007 20:19:30; 1 editări în total



Status:
Înregistrat pe:
05 May 2007 14:50:45
Vârsta: 29 ani
Mesaje: 301
Locatie:
Programator

 
    Postat la 20 Sep 2007 20:44:24    Subiect: < fara subiect >
Deliverance info:

Deliverance:

Cum anume creez matricea cu cele 3 rotatii?


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 
    Postat la 20 Sep 2007 20:59:16    Subiect: < fara subiect >
Pintea info:

Pintea:

Creezi matricile de rotatie pe cele 3 axe si le inmultesti.
Mai intai faci asta matematic folosind notatii ptr necunoscutele sin si cos din care obtii formula ptr matricea finala cu toate cele 3 rotatii aplicate.
Vezi in prezentarea mea de la gdcon in matrix.cpp



Status:
Înregistrat pe:
05 May 2007 14:50:45
Vârsta: 29 ani
Mesaje: 301
Locatie:
Programator

 
    Postat la 20 Sep 2007 21:05:59    Subiect: < fara subiect >
Deliverance info:

Deliverance:

Da, dar asta inseamna sa creez 3 matrice fiecare frame si sa inmultesc de 3 ori matricele pentru a obtine matricea finala. In codul meu creez o singura matrice la fiecare frame si modific vectorii care o compun doar cand utilizatorul modifica pozitia sau orientarea. Chiar si atunci creez o singura matrice si inmultesc doua nu creez 3 si le inmultesc.

Ultima editare efectuată de Deliverance pe 20 Sep 2007 21:09:32; 1 editări în total


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 
    Postat la 20 Sep 2007 21:13:02    Subiect: Re:
Pintea info:

Pintea:

Deliverance a scris:

Da, dar asta inseamna sa creez 3 matrice fiecare frame si sa inmultesc de 3 ori matricele pentru a obtine matricea finala. In codul meu creez o singura matrice la fiecare frame si modific vectorii care o compun doar cand utilizatorul modifica pozitia sau orientarea. Chiar si atunci creez o singura matrice si inmultesc doua nu creez 3 si le inmultesc.


tocmai asta ziceam, nu trebuie , scoti formula pentru matricea deja inmultita, cate un sin/cos ptr fiecare unghi si niste adunari/inmultiri.



Status:
Înregistrat pe:
05 May 2007 14:50:45
Vârsta: 29 ani
Mesaje: 301
Locatie:
Programator

 
    Postat la 20 Sep 2007 21:13:35    Subiect: < fara subiect >
Rimio info:

Rimio:

Te zgarcesti la nimic. Nici nu se simt cele 3 inmultiri, dar daca doresti tu neaparat, have it your way Smile.

If at first you don't succeed, you fail.



Status:
Înregistrat pe:
24 Mar 2007 21:50:44
Vârsta: 23 ani
Mesaje: 800
Locatie: Pitesti, Arges
Programator

 
    Postat la 20 Sep 2007 21:19:12    Subiect: Re: Re:
Deliverance info:

Deliverance:

Pintea a scris:

Deliverance a scris:

Da, dar asta inseamna sa creez 3 matrice fiecare frame si sa inmultesc de 3 ori matricele pentru a obtine matricea finala. In codul meu creez o singura matrice la fiecare frame si modific vectorii care o compun doar cand utilizatorul modifica pozitia sau orientarea. Chiar si atunci creez o singura matrice si inmultesc doua nu creez 3 si le inmultesc.


tocmai asta ziceam, nu trebuie , scoti formula pentru matricea deja inmultita, cate un sin/cos ptr fiecare unghi si niste adunari/inmultiri.


Am inteles


Status:
Înregistrat pe:
13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator

 

Pagina 1 din 2 [ 1 | 2 ]


Server time: 16:33:55 23.05.2012



[ Termeni si conditii | Contact | F.A.Q. | Funny Pictures ]

© 2006 - 2012 Copyright 7thFACTOR Entertainment - All rights reserved