코드 짤때는 GC호출을 최소화해야함


그러려면 가비지를 만드는일을 최소화해야하는데


그 중 Dictionary의 key를  Enum으로 쓰는 경우를 테스트 해봄



* Init


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


enum TestEnum

{

    A,

}


public class DictionaryEnumTest : MonoBehaviour

{


    Dictionary<TestEnum, string> testEnumDic;

    Dictionary<int, string> testIntDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        InitIntDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>();

    }


    void InitIntDic()

    {

        testIntDic = new Dictionary<int, string>();

    }


}


위 코드로 테스트한 프로파일러 결과임




빨간색 칠해둔것을 보면 Enum을 Key로 한 Dictionary가 GC Alloc 0.2KB 더 많이함

양이 많지는 않음(빈번하면 안좋음)




* Add


아까 생성한 두 Dictionary에 각각 값을 넣어봤음


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


enum TestEnum

{

    A,

}


public class DictionaryEnumTest : MonoBehaviour

{


    Dictionary<TestEnum, string> testEnumDic;

    Dictionary<int, string> testIntDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        InitIntDic();


        AddEnumDic();

        AddIntDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>();

    }


    void InitIntDic()

    {

        testIntDic = new Dictionary<int, string>();

    }


    void AddEnumDic()

    {

        testEnumDic.Add(TestEnum.A, "A");

    }


    void AddIntDic()

    {

        testIntDic.Add(1, "A");

    }

}



20B를 생성했음..

Dictionary에 값이 많이 들어간다 생각하면 개손해임



* TryGetValue


가장 빈번할것으로 예상되는 값 찾기


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


enum TestEnum

{

    A,

}


public class DictionaryEnumTest : MonoBehaviour

{

    Dictionary<TestEnum, string> testEnumDic;

    Dictionary<int, string> testIntDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        InitIntDic();


        AddEnumDic();

        AddIntDic();


        GetValueEnumDic();

        GetValueIntDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>();

    }


    void InitIntDic()

    {

        testIntDic = new Dictionary<int, string>();

    }


    void AddEnumDic()

    {

        testEnumDic.Add(TestEnum.A, "A");

    }


    void AddIntDic()

    {

        testIntDic.Add(1, "A");

    }


    void GetValueEnumDic()

    {

        string result;

        testEnumDic.TryGetValue(TestEnum.A, out result);

    }


    void GetValueIntDic()

    {

        string result;

        testIntDic.TryGetValue(1, out result);

    }

}




Key가 int인거는 0생성했는데

enum인거는 1번찾는데 60B 생성함... 핵손해


장난삼아 10만번 돌려봄




게임마다 다르겠지만 10만번을 찾을일이 게임에서 많지는 않을 것 같은데 아무튼 5.7MB나 생성함








* 해결책


https://stackoverflow.com/questions/26280788/dictionary-enum-key-performance

위 링크를 보고 함


저 중에서 가장 쉬워보이는 1번 솔루션을 적용해봄


첫번째 프로파일러 스크린샷인데 저걸 열어보면 EqualityComparer라는애가 있음

키를 비교할 때 enum이기때문에 비교할 때 Boxing UnBoxing하는데 비용이 크다고 함

그래서 비교하는애를 Dictionary 생성할 때 넣어주는거임


public struct MyEnumCOmparer : IEqualityComparer<MyEnum>
{
    public bool Equals(MyEnum x, MyEnum y)
    {
        return x == y;
    }

    public int GetHashCode(MyEnum obj)
    {
        // you need to do some thinking here,
        return (int)obj;
    } 

}


new Dictionary<MyEnum, int>(new MyEnumComparer());


이 코드를 나의 테스트 코드에 맞게 바꾸고 테스트 함


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public enum TestEnum

{

    A,

}


public struct TestEnumComparer : IEqualityComparer<TestEnum>

{

    public bool Equals(TestEnum x, TestEnum y)

    {

        return x == y;

    }


    public int GetHashCode(TestEnum obj)

    {

        return (int)obj;

    }

}


public class DictionaryEnumTest : MonoBehaviour

{

    Dictionary<TestEnum, string> testEnumDic;


    // Use this for initialization

    void Start()

    {

        InitEnumDic();

        AddEnumDic();

        GetValueEnumDic();

    }


    void InitEnumDic()

    {

        testEnumDic = new Dictionary<TestEnum, string>(new TestEnumComparer());

    }

    

    void AddEnumDic()

    {

        testEnumDic.Add(TestEnum.A, "A");

    }

    

    void GetValueEnumDic()

    {

        string result;

        for(int i=0;i<100000;i++)

            testEnumDic.TryGetValue(TestEnum.A, out result);

    }    

}




10만번 Get할때 가비지 한개도 안생기고 Add할때도 사라짐


