Three js 에서 애니메이션 재생시 애니메이션 한개마다 FBX 파일을 로드, 처리하는건 불필요하다고 판단되어


3D Max에서 JD 파일로 모델을 애니메이션 정보와 함께 출력했다.


JD 파일을 이용해서 씬에 출력 및 애니메이션을 재생해보자.


JDLoader.min.js


JDLoader 파일을 먼저 index에 추가, 로드 시킨다. (검색해도 찾을수 있음)


jd파일을 json로드한뒤 parse 하면 다양한 정보들이 담겨서 나오는데 해당 데이터를 담아보자.



static jdModel( data )
{
let meshes = [];
let mixers = [];
let actions = [];

for( let i = 0; i < data.objects.length; ++i )
{
if( data.objects[i].type == "Mesh" || data.objects[i].type == "SkinnedMesh" )
{
let mesh = null;
let matArray = this.createMaterials( data );
if ( data.objects[i].type == "SkinnedMesh")
{
mesh = new THREE.SkinnedMesh( data.objects[i].geometry, matArray );
}
else
{
mesh = new THREE.Mesh( data.objects[i].geometry, matArray );
}
meshes.push( mesh );

if( mesh && mesh.geometry.animations )
{
for(let j = 0, length = mesh.geometry.animations.length; j < length; j++)
{
let mixer = new THREE.AnimationMixer( mesh );
mixers.push( mixer );
let action = mixer.clipAction( mesh.geometry.animations[j] );
action.play();
actions.push( action );
}
}
}
else if ( data.objects[i].type == "Line" )
{
let jd_color = data.objects[i].jd_object.color;
let color1 = new THREE.Color( jd_color[0] / 255, jd_color[1] / 255, jd_color[2] / 255 );
let material = new THREE.LineBasicMaterial({ color: color1 }); //{ color: new THREE.Color( 0xff0000 ) }
let line = new THREE.Line( data.objects[i].geometry, material );
// scene.add( line );

if( line.geometry.animations )
{
for( let j = 0, length = mesh.geometry.animations.length; j < length; j++ )
{
let mixer = new THREE.AnimationMixer( line );
mixers.push( mixer );
let action = mixer.clipAction( line.geometry.animations[j] );
action.play();
actions.push( actions );
}
}
}
}

let object = {};
object.meshes = meshes;
object.mixers = mixers;
object.actions = actions;
return object;
}

static createMaterials( data )
{
let matArray = [];
for( let i = 0; i < data.materials.length; ++i )
{
let mat = new THREE.MeshPhongMaterial({});
mat.copy( data.materials[i] );
matArray.push( mat );
}

return matArray;
}

Static 함수로 처리했다.


기존의 JDModel 로드 방법에 일부 스크립트가 추가되었는데

반환되는 object내부에

meshes , mixers, actions가 담겨서 나오게 된다.


이 함수를 통해 오브젝트를 받은뒤

meshes에 들어있는 모든 오브젝트를 Scene에 등록해준다.


this.object = new THREE.Group();

let model = StaticMethodCall.jdModel( data );

for(let i = 0, length = model.meshes.length; i < length; i++)
this.object.add( model.meshes[i] );

Group을 하나 만든뒤 씬에 등록하고 그 자식으로 넣어주는 방법이 편하다.


mixer는 애니메이션을 담당하므로 update함수에서 지속적으로 호출한다.

this.mixers[0].update( delta );

애니메이션을 재생, 정지 하고 싶을때는 Actions를 이용한다.

this.actions[1].stop();
this.actions[0].play();


Vector3 Direction to Quaternion (Rotation)

방향 벡터를 이용해서 쿼터니언 (로테이션) 구하기


this.front.subVectors( this.finalTarget, this.resultPos );
this.front.normalize();

현재 좌표에서 바라볼 대상의 좌표를 뺀다.

정규화 (Normalize) 하면 대상을 바라보는 Look Vector (front)가 생긴다.


this.up.set( 0, 1, 0);

Up vector를 설정한다. (일반적으로 0, 1, 0인 상황)

만약 지구와 같은 구체주변을 맴돈다면


this.up.copy( this.object.position );
this.up.normalize();


자신의 좌표를 이용해서 Up벡터를 구한다. (지구의 중점이 0, 0, 0 이라는 기준으로)


this.right.crossVectors( this.up, this.front );
this.right.normalize();

up벡터와 front벡터를 Cross 시켜서 Right 벡터를 구한다.


