rl-loadout-lib
Version:
Load Rocket League assets into three.js
331 lines • 12.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const three_1 = require("three");
const object_1 = require("../object");
const util_1 = require("../../utils/util");
const axle_settings_1 = require("../../model/axle-settings");
const wheel_1 = require("../../model/wheel");
const constants_1 = require("../constants");
const skeleton_1 = require("../../utils/three/skeleton");
const chassis_material_1 = require("../../webgl/chassis-material");
const material_factory_1 = require("./material-factory");
/**
* Class that handles loading the 3D model of the car body.
*/
class BodyModel extends object_1.AbstractObject {
/**
* Create a body model object. You should **not** use this unless you know what you are doing. Use {@link createBodyModel} instead.
* @param body car body to load the model of
* @param decal car decal to load the textures of
* @param bodyAssets body assets
* @param decalAssets decal assets
* @param paints paints to be applied to the body
*/
constructor(body, decal, bodyAssets, decalAssets, paints) {
super(bodyAssets);
this.body = body;
this.bodyAssets = bodyAssets;
this.wheelRoll = 0;
this.bodyMaterial = material_factory_1.getBodyMaterial(body);
this.bodyMesh.material = this.bodyMaterial;
this.chassisMaterial = new chassis_material_1.ChassisMaterial();
this.chassisMesh.material = this.chassisMaterial;
this.applyAssets(paints, decalAssets);
}
applyAssets(paints, decalAssets) {
this.chassisMaterial.map = util_1.htmlImageToTexture(this.bodyAssets.chassisD);
this.chassisMaterial.normalMap = util_1.htmlImageToTexture(this.bodyAssets.chassisN);
this.chassisMaterial.rgbaMap = util_1.htmlImageToTexture(this.bodyAssets.chassisN);
this.chassisMaterial.paintable = this.body.chassis_paintable;
this.chassisMaterial.accentColor = paints.accent;
this.chassisMaterial.paintColor = paints.body;
this.chassisMaterial.skinning = true;
this.chassisMaterial.needsUpdate = true;
this.applyDecalAssets(paints, decalAssets);
}
applyDecalAssets(paints, decalAssets) {
if (decalAssets.baseTexture) {
this.bodyMaterial.map = util_1.htmlImageToTexture(decalAssets.baseTexture);
}
else {
this.bodyMaterial.map = util_1.htmlImageToTexture(this.bodyAssets.baseSkin);
}
this.bodyMaterial.rgbaMap = util_1.htmlImageToTexture(this.bodyAssets.blankSkin);
this.bodyMaterial.decalMap = util_1.htmlImageToTexture(decalAssets.rgbaMap);
this.bodyMaterial.primaryColor = paints.primary;
this.bodyMaterial.accentColor = paints.accent;
this.bodyMaterial.paintColor = paints.decal;
this.bodyMaterial.bodyPaintColor = paints.body;
this.bodyMaterial.needsUpdate = true;
}
dispose() {
super.dispose();
util_1.disposeIfExists(this.bodyMaterial);
util_1.disposeIfExists(this.chassisMaterial);
this.wheelsModel = undefined;
}
handleModel(scene) {
if ('hitbox' in scene.userData) {
this.hitboxConfig = scene.userData.hitbox;
}
if ('wheelSettings' in scene.userData) {
this.wheelSettings = {
frontAxle: axle_settings_1.AxleSettings.fromObject(scene.userData.wheelSettings.frontAxle),
backAxle: axle_settings_1.AxleSettings.fromObject(scene.userData.wheelSettings.backAxle)
};
}
this.hatSocket = scene.getObjectByName('HatSocket');
this.antennaSocket = scene.getObjectByName('AntennaSocket');
if (this.frontPivots == undefined) {
this.frontPivots = [];
}
scene.traverse(object => {
if (object['isBone'] && this.skeleton == undefined) {
this.skeleton = object;
}
else if (object['isMesh']) {
const mat = object.material;
const matName = mat.name.toLowerCase();
if (matName.includes('body')) {
this.bodyMesh = object;
}
else if (matName.includes('chassis')) {
const mesh = object;
this.chassisMesh = mesh;
// @ts-ignore
this.frontPivots.push(mesh.skeleton.getBoneByName('FL_Pivot_jnt'));
// @ts-ignore
this.frontPivots.push(mesh.skeleton.getBoneByName('FR_Pivot_jnt'));
}
else if (matName === 'window_material') {
mat.envMapIntensity = 3.0;
mat.needsUpdate = true;
}
}
});
this.getWheelPositions();
}
getWheelPositions() {
this.wheelConfig = [];
this.skeleton.traverse(object => {
if (object.name.endsWith('Disc_jnt')) {
const config = new wheel_1.WheelConfig();
const wheelType = object.name.substr(0, 2).toLowerCase();
config.front = wheelType[0] === 'f';
config.right = wheelType[1] === 'r';
config.joint = object;
if (this.wheelSettings != undefined) {
if (config.front) {
config.offset = this.wheelSettings.frontAxle.wheelMeshOffsetSide;
config.width = this.wheelSettings.frontAxle.wheelWidth;
config.radius = this.wheelSettings.frontAxle.wheelMeshRadius;
}
else {
config.offset = this.wheelSettings.backAxle.wheelMeshOffsetSide;
config.width = this.wheelSettings.backAxle.wheelWidth;
config.radius = this.wheelSettings.backAxle.wheelMeshRadius;
}
}
this.wheelConfig.push(config);
}
});
}
/**
* Add wheels to the body. This creates 4 copies of the wheel model and attaches them to the wheel joints. Replaces existing wheels.
* @param wheelsModel the wheels
*/
addWheelsModel(wheelsModel) {
this.clearWheelsModel();
this.wheelsModel = wheelsModel;
this.applyWheelConfig();
for (const wheel of this.wheels) {
wheel.config.joint.add(wheel.model);
}
}
applyWheelConfig() {
if (this.wheelConfig == undefined) {
return;
}
const config = this.wheelConfig;
this.wheels = [];
for (const conf of config) {
const widthScale = conf.width / constants_1.BASE_WHEEL_MESH_WIDTH;
const radiusScale = conf.radius / constants_1.BASE_WHEEL_MESH_RADIUS;
const offset = conf.offset;
const wheel = skeleton_1.SkeletonUtils.clone(this.wheelsModel.scene);
const position = new three_1.Vector3();
position.copy(conf.position);
if (!conf.right) {
wheel.rotation.set(-Math.PI / 2, 0, Math.PI);
position.add(new three_1.Vector3(0, offset, 0));
}
else {
wheel.rotation.set(Math.PI / 2, 0, 0);
position.add(new three_1.Vector3(0, -offset, 0));
}
wheel.scale.set(radiusScale, radiusScale, widthScale);
wheel.position.copy(position);
let spinnerJoint;
wheel.traverse(object => {
if (object['isBone']) {
if (object.name === 'spinner_jnt') {
spinnerJoint = object;
}
}
});
this.wheels.push({
model: wheel,
config: conf,
spinnerJoint
});
}
}
/**
* Remove the wheels from the body.
*/
clearWheelsModel() {
for (const conf of this.wheelConfig) {
for (let i = conf.joint.children.length - 1; i >= 0; i--) {
conf.joint.remove(conf.joint.children[i]);
}
}
this.wheels = [];
this.wheelsModel = undefined;
}
/**
* Add a topper to the body and attach it to the topper socket. It replaces existing toppers.
* @param topperModel the topper
*/
addTopperModel(topperModel) {
this.clearTopperModel();
this.topperModel = topperModel;
this.topperModel.applyAnchor(this.hatSocket);
this.topperModel.addToScene(this.scene);
}
/**
* Remove the topper from the body.
*/
clearTopperModel() {
if (this.topperModel != undefined) {
this.topperModel.removeFromScene(this.scene);
this.topperModel = undefined;
}
}
/**
* Add an antenna to the body and attach it to the antenna anchor. It replaces existing antennas.
* @param antennaModel the antenna
*/
addAntennaModel(antennaModel) {
this.clearAntennaModel();
this.antennaModel = antennaModel;
this.antennaModel.applyAnchor(this.antennaSocket);
this.antennaModel.addToScene(this.scene);
}
/**
* Remove the antenna from the body.
*/
clearAntennaModel() {
if (this.antennaModel != undefined) {
this.antennaModel.removeFromScene(this.scene);
this.antennaModel = undefined;
}
}
/**
* Set the paint color of this body.
* @param color paint color
*/
setPaintColor(color) {
this.bodyMaterial.bodyPaintColor = color;
this.bodyMaterial.needsUpdate = true;
this.chassisMaterial.paintColor = color;
this.chassisMaterial.needsUpdate = true;
}
/**
* Replace the current decal with a new one.
* @param decalAssets decal assets
* @param paints paint config needed for decal colors
*/
changeDecal(decalAssets, paints) {
this.applyDecalAssets(paints, decalAssets);
}
/**
* Set the primary color.
* @param color THREE Color object
*/
setPrimaryColor(color) {
this.bodyMaterial.primaryColor = color;
}
/**
* Set the accent color.
* @param color THREE Color object
*/
setAccentColor(color) {
this.bodyMaterial.accentColor = color;
}
/**
* Set the paint color of the decal.
* @param color THREE Color object
*/
setDecalPaintColor(color) {
this.bodyMaterial.paintColor = color;
}
/**
* Set the yaw rotation (turn) of the front wheels.
* @param angle yaw in radians
* @param clamped if true, the angle will be clamped and the absolute value will not be higher than {@link MAX_WHEEL_YAW}
*/
setFrontWheelYaw(angle, clamped = true) {
if (clamped) {
angle = Math.max(Math.min(angle, constants_1.MAX_WHEEL_YAW), -constants_1.MAX_WHEEL_YAW);
}
for (const pivot of this.frontPivots) {
pivot.rotation.z = angle;
}
}
/**
* Set roll rotation of the wheels.
* @param angle roll angle in radians
*/
setWheelRoll(angle) {
this.wheelRoll = angle;
for (const wheel of this.wheels) {
if (wheel.config.right) {
wheel.model.rotation.z = -angle;
}
else {
wheel.model.rotation.z = Math.PI + angle;
}
if (wheel.spinnerJoint != undefined) {
if (wheel.config.right) {
wheel.spinnerJoint.rotation.y = angle;
}
else {
wheel.spinnerJoint.rotation.y = -angle;
}
}
}
}
animate(time) {
var _a;
if (this.wheels != undefined) {
for (const wheel of this.wheels) {
(_a = this.wheelsModel) === null || _a === void 0 ? void 0 : _a.animate(time, wheel, this.wheelRoll);
}
}
}
copy(other) {
super.copy(other);
this.clearWheelsModel();
this.bodyAssets = other.bodyAssets;
if (other.wheelsModel != undefined) {
this.addWheelsModel(other.wheelsModel.clone());
}
}
clone() {
const m = new BodyModel();
m.copy(this);
return m;
}
}
exports.BodyModel = BodyModel;
//# sourceMappingURL=body-model.js.map