-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New
animation / skinning / ik
example (#24652)
* kira example * kira example * adding link to the example into CCDIKSolver documentation * removing old file * updating final url * lil-gui 0.16 + Tween * fix eslint issues * glb * no dead comments * remaining dead comments * adding to the screenshot's exceptionList * chore: textures from glb * feat: no fancy * re-enabling screenshot * tabs * followSphere off by default * Update webgl_animation_skinning_ik.html Clean up. * fix(CCDIKSolver warning): links order count + removing 1 useless link * chore: better camera angle * fix: eslint --fix * transformControls showX false * new glb version * updating screenshot * fixing link to the experiment * Update CCDIKSolver.js * Update webgl_animation_skinning_ik.html Co-authored-by: Michael Herzog <michael.herzog@human-interactive.org>
- Loading branch information
Showing
6 changed files
with
224 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>three.js webgl - animation - skinning - ik</title> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | ||
<meta name="author" content="Antoine BERNIER (abernier)" /> | ||
<link type="text/css" rel="stylesheet" href="main.css"> | ||
<style> | ||
body {color:white;} | ||
#info a { | ||
color:inherit; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="info"> | ||
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - <a href="https://assetstore.unity.com/packages/3d/characters/humanoids/humans/kira-lowpoly-character-100303" target="_blank" rel="noopener">Kira</a>'s "<a href="https://en.wikipedia.org/wiki/Hand_with_Reflecting_Sphere" target="_blank" rel="noopener">hand with Reflecting Sphere</a>"<br /> | ||
(see <a href="https://abernier.name/three.js/examples/webgl_esher.html" target="_blank" rel="noopener">full-experiment</a>) | ||
</div> | ||
|
||
<!-- Import maps polyfill --> | ||
<!-- Remove this when import maps will be widely supported --> | ||
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script> | ||
|
||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"three": "../build/three.module.js", | ||
"three/addons/": "./jsm/" | ||
} | ||
} | ||
</script> | ||
|
||
<script type="module"> | ||
import * as THREE from 'three'; | ||
|
||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; | ||
import { TransformControls } from 'three/addons/controls/TransformControls.js'; | ||
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; | ||
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; | ||
import { CCDIKSolver, CCDIKHelper } from './jsm/animation/CCDIKSolver.js'; | ||
import Stats from 'three/addons/libs/stats.module.js'; | ||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; | ||
|
||
let scene, camera, renderer, orbitControls, transformControls; | ||
let mirrorSphereCamera; | ||
|
||
const OOI = {}; | ||
let IKSolver; | ||
|
||
let stats, gui, conf; | ||
const v0 = new THREE.Vector3(); | ||
|
||
init().then( animate ); | ||
|
||
async function init() { | ||
|
||
conf = { | ||
followSphere: false, | ||
turnHead: true, | ||
ik_solver: true, | ||
}; | ||
|
||
scene = new THREE.Scene(); | ||
scene.fog = new THREE.FogExp2( 0xffffff, .17 ); | ||
scene.background = new THREE.Color( 0xdddddd ); | ||
|
||
camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.001, 5000 ); | ||
camera.position.set( 0.9728517749133652, 1.1044765132727201, 0.7316689528482836 ); | ||
camera.lookAt( scene.position ); | ||
|
||
const ambientLight = new THREE.AmbientLight( 0xffffff, 8 ); // soft white light | ||
scene.add( ambientLight ); | ||
|
||
renderer = new THREE.WebGLRenderer( { antialias: true, logarithmicDepthBuffer: true } ); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
renderer.outputEncoding = THREE.sRGBEncoding; | ||
renderer.physicallyCorrectLights = true; | ||
document.body.appendChild( renderer.domElement ); | ||
|
||
stats = new Stats(); | ||
document.body.appendChild( stats.dom ); | ||
|
||
orbitControls = new OrbitControls( camera, renderer.domElement ); | ||
orbitControls.minDistance = .2; | ||
orbitControls.maxDistance = 1.5; | ||
orbitControls.enableDamping = true; | ||
|
||
const dracoLoader = new DRACOLoader(); | ||
dracoLoader.setDecoderPath( 'js/libs/draco/' ); | ||
const gltfLoader = new GLTFLoader(); | ||
gltfLoader.setDRACOLoader( dracoLoader ); | ||
|
||
const gltf = await gltfLoader.loadAsync( 'models/gltf/kira.glb' ); | ||
gltf.scene.traverse( n => { | ||
|
||
if ( n.name === 'head' ) OOI.head = n; | ||
if ( n.name === 'lowerarm_l' ) OOI.lowerarm_l = n; | ||
if ( n.name === 'Upperarm_l' ) OOI.Upperarm_l = n; | ||
if ( n.name === 'hand_l' ) OOI.hand_l = n; | ||
if ( n.name === 'target_hand_l' ) OOI.target_hand_l = n; | ||
|
||
if ( n.name === 'boule' ) OOI.sphere = n; | ||
if ( n.name === 'Kira_Shirt' ) OOI.kira = n; | ||
|
||
if ( n.isMesh ) n.frustumCulled = false; | ||
|
||
} ); | ||
scene.add( gltf.scene ); | ||
|
||
orbitControls.target.copy( OOI.sphere.position ); // orbit controls lookAt the sphere | ||
OOI.hand_l.attach( OOI.sphere ); | ||
|
||
// mirror sphere cube-camera | ||
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 1024 ); | ||
mirrorSphereCamera = new THREE.CubeCamera( 0.05, 50, cubeRenderTarget ); | ||
scene.add( mirrorSphereCamera ); | ||
const mirrorSphereMaterial = new THREE.MeshBasicMaterial( { envMap: cubeRenderTarget.texture } ); | ||
OOI.sphere.material = mirrorSphereMaterial; | ||
|
||
transformControls = new TransformControls( camera, renderer.domElement ); | ||
transformControls.size = .75; | ||
transformControls.showX = false; | ||
transformControls.space = 'world'; | ||
transformControls.attach( OOI.target_hand_l ); | ||
scene.add( transformControls ); | ||
// disable orbitControls while using transformControls | ||
transformControls.addEventListener( 'mouseDown', () => orbitControls.enabled = false ); | ||
transformControls.addEventListener( 'mouseUp', () => orbitControls.enabled = true ); | ||
|
||
OOI.kira.add( OOI.kira.skeleton.bones[ 0 ] ); | ||
const iks = [ | ||
{ | ||
target: 25, // "target_hand_l" | ||
effector: 9, // "hand_l" | ||
links: [ | ||
{ | ||
index: 8, // "lowerarm_l" | ||
rotationMin: new THREE.Vector3( 1.2, - 1.8, - .4 ), | ||
rotationMax: new THREE.Vector3( 1.7, - 1.1, .3 ) | ||
}, | ||
{ | ||
index: 7, // "Upperarm_l" | ||
rotationMin: new THREE.Vector3( 0.1, - 0.7, - 1.8 ), | ||
rotationMax: new THREE.Vector3( 1.1, 0, - 1.4 ) | ||
}, | ||
], | ||
} | ||
]; | ||
IKSolver = new CCDIKSolver( OOI.kira, iks ); | ||
const ccdikhelper = new CCDIKHelper( OOI.kira, iks, 0.01 ); | ||
scene.add( ccdikhelper ); | ||
|
||
gui = new GUI(); | ||
gui.add( conf, 'followSphere' ).name( 'follow sphere' ); | ||
gui.add( conf, 'turnHead' ).name( 'turn head' ); | ||
gui.add( conf, 'ik_solver' ).name( 'IK auto update' ); | ||
gui.add( IKSolver, 'update' ).name( 'IK manual update()' ); | ||
gui.open(); | ||
|
||
window.addEventListener( 'resize', onWindowResize, false ); | ||
|
||
} | ||
|
||
function animate( ) { | ||
|
||
if ( OOI.sphere && mirrorSphereCamera ) { | ||
|
||
OOI.sphere.visible = false; | ||
OOI.sphere.getWorldPosition( mirrorSphereCamera.position ); | ||
mirrorSphereCamera.update( renderer, scene ); | ||
OOI.sphere.visible = true; | ||
|
||
} | ||
|
||
if ( OOI.sphere && conf.followSphere ) { | ||
|
||
// orbitControls follows the sphere | ||
OOI.sphere.getWorldPosition( v0 ); | ||
orbitControls.target.lerp( v0, .1 ); | ||
|
||
} | ||
|
||
if ( OOI.head && OOI.sphere && conf.turnHead ) { | ||
|
||
// turn head | ||
OOI.sphere.getWorldPosition( v0 ); | ||
OOI.head.lookAt( v0 ); | ||
OOI.head.rotation.set( OOI.head.rotation.x, OOI.head.rotation.y + Math.PI, OOI.head.rotation.z ); | ||
|
||
} | ||
|
||
if ( conf.ik_solver ) { | ||
|
||
IKSolver?.update(); | ||
|
||
} | ||
|
||
orbitControls.update(); | ||
renderer.render( scene, camera ); | ||
|
||
stats.update(); // fps stats | ||
|
||
requestAnimationFrame( animate ); | ||
|
||
} | ||
|
||
function onWindowResize() { | ||
|
||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
|
||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
|
||
} | ||
</script> | ||
</body> | ||
</html> |