답변:
더 나은 텍스쳐 패킹 알고리즘을 생각해 내기 위해 한 달에 몇 달을 보냈습니다.
우리가 시작한 알고리즘은 간단했습니다. 모든 입력 항목을 수집하십시오. 소비 한 총 픽셀 수를 기준으로 정렬합니다. 텍스쳐에 스캔 라인 순서로 배치하십시오. 왼쪽 위 픽셀에서 오른쪽 위 픽셀까지 테스트하고, 줄을 아래로 이동하고, 반복, 배치가 완료된 후 왼쪽 위 픽셀로 재설정하면됩니다.
너비를 하드 코딩하거나 다른 휴리스틱을 만들어야합니다. 직각도를 유지하기 위해 알고리즘은 128에서 시작한 다음 너비보다 깊지 않은 결과가 나올 때까지 128 초씩 증가합니다.
그래서 우리는 그 알고리즘을 가지고 있었고, 그것을 개선하기로 결정했습니다. 나는 엉뚱한 휴리스틱을 시도했다. 함께 맞는 객체를 찾고, 원하는 공간 패킹 속성에 대해 가중치를 부여하고, 회전하고 뒤집기. 문자 그대로 3 개월 동안 일한 결과, 3 %의 공간을 절약했습니다.
네. 삼%.
그리고 압축 루틴을 실행 한 후에는 실제로 더 커져서 (아직 설명 할 수 없습니다) 전체 내용을 버리고 이전 알고리즘으로 돌아갔습니다.
스캔 라인 순서대로 항목을 정렬하고 질감에 잼하십시오. 알고리즘이 있습니다. 코딩하기 쉽고 빠르게 실행할 수 있으며 놀라운 작업 없이는 더 나아지지 않을 것입니다. 회사 규모가 50 명 이상 이고 그 이상인 경우가 아니라면 그 작업은 가치가 없습니다 .
그리고 부수적으로, 나는 방금 말 그대로 당신이하고있는 것과 똑같은 응용 프로그램 (ftgles이 아니라 opengl- 렌더링 된 자유형 글리프)을 위해이 알고리즘 (고정 너비 512 픽셀)을 구현했습니다. 결과는 다음과 같습니다. 광산이 Valve의 거리 필드 기반 텍스트 렌더링 알고리즘을 사용하고 있기 때문에 흐릿하게 보입니다.이 알고리즘 은 글리프 사이의 추가 공간을 차지합니다. 분명히, 빈 공간이 많이 남아 있지 않으며 물건을 열린 곳으로 밀어 넣는 것이 좋습니다.
이에 대한 모든 코드는 BSD 라이센스이며 github에서 사용할 수 있습니다 .
Andrea Lodi의 박사 학위 논문은 2 차원 빈 포장 및 할당 문제에 대한 알고리즘 제목이 있습니다.
논문은이 문제의 더 어려운 형태를 다루고 있습니다. 운 좋게도 텍스쳐 패킹은 가장 쉬운 버전입니다. 그가 찾은 최고의 알고리즘은 Touching Perimeter 입니다.
52 페이지에서 인용하려면 :
TPRF (Touching Perimeter)라고하는 알고리즘은 비 증가 영역에 따라 항목을 정렬하고 (최소 증가하지 않는 min {wj, hj} 값으로 연결 해제) 가로 방향으로 시작합니다. 그런 다음 최적 솔루션 값의 하한 L이 계산되고 L 빈 빈이 초기화됩니다. (이전 섹션에서 정의 된 연속 하한 L0은 2BP | R | F에도 유효합니다. Dell'Amico, Martello 및 Vigo [56]에서 더 나은 범위를 제안합니다. 알고리즘은 한 번에 하나의 항목을 압축합니다. 기존 빈에서 또는 새 빈을 초기화하여. 빈에 포장 된 첫 번째 품목은 항상 왼쪽 하단에 있습니다. 각 후속 품목은 소위 정상 위치에 포장됩니다 (ChristoFade 및 Whitlock [41] 참조).
빈 및 포장 위치의 선택은 빈에 닿는 품목 주변 및 이미 포장 된 다른 품목의 백분율로 정의 된 점수를 평가하여 수행됩니다. 이 전략은 포장 된 품목이 작은 영역을 "트랩"하지 않는 패턴을 선호하므로 추가 배치에 사용하기 어려울 수 있습니다. 각 후보 포장 위치에 대해 두 항목 방향에 대해 점수가 두 번 평가되고 (둘 다 가능할 경우) 가장 높은 값이 선택됩니다. 최대 포장 영역이있는 용지함을 선택하면 점수 연계가 깨집니다. 전체 알고리즘은 다음과 같습니다.touching_perimeter: sort the items by nonincreaseing w,h values, and horizontally orient them; comment: Phase 1; compute a lower bound L on the optimal solution value, and open L empty bins; comment: Phase 2; for j := 1 to n do score := 0; for each normal packing position in an open bin do let score1 and score2 be scores with tow orientations; score := max{score,score1,score2}; end for; if score > 0 then pack item j in the bin, position and orientation corresponding to score; else open a new bin and horizontally pack item j into i; end if; end for; end;
또한이 논문은 최적으로 패킹 된 텍스처 맵의 크기를 결정하는 알고리즘을 설명합니다. 하나의 1024x1024 아틀라스에 모든 텍스처를 넣을 수 있는지 여부를 결정하는 데 유용합니다.
누구든지 여전히 관심이 있다면 rectpack2D 라이브러리를 완전히 다시 작성하여 보다 효율적입니다.
std::vector
초기 최대 크기 (일반적으로 특정 GPU에서 허용되는 최대 텍스처 크기)로 시작하여 첫 번째 가능한 빈 공간을 분할하고 분할을 벡터에 다시 저장하여 아틀라스에 빈 공간 을 유지합니다 .
성능 혁신은 이전처럼 전체 트리를 유지하는 대신 벡터를 사용하는 것만으로 이루어졌습니다.
절차는 README에 자세히 설명되어 있습니다.
도서관은 MIT에 있으므로 유용하다고 생각하면 기쁩니다!
테스트는 3.50GHz에서 Intel® Core ™ i7-4770K CPU에서 수행되었습니다. 바이너리는 -03 스위치를 사용하여 clang 6.0.0으로 빌드되었습니다.
런타임 : 4 밀리 초
낭비 된 픽셀 : 15538 (0.31 %-125 x 125 정사각형에 해당)
출력 (2116 x 2382) :
색상 :(
검정색 공간 낭비)
런타임 :
3.5-7ms 낭비 된 픽셀 : 9288 (1.23 %-96 x 96 정사각형에 해당)
출력 (866 x 871) :
색상 :(
검정색 공간 낭비)
좋은 휴리스틱 알고리즘은 여기 에서 찾을 수 있습니다 . 최근에 비슷한 것을 시도했을 때, 이것이 내가 본 대부분의 구현을위한 기본 시작점이라고 언급했습니다.
규칙적인 모양의 비슷한 크기의 항목이 많거나 작고 적은 큰 이미지가 잘 혼합되어있는 경우 특히 효과적입니다. 좋은 결과를 얻기위한 최선의 조언은 이미지 크기 측면에서 입력을 정렬 한 다음 작은 이미지가 큰 이미지 주위의 공간에 채워 지므로 최대에서 최소로 압축하는 것입니다. 이 정렬 방법은 자신에게 달려 있으며 목표에 따라 달라질 수 있습니다. 키가 + 얇고 / 짧고 + 넓은 이미지 (영역이 좁을 것임)가 실제로 팩에 나중에 배치하기가 매우 어렵다는 관점을 취했기 때문에 영역 대신 경계를 1 차 근사치로 사용했습니다. 주문의 앞쪽을 향한이 이상한 모양.
내 웹 사이트 이미지 덤프 디렉토리의 임의 이미지 세트에서 내 패커의 출력 샘플 샘플은 다음과 같습니다. :).
사각형의 숫자는 트리에 포함 된 블록의 ID이므로 삽입 순서를 알 수 있습니다. 첫 번째는 첫 번째 리프 노드 (잎에만 이미지가 포함되어 있고 결과적으로 2 개의 부모가 있음) 이므로 ID "3" 입니다.
Root[0]
/ \
Child[1] Child[2]
|
Leaf[3]
불규칙한 UV 맵에서도 잘 작동하는 것은 UV 패치를 비트 맵 마스크로 바꾸고 텍스처 자체의 마스크를 유지하여 UV 패치가 맞는 첫 번째 위치를 찾는 것입니다. 간단한 휴리스틱 (높이, 너비, 크기 등)에 따라 블록을 주문하고 블록을 회전하여 선택한 휴리스틱을 최소화하거나 최대화 할 수 있습니다. 이는 무차별 대입을위한 관리 가능한 검색 공간을 제공합니다.
그런 다음 여러 휴리스틱 시도를 반복하고 순서를 선택할 때 임의의 요소를 적용하고 시간 제한이 끝날 때까지 반복하십시오.
이 체계를 사용하면 작은 UV 아일랜드가 큰 것에 의해 만들어지는 틈새와 심지어 단일 UV 패치 자체에 남은 구멍에도 채워집니다.
우리는 최근에 텍스처를 주어진 크기의 여러 이미지 파일로 압축하는 파이썬 스크립트를 발표했습니다.
블로그에서 인용 :
"온라인에서 찾을 수있는 많은 패커가 있지만 여러 디렉토리에서 많은 수의 이미지를 처리 할 수있는 패커를 찾는 데 어려움이있었습니다. 따라서 자체 아틀라스 패커가 탄생했습니다!
마찬가지로 작은 스크립트는 기본 디렉토리에서 시작하여 모든 .PNG를 아틀라스에로드합니다. 해당 아틀라스가 채워지면 새로운 아틀라스가 생성됩니다. 그런 다음 새 이미지에서 지점을 찾기 전에 이전의 모든지도 책에서 나머지 이미지를 맞추려고 시도합니다. 이렇게하면 각 아틀라스가 가능한 한 꽉 채워집니다. 아틀라스는 이미지가있는 폴더를 기준으로 이름이 지정됩니다.
아틀라스의 크기 (65 행), 압축하려는 이미지의 형식 (67 행),로드 디렉토리 (10 행) 및 저장 디렉토리 (13 행)를 Python에서 전혀 경험하지 않고 상당히 쉽게 변경할 수 있습니다. 작은 면책 조항으로, 며칠 만에 우리 엔진과 함께 작동하기 위해 채찍질되었습니다. 기능을 요청하고 자신의 변형에 대해 의견을 말하고 오류를보고하는 것이 좋습니다. 그러나 스크립트에 대한 변경 사항은 자유 시간에 발생합니다. "
http://www.retroaffect.com/blog/159/Image_Atlas_Packer/#b 에서 전체 소스 코드를 확인하십시오.
글리프 텍스처의 모든 (또는 대부분) 크기가 거의 같기 때문에 서체를 포장하기가 쉽습니다. 당신에게 발생하는 가장 간단한 일을하고 최적에 매우 가깝습니다.
매우 다른 크기의 이미지를 포장 할 때 영리함이 더욱 중요해집니다. 그런 다음에도 공백 등으로 압축 할 수 있기를 원합니다. 그럼에도 불구하고 앞에서 설명한 스캔 라인 순서 검색과 같은 간단한 알고리즘은 매우 합리적인 결과를 생성합니다.
고급 알고 중 어느 것도 마법이 아닙니다. 그것들은 simpel algo보다 50 % 더 효율적이지 않을 것이며, 엄청나게 많은 수의 텍스쳐 시트가 없다면 그것들로부터 일관된 이점을 얻지 못할 것입니다. 더 나은 알고리즘의 작은 개선 사항은 전체적으로 볼 수 있기 때문입니다.
간단하게 노력하고 더 나은 보상을받을 수있는 곳으로 이동하십시오