프로그래밍 관련/3D,2D DRAW 관련

OpenGL 오픈지엘3D 2D처럼 이용하기 관련, How do I position a 2D camera in OpenGL?

AlrepondTech 2020. 9. 15. 21:51
반응형

 

 

=================================

=================================

=================================

 

 

출처:

- https://gamedev.stackexchange.com/questions/56512/how-do-i-position-a-2d-camera-in-opengl

 

 

I can't understand how the camera is working. It's a 2D game, so I'm displaying a game map from (0, 0, 0) to (mapSizeX, 0, mapSizeY).

I'm initializing the camera as follow :

 

Camera::Camera(void)
  : position_(0.0f, 0.0f, 0.0f), rotation_(0.0f, 0.0f, -1.0f)
{}

void            Camera::initialize(void)
{
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glTranslatef(position_.x, position_.y, position_.z);
  gluPerspective(70.0f, 800.0f/600.0f, 1.0f, 10000.0f);
  gluLookAt(0.0f, 6000.0f, 0.0f,
            0.0f, 0.0f, -1.0f,
            0.0f, 1.0f, 0.0f);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);
}

 

So the camera is looking down. I currently see the up right border of the map in the center of my window and the map expand to the down left border of my window. I would like to center the map.

 

The logical thing to do should be to move the camera to eyeX = mapSizeX / 2 and the same for z. My map has 10 x 10 cases with CASE = 400, so I should have :

gluLookAt((10 / 2) * CASE /* = 2000 */, 6000.0f, (10 / 2) * CASE /* = 2000 */,
            0.0f, 0.0f, -1.0f,
            0.0f, 1.0f, 0.0f);

 

But that doesn't move the camera, but seems to rotate it.

Am I doing something wrong?

 

EDIT :

I tried that:

gluLookAt(2000.0f, 6000.0f, 0.0f,
            2000.0f, 0.0f, -1.0f,
            0.0f, 1.0f, 0.0f);

 

Which correctly moves the map in the middle of the window in width. But I can't move if correctly in height. It always returns the axis Z. When I go up, It goes down and the same for right and left.

 

I don't see the map anymore when I do :

gluLookAt(2000.0f, 6000.0f, 2000.0f,
                2000.0f, 0.0f, 2000.0f,
                0.0f, 1.0f, 0.0f);

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

How does gluLookAt work?

It seems you need help with gluLookAt - it takes these nine parameters:

  1. Parameters 1 through 3 are the XYZ coordinates of your camera's position.
  2. Parameters 4 through 6 define the XYZ coordinates of the point that your camera will be centered on.
  3. Parameters 7 through 9 define which direction is "up". This allows you to roll the camera.

Where should one apply camera transformations?

Next, you should transform your view (move your camera) by using the Model-View matrix and not the Projection matrix.

The gluLookAt() function gives you a transformation matrix that transforms a rotation of an object in your scene. So this is clearly a model transformation and must go into the GL_MODELVIEW matrix.

Source

So your code should initialize function should look more like this:

 glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(70.0f, 800.0f/600.0f, 1.0f, 10000.0f);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(position_.x, position_.y, position_.z);
  gluLookAt(0.0f, 6000.0f, 0.0f,
            0.0f, 0.0f, -1.0f,
            0.0f, 1.0f, 0.0f);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

Is there a better way?

I think that instead of using gluLookAt, you should simply translate the camera instead. I'm not sure how you are drawing your 2D images, but typically you will draw your images with an X and Y coordinate and leave Z at 0. If you go this route, I recommend using gluOrtho instead of glPerspective.

Find a good book

I recommend finding a good book about OpenGL viewing transformations. Although this book is outdated, the concepts in this chapter remain useful:http://www.glprogramming.com/red/chapter03.html

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

 

I tried to gluLookAt in GL_MODELVIEW, it doesn't change anything. I see the map plan, but not the objects on it anymore. I don't understand why I have to set the z point view (6th param) at -1.0. It's suppose to look at the z = -1.0 , but when I change it to 0.0 (which shouldn't change anything), I only see the clear color of the window. That's the problem now. I've moved the camera on the X axis at 2000, the eye too so I don't see the scene by its side. BUT I can't move the camera on the Z axis as the X axis because of this -1.0 in param of the point looked. – Elfayer May 31 '13 at 8:39 
  Edit Camera constructor – Elfayer May 31 '13 at 8:47
  This is working if I move the camera withe the glTranslatef(x,y,0) and glLookAt(0,z,0,0,0,-1,0,1,0) !! For a map 10 x 10, x = y = 2000 and for example z = 5000. – Elfayer May 31 '13 at 10:03 
  @Elfayer You're misunderstanding glLookAt. It is for looking at a particular point in the world. You are making it look at point (0, 0, -1) which is always the point next to the corner of your map. It is not a direction (and if it were, it'd be the wrong direction). It doesn't matter where the camera is moved to, it will always look towards that point. The problem here is that you don't want to look at a particular point all the time, you want to look in a particular direction, so you should be using glRotate. You want to make your camera look down the y-axis. – Joseph Mansfield Jul 30 '13 at 13:45 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

