Last active
March 19, 2024 05:17
-
-
Save ShaneBrumback/7de47c89a634280a06690c060df6803b to your computer and use it in GitHub Desktop.
Three.js Examples - Raycaster GLTF 3D Model Selection
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
<!--//////////////////////////////////////////////////////////////////////////////////////// | |
/// /// | |
/// Example Using Three.js Library, HTML, CSS & JavaScript /// | |
// 3D Interactive Web Apps & Games 2021-2024 /// | |
/// Contact Shane Brumback https://www.shanebrumback.com /// | |
/// Send a message if you have questions about this code /// | |
/// I am a freelance developer. I develop any and all web. /// | |
/// Apps Websites 3D 2D CMS Systems etc. Contact me anytime :) /// | |
/// /// | |
////////////////////////////////////////////////////////////////////////////////////////////--> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Three.js Examples - Selecting 3D Minecraft Models Using Raycasters</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); | |
// Create a grid | |
var gridHelper = new THREE.GridHelper(10, 10); | |
scene.add(gridHelper); | |
// Create a raycaster for interaction | |
var raycaster = new THREE.Raycaster(); | |
var mouse = new THREE.Vector2(); | |
// Create a group for the model | |
var modelGroup = new THREE.Group(); | |
scene.add(modelGroup); | |
// Create a mixer for the animation | |
var mixer; | |
// Load GLTF model | |
var loader = new THREE.GLTFLoader(); | |
loader.load('../models/gltf/minecraft-zombie/zombie-001.glb', function (gltf) { | |
var model = gltf.scene; | |
modelGroup.add(model); | |
// Position and scale the model | |
model.position.set(0, 0, 0); | |
model.scale.set(1, 1, 1); | |
// Calculate the bounding box of the model | |
var boundingBox = new THREE.Box3().setFromObject(model); | |
// Get the center of the bounding box | |
var center = new THREE.Vector3(); | |
boundingBox.getCenter(center); | |
// Get the size of the bounding box | |
var size = new THREE.Vector3(); | |
boundingBox.getSize(size); | |
// Calculate the distance to the model based on the bounding box size | |
var maxDim = Math.max(size.x, size.y, size.z); | |
var distance = maxDim / Math.tan(THREE.MathUtils.degToRad(camera.fov * 0.5)); | |
// Set the camera position and look at the center of the model | |
camera.position.copy(center); | |
camera.position.z += distance; | |
camera.position.y += distance - 1.15; | |
camera.lookAt(center); | |
// Initialize OrbitControls | |
var controls = new THREE.OrbitControls(camera, renderer.domElement); | |
controls.autoRotate = true; | |
controls.target.copy(center); | |
// 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 the first animation | |
var action = mixer.clipAction(animations[1]); | |
action.play(); | |
// Calculate the top position of the bounding box | |
var topPosition = new THREE.Vector3(); | |
topPosition.addVectors(center, new THREE.Vector3(0, size.y / 2, 0)); | |
}); | |
// Handle mouse click | |
function onMouseClick(event) { | |
// Calculate mouse position in normalized device coordinates | |
mouse.x = (event.clientX / window.innerWidth) * 2 - 1; | |
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; | |
// Update the picking ray with the camera and mouse position | |
raycaster.setFromCamera(mouse, camera); | |
// Check for intersections only with the model group | |
var intersects = raycaster.intersectObjects(modelGroup.children, true); | |
if (intersects.length > 0) { | |
alert('Clicked on the model!'); | |
} | |
} | |
// Add event listener for mouse click | |
window.addEventListener('click', onMouseClick, false); | |
// Render the scene | |
function animate() { | |
requestAnimationFrame(animate); | |
// Update the mixer | |
if (mixer) { | |
mixer.update(0.02); | |
} | |
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