2012-10-25 8 views
5

그래서 저는 2D 스켈 레탈 애니메이션 시스템으로 작업하고 있습니다.OpenGL ES에서 스켈 레탈 애니메이션을위한 정점 최적화

뼈 수가 X 개 있고, 각 본은 적어도 1 부분 (쿼드, 2 개의 삼각형)을 가지고 있습니다. 평균적으로 나는 20 개의 뼈와 30 개의 부분을 가지고 있습니다. 대부분의 뼈는 부모에 달려 있고 뼈는 모든 프레임으로 움직입니다. 애니메이션 당 총 1000 프레임이 있으며 약 50 개의 애니메이션을 사용하고 있습니다. 한 번에 총 약 50,000 개의 프레임이 메모리에로드됩니다. 이 부분은 골격의 인스턴스마다 다릅니다.

[x1,y1,u1,v1],[x2,y2,u2,v2],[x3,y3,u3,v3],[x4,y4,u4,v4] 

그리고 glDrawElements 각 통해 전달 :

내가했다 첫 번째 방법은 각 뼈의 위치/회전을 계산하고 각 부분이 구성 정점 배열을 구축하는 것이 었습니다 틀.

괜찮아 보이고, 필요한 모든 시나리오를 다루고, 많은 메모리를 사용하지 않지만 개처럼 수행합니다. 아이팟 4의 경우, 렌더링되는 이러한 뼈대 중 10 개를 사용하여 15fps를 얻을 수 있습니다.

나는 각 프레임마다 너무 많은 정점 데이터를 복사하여 성능을 극대화하려고 노력했습니다. 나는 또 다른 극단으로 가서 각 캐릭터의 시작 부분에 모든 프레임에 대한 xyuv 좌표를 포함한 버텍스 버퍼를 구축하여 애니메이션을 "사전 계산"하기로 결정했습니다. 그런 다음 특정 시간에 사용해야하는 프레임의 인덱스를 계산하고 델타 값을 계산합니다. 델타 값은 현재 프레임과 다음 프레임 XY 위치 사이를 보간하는 데 사용되는 셰이더로 전달됩니다.

attribute vec4 a_position; 
attribute vec4 a_nextPosition; 
attribute vec2 a_texCoords; 
attribute float a_boneIndex; 

uniform mat4 u_projectionViewMatrix; 
uniform float u_boneAlpha[255]; 

varying vec2 v_texCoords; 

void main() { 
    float alpha = u_boneAlpha[int(a_boneIndex)]; 
    vec4 position = mix(a_position, a_nextPosition, alpha); 
    gl_Position = u_projectionViewMatrix * position; 
    v_texCoords = a_texCoords; 
} 

이제 성능이 화면에서 다음의 10, 훌륭한, 그것은에 편안하게 앉아 :

정점은

[--------------------- Frame 1 ---------------------],[------- Frame 2 ------] 
[x1,y1,u1,v1,boneIndex],[x2, ...],[x3, ...],[x4, ...],[x1, ...][x2, ...][....] 

버텍스 쉐이더는 다음과 같습니다 프레임 당이처럼 보였다 50fps. 하지만 지금은 메모리 사용량이 많습니다. xyuv에 대한 정밀도를 잃어 버려서 최적화했습니다. 이제는 ushorts입니다.

뼈 종속성이 손실되는 문제가 있습니다. 부모와 자식이 두 개 있고 자식이 0과 2에 키 프레임을 가지고있는 경우 부모는 0, 0.5, 1.5, 2 초에 키 프레임을가집니다. 그러면 0.5 초와 1 초 사이에 자식이 변경되지 않습니다. 1.5 초.

나는이 뼈 문제를 해결할 해결책을 생각해 냈습니다. 부모와 같은 지점에서 키 프레임을 갖도록 강요했습니다. 그러나 이것은 더 많은 메모리를 사용하고 기본적으로 뼈 계층 구조의 포인트를 없앱니다.

여기가 지금입니다. 성능과 메모리 사용간에 균형을 찾으려고합니다. 여기에 많은 중복 정보가 있습니다. (UV 좌표는 특정 부분의 모든 프레임에서 동일하므로 30 번 반복됩니다.) 그리고 새로운 버퍼는 모든 파트 세트 (고유 한 XYUV 좌표를 가지고 있습니다 - 다른 파트가 다른 크기이기 때문에 위치가 변경됩니다)

지금 당장 문자 당 하나의 버텍스 배열을 설정하려고합니다. 모든 파트에 대해 xyuv가 있고 각 파트에 대한 행렬을 계산하고 셰이더에서 위치를 재조정합니다. 이게 효과가있을 거라는 걸 알지만 성능이 처음 시작할 때 각 프레임마다 XYUV를 업로드하는 것보다 낫지 않을지 걱정됩니다.

내가 얻은 성능을 잃지 않고이를 수행하는 더 좋은 방법이 있습니까?

시도해 볼만한 아이디어가 있습니까?

+0

좋은 질문 각하 – Weacked

+0

모든 프레임이 모든 프레임에서 "자체적으로 이동"합니까 아니면 부모가 이동했기 때문에 많은 뼈가 이동 되었습니까? – Dirk

+0

뼈 중 하나를 제외하고 모두 부모와 함께 이동합니다. 부모와 독립적으로 거의 무의미한 뼈가 있습니다. 그리고 부모가 움직이는 것보다 더 많은 시간을 움직이는 것들도 있습니다. –

답변

1

이 작업을 수행하는 더 좋은 방법은 30 가지 파트를 즉시 변환하고 다른 위치에 파트를 수천 부씩 복사하지 않는 것입니다. 버텍스 버퍼에는 정점 데이터 복사본이 하나 포함되어있어 엄청난 양의 메모리를 절약 할 수 있습니다. 그런 다음 각 프레임은 glDrawElements()을 호출하여 그리는 각 뼈대에 대해 정점 쉐이더에 유니폼으로 전달 된 변형 집합으로 나타낼 수 있습니다. 각 종속 뼈의 변형은 부모 뼈대를 기준으로 작성됩니다. 그런 다음, 손으로 제작하고 절차 적으로 생성 된 연속물의 어디에서 애니메이션을 원 하느냐에 따라, 변환 세트의 공간 및 CPU 계산 시간이 다소 줄어들 수 있습니다.

제이슨 L. 맥 케슨 (McKesson)의 무료 책

, Learning Modern 3D Graphics Programming 는이 장 끝에 6 장에서 예제 프로그램을이 작업을 수행하는 방법에 대한 좋은 설명을 제공 계층 적 모델을 구현하기 위해 행렬 스택을 사용하는 방법을 보여줍니다. I have an OpenGL ES 2.0 on iOS port of this program available.

+0

불행히도, 그것이 정확히 원래의 버전이 어떻게 작동했는지입니다. 그리고 현재의 구현만큼 빠르게 아무데도 수행하지 않았습니다. 나는이 방법으로 성가신 많은 양의 메모리를 사용하고 로딩 시간을 늘릴 수 있음을 알았지 만 화면에 많은 문자를 넣으면 50 % 이상 빨라졌습니다. 그러나 제안에 감사 드리며 투표했습니다. –

관련 문제