three-stdlib
Version:
stand-alone library of threejs examples
169 lines (168 loc) • 5.57 kB
JavaScript
import { Object3D, Box3, AnimationMixer, MeshLambertMaterial, Mesh, TextureLoader, UVMapping } from "three";
import { MD2Loader } from "../loaders/MD2Loader.js";
class MD2Character {
constructor() {
this.scale = 1;
this.animationFPS = 6;
this.root = new Object3D();
this.meshBody = null;
this.meshWeapon = null;
this.skinsBody = [];
this.skinsWeapon = [];
this.weapons = [];
this.activeAnimation = null;
this.mixer = null;
this.onLoadComplete = function() {
};
this.loadCounter = 0;
}
loadParts(config) {
const scope = this;
function createPart(geometry, skinMap) {
const materialWireframe = new MeshLambertMaterial({
color: 16755200,
wireframe: true,
morphTargets: true,
morphNormals: true
});
const materialTexture = new MeshLambertMaterial({
color: 16777215,
wireframe: false,
map: skinMap,
morphTargets: true,
morphNormals: true
});
const mesh = new Mesh(geometry, materialTexture);
mesh.rotation.y = -Math.PI / 2;
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.materialTexture = materialTexture;
mesh.materialWireframe = materialWireframe;
return mesh;
}
function loadTextures(baseUrl, textureUrls) {
const textureLoader = new TextureLoader();
const textures = [];
for (let i = 0; i < textureUrls.length; i++) {
textures[i] = textureLoader.load(baseUrl + textureUrls[i], checkLoadingComplete);
textures[i].mapping = UVMapping;
textures[i].name = textureUrls[i];
if ("colorSpace" in textures[i])
textures[i].colorSpace = "srgb";
else
textures[i].encoding = 3001;
}
return textures;
}
function checkLoadingComplete() {
scope.loadCounter -= 1;
if (scope.loadCounter === 0)
scope.onLoadComplete();
}
this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
const weaponsTextures = [];
for (let i = 0; i < config.weapons.length; i++)
weaponsTextures[i] = config.weapons[i][1];
this.skinsBody = loadTextures(config.baseUrl + "skins/", config.skins);
this.skinsWeapon = loadTextures(config.baseUrl + "skins/", weaponsTextures);
const loader = new MD2Loader();
loader.load(config.baseUrl + config.body, function(geo) {
const boundingBox = new Box3();
boundingBox.setFromBufferAttribute(geo.attributes.position);
scope.root.position.y = -scope.scale * boundingBox.min.y;
const mesh = createPart(geo, scope.skinsBody[0]);
mesh.scale.set(scope.scale, scope.scale, scope.scale);
scope.root.add(mesh);
scope.meshBody = mesh;
scope.meshBody.clipOffset = 0;
scope.activeAnimationClipName = mesh.geometry.animations[0].name;
scope.mixer = new AnimationMixer(mesh);
checkLoadingComplete();
});
const generateCallback = function(index, name) {
return function(geo) {
const mesh = createPart(geo, scope.skinsWeapon[index]);
mesh.scale.set(scope.scale, scope.scale, scope.scale);
mesh.visible = false;
mesh.name = name;
scope.root.add(mesh);
scope.weapons[index] = mesh;
scope.meshWeapon = mesh;
checkLoadingComplete();
};
};
for (let i = 0; i < config.weapons.length; i++) {
loader.load(config.baseUrl + config.weapons[i][0], generateCallback(i, config.weapons[i][0]));
}
}
setPlaybackRate(rate) {
if (rate !== 0) {
this.mixer.timeScale = 1 / rate;
} else {
this.mixer.timeScale = 0;
}
}
setWireframe(wireframeEnabled) {
if (wireframeEnabled) {
if (this.meshBody)
this.meshBody.material = this.meshBody.materialWireframe;
if (this.meshWeapon)
this.meshWeapon.material = this.meshWeapon.materialWireframe;
} else {
if (this.meshBody)
this.meshBody.material = this.meshBody.materialTexture;
if (this.meshWeapon)
this.meshWeapon.material = this.meshWeapon.materialTexture;
}
}
setSkin(index) {
if (this.meshBody && this.meshBody.material.wireframe === false) {
this.meshBody.material.map = this.skinsBody[index];
}
}
setWeapon(index) {
for (let i = 0; i < this.weapons.length; i++)
this.weapons[i].visible = false;
const activeWeapon = this.weapons[index];
if (activeWeapon) {
activeWeapon.visible = true;
this.meshWeapon = activeWeapon;
this.syncWeaponAnimation();
}
}
setAnimation(clipName) {
if (this.meshBody) {
if (this.meshBody.activeAction) {
this.meshBody.activeAction.stop();
this.meshBody.activeAction = null;
}
const action = this.mixer.clipAction(clipName, this.meshBody);
if (action) {
this.meshBody.activeAction = action.play();
}
}
this.activeClipName = clipName;
this.syncWeaponAnimation();
}
syncWeaponAnimation() {
const clipName = this.activeClipName;
if (this.meshWeapon) {
if (this.meshWeapon.activeAction) {
this.meshWeapon.activeAction.stop();
this.meshWeapon.activeAction = null;
}
const action = this.mixer.clipAction(clipName, this.meshWeapon);
if (action) {
this.meshWeapon.activeAction = action.syncWith(this.meshBody.activeAction).play();
}
}
}
update(delta) {
if (this.mixer)
this.mixer.update(delta);
}
}
export {
MD2Character
};
//# sourceMappingURL=MD2Character.js.map