์ƒˆ์†Œ์‹

๊ณต๋ถ€/OpenGL ์ž๋ฃŒ ๋ฒˆ์—ญ

[๋ฒˆ์—ญ] ํŠœํ† ๋ฆฌ์–ผ 38 : Skeletal Animation with Assimp

  • -
728x90

์›๋ณธ : 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
Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.