First understand the difference between the GL_MODELVIEW and GL_PROJECTION matrix stacks.

The GL_MODELVIEW matrix is for positioning and orientating the objects in the world with respect to the camera. This moves your objects through the following coordinate spaces:

 

Object Space -> World Space -> Eye Space

 

In object space, the object is the centre of everything. It does not yet know where in the world it is. You then apply the model transformation to the object and it positions it in the world. When this is done to every object, you have them all in world space. At this point, the (0,0,0) coordinate is just some arbitrary origin point in the world.

Your camera has some position and orientation in the world space. The view transformation rotates and translates the world space so that the camera is at the origin (0,0,0) and looking along the negative Z-axis. This is eye space. In eye space, the camera is the centre of everything.

 

These two transformations are combined into one, the modelview transformation, since they really just both work together to move objects around in the world with respect to the camera.

The GL_PROJECTION matrix transforms your objects through the following spaces:

Eye Space -> Clip Space

 

This can be a difficult transformation to imagine conceptually. If you imagine the frustum of the camera as a 6-faced volume (which is very near to the origin in eye space), this transformation moves and warps it so that it is in the shape of a cube with the centre of the cube at (0,0,0).

 

The first problem you've got is that you're trying to apply the view transformation to the GL_PROJECTION matrix. That's wrong. The view transformation should be part of the GL_MODELVIEWmatrix. The view transformations you're applying are a glTranslatef and gluLookAt. These should be applied to the GL_MODELVIEW matrix.

 

Your second problem is that you misunderstand gluLookAt - in particular, the 4th to 6th arguments. You are attempting to give it a direction in which the camera should look, (0,0,-1), along the negative z-axis. Firstly, if this was what gluLookAt expected, it would still be wrong, because you want your camera to look along the y-axis. Nonetheless, it actually expects a position in the world to look at. No matter where you place your camera, it will look at the point (0,0,-1), which happens to be right next to the corner of your map, which is at (0,0,0).

 

You shouldn't be using gluLookAt at all, because you don't want to look at a particular point. This is much easier to do with a rotation to make the camera look along the negative Y-axis, combined with a translation so that the camera is at a height away from the map. Note, you should apply the inverse transformations than you expect to, because you're really moving the map away from the camera, and not the camera away from the map. Something like this:

 

glRotatef(1.0f, 0.0f, 0.0f, 90.0f); // Rotate the camera to look down the y-axis
glTranslatef(-position_.x, -position_.y, -position_.z); // Move camera to correct location

Make sure these are the first transformations on the GL_MODELVIEW matrix.

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://gpgstudy.com/forum/viewtopic.php?t=19850

opengl에서 2d와 3d를 동시에 그리기

전체글 글쓴이: 비회원 » 2008-05-26 17:48

3d화면을 그리고 그 위에 2d를 그리려고 합니다.
3d는 좌표계가 따로 있고, 2d는 윈도우에 맞춰서 x, y로 그리고 싶은데요.
마치 3d 화면 위에 뿌려지는 UI처럼 말이죠.
이렇게 하려면 어떻게 작업을 진행해야하나요?

흠..

전체글 글쓴이: 비회원 » 2008-05-26 19:19

프로젝션 메트릭스를 
perspective View로 해서 3D를 그리시구요, 
2D 그리실 때는 Ortho View로 해서 2D 그리시면 됩니다.

이렇게 하면 되겠네요.

gluPerspective(...) glMatrixMode(GL_MODELVIEW);
glLoadIdentity();...신나게 3 D 그리자~~...windowWidth = 윈도우 너비;
windowHeight = 윈도우 높이;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, windowWidth, 0, windowHeight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

 

ㅎㅎ
헌데 윈도우에선 y좌표계가 반대여서 그것만 조심하면 될 듯한데...
y좌표계를 윈도우 좌표계에 맞추려면 어떻게 해야 될지 모르겠네요...ㅡㅡ;(죄송)

프로그래머의 프로!!
를 희망하는 젊은 하수중의 하수.

Re: 이렇게 하면 되겠네요.

전체글 글쓴이: Xine » 2008-05-26 21:21

Prin_E 작성:

코드: 모두 선택

... gluOrtho2D(0, windowWidth, 0, windowHeight); ...