this.up.crossVectors( this.front, this.right );
this.up.normalize();

front와 right를 이용해서 다시 Up벡터를 구한다.


일반적으론 이렇게 나온 right, up, front에 적용시키면 로테이션이 적용된다.

이번은 Matrix를 이용해서 Quaternion을 구해보자.


Matrix mBasis = new Matrix(vRight.X, vRight.Y, vRight.Z, 0.0f,
vUp.X, vUp.Y, vUp.Z, 0.0f,
vDirection.X, vDirection.Y, vDirection.Z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);

Quaternion qrot = new Quaternion();
qrot.W = (float)Math.Sqrt(1.0f + mBasis.M11 + mBasis.M22 + mBasis.M33) / 2.0f;
double dfWScale = qrot.W * 4.0;
qrot.X = (float)((mBasis.M32 - mBasis.M23) / dfWScale);
qrot.Y = (float)((mBasis.M13 - mBasis.M31) / dfWScale);
qrot.Z = (float)((mBasis.M21 - mBasis.M12) / dfWScale);

이렇게 나온 쿼터니언 (Quaternion)을 이용해서 Rotation을 적용시키면 된다.

acos(x) 로 구했다가 난감한 경험이 있었다.


제대로된 Angle을 구하고 싶다면


let angle = Math.atan2( y, x ) * RAD2DEG; 하면 정상적인 각도가 나옴


디스플레이 화면 특성상 Y값이 밑으로 갈수록 증가하기 때문에


실제로는 다음과 같은 식으로 구현했다.


var RAD2DEG = 180 / Math.PI;
let angle = Math.atan2( -y, x ) * RAD2DEG;


색상코드를 보면 가끔 RGB도 HEX도 아닌 Decimal로 되어있는 색상 코드가 있다.


예시

RGB : 255, 255, 255 => 16777215

RGB : 255, 0, 0 => 16711680


이러한 Decimal 색상 코드를 RGB 로 변환해 보자.


Color = 16777215


R = Math.floor( Color / ( 256 * 256 ) )

G = Math.floor( Color / 256 ) % 256;

B = Color % 256;


유니티 앱 이름 변경은 프로젝트 셋팅에서 간단히 진행하면 되지만

Firebase, Facebook, Google Auth (인증)이 추가되고 나서는 APK이름 바꾸는게 쉽지가 않다.

페이스북, 구글 로그인을 적용하고 나서 다른 앱 이름으로 빌드하는 방법이다.


1. Project 폴더에서 google-services.json 파일의 package 이름을 새 APK 이름으로 변경한다.


2. Project Setting에서 AppId 및 App 이름 변경


3. Build Setting에서 Minify -> Proguard를 None으로 변경한다.


4. Facebook메뉴 -> EditSettings -> Selected App Id 를 다른 App Id로 변경한다.


5. Assets 메뉴 -> PlayService Resolver -> Android Resolver -> Resolve를 눌러 처리한다.


6. PlayerSettings 에서 Product Name, Package Name을 변경한뒤 빌드한다.


* 이때 Product Name과 google-service.json의 package 이름이 같아야 한다.

'프로그래밍 > Unity (유니티)' 카테고리의 다른 글

[Unity] 애니메이션 메카님 시스템 (Mecanim)  (2) 2020.02.12
WWW Request (post)  (0) 2018.09.05

Javascript 에서 모바일 브라우저인지 감지하는 코드


static isMobile(){
// if we want a more complete list use this: http://detectmobilebrowsers.com/
// str.test() is more efficent than str.match()
// remember str.test is case sensitive
let isMobile = (/iphone|ipod|android|ie|blackberry|fennec/).test
(navigator.userAgent.toLowerCase());
return isMobile;
}


'프로그래밍 > JavaScript' 카테고리의 다른 글

WebPack 빌드 및 사용하기  (2) 2018.08.21
Three.js 에서 jd 모델 사용하기.  (0) 2018.08.08
스파인 애니메이션 재생 문제 (Spine Animation)  (0) 2018.07.13
Threejs repeat  (0) 2018.07.04
Spine Attachment Off  (0) 2018.06.20

Spine으로 특정시점에 애니메이션을 재생시키거나 AddAnimation으로 애니메이션을 이어서 재생할때

애니메이션이 출력이 안되거나 재생 시점이 각기 다른 현상이 있었다.


Spine의 Visible을 False로 처리했을때 이러한 현상이 발생했었다.