개이득


생성할 때도 없애기 위해서 Dictionary key값을 int로 바꾸는거는 너무 가독성면에서나 작업량에서나 손해고


Key는 enum으로 쓰면서 위 방법을 사용하면 어느정도 쉽고 빠르게 해결 가능





lighthouse3d.com 보고 하고있는데 키보드 인풋, 카메라이동이 따로있는데 합쳐서 봄. 어차피 키보드로 움직이는거라


눈사람을 여러마리 그릴껀데 함수화한다 (코드는 lighthouse3d.com에서 가져옴)

void DrawSnowMan() { glColor3f(1.0f, 1.0f, 1.0f); // 몸 glTranslatef(0.0f ,0.75f, 0.0f); glutSolidSphere(0.75f,20,20); // 머리 glTranslatef(0.0f, 1.0f, 0.0f); glutSolidSphere(0.25f,20,20); // 눈 glPushMatrix(); glColor3f(0.0f,0.0f,0.0f); glTranslatef(0.05f, 0.10f, 0.18f); glutSolidSphere(0.05f,10,10); glTranslatef(-0.1f, 0.0f, 0.0f); glutSolidSphere(0.05f,10,10); glPopMatrix(); //코 glColor3f(1.0f, 0.5f , 0.5f); glutSolidCone(0.08f,0.5f,10,2);

}


여기서 두 함수를 보면


void WINAPI glPushMatrix(void);
void WINAPI glPopMatrix(void);


현재까지의 ModelViewMatrix를 스택에 넣고 빼는 역할을 함


Save, Load 의 역할이라고 보면 된다.





Draw를 다시 만들고 돌리면


void Draw()

{

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    

    glLoadIdentity();

    gluLookAt(0.0f, 1.0f, 5.0f,

              0, 1.0f, 4.0f,

              0, 1.0f, 0);

    

//판때기 그림

    glColor3f(0.9f, 0.9f, 0.9f);

    glBegin(GL_QUADS);

    glVertex3f(-100.0f, 0.0f, -100.0f);

    glVertex3f(-100.0f, 0.0f100.0f);

    glVertex3f( 100.0f, 0.0f100.0f);

    glVertex3f( 100.0f, 0.0f, -100.0f);

    glEnd();

    

//눈사람 그림

    for(int i = -3; i < 3; i++)

        for(int j=-3; j < 3; j++) {

            glPushMatrix();

            glTranslatef(i*10.0,0,j * 10.0);

            DrawSnowMan();

            glPopMatrix();

        }

    

    glutSwapBuffers();

}





여기서 카메라를 움직이기 위해서 키보드 입력을 받자


void glutKeyboardFunc(void (*func) (unsigned char key, int x, int y));

void glutSpecialFunc(void (*func) (int key, int x, int y));


이거 두개를 사용해서 콜백등록하면됨


등록할 함수


void ProcessNormalKeys(unsigned char key, int x, int y) {

    

    if (key == 27)

        exit(0);

}


void ProcessSpecialKeys(int key, int x, int y) {

    

    float fraction = 0.1f;

    

    switch (key) {

        case GLUT_KEY_LEFT :

            angle -= 0.01f;

            lx = sin(angle);

            lz = -cos(angle);

            break;

        case GLUT_KEY_RIGHT :

            angle += 0.01f;

            lx = sin(angle);

            lz = -cos(angle);

            break;

        case GLUT_KEY_UP :

            x += lx * fraction;

            z += lz * fraction;

            break;

        case GLUT_KEY_DOWN :

            x -= lx * fraction;

            z -= lz * fraction;

            break;

    }

}


저거는 키 입력받으면 값만바꿈


바뀐 값으로 카메라를위치시키기위해 gluLookAt 파라미터 변경


    gluLookAt(x, 1.0f, z,

              x+lx, 1.0f, z+lz,

              0, 1.0f, 0);






int glutGetModifiers(void);


참고로 이거쓰면 특수키 정의할 수 있음


void processNormalKeys(unsigned char key, int x, int y) {

	if (key == 27)
		exit(0);
	else if (key=='r') {
		int mod = glutGetModifiers();
		if (mod == GLUT_ACTIVE_ALT)
			red = 0.0;
		else
			red = 1.0;
	}
}


이런식으로





* 이거 말고도 키를 뗐을 때 콜백도 있고 반복입력설정하는 함수도 있다 근데 나는 이게 필요하지 않기 때문에 포스팅 안하는데 lighthouse3d.com가면 찾을 수 있음






'OpenGL' 카테고리의 다른 글

[OpenGL]GLUT Idle  (0) 2017.07.01
[OpenGL]GLUT Reshape  (0) 2017.06.30
[OpenGL]GLUT Initializatio  (0) 2017.06.24
xcode에서 opengl 프로젝트 만들기  (0) 2017.06.23

