์๋ณธ : https://ogldev.org/www/tutorial38/tutorial38.html
๋ฐฐ๊ฒฝ
๋ง์นจ๋ด ์๋ฐฑ๋ง๋ช ์ ๋ ์๋ค์ด ์๊ตฌํด์จ ํํ ๋ฆฌ์ผ. ์คํค๋์ผ๋ก๋ ์๋ ค์ง ๊ณจ๊ฒฉ ์ ๋๋ฉ์ด์ ์ผ๋ก, Assimp ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๊ณจ๊ฒฉ ์ ๋๋ฉ์ด์ ์ ์ฌ์ค ๋ ๋ถ๋ถ์ผ๋ก ์ด๋ฃจ์ด์ง ๊ณผ์ ์ ๋๋ค.
์ฒซ ๋ฒ์งธ๋ ์ํฐ์คํธ๊ฐ ์คํํ๊ณ ๋ ๋ฒ์งธ๋ ํ๋ก๊ทธ๋๋จธ์ธ ์ฌ์ฉ์(๋๋ ์์ฑํ ์์ง)๊ฐ ์คํํฉ๋๋ค.
์ฒซ ๋ฒ์งธ ๋ถ๋ถ์ ๋ชจ๋ธ๋ง ์ํํธ์จ์ด ๋ด๋ถ์์ ๋ฐ์ํ๋ฉฐ ๋ฆฌ๊น ์ด๋ผ๊ณ ํฉ๋๋ค.
์ฌ๊ธฐ์ ์ผ์ด๋๋ ์ผ์ ์ํฐ์คํธ๊ฐ mesh ์๋ ๋ผ(skeleton)์ ๊ณจ๊ฒฉ(bones)์ ์ ์ํ๋ ๊ฒ์ ๋๋ค.
mesh๋ ๋ฌผ์ฒด์ ํผ๋ถ(์ธ๊ฐ์ด๋ ๊ดด๋ฌผ์ด๋ ๋ฌด์์ด๋ )๋ฅผ ๋ํ๋ด๋ฉฐ skeleton์ ์ค์ ์ธ๊ณ์์ ์ค์ ์์ง์์ ๋ชจ๋ฐฉํ๋ ๋ฐฉ์์ผ๋ก mesh๋ฅผ ์์ง์ด๋๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์ด ์์ ์ ๊ฐ ์ ์ ์ ํ๋ ์ด์์ ๋ผ์ ํ ๋นํ์ฌ ์ํ๋ฉ๋๋ค.
์ ์ ์ด ๋ผ์ ํ ๋น๋๋ฉด ๋ผ๊ฐ ์ด๋ํ ๋ ์ ์ ์ ๋ฏธ์น๋ ์ํฅ์ ์์ ๊ฒฐ์ ํ๋ ๊ฐ์ค์น๊ฐ ์ ์๋ฉ๋๋ค.
์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ ๋ชจ๋ ๊ฐ์ค์น์ ํฉ์ (์ ์ ๋น) 1๋ก ๋ง๋๋ ๊ฒ์ ๋๋ค.
์๋ฅผ ๋ค์ด, ๊ผญ์ง์ ์ด ๋ ๋ผ ์ฌ์ด์ ์ ํํ ์์นํ๋ค๋ฉด ์ฐ๋ฆฌ๋ ๋ผ๊ฐ ๊ผญ์ง์ ์ ๋ฏธ์น๋ ์ํฅ์ด ๊ฐ์ ๊ฒ์ผ๋ก ์์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ ๋ผ์ 0.5์ ๊ฐ์ค์น๋ฅผ ํ ๋นํ๊ณ ์ถ์ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ๊ผญ์ง์ ์ด ์์ ํ ๋จ์ผ ๋ผ์ ์ํฅ ๋ฒ์ ๋ด์ ์๋ ๊ฒฝ์ฐ ๊ฐ์ค์น๋ 1์ด ๋ฉ๋๋ค(๋ผ๊ฐ ์ ์ ์ ์์ง์์ ์์จ์ ์ผ๋ก ์ ์ดํจ).
๋ธ๋ ๋์์ ์์ฑ๋ ๊ณจ๊ฒฉ ๊ตฌ์กฐ์ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
์ฐ๋ฆฌ๊ฐ ์์์ ๋ณธ ๊ฒ์ ์ฌ์ค ์ ๋๋ฉ์ด์ ์ ์ค์ํ ๋ถ๋ถ์ ๋๋ค. ์ํฐ์คํธ๋ ๊ณจ๊ฒฉ ๊ตฌ์กฐ๋ฅผ ์ฐ๊ฒฐํ๊ณ ๊ฐ ์ ๋๋ฉ์ด์ ์ ํ("walk","run","die" ๋ฑ)์ ๋ํ ํค ํ๋ ์ ์ธํธ๋ฅผ ์ ์ํฉ๋๋ค.
ํค ํ๋ ์์๋ ์ ๋๋ฉ์ด์ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ผ ์๊ณ์ ์ ์๋ ๋ชจ๋ ๋ผ์ ๋ณํ์ด ํฌํจ๋์ด ์์ต๋๋ค.
๊ทธ๋ํฝ ์์ง์ ํค ํ๋ ์์ ๋ณํ ์ฌ์ด๋ฅผ ๋ณด๊ฐํ์ฌ ํค ํ๋ ์ ๊ฐ์ ๋ถ๋๋ฌ์ด ์์ง์์ ๋ง๋ญ๋๋ค.
๊ณจ๊ฒฉ ์ ๋๋ฉ์ด์ ์ ์ฌ์ฉ๋๋ ๊ณจ๊ฒฉ ๊ตฌ์กฐ๋ ์ข ์ข ๊ณ์ธต ๊ตฌ์กฐ์ ๋๋ค.
์ด๊ฒ์ skeleton์ด ์์/๋ถ๋ชจ ๊ด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก skeleton tree๊ฐ ์์ฑ๋๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
root bone์ ์ ์ธํ ๋ชจ๋ ๋ผ์๋ ๋ถ๋ชจ๊ฐ ํ๋์ฉ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ์ธ์ฒด์ ๊ฒฝ์ฐ ํ, ๋ค๋ฆฌ, ์๊ฐ๋ฝ ๋ผ์ ๊ฐ์ ์์ ๋ผ๋ฅผ ๋ค์ ๋จ๊ณ๋ก ํ์ฌ ๋ฑ๋ผ๋ฅผ root๋ก ์ง์ ํ ์ ์์ต๋๋ค.
๋ถ๋ชจ์ ๋ผ๊ฐ ์์ง์ด๋ฉด ๋ชจ๋ ์์ ๋ผ๋ค๋ ์์ง์ด์ง๋ง, ์์์ ๋ผ๊ฐ ์์ง์ด๋ฉด ๋ถ๋ชจ๋ ์์ง์ด์ง ์์ต๋๋ค(์ฐ๋ฆฌ์ ์๊ฐ๋ฝ์ ์์ ์์ง์ด์ง ์๊ณ ๋ ์์ง์ผ ์ ์์ง๋ง, ์์ด ์์ง์ด๋ฉด ๋ชจ๋ ์๊ฐ๋ฝ์ด ์์ง์ ๋๋ค). ์ค์ง์ ์ธ ๊ด์ ์์ ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ๋ผ์ ๋ณํ์ ์ฒ๋ฆฌํ ๋ ๊ทธ๊ฒ์ ๊ทธ๊ฒ์ผ๋ก๋ถํฐ root๋ก ์ด๋๋ ๋ชจ๋ ๋ถ๋ชจ ๋ผ์ ๋ณํ๊ณผ ๊ฒฐํฉํ ํ์๊ฐ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๋ ์ด์ ์กฐ์์ ๋ํด ๋ ผ์ํ์ง ์์ ๊ฒ์ ๋๋ค. ๊ทธ๊ฒ์ ๊ทธ๋ํฝ ํ๋ก๊ทธ๋๋จธ์ ์์ญ ๋ฐ์ ์๋ ๋ณต์กํ ์ฃผ์ ์ ๋๋ค. ๋ชจ๋ธ๋ง ์ํํธ์จ์ด๋ ์์ ๊ฐ๊ฐ ์ด ์ผ์ ํ ์ ์๋๋ก ๋์์ฃผ๋ ๊ณ ๊ธ ๋๊ตฌ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ๋น์ ์ ๋ฉ์ง mesh์ skeleton์ ๋ง๋ค๊ธฐ ์ํด ํ๋ฅญํ ์์ ๊ฐ๊ฐ ๋์ด์ผ ํฉ๋๋ค. skeletal ์ ๋๋ฉ์ด์ ์ ๋ง๋ค๊ธฐ ์ํด ๊ทธ๋ํฝ ์์ง์ด ๋ฌด์์ ํด์ผ ํ๋์ง ์์๋ณด๊ฒ ์ต๋๋ค.
์ฒซ ๋ฒ์ฌ ๋จ๊ณ๋ ์ ์ ๋ฒํผ๋ฅผ ์ ์ ๋ณ ๊ณจ๊ฒฉ ์ ๋ณด๋ก ๋ณด๊ฐํ๋ ๊ฒ์ ๋๋ค.
๋ช ๊ฐ์ง ์ต์ ์ ์ฌ์ฉํ ์ ์์ง๋ง ์ฐ๋ฆฌ๊ฐ ํ๋ ค๋ ๊ฒ์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
๊ฐ ๊ผญ์ง์ ์ ๋ํด ๊ฐ ์ฌ๋กฏ์ ๊ณจ๊ฒฉ ID์ ๊ฐ์ค์น๊ฐ ํฌํจ๋ ์ฌ๋กฏ ๋ฐฐ์ด์ ์ถ๊ฐํฉ๋๋ค.
์ฐ๋ฆฌ์ ์ถ์ ๋ ๋จ์ํ๊ฒ ๋ง๋ค๊ธฐ ์ํด ์ฐ๋ฆฌ๋ 4๊ฐ์ ์ฌ๋กฏ์ด ์๋ ๋ฐฐ์ด์ ์ฌ์ฉํ ๊ฒ์ ๋๋ค.
์ด๊ฒ์ 4๊ฐ ์ด์์ ๋ผ์ ์ํด ์ํฅ์ ๋ฐ์ ์ ์๋ ์ ์ ์ด ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๊ณจ๊ฒฉ์ด ๋ ๋ง์ ๋ชจ๋ธ์ ๋ก๋ํ๋ ค๋ฉด ๋ฐฐ์ด ํฌ๊ธฐ๋ฅผ ์กฐ์ ํด์ผ ํ์ง๋ง ์ด ํํ ๋ฆฌ์ผ ๋ฐ๋ชจ์ ํฌํจ๋ Doom 3 ๋ชจ๋ธ์ ๊ฒฝ์ฐ ๊ณจ๊ฒฉ 4๊ฐ๋ก ์ถฉ๋ถํฉ๋๋ค. ๊ทธ๋์ ์ฐ๋ฆฌ์ ์๋ก์ด ๊ผญ์ง์ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ์ด ๋ณด์ผ ๊ฒ์ ๋๋ค.
bone ID๋ bone ๋ณํ ๋ฐฐ์ด์ ์ธ๋ฑ์ค์ ๋๋ค.
์ด๋ฌํ ๋ณํ์ WVP ํ๋ ฌ ์์ ์์น์ ์ ๊ท์ ์ ์ฉ๋ฉ๋๋ค(์ฆ, ์ ์ ์ "bone space"์์ ๋ก์ปฌ ๊ณต๊ฐ์ผ๋ก ๋ณํ).
๊ฐ์ค์น๋ ์ฌ๋ฌ ๋ผ์ ๋ณํ์ ํ๋์ ๋ณํ์ผ๋ก ๊ฒฐํฉํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์ด๋ค ๊ฒฝ์ฐ์๋ ์ด ๊ฐ์ค์น๋ ์ ํํ 1(๋ชจ๋ธ๋ง ์ํํธ์จ์ด์ ์ฑ ์)์ด์ด์ผ ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ ๋๋ฉ์ด์ ํค ํ๋ ์ ์ฌ์ด๋ฅผ ๋ณด๊ฐํ๊ณ ๋ชจ๋ ํ๋ ์์ ๊ณจ๊ฒฉ ๋ณํ ๋ฐฐ์ด์ ์ ๋ฐ์ดํธํฉ๋๋ค.
๋ผ ๋ณํ์ ๋ฐฐ์ด์ด ๋ง๋ค์ด์ง๋ ๋ฐฉ๋ฒ์ ๋๊ฐ ๊น๋ค๋ก์ด ๋ถ๋ถ์ ๋๋ค.
๋ณํ์ ๊ณ์ธต ๊ตฌ์กฐ(์ฆ, ํธ๋ฆฌ)๋ก ์ค์ ๋๋ฉฐ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ ํธ๋ฆฌ์ ๋ชจ๋ ๋ ธํธ์ ์ค์ผ์ผ๋ง ๋ฒกํฐ, ํ์ ์ฟผํฐ ๋ฐ ๋ณํ ๋ฒกํฐ๋ฅผ ๊ฐ๋ ๊ฒ์ ๋๋ค.
์ค์ ๋ก ๊ฐ ๋ ธ๋์๋ ์ด๋ฌํ ํญ๋ชฉ์ ๋ฐฐ์ด์ด ํฌํจ๋์ด ์์ต๋๋ค. ๋ฐฐ์ด์ ๋ชจ๋ ํญ๋ชฉ์๋ ํ์์คํฌํ๊ฐ ์์ด์ผํฉ๋๋ค. ์์ฉ ํ๋ก๊ทธ๋จ ์๊ฐ์ด ํ์์คํฌํ ์ค ํ๋์ ์ ํํ ์ผ์นํ๋ ๊ฒฝ์ฐ๋ ๋๋ฌผ๊ธฐ ๋๋ฌธ์ ์์ฉ ํ๋ก๊ทธ๋จ์ ์์ ์ ๋ํ ์ ํํ ๋ณํ์ ์ป์ผ๋ ค๋ฉด ์ฝ๋๊ฐ ์ค์ผ์ผ๋ง/ํ์ /๋ฒ์ญ์ ๋ณด๊ฐํ ์ ์์ด์ผ ํฉ๋๋ค.
์ฐ๋ฆฌ๋ ํ์ฌ์ ๋ผ์์ root๊น์ง ๊ฐ ๋ ธ๋์ ๋ํด ๋์ผํ ํ๋ก์ธ์ค๋ฅผ ์ํํ๊ณ ์ด ๋ณํ ์ฒด์ธ์ ํจ๊ป ๊ณฑํ์ฌ ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค. ๊ฐ ๊ณจ๊ฒฉ์ ๋ํด ์ด ์์ ์ ์ํํ ๋ค์ ์์ด๋๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
์ง๊ธ๊น์ง ์ฐ๋ฆฌ๊ฐ ์ด์ผ๊ธฐํ ๋ชจ๋ ๊ฒ์ ๊ฝค ์ผ๋ฐ์ ์ด์์ต๋๋ค.
ํ์ง๋ง ์ด๊ฒ์ Assimp์ ๊ณจ๊ฒฉ ์ ๋๋ฉ์ด์ ์ ๋ํ ํํ ๋ฆฌ์ผ ์ ๋๋ค.
๊ทธ๋์ ์ฐ๋ฆฌ๋ ๊ทธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ค์ ๋ค์ด๊ฐ์ ์ด๋ป๊ฒ ์คํค๋์ ํ ์ ์๋์ง ๋ณผ ํ์๊ฐ ์์ต๋๋ค.
Assimip์ ์ข์ ์ ์ ์ฌ๋ฌ ํ์์ ๊ณจ๊ฒฉ ์ ๋ณด ๋ก๋๋ฅผ ์ง์ํ๋ค๋ ๊ฒ์ ๋๋ค.
๋์์ ์ ์์ด๋์ ํ์ํ ๊ณจ๊ฒฉ ๋ณํ์ ์์ฑํ๊ธฐ ์ํด ์์ฑ๋๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๋ํด ์ฌ์ ํ ์๋นํ ์์ ์ด ํ์ํ๋ค๋ ๊ฒ์ ๋๋ค.
์ ์ ์์ค์ ๋ผ ์ ๋ณด๋ถํฐ ์์ํด๋ณด๊ฒ ์ต๋๋ค. ๋ค์์ Assimp ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๊ด๋ จ ๋ถ๋ถ์ ๋๋ค:
์๋ง Assimp์ ๋ํ ํํ ๋ฆฌ์ผ์์ ๊ธฐ์ตํ์๊ฒ ์ง๋ง, ๋ชจ๋ ๊ฒ์ด aiScene ํด๋์ค(๋งค์ฌ ํ์ผ์ ๊ฐ์ ธ์ฌ ๋ ๋ฐ๋ ๊ฐ์ฒด)์ ํฌํจ๋์ด ์์ต๋๋ค. aiScene์๋ aiMesh ๊ฐ์ฒด์ ๋ฐฐ์ด์ด ํฌํจ๋์ด ์์ต๋๋ค. aiMesh๋ ๋ชจ๋ธ์ ์ผ๋ถ์ด๋ฉฐ ์์น, ์ ๊ท ํ ์ค์ฒ ์ขํ ๋ฑ๊ณผ ๊ฐ์ ์ ์ ์์ค์ ํญ๋ชฉ์ ํฌํจํฉ๋๋ค. ์ด์ aiMesh์๋ aiBone ๊ฐ์ฒด์ ๋ฐฐ์ด๋ ํฌํจ๋์ด ์์ต๋๋ค.
๋๋ ๊ฒ๋ ์์ด, aiBone์ mesh์ ๊ณจ๊ฒฉ์ ์๋ ํ๋์ ๋ผ๋ฅผ ๋ํ๋ ๋๋ค. ๊ฐ ๊ณจ๊ฒฉ์๋ ๊ณจ๊ฒฉ ๊ณ์ธต ๊ตฌ์กฐ(์๋ ์ฐธ์กฐ), ์ ์ ๊ฐ์ค์น ๋ฐฐ์ด ๋ฐ 4x4 ์คํ์ ํ๋ ฌ์์ ์ฐพ์ ์ ์๋ ์ด๋ฆ์ด ์์ต๋๋ค. ์ด ํ๋ ฌ์ด ํ์ํ ์ด์ ๋ ์ ์ ์ด ์ผ๋ฐ์ ์ธ ๋ก์ปฌ ๊ณต๊ฐ์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ ๊ณจ๊ฒฉ ์ ๋๋ฉ์ด์ ์ด ์ง์๋์ง ์๋๋ผ๋ ๊ธฐ์กด ์ฝ๋ ๊ธฐ๋ฐ์ด ๋ชจ๋ธ์ ๋ก๋ํ๊ณ ์ฌ๋ฐ๋ฅด๊ฒ ๋ ๋๋งํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ณ์ธต ๊ตฌ์กฐ์ ๋ผ ๋ณํ์ ๋ผ ๊ณต๊ฐ์์ ์๋ํฉ๋๋ค.(๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ๋ผ๋ ๊ณ ์ ํ ๊ณต๊ฐ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๊ฒ์ด ์ฐ๋ฆฌ๊ฐ ํจ๊ป ๋ณํ์ ๊ณฑํด์ผ ํ๋ ์ด์ ์ ๋๋ค). ์คํ์ ๋งคํธ๋ฆญ์ค์ ์์ ์ ๋งค์ฌ์ ๊ตญ์ ๊ณต๊ฐ์์ ์ ์ ์์น๋ฅผ ํน์ ๋ผ์ ๊ณต๊ฐ์ผ๋ก ์ด๋์ํค๋ ๊ฒ์ ๋๋ค.
์ ์ ๊ฐ์ค์น ๋ฐฐ์ด์ ์ฌ๋ฌผ๋ค์ด ํฅ๋ฏธ๋ก์์ง๊ธฐ ์์ํ๋ ๊ณณ์ ๋๋ค.
์ด ๋ฐฐ์ด์ ๊ฐ ํญ๋ชฉ์๋ aiMesh์ ์ ์ ๋ฐฐ์ด์ ๋ํ ์ธ๋ฑ์ค(๊ผญ์ง์ ์ด ๋์ผํ ๊ธธ์ด๋ฅผ ๊ฐ์ง ์ฌ๋ฌ ๋ฐฐ์ด์ ๊ฑธ์ณ ๋ถ์ฐ๋จ)์ ๊ฐ์ค์น๊ฐ ํฌํจ๋ฉ๋๋ค. ๋ชจ๋ ๊ผญ์ง์ ๊ฐ์ค์น์ ํฉ์ 1์ด์ด์ผ ํ์ง๋ง ์ด๋ฅผ ์ฐพ์ผ๋ ค๋ฉด ๋ชจ๋ ๋ผ๋ฅผ ํต๊ณผํ๊ณ ๊ฐ ํน์ ๊ผญ์ง์ ์ ๋ํ ์ผ์ข ์ ๋ชฉ๋ก์ผ๋ก ๊ฐ์ค์น๋ฅผ ๋์ ํด์ผ ํฉ๋๋ค.
์ ์ ์์ค์์ ๊ณจ๊ฒฉ ์ ๋ณด๋ฅผ ๊ตฌ์ถํ ํ ๊ณจ๊ฒฉ ๋ณํ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์์ด๋์ ๋ก๋ํ ์ต์ข ๋ณํ์ ์์ฑํด์ผ ํฉ๋๋ค. ๋ค์ ๊ทธ๋ฆผ์๋ ๊ด๋ จ ๋ฐ์ดํฐ ๊ตฌ์กฐ๊ฐ ํ์๋์ด ์์ต๋๋ค:
๋ค์, ์ฐ๋ฆฌ๋ aiScene์์ ์์ํฉ๋๋ค. aiScene ๊ฐ์ฒด์๋ ๋ ธ๋ ๊ณ์ธต ๊ตฌ์กฐ(์ฆ, ํธ๋ฆฌ)์ ๋ฃจํธ์ธ aiNode ํด๋์ค์ ๊ฐ์ฒด์ ๋ํ ํฌ์ธํฐ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ํธ๋ฆฌ์ ๊ฐ ๋ ธ๋์๋ ๋ถ๋ชจ์ ๋ํ ํฌ์ธํฐ์ ์์์ ๋ํ ํฌ์ธํฐ ๋ฐฐ์ด์ด ์์ต๋๋ค. ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ tree๋ฅผ ํธ๋ฆฌํ๊ฒ ์๋ค๊ฐ๋ค ํ ์ ์๊ฒ ํด์ค๋๋ค.
๋ํ ๋ ธ๋๋ ๋ ธ๋ ๊ณต๊ฐ์์ ๋ถ๋ชจ ๊ณต๊ฐ์ผ๋ก ๋ณํํ๋ ๋ณํ ํ๋ ฌ์ ์ ๋ฌํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก ๋ ธ๋์ ์ด๋ฆ์ด ์์ ์๋ ์๊ณ ์์ ์๋ ์์ต๋๋ค. ๋ ธ๋๊ฐ ๊ณ์ธต์์ ๊ณจ๊ฒฉ์ ๋ํ๋ด๋ ๊ฒฝ์ฐ ๋ ธ๋ ์ด๋ฆ์ด ๊ณจ๊ฒฉ ์ด๋ฆ๊ณผ ์ผ์นํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ ธ๋์ ์ด๋ฆ์ด ์๋ ๊ฒฝ์ฐ(์ฆ, ๋์ํ๋ ๊ณจ๊ฒฉ์ด ์์) ๋ ธ๋์ ์ญํ ์ ๋จ์ํ ๋ชจ๋ธ์ ๋ถํดํ๊ณ ์ค๊ฐ ๋ณํ์ ๋ฐฐ์นํ๋ ๊ฒ์ ๋๋ ๊ฒ์ ๋๋ค.
ํผ์ฆ์ ๋ง์ง๋ง ์กฐ๊ฐ์ aiScene ๊ฐ์ฒด์๋ ์ ์ฅ๋ aiAnimation ๋ฐฐ์ด์ ๋๋ค. ๋จ์ผ aiAnimation ๊ฐ์ฒด๋ "walk", "run", "shoot" ๋ฑ๊ณผ ๊ฐ์ ์ผ๋ จ์ ์ ๋๋ฉ์ด์ ํ๋ ์์ ๋ํ๋ ๋๋ค. ํ๋ ์ ์ฌ์ด๋ฅผ ๋ณด๊ฐํจ์ผ๋ก์จ ์ ๋๋ฉ์ด์ ์ด๋ฆ๊ณผ ์ผ์นํ๋ ์ํ๋ ์๊ฐ์ ํจ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ์ ๋๋ฉ์ด์ ์๋ ๋๊ธ์ ์ง์ ์๊ฐ๊ณผ ์ด๋น ๋๊ธ ์(์: 100๊ฐ์ ๋๊ธ๊ณผ 25๊ฐ์ ๋๊ธ์ 4์ด์ ์ ๋๋ฉ์ด์ ์ ๋ํ๋)๊ฐ ์์ด ์ ๋๋ฉ์ด์ ์ด ๋ชจ๋ ํ๋์จ์ด์์ ๋์ผํ๊ฒ ๋ณด์ด๋๋ก ์งํ ์๊ฐ์ ์กฐ์ ํ ์ ์์ต๋๋ค. ๋ํ ์ด ์ ๋๋ฉ์ด์ ์๋ ์ฑ๋์ด๋ผ๊ณ ํ๋ aiNodeAnim ๊ฐ์ฒด์ ๋ฐฐ์ด์ด ์์ต๋๋ค. ๊ฐ๊ฐ์ ์ฑ๋์ ์ฌ์ค ๋ชจ๋ ๋ณํ์ด ์๋ ๋ผ์ ๋๋ค. ์ฑ๋์๋ ๊ณ์ธต ๊ตฌ์กฐ์ ๋ ธ๋ ์ค ํ๋์ ์ธ ๊ฐ์ ๋ณํ ๋ฐฐ์ด๊ณผ ์ผ์นํด์ผ ํ๋ ์ด๋ฆ์ด ํฌํจ๋์ด ์์ต๋๋ค.
ํน์ ์์ ์ ์ต์ข ๋ผ ๋ณํ์ ๊ณ์ฐํ๊ธฐ ์ํด์๋ ์ด ์ธ ๋ฐฐ์ด์์ ๊ฐ๊ฐ ์๊ฐ๊ณผ ์ผ์นํ๋ ๋ ๊ฐ์ ํญ๋ชฉ์ ์ฐพ๊ณ ๊ทธ ์ฌ์ด๋ฅผ ๋ณด๊ฐํด์ผ ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ณํ์ ํ๋์ ํ๋ ฌ๋ก ๊ฒฐํฉํด์ผ ํฉ๋๋ค. ์ด ์์ ์ ์ํํ ํ์๋ ๊ณ์ธต ๊ตฌ์กฐ์์ ํด๋น ๋ ธ๋๋ฅผ ์ฐพ์ ์์ ๋ ธ๋๋ก ์ด๋ํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ๋ถ๋ชจ์ ํด๋นํ๋ ์ฑ๋์ด ํ์ํ๊ณ ๋์ผํ ๋ณด๊ฐ ๊ณผ์ ์ ์ํํด์ผ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๋ ๋ณํ์ ํจ๊ป ๊ณฑํ๊ณ ๊ณ์ธต์ root์ ๋๋ฌํ ๋๊น์ง ๊ณ์ํฉ๋๋ค.
Source Walthru
(mesh.cpp:75)
bool Mesh::LoadMesh(const string& Filename)
{
// Release the previously loaded mesh (if it exists)
Clear();
// Create the VAO
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
// Create the buffers for the vertices attributes
glGenBuffers(ARRAY_SIZE_IN_ELEMENTS(m_Buffers), m_Buffers);
bool Ret = false;
m_pScene = m_Importer.ReadFile(Filename.c_str(), aiProcess_Triangulate | aiProcess_GenSmoothNormals |
aiProcess_FlipUVs);
if (m_pScene) {
m_GlobalInverseTransform = m_pScene->mRootNode->mTransformation;
m_GlobalInverseTransform = m_GlobalInverseTransform.Inverse();
Ret = InitFromScene(m_pScene, Filename);
}
else {
printf("Error parsing '%s': '%s'\n", Filename.c_str(), m_Importer.GetErrorString());
}
// Make sure the VAO is not changed from the outside
glBindVertexArray(0);
return Ret;
}
๋ค์์ ๋งค์ฌ ํด๋์ค์ ์ ๋ฐ์ดํธ๋ ์ง์ ์ ์ผ๋ก, ๋ณ๊ฒฝ ์ฌํญ์ ๊ตต์ ๊ธ์จ๋ก ํ์๋ฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ฃผ๋ชฉํด์ผ ํ ๋ช ๊ฐ์ง ๋ณํ๊ฐ ์์ต๋๋ค. ํ๋๋ ์ํฌํฐ์ aiScene ๊ฐ์ฒด๊ฐ ์ด์ ๋ณ์๋ฅผ ์์ง ์๊ณ ํด๋์ค ๋ฉค๋ฒ๊ฐ ๋๋ค๋ ๊ฒ์ ๋๋ค. ๊ทธ ์ด์ ๋ ๋ฐํ์ ์ค์ ์ฐ๋ฆฌ๋ aiScene ๊ฐ์ฒด๋ก ๋ค์ ๋์๊ฐ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์์ ์์ ์ฅ๋ฉด์ ๋ฒ์๋ฅผ ๋ชจ๋ ํ์ฅํด์ผ ํฉ๋๋ค. ์ค์ ๊ฒ์์์๋ ํ์ํ ๊ฒ์ ๋ณต์ฌํ์ฌ ์ต์ ํ๋ ํ์์ผ๋ก ์ ์ฅํ๊ณ ์ถ์ ์ ์์ง๋ง ๊ต์ก์ ์ธ ๋ชฉ์ ์ ์ํด์๋ ์ด๊ฒ์ผ๋ก ์ถฉ๋ถํฉ๋๋ค.
๋ ๋ฒ์งธ ๋ณ๊ฒฝ ์ฌํญ์ ๊ณ์ธต ๊ตฌ์กฐ์ ๋ฃจํธ์ ๋ํ ๋ณํ ํ๋ ฌ์ด ์ถ์ถ๋๊ณ ์ญ๋ฐฉํฅ์ผ๋ก ์ ์ฅ๋๋ค๋ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ ์์ผ๋ก ๋ ๋ฉ๋ฆฌ์ ๊ทธ๊ฒ์ ์ฌ์ฉํ ๊ฒ์ ๋๋ค. ํ๋ ฌ ์ญ์ฝ๋๊ฐ Assimp ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ Matrix4f ํด๋์ค๋ก ๋ณต์ฌ๋์์ต๋๋ค.
(mesh.h:69)
struct VertexBoneData
{
uint IDs[NUM_BONES_PER_VERTEX];
float Weights[NUM_BONES_PER_VERTEX];
}
(mesh.cpp:107)
bool Mesh::InitFromScene(const aiScene* pScene, const string& Filename)
{
...
vector<VertexBoneData> Bones;
...
Bones.resize(NumVertices);
...
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[BONE_VB]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Bones[0]) * Bones.size(), &Bones[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(BONE_ID_LOCATION);
glVertexAttribIPointer(BONE_ID_LOCATION, 4, GL_INT, sizeof(VertexBoneData), (const GLvoid*)0);
glEnableVertexAttribArray(BONE_WEIGHT_LOCATION);
glVertexAttribPointer(BONE_WEIGHT_LOCATION, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)16);
...
}
์์ ๊ตฌ์กฐ๋ ๊ผญ์ง์ ์์ค์์ ์ฐ๋ฆฌ๊ฐ ํ์๋ก ํ๋ ๋ชจ๋ ๊ฒ์ ํฌํจํ๊ณ ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก 4๊ฐ์ ๋ผ(๋ผ๋น ID ๋ฐ ๋ฌด๊ฒ)๋ฅผ ์ ์ฅํ ์ ์๋ ์ถฉ๋ถํ ์ ์ฅ ๊ณต๊ฐ์ด ์์ต๋๋ค.
VertexBoneData๋ ์์ด๋์ ์ฝ๊ฒ ์ ๋ฌํ ์ ์๋๋ก ๊ทธ๋ ๊ฒ ๊ตฌ์ฑ๋์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฏธ ์์น 0, 1, 2์ ๊ฐ๊ฐ ์์น, ํ ์ค์ฒ ์ขํ ๋ฐ ์ผ๋ฐ ๊ฒฝ๊ณ๋ฅผ ํ๋ณดํ์ต๋๋ค. ๋ฐ๋ผ์ ์์น 3์์ ๊ณจ๊ฒฉ ID๋ฅผ ๋ฐ์ธ๋ฉํ๊ณ ์์น 4์์ ๊ฐ์ค์น๋ฅผ ๋ฐ์ธ๋ฉํ๋๋ก VAO๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. ์ฐ๋ฆฌ๊ฐ glVertexAttribute๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ์ฃผ๋ชฉํ๋ ๊ฒ๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ID๋ฅผ ๋ฐ์ธ๋ฉํ glVertexAttributePointer๊ฐ ์๋ IPointer์ ๋๋ค. ์ด ์ ์ ์ฃผ์ํ์ญ์์ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์์ด๋์ ์์๋ ๋ฐ์ดํฐ๊ฐ ํ์๋ฉ๋๋ค.
(mesh.cpp:213)
void Mesh::LoadBones(uint MeshIndex, const aiMesh* pMesh, vector& Bones)
{
for (uint i = 0 ; i < pMesh->mNumBones ; i++) {
uint BoneIndex = 0;
string BoneName(pMesh->mBones[i]->mName.data);
if (m_BoneMapping.find(BoneName) == m_BoneMapping.end()) {
BoneIndex = m_NumBones;
m_NumBones++;
BoneInfo bi;
m_BoneInfo.push_back(bi);
}
else {
BoneIndex = m_BoneMapping[BoneName];
}
m_BoneMapping[BoneName] = BoneIndex;
m_BoneInfo[BoneIndex].BoneOffset = pMesh->mBones[i]->mOffsetMatrix;
for (uint j = 0 ; j < pMesh->mBones[i]->mNumWeights ; j++) {
uint VertexID = m_Entries[MeshIndex].BaseVertex + pMesh->mBones[i]->mWeights[j].mVertexId;
float Weight = pMesh->mBones[i]->mWeights[j].mWeight;
Bones[VertexID].AddBoneData(BoneIndex, Weight);
}
}
}
์์ ํจ์๋ ๋จ์ผ aiMesh ๊ฐ์ฒด์ ๋ํ ์ ์ ๊ณจ๊ฒฉ ์ ๋ณด๋ฅผ ๋ก๋ํฉ๋๋ค. Mesh::InitMesh()์์ ํธ์ถ๋ฉ๋๋ค. ์ด ํจ์๋ VertexBoneData ๊ตฌ์กฐ๋ฅผ ์ฑ์ฐ๋ ๊ฒ ์ธ์๋ ๊ณจ๊ฒฉ ์ด๋ฆ๊ณผ ๊ณจ๊ฒฉ ID(์ด ํจ์์ ์ํด ๊ด๋ฆฌ๋๋ ์คํ์ค์ธ ์ธ๋ฑ์ค) ์ฌ์ด์ ๋งต์ ์ ๋ฐ์ดํธํ๊ณ ๊ณจ๊ฒฉ ID๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฒกํฐ์ ์คํ์ ํ๋ ฌ์ ์ ์ฅํฉ๋๋ค. ์ ์ ID๊ฐ ๊ณ์ฐ๋๋ ๋ฐฉ๋ฒ์ ๊ธฐ๋กํฉ๋๋ค. ์ ์ ID๋ ๋จ์ผ ๋งค์ฌ์ ๊ด๋ จ์ด ์๊ณ ๋ชจ๋ ๋งค์ฌ๋ฅผ ๋จ์ผ ๋ฒกํฐ์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ ํ์ฌ aiMesh์ ๊ธฐ๋ณธ ์ ์ ID๋ฅผ mWeights ๋ฐฐ์ด์ ์ ์ ID์ ์ถ๊ฐํ์ฌ ์ ๋ ์ ์ ID๋ฅผ ์ป์ต๋๋ค.
(mesh.cpp:29)
void Mesh::VertexBoneData::AddBoneData(uint BoneID, float Weight)
{
for (uint i = 0 ; i < ARRAY_SIZE_IN_ELEMENTS(IDs) ; i++) {
if (Weights[i] == 0.0) {
IDs[i] = BoneID;
Weights[i] = Weight;
return;
}
}
// should never get here - more bones than we have space for
assert(0);
}
์ด ์ ํธ๋ฆฌํฐ ํจ์๋ VertexBoneData ๊ตฌ์กฐ์์ ๋น ์ฌ๋กฏ์ ์ฐพ์ ๊ณจ๊ฒฉ ID์ ๊ฐ์ค์น๋ฅผ ๋ฐฐ์นํฉ๋๋ค. ์ผ๋ถ ์ ์ ์ 4๊ฐ ๋ฏธ๋ง์ ๋ผ์ ์ํด ์ํฅ์ ๋ฐ์ง๋ง ์กด์ฌํ์ง ์๋ ๋ผ์ ๋ฌด๊ฒ๊ฐ 0์ผ๋ก ์ ์ง๋๊ธฐ ๋๋ฌธ์(VertexBoneData ์์ฑ์ ์ฐธ์กฐ), ์ด๋ ๋ชจ๋ ๋ผ ์์ ๋ํด ๋์ผํ ๊ฐ์ค์น ๊ณ์ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
(mesh.cpp:473)
Matrix4f Mesh::BoneTransform(float TimeInSeconds, vector<Matrix4f>& Transforms)
{
Matrix4f Identity;
Identity.InitIdentity();
float TicksPerSecond = m_pScene->mAnimations[0]->mTicksPerSecond != 0 ?
m_pScene->mAnimations[0]->mTicksPerSecond : 25.0f;
float TimeInTicks = TimeInSeconds * TicksPerSecond;
float AnimationTime = fmod(TimeInTicks, m_pScene->mAnimations[0]->mDuration);
ReadNodeHierarchy(AnimationTime, m_pScene->mRootNode, Identity);
Transforms.resize(m_NumBones);
for (uint i = 0 ; i < m_NumBones ; i++) {
Transforms[i] = m_BoneInfo[i].FinalTransformation;
}
}
์์ ๋ณธ ์ ์ ์์ค์ ๊ณจ๊ฒฉ ์ ๋ณด ๋ก๋๋ ๋งค์ฌ๊ฐ ์์ ์ค์ ๋ก๋๋ ๋ ํ ๋ฒ๋ง ์ํ๋ฉ๋๋ค. ์ด์ ์ฐ๋ฆฌ๋ ๋งค ํ๋ ์๋ง๋ค ์์ด๋์ ๋ค์ด๊ฐ๋ ๋ผ ๋ณํ์ ๊ณ์ฐํ๋ ๋ ๋ฒ์ฌ ๋ถ๋ถ์ผ๋ก ๋์ด๊ฐ๋๋ค. ์์ ๊ธฐ๋ฅ์ ์ด ํ๋์ ์์์ ์ ๋๋ค. ํธ์ถ์๋ ํ์ฌ ์๊ฐ์ ์ด ๋จ์๋ก ๋ณด๊ณ ํ๊ณ (๋ถ์์ผ ์ ์์), ์ ๋ฐ์ดํธํด์ผํ๋ ํ๋ ฌ์ ๋ฒกํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ ๋๋ฉ์ด์ ์ฃผ๊ธฐ ๋ด์์ ์๋์ ์ธ ์๊ฐ์ ์ฐพ๊ณ ๋ ธ๋ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๊ฒฐ๊ณผ๋ ํธ์ถ์์๊ฒ ๋ฐํ๋๋ ์ผ๋ จ์ ๋ณํ์ ๋๋ค.
(mesh.cpp:428)
void Mesh::ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const Matrix4f& ParentTransform)
{
string NodeName(pNode->mName.data);
const aiAnimation* pAnimation = m_pScene->mAnimations[0];
Matrix4f NodeTransformation(pNode->mTransformation);
const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnimation, NodeName);
if (pNodeAnim) {
// Interpolate scaling and generate scaling transformation matrix
aiVector3D Scaling;
CalcInterpolatedScaling(Scaling, AnimationTime, pNodeAnim);
Matrix4f ScalingM;
ScalingM.InitScaleTransform(Scaling.x, Scaling.y, Scaling.z);
// Interpolate rotation and generate rotation transformation matrix
aiQuaternion RotationQ;
CalcInterpolatedRotation(RotationQ, AnimationTime, pNodeAnim);
Matrix4f RotationM = Matrix4f(RotationQ.GetMatrix());
// Interpolate translation and generate translation transformation matrix
aiVector3D Translation;
CalcInterpolatedPosition(Translation, AnimationTime, pNodeAnim);
Matrix4f TranslationM;
TranslationM.InitTranslationTransform(Translation.x, Translation.y, Translation.z);
// Combine the above transformations
NodeTransformation = TranslationM * RotationM * ScalingM;
}
Matrix4f GlobalTransformation = ParentTransform * NodeTransformation;
if (m_BoneMapping.find(NodeName) != m_BoneMapping.end()) {
uint BoneIndex = m_BoneMapping[NodeName];
m_BoneInfo[BoneIndex].FinalTransformation = m_GlobalInverseTransform * GlobalTransformation *
m_BoneInfo[BoneIndex].BoneOffset;
}
for (uint i = 0 ; i < pNode->mNumChildren ; i++) {
ReadNodeHierarchy(AnimationTime, pNode->mChildren[i], GlobalTransformation);
}
}
์ด ํจ์๋ ๋ ธ๋ ํธ๋ฆฌ๋ฅผ ํต๊ณผํ๊ณ ์ง์ ๋ ์ ๋๋ฉ์ด์ ์๊ฐ์ ๋ฐ๋ผ ๊ฐ ๋ ธ๋/๋ณธ์ ๋ํ ์ต์ข ๋ณํ์ ์์ฑํฉ๋๋ค. ๋งค์ฌ๊ฐ ํ๋์ ์ ๋๋ฉ์ด์ ์ํ์ค๋ง ๊ฐ์ง๊ณ ์๋ค๊ณ ๊ฐ์ ํ๋ค๋ ์ ์์ ์ ํ์ ์ ๋๋ค.
์ฌ๋ฌ ์ ๋๋ฉ์ด์ ์ ์ง์ํ๋ ค๋ฉด ์ ๋๋ฉ์ด์ ์ด๋ฆ์ ๋งํ๊ณ m_pScene->mAnimations[] ๋ฐฐ์ด์์ ๊ฒ์ํด์ผ ํฉ๋๋ค. ์์ ์ฝ๋๋ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ๋ฐ๋ชจ ๋งค์ฌ์ ์ถฉ๋ถํฉ๋๋ค.
๋ ธ๋ ๋ณํ์ ๋ ธ๋์ mTransformation ๋ฉค๋ฒ์์ ์ด๊ธฐํ๋ฉ๋๋ค. ๋ง์ฝ ๋ ธ๋๊ฐ ๋ผ์ ์ผ์นํ์ง ์๋๋ค๋ฉด ๊ทธ๊ฒ์ด ๋ผ์ ์ต์ข ๋ณํ์ ๋๋ค. ๊ทธ๋ ๊ฒ ๋๋ฉด ์์ฑํ ํ๋ ฌ๋ก ๋ฎ์ด์๋๋ค. ์ด ์์ ์ ๋ค์๊ณผ ๊ฐ์ด ์ํ๋ฉ๋๋ค. ๋จผ์ ์ ๋๋ฉ์ด์ ์ ์ฑ๋ ๋ฐฐ์ด์์ ๋ ธ๋ ์ด๋ฆ์ ๊ฒ์ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ ๋๋ฉ์ด์ ์๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ค์ผ์ผ๋ง ๋ฒกํฐ, ํ์ ์ฟผํฐ ๋ฐ ๋ณํ ๋ฒกํฐ๋ฅผ ๋ณด๊ฐํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ๊ฒ๋ค์ ํ๋์ ํ๋ ฌ๋ก ๊ฒฐํฉํ๊ณ ๋งค๊ฐ ๋ณ์๋ก ์ป์ ํ๋ ฌ(GlobablTransformation)๋ก ๊ณฑํฉ๋๋ค.
์ด ํจ์๋ ์ฌ๊ท์ ์ด๋ฉฐ ๊ธ๋ก๋ฒ ๋ณํ ๋งค๊ฐ ๋ณ์๊ฐ ID ๋งคํธ๋ฆญ์ค์ธ root ๋ ธ๋์ ๋ํด ํธ์ถ๋ฉ๋๋ค. ๊ฐ ๋ ธ๋๋ ๋ชจ๋ ์์์ ๋ํด ์ด ํจ์๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๊ณ ์์ฒด ๋ณํ์ ์ ์ญ ๋ณํ์ผ๋ก ์ ๋ฌํฉ๋๋ค. ์ฒ์๋ถํฐ ๋๊น์ง ๋ชจ๋ ๋ ธ๋์์ ํตํฉ๋ ๋ณํ ์ฒด์์ ์ป์ ์ ์์ต๋๋ค.
m_BoneMapping ๋ฐฐ์ด์ ๋ ธ๋ ์ด๋ฆ์ ์์ฑํ๋ ์ธ๋ฑ์ค์ ๋งคํํ๊ณ ์ด ์ธ๋ฑ์ค๋ฅผ ์ต์ข ๋ณํ์ด ์ ์ฅ๋๋ m_BoneInfo ๋ฐฐ์ด์ ํญ๋ชฉ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. ์ต์ข ๋ณํ์ ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ฐ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ๋ก์ปฌ ๊ณต๊ฐ ์์น์์ ์ ์ ์ ๋ ธ๋ ๊ณต๊ฐ์ผ๋ก ๊ฐ์ ธ์ค๋ ๋ ธ๋ ์คํ์ ํ๋ ฌ๋ก ์์ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ชจ๋ ๋ ธ๋ ๋ถ๋ชจ์ ๊ฒฐํฉ๋ ๋ณํ๊ณผ ์ ๋๋ฉ์ด์ ์๊ฐ์ ๋ฐ๋ผ ๋ ธ๋์ ๋ํด ๊ณ์ฐํ ํน์ ๋ณํ์ ๊ณฑํฉ๋๋ค.
์ฌ๊ธฐ์๋ Assimp ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ํ ๋ฌธ์ ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ์ฐ๋ฆฌ๋ง์ ์ฝ๋ ๋ฒ ์ด์ค๋ก ๋ณต์ ํ๋ ๊ฒ์ด ์๋ฏธ๊ฐ ์๋ค๊ณ ์๊ฐํด์ ๊ทธ๋ฅ Assimp๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
(mesh.cpp:387)
void Mesh::CalcInterpolatedRotation(aiQuaternion& Out, float AnimationTime, const aiNodeAnim* pNodeAnim)
{
// we need at least two values to interpolate...
if (pNodeAnim->mNumRotationKeys == 1) {
Out = pNodeAnim->mRotationKeys[0].mValue;
return;
}
uint RotationIndex = FindRotation(AnimationTime, pNodeAnim);
uint NextRotationIndex = (RotationIndex + 1);
assert(NextRotationIndex < pNodeAnim->mNumRotationKeys);
float DeltaTime = pNodeAnim->mRotationKeys[NextRotationIndex].mTime - pNodeAnim->mRotationKeys[RotationIndex].mTime;
float Factor = (AnimationTime - (float)pNodeAnim->mRotationKeys[RotationIndex].mTime) / DeltaTime;
assert(Factor >= 0.0f && Factor <= 1.0f);
const aiQuaternion& StartRotationQ = pNodeAnim->mRotationKeys[RotationIndex].mValue;
const aiQuaternion& EndRotationQ = pNodeAnim->mRotationKeys[NextRotationIndex].mValue;
aiQuaternion::Interpolate(Out, StartRotationQ, EndRotationQ, Factor);
Out = Out.Normalize();
}
์ด ๋ฐฉ๋ฒ์ ์ ๋๋ฉ์ด์ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ง์ ๋ ์ฑ๋์ ํ์ ์ฟผํฐ๋ฅผ ๋ณด๊ฐํฉ๋๋ค(์ฑ๋์ ํค ์ฟผํฐ ๋ฐฐ์ด์ด ํฌํจ๋์ด ์์). ๋จผ์ ํ์ํ ์ ๋๋ฉ์ด์ ์๊ฐ ์ง์ ์ ํต์ฌ ์ฟผํฐ์ ์ธ๋ฑ์ค๋ฅผ ์ฐพ์ต๋๋ค. ์ ๋๋ฉ์ด์ ์๊ฐ์์ ์ด์ ํค๊น์ง์ ๊ฑฐ๋ฆฌ์ ํด๋น ํค์ ๋ค์ ํค ์ฌ์ด์ ๊ฑฐ๋ฆฌ ์ฌ์ด์ ๋น์จ์ ๊ณ์ฐํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๊ทธ ์์๋ฅผ ์ฌ์ฉํ์ฌ ์ด ๋ ํค ์ฌ์ด๋ฅผ ๋ณด๊ฐํด์ผ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ Assimp ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด๊ฐ์ ์ํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ทํํฉ๋๋ค. ์์น ๋ฐ ์ค์ผ์ผ๋ง์ ๋ํ ํด๋น ๋ฐฉ๋ฒ์ ๋งค์ฐ ์ ์ฌํ๋ฏ๋ก ์ฌ๊ธฐ์๋ ์ธ์ฉํ์ง ์์ต๋๋ค.
(mesh.cpp:335)
uint Mesh::FindRotation(float AnimationTime, const aiNodeAnim* pNodeAnim)
{
assert(pNodeAnim->mNumRotationKeys > 0);
for (uint i = 0 ; i < pNodeAnim->mNumRotationKeys - 1 ; i++) {
if (AnimationTime < (float)pNodeAnim->mRotationKeys[i + 1].mTime) {
return i;
}
}
assert(0);
}
์ด ์ ํธ๋ฆฌํฐ ๋ฐฉ๋ฒ์ ์ ๋๋ฉ์ด์ ์๊ฐ ์ง์ ์ ํค ํ์ ์ ์ฐพ์ต๋๋ค. N ํค ํ์ ์ด ์์ผ๋ฉด ๊ฒฐ๊ณผ๋ 0์์ N-2๊ฐ ๋ ์ ์์ต๋๋ค. ์ ๋๋ฉ์ด์ ์๊ฐ์ ํญ์ ์ฑ๋์ ์ง์ ์๊ฐ ๋ด์ ํฌํจ๋๋ฏ๋ก ๋ง์ง๋ง ํค(N-1)๋ ์ ํจํ ๊ฒฐ๊ณผ๊ฐ ๋ ์ ์์ต๋๋ค.
(skihnning.vs)
#version 330
layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;
layout (location = 3) in ivec4 BoneIDs;
layout (location = 4) in vec4 Weights;
out vec2 TexCoord0;
out vec3 Normal0;
out vec3 WorldPos0;
const int MAX_BONES = 200;
uniform mat4 gWVP;
uniform mat4 gWorld;
uniform mat4 gBones[MAX_BONES];
void main()
{
mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
BoneTransform += gBones[BoneIDs[1]] * Weights[1];
BoneTransform += gBones[BoneIDs[2]] * Weights[2];
BoneTransform += gBones[BoneIDs[3]] * Weights[3];
vec4 PosL = BoneTransform * vec4(Position, 1.0);
gl_Position = gWVP * PosL;
TexCoord0 = TexCoord;
vec4 NormalL = BoneTransform * vec4(Normal, 0.0);
Normal0 = (gWorld * NormalL).xyz;
WorldPos0 = (gWorld * PosL).xyz;
}
์ด์ ๋งค์ฌ ํด๋์ค์ ๋ณ๊ฒฝ ์์ ์ ๋ง์ณค์ผ๋ฏ๋ก ์์ด๋ ์์ค์์ ์ํํด์ผ ํ ์์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ VSInput ๊ตฌ์กฐ์ ๊ณจ๊ฒฉ ID ๋ฐ ๊ฐ์ค์น ๋ฐฐ์ด์ ์ถ๊ฐํ์ต๋๋ค.
๋ค์์ผ๋ก, ๊ณจ๊ฒฉ ๋ณํ์ ํฌํจํ๋ ์๋ก์ด ๊ท ์ผ ๋ฐฐ์ด์ด ์์ต๋๋ค. ์์ด๋ ์์ฒด์์ ์ฐ๋ฆฌ๋ ์ ์ ์ ๋ผ ๋ณํ ํ๋ ฌ๊ณผ ๊ฐ์ค์น์ ์กฐํฉ์ผ๋ก ์ต์ข ๋ผ ๋ณํ์ ๊ณ์ฐํฉ๋๋ค. ์ด ์ต์ข ํ๋ ฌ์ ์์น์ ๋ ธ๋ง์ ๊ณจ๊ฒฉ ๊ณต๊ฐ์์ ๋ก์ปฌ ๊ณต๊ฐ์ผ๋ก ๋ณํํ๋๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ฌ๊ธฐ์ ๋ถํฐ ๋ชจ๋ ๊ฒ์ด ๋์ผํฉ๋๋ค.
(tutorial38.cpp:140)
float RunningTime = (float)((double)GetCurrentTimeMillis() - (double)m_startTime) / 1000.0f;
m_mesh.BoneTransform(RunningTime, Transforms);
for (uint i = 0 ; i < Transforms.size() ; i++) {
m_pEffect->SetBoneTransform(i, Transforms[i]);
}
์ฐ๋ฆฌ๊ฐ ๋ง์ง๋ง์ผ๋ก ํด์ผ ํ ์ผ์ ์ด ๋ชจ๋ ๊ฒ๋ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ํตํฉํ๋ ๊ฒ์ ๋๋ค.
์ด ์์ ์ ์์ ๊ฐ๋จํ ์ฝ๋๋ก ์ํ๋ฉ๋๋ค. ์ด ์์ ์ ์์ ๊ฐ๋จํ ์ฝ๋๋ก ์ํ๋ฉ๋๋ค.
GetCurrentTimeMillis() ํจ์๋ ์์ฉ ํ๋ก๊ทธ๋จ ์์ ์ดํ์ ์๊ฐ์ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ๋ฐํํฉ๋๋ค(๋ถ์๋ฅผ ์์ฉํ๋ ค๋ฉด ๋ถ๋ ์์์ ์ ์ฐธ๊ณ ํ์ญ์์ค).
๋ชจ๋ ์์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ํํ ๊ฒฝ์ฐ ์ต์ข ๊ฒฐ๊ณผ๋ ์ด๊ฒ๊ณผ ์ ์ฌํฉ๋๋ค.
์์ค ์ฝ๋ ์ฃผ์ : https://github.com/emeiri/ogldev/tree/master/tutorial28_youtube
'๊ณต๋ถ > OpenGL ์๋ฃ ๋ฒ์ญ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ฒ์ญ] Tutorial 16 : Shadow mapping (0) | 2023.04.23 |
---|