우선 openGL에 대한 기본적인 지식을 learnOpenGL 이라는 사이트에서 공부했다.
컴퓨터 그래픽스에 관심있는 사람들에겐 나름 유명한 사이트인듯?
어쨌든 learnOpenGL에서 한 대로 개발환경을 설정했는데( GLFW, glad, glm등..)
GLFW는 모바일 환경을 지원하지 않는다고 한다.
아이패드 앱을 만드려면 OpenGL ES나 metal을 써야할 것 같은데
이미 OpenGL은 애플측에서 더이상 지원하지 않겠다고 해서 아마 메탈을 쓸것 같다.
그래서 공부하고 만들어 놓은게 있으니, openGL로 좀 더 개발하고 메탈로 넘어갈 계획이다.
카메라 이동
지금까지 기본적인 조작과 버텍스를 수정하는 기능을 만들었다.
WASD로 X, Y축으로 이동할 수 있고,
오른쪽 버튼을 누른채로 드래그하면 회전할 수 있다.
void processInput(GLFWwindow *window)
{
float cameraSpeed = 0.05f;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
if(glfwGetKey(window,GLFW_KEY_W) == GLFW_PRESS)
cameraPos +=cameraSpeed *cameraFront;
if(glfwGetKey(window,GLFW_KEY_S)==GLFW_PRESS)
cameraPos -= cameraSpeed*cameraFront;
if(glfwGetKey(window,GLFW_KEY_A)==GLFW_PRESS)
cameraPos -= glm::normalize(glm::cross(cameraFront,cameraUp)) * cameraSpeed;
if(glfwGetKey(window,GLFW_KEY_D) ==GLFW_PRESS)
cameraPos += glm::normalize(glm::cross(cameraFront,cameraUp))*cameraSpeed;
}
사실 이동은 LearnOpenGL의 것과 거의 똑같다
카메라 회전
회전은 마우스가 얼마나 움직였는지 오프셋을 구하고,
만약 오른쪽 버튼을 누르는 중이라면 오프셋만큼 카메라를 회전한다.
우선은 glfwSetMouseButtonCallback에 콜백함수를 등록해서 오른쪽 버튼을 누르고 있는 상태인지 아닌지 체크한다.
유니티의 GetKeyDown, GetKey, GetKeyUp처럼 3가지 상태를 다 받을 수 있을 줄 알았는데,
PRESS 또는 RELEASE 두 개만 받을 수 있는것 같아서
따로 bool 변수를 만들어서 상태를 저장한다.
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods){
if(button==GLFW_MOUSE_BUTTON_RIGHT && action==GLFW_PRESS){
bLastRightBtn=true;
}
if(button==GLFW_MOUSE_BUTTON_RIGHT && action==GLFW_RELEASE){
bLastRightBtn=false;
}
}
그리고 glfwSetCursorPosCallback에도 콜백함수를 등록해서
마우스의 위치(스크린 좌표라고 한다)를 구하고
마우스 위치의 오프셋을 구해서 그만큼 카메라(view 행렬)를 회전시킨다
void mouse_callback(GLFWwindow* window, double xpos, double ypos){
float xoffset=xpos-lastX;
float yoffset = lastY-ypos;
lastX=xpos;
lastY=ypos;
float sensitivity =0.005f;
xoffset *=sensitivity;
yoffset *=sensitivity;
x =static_cast<float>(xoffset);
y = static_cast<float>(yoffset);
if(bLastRightBtn)
rotateView(xoffset,yoffset);
}
void rotateView(float xoffset, float yoffset){
if(bFirstRotate){
yaw=xoffset*CAMERA_ROTATE_SPEED;
pitch=yoffset*CAMERA_ROTATE_SPEED;
bfirstRotate =false;
}
yaw += xoffset*CAMERA_ROTATE_SPEED;
pitch += yoffset*CAMERA_ROTATE_SPEED;
glm::vec3 front;
if(pitch >89.0f){
pitch =89.0f;
}
if(pitch<-89.0f){
pitch =-89.0f;
}
front.x= cos(glm::radians(yaw)) *cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z= cos(glm::radians(pitch)) *sin(glm::radians(yaw));
cameraFront = glm:: normalize(front);
}
roateView()안의 내용 역시 LearnOpenGL의 것과 매우 유사함..
그리고 저 큐브가 찌그러진건..
아마 EBO를 잘못 설정한 것 같은데 그냥 귀찮아서 냅뒀다
버텍스 수정
모델의 특정 버텍스를 집어서 위치를 수정할 수 있는 기능을 만들었다.
우선 왼쪽 버튼 입력이 들어오면 searchVertex()를 통해 마우스 입력값의 일정 범위내에 버텍스가 있는지 조사한다.
bool searchVertex(){
for(int i=0; i<8;i++){
glm::vec2 screenCube = coordinatelocalToScreen(cube2[6*i+0],cube2[6*i+1],cube2[6*i+2]);
if(abs(screenCube.x- lastX)<=70 && abs(screenCube.y- (SCR_HEIGHT-lastY))<=70){
selectX = 6*i+0;
selectY = 6*i+1;
selectZ = 6*i+2;
return true;
}
}
return false;
}
마우스 인풋으로 받는 값이 스크린 좌표이기에,
버텍스 배열에 있는 좌표들을 coordinateLocalToScreen()이라는 함수를 통해
로컬에서 스크린 좌표로 변환 후 비교해줬다.
glm::vec2 coordinatelocalToScreen(float x,float y, float z){
glm::vec4 local = glm::vec4(x,y,z,1.0f);
glm::vec4 viewCoord = view*local;
glm::vec4 clipCoord = projection * viewCoord;
glm::vec3 ndc = glm::vec3(clipCoord)/clipCoord.w;
glm::vec2 screen = glm::vec2((ndc.x+1)*(SCR_WIDTH/2),(ndc.y+1)*(SCR_HEIGHT/2));
return screen;
}
여기서 좀 헤맨게,
스크린 좌표에서 y좌표는 반대라는걸 몰라서 삽질 좀 했다
아니 당연히 오른쪽 위가 (300,300) 이여야 하는거 아냐??
쨌든 일정 범위내에 버텍스가 있다면 modifyVertex()로 버텍스의 위치를 수정한다.
void modifyVertex(){
float offset[2] ={cube2[selectX],cube2[selectY]};
offset[0] += x;
offset[1] += y;
glBindBuffer(GL_ARRAY_BUFFER,newVBO);
glBufferSubData(GL_ARRAY_BUFFER,selectX*sizeof(float),sizeof(offset),offset);
}
그런데 여기서..
glBufferSubData()라는 함수를 통해 버텍스 배열을 수정하는데..
짤에서 보다시피 자꾸 원래의 버텍스 위치로 돌아가는 버그가 있었다.
저 함수가 실제 배열을 수정하는게 아니라 한 프레임만 바꿔주는 건지..
직접 버텍스 배열을 바인드해서 glBufferData로 데이터를 수정해주면 원하는대로 잘 동작했다.
그래서 glBufferSubData() 이후에 실제 버텍스 배열에도 똑같은 값을 더해주니..
원하는 대로 잘 동작한다.
void modifyVertex(){
float offset[2] ={cube2[selectX],cube2[selectY]};
offset[0] += x;
offset[1] += y;
glBindBuffer(GL_ARRAY_BUFFER,newVBO);
glBufferSubData(GL_ARRAY_BUFFER,selectX*sizeof(float),sizeof(offset),offset);
cube2[selectX]+=x;
cube2[selectY]+=y;
}
근데 또 여기서 끝이 아니라
일반적인 상황에선 잘 되는데
카메라가 돌아가면 수정이 좀 이상하게 되는 경우가 생긴다.
처음에는 잘 동작하다가도
카메라를 회전시키면 x축이 반대가 된다.
사실 당연한 것이
카메라가 회전을 하면 카메라 입장에서 x축은 계속 변하는데
로컬 입장에서 x축은 변하지 않으니깐..
그래서 카메라의 오른쪽 축(x축)을 구한 뒤에
그 방향으로 버텍스가 수정되게끔 만들었다.
void modifyVertex(){
glm::vec3 up = glm::vec3(0.0f,1.0f,0.0f);
glm::vec3 right = glm::normalize(glm::cross(up,-cameraFront));
float offset[3] ={cube2[selectX],cube2[selectY],cube2[selectZ]};
offset[0] += x*right.x;
offset[1] += y;
offset[2] += x*right.z;
glBindBuffer(GL_ARRAY_BUFFER,newVBO);
glBufferSubData(GL_ARRAY_BUFFER,selectX*sizeof(float),sizeof(offset),offset);
cube2[selectX]+= x*right.x;
cube2[selectY]+= y;
cube2[selectZ]+= x*right.z;
}
이젠 어느 방향에서 수정해도 잘 동작한다..
'컴퓨터 그래픽스 > OpenGL' 카테고리의 다른 글
#5 tinylender 개발일지 : 상태 머신 적용 (0) | 2024.05.12 |
---|---|
#4 gulender 개발일지 : mesh, model 그리고 assimp 세팅 (0) | 2024.05.12 |
#3 gulender 개발일지 : rpath 설정 (0) | 2024.05.08 |
#2 gulender 개발일지 : GUI 개발 (0) | 2024.05.01 |
#0 gulender 개발일지 : 개요 (1) | 2024.03.30 |