처음에는 visible을 true로 놔둔 상태에서 스크린 밖의 좌표에 이동시켰으나


Render함수의 부하가 관찰됨.


this.sprite.autoUpdate = false;

먼저 spine의 autoUpdate를 false로 설정한다.


this.sprite.update( delta );


이후 Delta값을 이용해서 업데이트 한다. (Delta는 프레임간 시간을 넣어주면 됨 [dt], 일반적인 상황에서는 1 / 60 )


관찰시 visible을 false 상태에서 true로 전환되도 정상적으로 애니메이션이 재생되는걸 확인할 수 있음

'프로그래밍 > JavaScript' 카테고리의 다른 글

Three.js 에서 jd 모델 사용하기.  (0) 2018.08.08
자바스크립트 모바일 브라우저 감지하기  (0) 2018.07.17
Threejs repeat  (0) 2018.07.04
Spine Attachment Off  (0) 2018.06.20
p2 reflection angle (반사각) 설정  (0) 2018.04.13

빛이 벽을 통해서 반사 되거나


공튕기기 게임에서 벽에 부딪힐때 반사각을 구해보자


1. 진행방향 벡터 (p) 와 충돌한 부분의 법선벡터 (n) 가 필요하다.

let n = this.result.normal; // 법선 벡터
let p = []; // 원래 벡터
p2.vec2.sub( p, this.rayClosest.from, this.rayClosest.to );

2. 진행방향 벡터의 역벡터 (-p) 를 구한다.

let minusP = [];         // 역 벡터
p2.vec2.sub( minusP, this.rayClosest.to, this.rayClosest.from);

3. 역벡터 (-p) 와 법선 벡터의 (n) 내적 (dot)을 구한다.

// 내적 계산
let dot = p2.vec2.dot( minusP, n );

4. 법선 벡터를 2배로 (2 * n) 늘린다.

// 법선 벡터 2배
let mulNormal = [];
p2.vec2.scale( mulNormal, this.result.normal, 2 );

5. 2배 길이의 법선벡터를 내적이 계산된 값만큼 스케일을 조절한다. ( 2 * n * dot(-p, n) )

let finalNormal = [];
p2.vec2.scale( finalNormal, mulNormal, dot );

6. 원래 진행방향 벡터 (p)에 5번에서 계산된 벡터 (스케일 조절된 법선 벡터) 를 더한다. ( p + 5번 결과 벡터 )

p2.vec2.add( reflect, p, finalNormal ); // 반사벡터 산출

7. 구해진 반사벡터를 정규화시킨다. ( normalize reflect )

p2.vec2.normalize( reflect, reflect );  // 정규화

8. 2d Screen의 특성에 따라 (y값이 밑으로 갈수록 증가) 역벡터를 구하면 완성( negate reflect )

p2.vec2.negate( reflect, reflect );     // 스크린 특성


마지막으로 계산된 reflect를 물체의 방향 (direction) 으로 사용하면 잘 반사된다.


- 참고 하면 좋은 수학적 개념 -

http://toymaker.tistory.com/entry/%EB%B0%98%EC%82%AC-%EB%B2%A1%ED%84%B0-Reflection-Vector

https://www.slideshare.net/cancan21st/ss-17299826

http://ifyouwanna.tistory.com/entry/%EB%B0%98%EC%82%AC%EB%B2%A1%ED%84%B0

Three js 에서 repeat는 텍스처 출력 크기를 의미


ex)  repeat.x 가 0.5일 경우 offset.x 의 위치부터 repeat.x의 크기만큼 텍스처를 자른다.

repeat.y 가 0.5일 경우 offset.y 의 위치부터 repeat.y의 크기만큼 텍스처를 자른다.


그다음 모델에 적용시킨다.


주의할점은 모든 모델들이 하나의 텍스처를 공유하기 때문에

texture의 uv를 변경하면 같은 texture를 사용하는 모든 object들의 uv가 변경된다.


Duplicate Class Define 에러가 발생하는데 빌드는 당장 해야되면


빌드 옵션 설정 -> Minify 에서 Proguard를 사용하지 않는다.

'기타 > ETC' 카테고리의 다른 글

유니티 안드로이드 APK 빌드 하기 (Unity to Android APK)  (1) 2017.08.16
API 에러창 띄우기  (0) 2017.04.20
size_t 란 무엇인가? C++  (0) 2017.04.09

+ Recent posts