ㅎㅎ
헌데 윈도우에선 y좌표계가 반대여서 그것만 조심하면 될 듯한데...
y좌표계를 윈도우 좌표계에 맞추려면 어떻게 해야 될지 모르겠네요...ㅡㅡ;(죄송)

3번째 인자, 4번째 인자 서로 바꾸면 되지 않나요?

 

전체글 글쓴이: 비회원 » 2008-05-27 09:09

참고로... 2D 를 말씀하시는거면, 아마 UI 같이 뿌려지는걸 원하시겠죠??
대체적으로 depth test 를 끄고, lighting 도 꺼야지 제대로 나옵니다.
참고하세요..

 

전체글 글쓴이: oranke » 2008-05-27 10:41

Prin_E님의 답변 뒤에 모델뷰 좌표계를 추가로 "Y축 뒤집고, Y축 높이만큼 빼주기" 하면
윈도 좌표계 처럼 사용할 수 있습니다. 

코드: 모두 선택

 

GLvoid ReSizeGLScene(GLsizei width, GLsizei height) {
    // 여기서는 윈도 좌표계와 일치하도록 화면 좌상단을 원점으로 하는 좌표계를 설정한다. 
    glViewport(0, 0, width, height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(-0.0 f, (GLfloat) width, -0.0 f, (GLfloat) height, -32768.0 f, 32767.0 f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glScalef(1.0 f, -1.0 f, 1.0 f);
    glTranslatef(0, -(GLfloat) height, 0);
}


도움이 되실지 모르겠지만... 오래전에 만들었던 추억의 예제... ^^;;
(화면 구성요소 배치에 640*480 기준의 윈도좌표계를 사용하네요~) 

 

 

=================================

=================================

=================================

 

 

 

반응형

 

728x90

 

 

 

출처: http://tibyte.kr/232

 

 

OpenGL로 외부 이미지파일을 읽어와서 출력할 때

glDrawPixels()함수를 쓰는 방법과 텍스쳐(texture)를 사용하는 방법이 있는데,

glDrawPixels()는 그릴 때마다 메인 메모리에서 픽셀값들을 읽어들이는 반면

텍스쳐는 생성할 때 그래픽 처리 장치의 메모리에 저장되므로 속도가 더 빠르다.

또한 텍스쳐를 그릴 때 확대/축소와 위치 지정 자유롭게 할 수 있다.

 

 

먼저 테스트용으로 쓸 이미지 배열을 만든다.

여기서는 텍스쳐 포멧으로 RGBA_8888를 사용할 것인데,

Red, Green, Blue, Alpha(불투명도)에 해당하는 정보들을 각각 8비트(1바이트)씩 사용하는 방법이다.

int w = 100;

int h = 100;

GLubyte map[100 * 100 * 4];

int i, j;

for (i = 0; i < h; i++) {

    for (j = 0; j < w; j++) {

        map[w * i * 4 + j * 4 + 0] = 0x99; //Red

        map[w * i * 4 + j * 4 + 1] = 0x99; //Green

        map[w * i * 4 + j * 4 + 2] = 0xCC; //Blue

        map[w * i * 4 + j * 4 + 3] = 0xAA; //Alpha

    }

}

100x100 크기의 0x9999CCAA색 사각형을 나타내는 1차원 배열이 생성된다.

(그릴 때는 2차원으로 처리된다.)

 

 

알파 채널을 사용하기 위해 GL_BLEND를 활성화하고, 

텍스쳐id로 텍스쳐를 생성한 뒤 glBindTexture()로 텍스쳐id와 텍스쳐라이징 대상을 연결한다.

 

그리고 glTexImage2D()로 텍스쳐로 쓸 GLubyte 배열을 쓴다.

 

glTexParameteri()로 확대/축소시 텍스쳐 필터를 설정하고

glTexEnvi()로 텍스쳐 환경 설정을 한다.(레퍼런스 참고)

 

 

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);



glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    w, h, 0,
    GL_RGBA, GL_UNSIGNED_BYTE,
    map
);

 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

 

 

텍스쳐의 너비와 높이가 각각 2의 거듭제곱 꼴일 때 높은 성능을 얻을 수 있다.

(메모리에 2의 거듭제곱 단위로 할당되기 때문에..)

OpenGL ES에서는 아예 2의 거듭제곱꼴만 하용하고 있다.

예시) 64x128, 128x128, 256x64 등

 

 

이제 텍스쳐를 그리는 부분이다.

여기서는 평면상에 텍스쳐를 그릴 것인데, 먼저 OpenGL의 좌표계에 대해 알아야 한다.

 

별도의 설정을 하지 않을 시, 화면의 중앙이 원점이 되며 우측 상단으로 갈 수록 x와 y 값이 각각 증가한다.

우측 상단 꼭지점의 좌표는 (1, 1)이다.

 

 

