three.js - 在 ThreeJS 中使用 GLTFExporter 导出动画场景?
问题描述
我正在尝试使用 GLTFExporter 在 ThreeJS 中导出动画场景,但动画没有被导出。一切都正确导出,形状,颜色......这个项目正在使用示例导出:https ://threejs.org/examples/#misc_exporter_gltf ,以及动画示例:https ://threejs.org/examples /#misc_animation_keys,但它们不能一起工作。任何想法?
如果我使用https://gltf-viewer.donmccurdy.com/打开文件,我会看到一个错误:
这是代码:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - exporter - gltf</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info">
<button id="export_scene">Export Scene</button>
</div>
<script type="module">
import * as THREE from '../../build/three.module.js';
import { GLTFExporter } from './jsm/exporters/GLTFExporter.js';
function exportGLTF(input, animationClip) {
const gltfExporter = new GLTFExporter();
const options = {
binary: true,
maxTextureSize: 4096,
animations: [animationClip],
includeCustomExtensions: true
};
console.log(options);
gltfExporter.parse(input, function (result) {
if (result instanceof ArrayBuffer) {
saveArrayBuffer(result, 'scene.glb');
} else {
const output = JSON.stringify(result, null, 2);
console.log(output);
saveString(output, 'scene.gltf');
}
}, options);
}
document.getElementById('export_scene').addEventListener('click', function () {
exportGLTF(scene, clip);
});
const link = document.createElement('a');
link.style.display = 'none';
document.body.appendChild(link); // Firefox workaround, see #6594
function save(blob, filename) {
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
}
function saveString(text, filename) {
save(new Blob([text], { type: 'text/plain' }), filename);
}
function saveArrayBuffer(buffer, filename) {
save(new Blob([buffer], { type: 'application/octet-stream' }), filename);
}
let clock;
let camera, geometry, scene, renderer, mixer, clip;
let gridHelper, sphere, smallSphere;
init();
animate();
function init() {
scene = new THREE.Scene();
scene.name = 'scene';
// Perspective Camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.set(10, 300, 0);
camera.name = "PerspectiveCamera";
scene.add(camera);
// Ambient light
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
ambientLight.name = 'AmbientLight';
scene.add(ambientLight);
// DirectLight
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.target.position.set(0, 0, - 1);
dirLight.add(dirLight.target);
dirLight.lookAt(- 1, - 1, 0);
dirLight.name = 'DirectionalLight';
scene.add(dirLight);
//Axes
/*
const axes = new THREE.AxesHelper(500);
axes.name = "AxesHelper";
scene.add(axes);*/
// Sphere
const material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true });
sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 10, 10), material);
sphere.position.set(0, 0, 0);
sphere.name = "Sphere";
scene.add(sphere);
// Small sphere
smallSphere = new THREE.Mesh(new THREE.SphereGeometry(20, 10, 10), material);
smallSphere.position.set(80, 0, 0);
smallSphere.name = "SmallSphere";
scene.add(smallSphere);
// POSITION
const positionKF = new THREE.VectorKeyframeTrack('.position', [0, 1, 2], [0, 90, 60, 30, 0, 60, 70, 40, 50]);
// SCALE
const scaleKF = new THREE.VectorKeyframeTrack('.scale', [0, 1, 2], [1, 1, 1, 2, 2, 2, 1, 1, 1]);
// ROTATION
// Rotation should be performed using quaternions, using a THREE.QuaternionKeyframeTrack
// Interpolating Euler angles (.rotation property) can be problematic and is currently not supported
// set up rotation about x axis
const xAxis = new THREE.Vector3(1, 0, 0);
const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis, 0);
const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis, Math.PI);
const quaternionKF = new THREE.QuaternionKeyframeTrack('.quaternion', [0, 1, 2], [qInitial.x, qInitial.y, qInitial.z, qInitial.w, qFinal.x, qFinal.y, qFinal.z, qFinal.w, qInitial.x, qInitial.y, qInitial.z, qInitial.w]);
// COLOR
const colorKF = new THREE.ColorKeyframeTrack('.material.color', [0, 1, 2], [1, 0, 0, 0, 1, 0, 0, 0, 1], THREE.InterpolateDiscrete);
// OPACITY
const opacityKF = new THREE.NumberKeyframeTrack('.material.opacity', [0, 1, 2], [1, 0, 1]);
// Clip
clip = new THREE.AnimationClip('Action', 3, [scaleKF, positionKF, quaternionKF, colorKF, opacityKF]);
// Mixer
mixer = new THREE.AnimationMixer(smallSphere);
const clipAction = mixer.clipAction(clip);
clipAction.play();
// Clock
clock = new THREE.Clock();
// Renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
const timer = Date.now() * 0.0001;
const delta = clock.getDelta();
if (mixer) {
mixer.update(delta);
}
camera.position.x = Math.cos(timer) * 400;
camera.position.z = Math.sin(timer) * 400;
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
</script>
</body>
</html>
任何想法?
解决方案
正如 Don McCurdy 在评论中解释的那样,存在两个问题:
- 无法导出材质属性(不透明度和颜色)的动画。
- 我必须在每个指针之前指定对象名称:
<object-name>.position
.
谢谢唐·麦柯迪。
推荐阅读
- javascript - 使用javascript的切片函数的异步问题
- google-apps-script - 应用程序活动服务不可用
- javascript - 纱线构建在第一行失败,无论那里有什么
- ios - 如何在 Objective-C 中将 UIImage 上传到服务器?
- c - 用scanf C识别“空格”和“输入”
- scala - Flink Scala 作业运行时错误:java.lang.NoSuchMethodError
- javascript - 为什么合并流需要异步完成信号?
- c - 如何查找总成绩,然后使用 qsort() 进行排序
- android - 谷歌地图和视图模型
- date-fns - date-fns utcToZonedTime 有意外的输出