Skip to content

Commit

Permalink
Revert "Revert "feature: VRMAnimation""
Browse files Browse the repository at this point in the history
This reverts commit 2f09d71.
  • Loading branch information
0b5vr committed Dec 4, 2023
1 parent 6e3019f commit ebec9fd
Show file tree
Hide file tree
Showing 30 changed files with 1,351 additions and 0 deletions.
9 changes: 9 additions & 0 deletions packages/three-vrm-animation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# @pixiv/three-vrm-animation

The implementation of VRM Animation

[GitHub Repository](https://github.com/pixiv/three-vrm/tree/dev/packages/three-vrm-animation)

[Examples](https://pixiv.github.io/three-vrm/packages/three-vrm-animation/examples)

[Documentation](https://pixiv.github.io/three-vrm/packages/three-vrm-animation/docs)
2 changes: 2 additions & 0 deletions packages/three-vrm-animation/examples/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[*]
indent_style = tab
11 changes: 11 additions & 0 deletions packages/three-vrm-animation/examples/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"root": true,
"plugins": [
"html"
],
"extends": "mdcs",
"rules": {
"padded-blocks":"off",
"no-unused-vars": "off"
}
}
281 changes: 281 additions & 0 deletions packages/three-vrm-animation/examples/dnd.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8" />
<title>three-vrm-animation example</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<style>
body {
margin: 0;
}
canvas {
display: block;
}
</style>
</head>

<body>
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/",
"@pixiv/three-vrm": "https://unpkg.com/@pixiv/[email protected]/lib/three-vrm.module.js",
"@pixiv/three-vrm-animation": "../lib/three-vrm-animation.module.js"
}
}
</script>

<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import GUI from 'three/addons/libs/lil-gui.module.min.js';
import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm';
import { createVRMAnimationClip, VRMAnimationLoaderPlugin, VRMLookAtQuaternionProxy } from '@pixiv/three-vrm-animation';

// renderer
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );

// camera
const camera = new THREE.PerspectiveCamera( 30.0, window.innerWidth / window.innerHeight, 0.1, 20.0 );
camera.position.set( 0.0, 1.0, 5.0 );

// camera controls
const controls = new OrbitControls( camera, renderer.domElement );
controls.screenSpacePanning = true;
controls.target.set( 0.0, 1.0, 0.0 );
controls.update();

// scene
const scene = new THREE.Scene();

// light
const light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1.0, 1.0, 1.0 ).normalize();
scene.add( light );

// gltf, vrm, and vrma
let currentVrm = undefined;
let currentVrmAnimation = undefined;
let currentMixer = undefined;

const loader = new GLTFLoader();
loader.crossOrigin = 'anonymous';

loader.register( ( parser ) => {

return new VRMLoaderPlugin( parser );

} );

loader.register( ( parser ) => {

return new VRMAnimationLoaderPlugin( parser );

} );

function tryInitVRM( gltf ) {

const vrm = gltf.userData.vrm;

if ( vrm == null ) {

return;

}

// calling these functions greatly improves the performance
VRMUtils.removeUnnecessaryVertices( gltf.scene );
VRMUtils.removeUnnecessaryJoints( gltf.scene );

if ( currentVrm ) {

scene.remove( currentVrm.scene );
VRMUtils.deepDispose( currentVrm.scene );

}

// Add look at quaternion proxy to the VRM; which is needed to play the look at animation
const lookAtQuatProxy = new VRMLookAtQuaternionProxy( vrm.lookAt );
lookAtQuatProxy.name = 'lookAtQuaternionProxy';
vrm.scene.add( lookAtQuatProxy );

// Disable frustum culling
vrm.scene.traverse( ( obj ) => {

obj.frustumCulled = false;

} );

currentVrm = vrm;
scene.add( vrm.scene );

// rotate if the VRM is VRM0.0
VRMUtils.rotateVRM0( vrm );

initAnimationClip();

console.log( vrm );

}

function tryInitVRMA( gltf ) {

const vrmAnimations = gltf.userData.vrmAnimations;

if ( vrmAnimations == null ) {

return;

}

currentVrmAnimation = vrmAnimations[ 0 ] ?? null;
initAnimationClip();

console.log( vrmAnimations );

}

function initAnimationClip() {

if ( currentVrm && currentVrmAnimation ) {

currentMixer = new THREE.AnimationMixer( currentVrm.scene );

const clip = createVRMAnimationClip( currentVrmAnimation, currentVrm );
currentMixer.clipAction( clip ).play();
currentMixer.timeScale = params.timeScale;

currentVrm.humanoid.resetNormalizedPose();
// currentVrm.expressions.resetAll(); // will implement later
currentVrm.lookAt.reset();
currentVrm.lookAt.autoUpdate = currentVrmAnimation.lookAtTrack != null;

}

}

function load( url ) {

loader.load(

url,

( gltf ) => {

tryInitVRM( gltf );
tryInitVRMA( gltf );

},

( progress ) => console.log( 'Loading model...', 100.0 * ( progress.loaded / progress.total ), '%' ),

( error ) => console.error( error )

);

}

load( './models/VRM1_Constraint_Twist_Sample.vrm' );
load( './models/test.vrma' );

// helpers
const gridHelper = new THREE.GridHelper( 10, 10 );
scene.add( gridHelper );

const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );

// animate
const clock = new THREE.Clock();
clock.start();

function animate() {

requestAnimationFrame( animate );

const deltaTime = clock.getDelta();

if ( currentMixer ) {

currentMixer.update( deltaTime );

}

if ( currentVrm ) {

currentVrm.update( deltaTime );

}

renderer.render( scene, camera );

}

animate();

// gui
const gui = new GUI();

const params = {

timeScale: 1.0,

};

gui.add( params, 'timeScale', 0.0, 2.0, 0.001 ).onChange( ( value ) => {

if ( currentMixer ) {

currentMixer.timeScale = value;

}

} );

// dnd handler
window.addEventListener( 'dragover', function ( event ) {

event.preventDefault();

} );

window.addEventListener( 'drop', function ( event ) {

event.preventDefault();

// read given file then convert it to blob url
const files = event.dataTransfer.files;
if ( ! files ) {

return;

}

const file = files[ 0 ];
if ( ! file ) {

return;

}

const blob = new Blob( [ file ], { type: "application/octet-stream" } );
const url = URL.createObjectURL( blob );
load( url );

} );
</script>
</body>
</html>
24 changes: 24 additions & 0 deletions packages/three-vrm-animation/examples/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8" />
<title>three-vrm-animation examples</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
</head>

<body>
<h1>examples of <a href="https://github.com/pixiv/three-vrm/tree/dev/packages/three-vrm-animation">@pixiv/three-vrm-animation</a></h1>
<p>
<a href="loader-plugin.html">loader-plugin.html</a><br />
Import a VRM Animation from gltf
</p>
<p>
<a href="dnd.html">dnd.html</a><br />
A slightly advanced example with a drag-and-drop capability
</p>
</body>
</html>
Loading

0 comments on commit ebec9fd

Please sign in to comment.