텍스쳐 이미지 자체의 좌표는, 이미지의 좌측하단이 원점이며,

이미지의 우측상단이 (1, 1)이다.

 

 

 

 

glOrtho()함수를 쓰면 좌표계(클리핑 범위)를 재설정할 수 있다. 형식은 아래와 같다.

glOrtho(왼쪽, 오른쪽, 아래, 위, z축 근거리방향, z축 원거리방향)

 

2D만 고려할 때, glOrtho(0, 너비, 높이, 0 정도로 지정하면

MFC, JS 등에서처럼 좌측상단을 원점으로 쓸 수 있다.

 

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glOrtho(0, 창의 너비, 창의 높이, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glBindTexture(GL_TEXTURE_2D, texId);

glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
    glTexCoord2f(1.0, 0.0); glVertex2f(w, 0);
    glTexCoord2f(1.0, 1.0); glVertex2f(w, h);
    glTexCoord2f(0.0, 1.0); glVertex2f(0, h);
glEnd();
 

 

 

glTexCoord2f()로 그릴 텍스쳐 영역을 지정할 때 

텍스쳐가 뒤집혀 있는 상태이므로 아래와 같은 순서로 그린 것이다.

 

 

 

 

아래는 png 이미지를 로드하여 화면에 두 번 표시해본 화면이다.

이미지를 로드하기 위해 SDL2를 사용했는데, SDL2 대신 glut과 pnglib라이브러리 써도 png 이미지파일을 읽어올 수 있다. (pnglib라이브러리 없이도 BMP파일은 로드 가능.) 

 

 

 

#pragma comment(lib, "SDL2")

#pragma comment(lib, "SDL2main")

#pragma comment(lib, "SDL2_image")

#pragma comment(lib, "opengl32.lib")

#include <cstdio>

#include <SDL.h>

#include <SDL_opengl.h>

#include <SDL_image.h>


using namespace std;

SDL_Renderer * renderer;

int main(int argc, char ** argv) {

    int winWidth = 800;

    int winHeight = 600;

    SDL_Window * win = NULL;

    SDL_Renderer * renderer = NULL;

    SDL_Surface * image;

    SDL_RWops * rwop;

    rwop = SDL_RWFromFile("../res/img.png", "rb");

    image = IMG_LoadPNG_RW(rwop);

    GLubyte * map = (GLubyte * ) image - > pixels;

    int w, h;

    w = image - > w;

    h = image - > h;

    if (SDL_Init(SDL_INIT_VIDEO) < 0)

        return 1;

    win = SDL_CreateWindow("gl", 100, 100, winWidth, winHeight, SDL_WINDOW_OPENGL);

    renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);

    SDL_GLContext context;

    context = SDL_GL_CreateContext(win);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glEnable(GL_BLEND);

    glEnable(GL_TEXTURE_2D);

    GLuint texId;

    glGenTextures(1, & texId);

    glBindTexture(GL_TEXTURE_2D, texId);

    glTexImage2D(

        GL_TEXTURE_2D, 0, GL_RGBA,

        w, h, 0,

        GL_RGBA, GL_UNSIGNED_BYTE,

        map

    );

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    while (1) {

        SDL_Event e;

        if (SDL_PollEvent( & e)) {

            if (e.type == SDL_QUIT)

                break;

            else if (e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE)

                break;

        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glOrtho(0, winWidth, winHeight, 0, -1, 1);

        glMatrixMode(GL_PROJECTION);

        glLoadIdentity();

        glBindTexture(GL_TEXTURE_2D, texId);

        glBegin(GL_QUADS);

        glTexCoord2f(0.0, 0.0);
        glVertex2f(0, 0);

        glTexCoord2f(1.0, 0.0);
        glVertex2f(w, 0);

        glTexCoord2f(1.0, 1.0);
        glVertex2f(w, h);

        glTexCoord2f(0.0, 1.0);
        glVertex2f(0, h);

        glEnd();

        glBegin(GL_QUADS);

        glTexCoord2f(0.0, 0.0);
        glVertex2f(0 + 30, 0 + 30);

        glTexCoord2f(1.0, 0.0);
        glVertex2f(w + 30, 0 + 30);

        glTexCoord2f(1.0, 1.0);
        glVertex2f(w + 30, h + 30);

        glTexCoord2f(0.0, 1.0);
        glVertex2f(0 + 30, h + 30);

        glEnd();

        SDL_GL_SwapWindow(win);

        SDL_Delay(21);

    }

    SDL_GL_DeleteContext(context);

    SDL_DestroyRenderer(renderer);

    SDL_DestroyWindow(win);

    return 0;

}

 

출처: http://tibyte.kr/232 [티바이트]

 

 

=================================

=================================

=================================

 

 

 

 

반응형