Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ShaneBrumback/7de47c89a634280a06690c060df6803b to your computer and use it in GitHub Desktop.
Save ShaneBrumback/7de47c89a634280a06690c060df6803b to your computer and use it in GitHub Desktop.
Three.js Examples - Raycaster GLTF 3D Model Selection
<!--////////////////////////////////////////////////////////////////////////////////////////
/// ///
/// 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