OpenGL이 Idle상태일 때 그리는 콜백을 등록해서 애니메이션을 해보겠다


void glutIdleFunc (void (* func) (void));


이 함수에 앞서 만든 Draw함수를 쓰면 등록 완료


int main(int argc, char** argv)

{

     //GLUT 속성 설정, 생성

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DEPTH|GLUT_RGBA|GLUT_DOUBLE);

    glutInitWindowPosition(200, 200);

    glutInitWindowSize(300, 300);

    glutCreateWindow("OpenGL");

    

    // 콜백 등록

    glutDisplayFunc(Draw);

    glutReshapeFunc(Reshape);

    glutIdleFunc(Draw);

    

    // 이벤트 프로세싱 사이클 진입

    glutMainLoop();

    

    return 0;

}


밑줄 친 코드임


원래 Draw를 보면 삼각형만 그리는 코드인데 이 삼각형을 돌려보겠다


void Draw()

{

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    

    glLoadIdentity();

    gluLookAt(0, 0, 0.0f,

              0, 0, -10,

              0, 1.0f, 0);

    

    glTranslatef(0, 0, -2);

    glRotatef(rotate, 0, 1, 0);

    

    glBegin(GL_TRIANGLES);

        glVertex3f(-0.5f,-0.4f,0.0);

        glVertex3f(0.5f,-0.4f,0.0);

        glVertex3f(0.0,0.4f,0.0);

    glEnd();

    

    rotate += 1.0f;

    

    glutSwapBuffers();

}


얘가 새로운 Draw 코드


gluLookAt은 카메라를 만드는 함수임(내부적으로 Viewing Tranformation Matrix를 만듬)


아래 glTranslatef와 glRotate는 아래 삼각형을 Translate하는 함수


사실 gluLookAt 파라미터에 0,0,2 / 0,0,0 / 0,1,0 을 넣으면 아래 Translate를 안써도 되지만 저렇게 한번 그려봄


마지막에 rotate를 더해주면 gluItIdleFunc에 등록된 Draw(이 함수임)가 계속 호출되면서 값이 더해지고 증가된 만큼 돌림


프레임이 지날때 마다 rotate는 증가하므로 돌아가는 애니메이션처럼 됨


마지막으로 glutSwapBuffers를 호출하면 그려짐


이 함수는


glutInitDisplayMode(GLUT_DEPTH|GLUT_RGBA|GLUT_DOUBLE);


위 처럼 더블버퍼를 썻기 때문에 프론트버퍼와 백버퍼를 바꿔주는 역할을 하고


만약 싱글버퍼를 쓴다면 버퍼에 새로 그리는 역할을 한다


내부적으로는 glFlush()가 호출된다


glFlush는 쌓여있는 명령을 지우는 일을 함


gif만드는법 몰라서 일단 코드만 올렸는데 한번 돌려보셈



#include <iostream>

#include <GLUT/glut.h>


float rotate = 0.0f;


void Reshape(int w, int h)

{

    if(h == 0)

        h = 1;

    

    float ratio = 1.0f * w/h;

    

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    glViewport(0, 0, w, h);

    gluPerspective(45, ratio, 0.1f, 100);

    glMatrixMode(GL_MODELVIEW);

}


void Draw()

{

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    

    glLoadIdentity();

    gluLookAt(0, 0, 0.0f,

              0, 0, -10,

              0, 1.0f, 0);

    

    glTranslatef(0, 0, -2);

    glRotatef(rotate, 0, 1, 0);

    

    glBegin(GL_TRIANGLES);

        glVertex3f(-0.5f,-0.4f,0.0);

        glVertex3f(0.5f,-0.4f,0.0);

        glVertex3f(0.0,0.4f,0.0);

    glEnd();

    

    rotate += 1.0f;

    

    glutSwapBuffers();

}


int main(int argc, char** argv)

{

     //GLUT 속성 설정, 생성

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DEPTH|GLUT_RGBA|GLUT_DOUBLE);

    glutInitWindowPosition(200, 200);

    glutInitWindowSize(300, 300);

    glutCreateWindow("OpenGL");

    

    // 콜백 등록

    glutDisplayFunc(Draw);

    glutReshapeFunc(Reshape);

    glutIdleFunc(Draw);

    

    // 이벤트 프로세싱 사이클 진입

    glutMainLoop();

    

    return 0;

}







'OpenGL' 카테고리의 다른 글

[OpenGL]GLUT Keyboard  (1) 2017.07.01
[OpenGL]GLUT Reshape  (0) 2017.06.30
[OpenGL]GLUT Initializatio  (0) 2017.06.24
xcode에서 opengl 프로젝트 만들기  (0) 2017.06.23

+ Recent posts