Last active
March 19, 2024 05:17
-
-
Save ShaneBrumback/9b0e864813d0ec3f13aa664b397a5dd5 to your computer and use it in GitHub Desktop.
Threejs Examples Loading and Animating 3D 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
| |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title> Loading and Animating 3D Characters Using Threejs</title> | |
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | |
</head> | |
<body> | |
<script src="https://cdn.jsdelivr.net/npm/three@latest/build/three.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/three@latest/examples/js/controls/OrbitControls.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/three@latest/examples/js/loaders/GLTFLoader.js"></script> | |
<script> | |
// Set up the scene, camera, and renderer | |
var scene = new THREE.Scene(); | |
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
//Set up the renderer | |
let renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); | |
renderer.setPixelRatio(window.devicePixelRatio); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
renderer.toneMapping = THREE.ReinhardToneMapping; | |
renderer.shadowMap.enabled = true; | |
renderer.shadowMap.type = THREE.PCFSoftShadowMap; | |
renderer.domElement.id = 'renderer'; | |
renderer.setClearColor(0x000000, 1); // Set background color to black | |
renderer.domElement.style.position = 'fixed'; | |
renderer.domElement.style.zIndex = '-1'; | |
renderer.domElement.style.left = '0'; | |
renderer.domElement.style.top = '0'; | |
document.body.appendChild(renderer.domElement); | |
// Add ambient light | |
var ambientLight = new THREE.AmbientLight(0xffffff, 0.5); | |
scene.add(ambientLight); | |
// Add directional light | |
var directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); | |
directionalLight.position.set(1, 1, 1); | |
scene.add(directionalLight); | |
// Initialize OrbitControls | |
var controls = new THREE.OrbitControls(camera, renderer.domElement); | |
controls.autoRotate = true; // Enable auto-rotation | |
controls.autoRotateSpeed = 2; // Set auto-rotation speed | |
// Create a grid | |
var gridHelper = new THREE.GridHelper(10, 50); | |
scene.add(gridHelper); | |
// Create a group for the model | |
var modelGroup = new THREE.Group(); | |
scene.add(modelGroup); | |
// Create a mixer for the animation | |
var mixer; | |
var center = new THREE.Vector3(); // Declare the center variable outside the loader callback | |
// Load GLTF model | |
var loader = new THREE.GLTFLoader(); | |
loader.load('https://www.shanebrumback.com/models/glb/swat/swat-character.glb', function (gltf) { | |
var model = gltf.scene; | |
modelGroup.add(model); | |
// Calculate the bounding box of the model | |
var boundingBox = new THREE.Box3().setFromObject(model); | |
// Get the center of the bounding box | |
boundingBox.getCenter(center); | |
// Get the size of the bounding box | |
var size = new THREE.Vector3(); | |
boundingBox.getSize(size); | |
// Get the animations from the GLTF model | |
var animations = gltf.animations; | |
// Create a mixer and assign it to the global mixer variable | |
mixer = new THREE.AnimationMixer(model); | |
// Play all animations | |
animations.forEach(function (animation) { | |
mixer.clipAction(animation).play(); | |
}); | |
// Fly around the model at random distances | |
flyAroundModel(); | |
}); | |
// Function to fly around the model | |
function flyAroundModel() { | |
// Set the maximum angle to 54 degrees (π/3 radians) | |
var maxAngle = Math.PI / 6; | |
// Randomly set camera position around the model within the specified angle limit | |
var angle = Math.random() * maxAngle * 2 - maxAngle; // Random angle between -maxAngle and +maxAngle | |
var radius = Math.random() * 3 + 3; // Random distance between 5 and 15 | |
var targetPos = new THREE.Vector3( | |
center.x + radius * Math.cos(angle), | |
center.y + radius * Math.cos(angle), | |
center.z + radius * Math.sin(angle) | |
); | |
// Smoothly interpolate camera position towards the target position | |
var duration = 2000; // Duration of the lerp animation in milliseconds | |
var start = new THREE.Vector3().copy(camera.position); | |
var startTime = performance.now(); | |
function lerpPosition() { | |
var elapsed = performance.now() - startTime; | |
var t = Math.min(1, elapsed / duration); // Ensure t doesn't exceed 1 | |
camera.position.lerpVectors(start, targetPos, t); | |
// Look at the center of the model | |
camera.lookAt(center); | |
// Render the scene | |
renderer.render(scene, camera); | |
if (t < 1) { | |
// Continue lerping until t reaches 1 | |
requestAnimationFrame(lerpPosition); | |
} else { | |
// Call this function again after a random time interval between 2 to 5 seconds | |
var randomTimeInterval = Math.random() * 3000 + 2000; | |
setTimeout(flyAroundModel, randomTimeInterval); | |
} | |
} | |
// Start the lerping animation | |
lerpPosition(); | |
} | |
// Render the scene | |
function animate() { | |
requestAnimationFrame(animate); | |
// Update the mixer | |
if (mixer) { | |
mixer.update(0.02); | |
} | |
controls.update(); | |
renderer.render(scene, camera); | |
} | |
animate(); | |
// Add window resize event listener | |
window.addEventListener('resize', onWindowResize); | |
// Function to handle window resize event | |
function onWindowResize() { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment