Hello,
I am a beginner in Threejs, I have created the WebAR viewer for my project.
For testing I am loading my glb model which has a basic rotation animation for testing purpose.
The model loads but I am not able to make the animation play. I have googled almost all the results on the glb animation but none of those are working.
The goal for me is after placing the model in AR the animation should start playing,
I even don’t know how to make the gltf scene as a global variable for accessing the animation later on in the project.
This is my code,
<link rel="stylesheet" href="three.js/main/css/main.css" />
<script type="module">
import * as THREE from "./three.js/build/three.module.js";
import { OrbitControls } from "./three.js/examples/jsm/controls/OrbitControls.js";
import { ARButton } from "./three.js/examples/jsm/webxr/ARButton.js";
import { RGBELoader } from "./three.js/examples/jsm/loaders/RGBELoader.js";
import { GLTFLoader } from "./three.js/examples/jsm/loaders/GLTFLoader.js";
let container;
let camera, scene, renderer, mixer;
let controller;
let reticle;
let hitTestSource = null;
let hitTestSourceRequested = false;
Init();
Animate();
function Init() {
container = document.createElement("div");
document.body.appendChild(container);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.01,
20
);
new RGBELoader()
.setDataType(THREE.UnsignedByteType)
.setPath("three.js/main/hdr/")
.load("studio.hdr", function (texture) {
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
//scene.background = envMap;
scene.environment = envMap;
texture.dispose();
pmremGenerator.dispose();
});
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.xr.enabled = true;
const pmremGenerator = new THREE.PMREMGenerator(renderer);
pmremGenerator.compileEquirectangularShader();
container.appendChild(renderer.domElement);
document.body.appendChild(
ARButton.createButton(renderer, { requiredFeatures: ["hit-test"] })
);
const gltfLoader = new GLTFLoader();
var model = new THREE.Object3D();
gltfLoader.load("three.js/main/glb/Ganesha.glb", (gltf, el) => {
model = gltf.scene;
model.name = "model";
console.log(gltf.animations);
mixer = new THREE.AnimationMixer( model );
gltf.animations.forEach(( clip ) => {
mixer.clipAction(clip).play();
});
});
function OnSelect() {
if (reticle.visible) {
scene.add(model);
model.position.setFromMatrixPosition(reticle.matrix);
model.isvisible = true;
}
}
controller = renderer.xr.getController(0);
controller.addEventListener("select", OnSelect);
scene.add(controller);
reticle = new THREE.Mesh(
new THREE.RingGeometry(0.15, 0.2, 32).rotateX(-Math.PI / 2),
new THREE.MeshBasicMaterial()
);
reticle.matrixAutoUpdate = false;
reticle.visible = false;
scene.add(reticle);
window.addEventListener("resize", OnWindowResize);
}
function OnWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function Animate() {
var mixerUpdateDelta = new THREE.Clock();
if(typeof mixer !== "undefined") mixer.update( mixerUpdateDelta.getDelta());
renderer.setAnimationLoop(Render);
}
function Render(timestamp, frame) {
if (frame) {
const referenceSpace = renderer.xr.getReferenceSpace();
const session = renderer.xr.getSession();
if (hitTestSourceRequested === false) {
session
.requestReferenceSpace("viewer")
.then(function (referenceSpace) {
session
.requestHitTestSource({ space: referenceSpace })
.then(function (source) {
hitTestSource = source;
});
});
session.addEventListener("end", function () {
hitTestSourceRequested = false;
hitTestSource = null;
});
hitTestSourceRequested = true;
}
if (hitTestSource) {
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length) {
const hit = hitTestResults[0];
reticle.visible = true;
reticle.matrix.fromArray(
hit.getPose(referenceSpace).transform.matrix
);
} else {
reticle.visible = false;
}
}
}
renderer.render(scene, camera);
}
</script>
Ganesha.glb (2.5 MB)