1 Star 0 Fork 0

ing10010/verge3d-code-examples

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
webgl_animation_multiple.html 11.24 KB
一键复制 编辑 原始数据 按行查看 历史
<!DOCTYPE html>
<html lang="en">
<head>
<title>Multiple animated objects</title>
<meta charset="utf-8">
<meta content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" name="viewport">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="container"></div>
<div id="info">
This demo shows how clone a skinned 3d model using <strong>SkeletonUtils.clone()</strong><br/>
Soldier model from <a href="https://www.mixamo.com" target="_blank" rel="noopener">https://www.mixamo.com</a>.
</div>
<script type="module">
import * as v3d from '../build/v3d.module.js';
import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
import { SkeletonUtils } from './jsm/utils/SkeletonUtils.js';
//////////////////////////////
// Global objects
//////////////////////////////
let worldScene = null; // v3d.Scene where it all will be rendered
let renderer = null;
let camera = null;
let clock = null;
const mixers = []; // All the v3d.AnimationMixer objects for all the animations in the scene
//////////////////////////////
//////////////////////////////
// Information about our 3D models and units
//////////////////////////////
// The names of the 3D models to load. One-per file.
// A model may have multiple SkinnedMesh objects as well as several rigs (armatures). Units will define which
// meshes, armatures and animations to use. We will load the whole scene for each object and clone it for each unit.
// Models are from https://www.mixamo.com/
const MODELS = [
{ name: "Soldier" },
{ name: "Parrot" },
// { name: "RiflePunch" },
];
// Here we define instances of the models that we want to place in the scene, their position, scale and the animations
// that must be played.
const UNITS = [
{
modelName: "Soldier", // Will use the 3D model from file models/gltf/Soldier.glb
meshName: "vanguard_Mesh", // Name of the main mesh to animate
position: { x: 0, y: 0, z: 0 }, // Where to put the unit in the scene
scale: 1, // Scaling of the unit. 1.0 means: use original size, 0.1 means "10 times smaller", etc.
animationName: "Idle" // Name of animation to run
},
{
modelName: "Soldier",
meshName: "vanguard_Mesh",
position: { x: 3, y: 0, z: 0 },
scale: 2,
animationName: "Walk"
},
{
modelName: "Soldier",
meshName: "vanguard_Mesh",
position: { x: 1, y: 0, z: 0 },
scale: 1,
animationName: "Run"
},
{
modelName: "Parrot",
meshName: "mesh_0",
position: { x: - 4, y: 0, z: 0 },
rotation: { x: 0, y: Math.PI, z: 0 },
scale: 0.01,
animationName: "parrot_A_"
},
{
modelName: "Parrot",
meshName: "mesh_0",
position: { x: - 2, y: 0, z: 0 },
rotation: { x: 0, y: Math.PI / 2, z: 0 },
scale: 0.02,
animationName: null
},
];
//////////////////////////////
// The main setup happens here
//////////////////////////////
let numLoadedModels = 0;
initScene();
initRenderer();
loadModels();
animate();
//////////////////////////////
//////////////////////////////
// Function implementations
//////////////////////////////
/**
* Function that starts loading process for the next model in the queue. The loading process is
* asynchronous: it happens "in the background". Therefore we don't load all the models at once. We load one,
* wait until it is done, then load the next one. When all models are loaded, we call loadUnits().
*/
function loadModels() {
for (let i = 0; i < MODELS.length; ++ i) {
const m = MODELS[i];
loadGltfModel(m, function() {
++ numLoadedModels;
if (numLoadedModels === MODELS.length) {
console.log("All models loaded, time to instantiate units...");
instantiateUnits();
}
});
}
}
/**
* Look at UNITS configuration, clone necessary 3D model scenes, place the armatures and meshes in the scene and
* launch necessary animations
*/
function instantiateUnits() {
let numSuccess = 0;
for (let i = 0; i < UNITS.length; ++ i) {
const u = UNITS[i];
const model = getModelByName(u.modelName);
if (model) {
const clonedScene = SkeletonUtils.clone(model.scene);
if (clonedScene) {
// v3d.Scene is cloned properly, let's find one mesh and launch animation for it
const clonedMesh = clonedScene.getObjectByName(u.meshName);
if (clonedMesh) {
const mixer = startAnimation(clonedMesh, model.animations, u.animationName);
// Save the animation mixer in the list, will need it in the animation loop
mixers.push(mixer);
numSuccess ++;
}
// Different models can have different configurations of armatures and meshes. Therefore,
// We can't set position, scale or rotation to individual mesh objects. Instead we set
// it to the whole cloned scene and then add the whole scene to the game world
// Note: this may have weird effects if you have lights or other items in the GLTF file's scene!
worldScene.add(clonedScene);
if (u.position) {
clonedScene.position.set(u.position.x, u.position.y, u.position.z);
}
if (u.scale) {
clonedScene.scale.set(u.scale, u.scale, u.scale);
}
if (u.rotation) {
clonedScene.rotation.x = u.rotation.x;
clonedScene.rotation.y = u.rotation.y;
clonedScene.rotation.z = u.rotation.z;
}
}
} else {
console.error("Can not find model", u.modelName);
}
}
console.log(`Successfully instantiated ${numSuccess} units`);
}
/**
* Start animation for a specific mesh object. Find the animation by name in the 3D model's animation array
* @param skinnedMesh {v3d.SkinnedMesh} The mesh to animate
* @param animations {Array} Array containing all the animations for this model
* @param animationName {string} Name of the animation to launch
* @return {v3d.AnimationMixer} Mixer to be used in the render loop
*/
function startAnimation(skinnedMesh, animations, animationName) {
const mixer = new v3d.AnimationMixer(skinnedMesh);
const clip = v3d.AnimationClip.findByName(animations, animationName);
if (clip) {
const action = mixer.clipAction(clip);
action.play();
}
return mixer;
}
/**
* Find a model object by name
* @param name
* @returns {object|null}
*/
function getModelByName(name) {
for (let i = 0; i < MODELS.length; ++ i) {
if (MODELS[i].name === name) {
return MODELS[i];
}
}
return null;
}
/**
* Load a 3D model from a GLTF file. Use the GLTFLoader.
* @param model {object} Model config, one item from the MODELS array. It will be updated inside the function!
* @param onLoaded {function} A callback function that will be called when the model is loaded
*/
function loadGltfModel(model, onLoaded) {
const loader = new GLTFLoader();
const modelName = "models/gltf/" + model.name + ".glb";
loader.load(modelName, function(gltf) {
const scene = gltf.scene;
model.animations = gltf.animations;
model.scene = scene;
// Enable Shadows
gltf.scene.traverse(function(object) {
if (object.isMesh) {
object.castShadow = true;
}
});
console.log("Done loading model", model.name);
onLoaded();
});
}
/**
* Render loop. Renders the next frame of all animations
*/
function animate() {
requestAnimationFrame(animate);
// Get the time elapsed since the last frame
const mixerUpdateDelta = clock.getDelta();
// Update all the animation frames
for (let i = 0; i < mixers.length; ++ i) {
mixers[i].update(mixerUpdateDelta);
}
renderer.render(worldScene, camera);
}
//////////////////////////////
// General Three.JS stuff
//////////////////////////////
// This part is not anyhow related to the cloning of models, it's just setting up the scene.
/**
* Initialize ThreeJS scene renderer
*/
function initRenderer() {
const container = document.getElementById('container');
renderer = new v3d.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.outputEncoding = v3d.sRGBEncoding;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = v3d.PCFSoftShadowMap;
container.appendChild(renderer.domElement);
}
/**
* Initialize ThreeJS v3d.Scene
*/
function initScene() {
camera = new v3d.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(3, 6, - 10);
camera.lookAt(0, 1, 0);
clock = new v3d.Clock();
worldScene = new v3d.Scene();
worldScene.background = new v3d.Color(0xa0a0a0);
worldScene.fog = new v3d.Fog(0xa0a0a0, 10, 22);
const hemiLight = new v3d.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(0, 20, 0);
worldScene.add(hemiLight);
const dirLight = new v3d.DirectionalLight(0xffffff);
dirLight.position.set(- 3, 10, - 10);
dirLight.castShadow = true;
dirLight.shadow.camera.top = 10;
dirLight.shadow.camera.bottom = - 10;
dirLight.shadow.camera.left = - 10;
dirLight.shadow.camera.right = 10;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 40;
worldScene.add(dirLight);
// ground
const groundMesh = new v3d.Mesh(
new v3d.PlaneBufferGeometry(40, 40),
new v3d.MeshPhongMaterial({
color: 0x999999,
depthWrite: false
})
);
groundMesh.rotation.x = - Math.PI / 2;
groundMesh.receiveShadow = true;
worldScene.add(groundMesh);
window.addEventListener('resize', onWindowResize, false);
}
/**
* A callback that will be called whenever the browser window is resized.
*/
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
</body>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
HTML
1
https://gitee.com/ing/verge3d-code-examples.git
git@gitee.com:ing/verge3d-code-examples.git
ing
verge3d-code-examples
verge3d-code-examples
master

搜索帮助