2020-01-26 20:39:29 +01:00
|
|
|
import { ModelType } from "skinview-utils";
|
2020-01-18 15:54:54 +01:00
|
|
|
import { BoxGeometry, DoubleSide, FrontSide, Group, Mesh, MeshBasicMaterial, Object3D, Texture, Vector2 } from "three";
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-10-09 10:45:08 +02:00
|
|
|
function setUVs(box: BoxGeometry, u: number, v: number, width: number, height: number, depth: number, textureWidth: number, textureHeight: number): void {
|
|
|
|
|
const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [
|
|
|
|
|
new Vector2(x1 / textureWidth, 1.0 - y2 / textureHeight),
|
|
|
|
|
new Vector2(x2 / textureWidth, 1.0 - y2 / textureHeight),
|
|
|
|
|
new Vector2(x2 / textureWidth, 1.0 - y1 / textureHeight),
|
|
|
|
|
new Vector2(x1 / textureWidth, 1.0 - y1 / textureHeight)
|
2017-10-01 14:00:45 +02:00
|
|
|
];
|
|
|
|
|
|
2020-10-09 10:45:08 +02:00
|
|
|
const top = toFaceVertices(u + depth, v, u + width + depth, v + depth);
|
|
|
|
|
const bottom = toFaceVertices(u + width + depth, v, u + width * 2 + depth, v + depth);
|
|
|
|
|
const left = toFaceVertices(u, v + depth, u + depth, v + depth + height);
|
|
|
|
|
const front = toFaceVertices(u + depth, v + depth, u + width + depth, v + depth + height);
|
|
|
|
|
const right = toFaceVertices(u + width + depth, v + depth, u + width + depth * 2, v + height + depth);
|
|
|
|
|
const back = toFaceVertices(u + width + depth * 2, v + depth, u + width * 2 + depth * 2, v + height + depth);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-10-09 16:23:28 +02:00
|
|
|
box.faceVertexUvs[0] = [
|
|
|
|
|
[right[3], right[0], right[2]],
|
|
|
|
|
[right[0], right[1], right[2]],
|
|
|
|
|
[left[3], left[0], left[2]],
|
|
|
|
|
[left[0], left[1], left[2]],
|
|
|
|
|
[top[3], top[0], top[2]],
|
|
|
|
|
[top[0], top[1], top[2]],
|
|
|
|
|
[bottom[0], bottom[3], bottom[1]],
|
|
|
|
|
[bottom[3], bottom[2], bottom[1]],
|
|
|
|
|
[front[3], front[0], front[2]],
|
|
|
|
|
[front[0], front[1], front[2]],
|
|
|
|
|
[back[3], back[0], back[2]],
|
|
|
|
|
[back[0], back[1], back[2]]
|
|
|
|
|
];
|
2017-10-01 14:00:45 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-09 10:45:08 +02:00
|
|
|
function setSkinUVs(box: BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void {
|
|
|
|
|
setUVs(box, u, v, width, height, depth, 64, 64);
|
2020-06-08 22:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-09 10:45:08 +02:00
|
|
|
function setCapeUVs(box: BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void {
|
|
|
|
|
setUVs(box, u, v, width, height, depth, 64, 32);
|
2020-04-26 01:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 18:52:27 +01:00
|
|
|
function setEarUVs(box: BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void {
|
|
|
|
|
setUVs(box, u, v, width, height, depth, 14, 7)
|
2017-10-01 14:00:45 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-20 09:32:56 +02:00
|
|
|
/**
|
|
|
|
|
* Notice that innerLayer and outerLayer may NOT be the direct children of the Group.
|
|
|
|
|
*/
|
2020-01-01 10:18:06 +01:00
|
|
|
export class BodyPart extends Group {
|
2018-10-20 16:28:58 +02:00
|
|
|
constructor(
|
2020-01-01 10:18:06 +01:00
|
|
|
readonly innerLayer: Object3D,
|
|
|
|
|
readonly outerLayer: Object3D
|
2018-10-20 16:28:58 +02:00
|
|
|
) {
|
2018-10-20 09:32:56 +02:00
|
|
|
super();
|
2019-04-20 16:08:49 +02:00
|
|
|
innerLayer.name = "inner";
|
|
|
|
|
outerLayer.name = "outer";
|
2018-10-20 09:32:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
export class SkinObject extends Group {
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2018-07-21 05:07:52 +02:00
|
|
|
// body parts
|
2018-10-20 09:32:56 +02:00
|
|
|
readonly head: BodyPart;
|
|
|
|
|
readonly body: BodyPart;
|
|
|
|
|
readonly rightArm: BodyPart;
|
|
|
|
|
readonly leftArm: BodyPart;
|
|
|
|
|
readonly rightLeg: BodyPart;
|
|
|
|
|
readonly leftLeg: BodyPart;
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2018-08-16 13:23:49 +02:00
|
|
|
private modelListeners: Array<() => void> = []; // called when model(slim property) is changed
|
2020-01-26 20:39:29 +01:00
|
|
|
private slim = false;
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2020-01-18 15:54:54 +01:00
|
|
|
constructor(texture: Texture) {
|
2017-10-01 14:00:45 +02:00
|
|
|
super();
|
|
|
|
|
|
2020-08-31 01:38:19 +02:00
|
|
|
const layer1Material = new MeshBasicMaterial({
|
2020-01-30 15:44:25 +01:00
|
|
|
map: texture,
|
|
|
|
|
side: FrontSide
|
2020-08-31 01:38:19 +02:00
|
|
|
});
|
|
|
|
|
const layer2Material = new MeshBasicMaterial({
|
2020-01-30 15:44:25 +01:00
|
|
|
map: texture,
|
|
|
|
|
side: DoubleSide,
|
|
|
|
|
transparent: true,
|
2020-08-18 09:37:02 +02:00
|
|
|
alphaTest: 1e-5
|
2020-08-31 01:38:19 +02:00
|
|
|
});
|
2020-01-30 15:44:25 +01:00
|
|
|
|
2020-09-05 06:09:03 +02:00
|
|
|
const layer1MaterialBiased = layer1Material.clone();
|
|
|
|
|
layer1MaterialBiased.polygonOffset = true;
|
|
|
|
|
layer1MaterialBiased.polygonOffsetFactor = 1.0;
|
|
|
|
|
layer1MaterialBiased.polygonOffsetUnits = 1.0;
|
|
|
|
|
|
2020-08-31 01:38:19 +02:00
|
|
|
const layer2MaterialBiased = layer2Material.clone();
|
|
|
|
|
layer2MaterialBiased.polygonOffset = true;
|
|
|
|
|
layer2MaterialBiased.polygonOffsetFactor = 1.0;
|
|
|
|
|
layer2MaterialBiased.polygonOffsetUnits = 1.0;
|
2020-01-18 15:54:54 +01:00
|
|
|
|
2017-10-01 14:00:45 +02:00
|
|
|
// Head
|
2020-08-31 01:56:13 +02:00
|
|
|
const headBox = new BoxGeometry(8, 8, 8);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(headBox, 0, 0, 8, 8, 8);
|
2020-01-01 10:18:06 +01:00
|
|
|
const headMesh = new Mesh(headBox, layer1Material);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-08-31 01:56:13 +02:00
|
|
|
const head2Box = new BoxGeometry(9, 9, 9);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(head2Box, 32, 0, 8, 8, 8);
|
2020-01-01 10:18:06 +01:00
|
|
|
const head2Mesh = new Mesh(head2Box, layer2Material);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2018-10-20 09:32:56 +02:00
|
|
|
this.head = new BodyPart(headMesh, head2Mesh);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.head.name = "head";
|
2018-10-20 09:32:56 +02:00
|
|
|
this.head.add(headMesh, head2Mesh);
|
2020-10-03 16:59:59 +02:00
|
|
|
this.head.position.y = 4;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.head);
|
|
|
|
|
|
|
|
|
|
// Body
|
2020-08-31 01:56:13 +02:00
|
|
|
const bodyBox = new BoxGeometry(8, 12, 4);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(bodyBox, 16, 16, 8, 12, 4);
|
2020-08-31 01:38:19 +02:00
|
|
|
const bodyMesh = new Mesh(bodyBox, layer1Material);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-10-03 14:42:22 +02:00
|
|
|
const body2Box = new BoxGeometry(8.5, 12.5, 4.5);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(body2Box, 16, 32, 8, 12, 4);
|
2020-08-31 01:38:19 +02:00
|
|
|
const body2Mesh = new Mesh(body2Box, layer2Material);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2018-10-20 09:32:56 +02:00
|
|
|
this.body = new BodyPart(bodyMesh, body2Mesh);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.body.name = "body";
|
2018-10-20 09:32:56 +02:00
|
|
|
this.body.add(bodyMesh, body2Mesh);
|
2020-10-03 16:59:59 +02:00
|
|
|
this.body.position.y = -6;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.body);
|
|
|
|
|
|
|
|
|
|
// Right Arm
|
2020-08-31 01:56:13 +02:00
|
|
|
const rightArmBox = new BoxGeometry();
|
2020-10-10 13:26:25 +02:00
|
|
|
const rightArmMesh = new Mesh(rightArmBox, layer1MaterialBiased);
|
2018-07-02 09:46:48 +02:00
|
|
|
this.modelListeners.push(() => {
|
2020-01-30 15:44:25 +01:00
|
|
|
rightArmMesh.scale.x = this.slim ? 3 : 4;
|
|
|
|
|
rightArmMesh.scale.y = 12;
|
|
|
|
|
rightArmMesh.scale.z = 4;
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(rightArmBox, 40, 16, this.slim ? 3 : 4, 12, 4);
|
2018-07-02 09:46:48 +02:00
|
|
|
rightArmBox.uvsNeedUpdate = true;
|
|
|
|
|
rightArmBox.elementsNeedUpdate = true;
|
|
|
|
|
});
|
|
|
|
|
|
2020-08-31 01:56:13 +02:00
|
|
|
const rightArm2Box = new BoxGeometry();
|
2020-08-31 01:38:19 +02:00
|
|
|
const rightArm2Mesh = new Mesh(rightArm2Box, layer2MaterialBiased);
|
2018-07-02 09:46:48 +02:00
|
|
|
this.modelListeners.push(() => {
|
2020-10-03 14:42:22 +02:00
|
|
|
rightArm2Mesh.scale.x = this.slim ? 3.5 : 4.5;
|
|
|
|
|
rightArm2Mesh.scale.y = 12.5;
|
2020-01-30 15:44:25 +01:00
|
|
|
rightArm2Mesh.scale.z = 4.5;
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(rightArm2Box, 40, 32, this.slim ? 3 : 4, 12, 4);
|
2018-07-02 09:46:48 +02:00
|
|
|
rightArm2Box.uvsNeedUpdate = true;
|
|
|
|
|
rightArm2Box.elementsNeedUpdate = true;
|
|
|
|
|
});
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
const rightArmPivot = new Group();
|
2018-10-20 09:32:56 +02:00
|
|
|
rightArmPivot.add(rightArmMesh, rightArm2Mesh);
|
2020-10-03 18:43:21 +02:00
|
|
|
this.modelListeners.push(() => {
|
|
|
|
|
rightArmPivot.position.x = this.slim ? -.5 : -1;
|
|
|
|
|
});
|
2020-05-24 06:05:53 +02:00
|
|
|
rightArmPivot.position.y = -4;
|
2018-10-20 09:32:56 +02:00
|
|
|
|
|
|
|
|
this.rightArm = new BodyPart(rightArmMesh, rightArm2Mesh);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.rightArm.name = "rightArm";
|
2017-10-01 14:00:45 +02:00
|
|
|
this.rightArm.add(rightArmPivot);
|
2020-10-03 18:43:21 +02:00
|
|
|
this.rightArm.position.x = -5;
|
2020-10-03 16:59:59 +02:00
|
|
|
this.rightArm.position.y = -2;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.rightArm);
|
|
|
|
|
|
|
|
|
|
// Left Arm
|
2020-08-31 01:56:13 +02:00
|
|
|
const leftArmBox = new BoxGeometry();
|
2020-10-10 13:26:25 +02:00
|
|
|
const leftArmMesh = new Mesh(leftArmBox, layer1MaterialBiased);
|
2018-07-02 09:46:48 +02:00
|
|
|
this.modelListeners.push(() => {
|
2020-01-30 15:44:25 +01:00
|
|
|
leftArmMesh.scale.x = this.slim ? 3 : 4;
|
|
|
|
|
leftArmMesh.scale.y = 12;
|
|
|
|
|
leftArmMesh.scale.z = 4;
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(leftArmBox, 32, 48, this.slim ? 3 : 4, 12, 4);
|
2018-07-02 09:46:48 +02:00
|
|
|
leftArmBox.uvsNeedUpdate = true;
|
2018-07-17 20:49:00 +02:00
|
|
|
leftArmBox.elementsNeedUpdate = true;
|
2018-07-02 09:46:48 +02:00
|
|
|
});
|
|
|
|
|
|
2020-08-31 01:56:13 +02:00
|
|
|
const leftArm2Box = new BoxGeometry();
|
2020-08-31 01:38:19 +02:00
|
|
|
const leftArm2Mesh = new Mesh(leftArm2Box, layer2MaterialBiased);
|
2018-07-02 09:46:48 +02:00
|
|
|
this.modelListeners.push(() => {
|
2020-10-03 14:42:22 +02:00
|
|
|
leftArm2Mesh.scale.x = this.slim ? 3.5 : 4.5;
|
|
|
|
|
leftArm2Mesh.scale.y = 12.5;
|
2020-01-30 15:44:25 +01:00
|
|
|
leftArm2Mesh.scale.z = 4.5;
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(leftArm2Box, 48, 48, this.slim ? 3 : 4, 12, 4);
|
2018-07-02 09:46:48 +02:00
|
|
|
leftArm2Box.uvsNeedUpdate = true;
|
|
|
|
|
leftArm2Box.elementsNeedUpdate = true;
|
|
|
|
|
});
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
const leftArmPivot = new Group();
|
2018-10-20 09:32:56 +02:00
|
|
|
leftArmPivot.add(leftArmMesh, leftArm2Mesh);
|
2020-10-03 18:43:21 +02:00
|
|
|
this.modelListeners.push(() => {
|
|
|
|
|
leftArmPivot.position.x = this.slim ? 0.5 : 1;
|
|
|
|
|
});
|
2020-05-24 06:05:53 +02:00
|
|
|
leftArmPivot.position.y = -4;
|
2018-10-20 09:32:56 +02:00
|
|
|
|
|
|
|
|
this.leftArm = new BodyPart(leftArmMesh, leftArm2Mesh);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.leftArm.name = "leftArm";
|
2017-10-01 14:00:45 +02:00
|
|
|
this.leftArm.add(leftArmPivot);
|
2020-10-03 18:43:21 +02:00
|
|
|
this.leftArm.position.x = 5;
|
2020-10-03 16:59:59 +02:00
|
|
|
this.leftArm.position.y = -2;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.leftArm);
|
|
|
|
|
|
|
|
|
|
// Right Leg
|
2020-08-31 01:56:13 +02:00
|
|
|
const rightLegBox = new BoxGeometry(4, 12, 4);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(rightLegBox, 0, 16, 4, 12, 4);
|
2020-09-05 06:09:03 +02:00
|
|
|
const rightLegMesh = new Mesh(rightLegBox, layer1MaterialBiased);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-10-03 14:42:22 +02:00
|
|
|
const rightLeg2Box = new BoxGeometry(4.5, 12.5, 4.5);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(rightLeg2Box, 0, 32, 4, 12, 4);
|
2020-08-31 01:38:19 +02:00
|
|
|
const rightLeg2Mesh = new Mesh(rightLeg2Box, layer2MaterialBiased);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
const rightLegPivot = new Group();
|
2018-10-20 09:32:56 +02:00
|
|
|
rightLegPivot.add(rightLegMesh, rightLeg2Mesh);
|
2017-10-01 14:00:45 +02:00
|
|
|
rightLegPivot.position.y = -6;
|
2018-10-20 09:32:56 +02:00
|
|
|
|
|
|
|
|
this.rightLeg = new BodyPart(rightLegMesh, rightLeg2Mesh);
|
2019-05-02 10:33:13 +02:00
|
|
|
this.rightLeg.name = "rightLeg";
|
2017-10-01 14:00:45 +02:00
|
|
|
this.rightLeg.add(rightLegPivot);
|
2020-10-03 18:43:21 +02:00
|
|
|
this.rightLeg.position.x = -1.9;
|
2020-10-03 16:59:59 +02:00
|
|
|
this.rightLeg.position.y = -12;
|
2020-10-03 18:43:21 +02:00
|
|
|
this.rightLeg.position.z = -.1;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.rightLeg);
|
|
|
|
|
|
|
|
|
|
// Left Leg
|
2020-08-31 01:56:13 +02:00
|
|
|
const leftLegBox = new BoxGeometry(4, 12, 4);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(leftLegBox, 16, 48, 4, 12, 4);
|
2020-09-05 06:09:03 +02:00
|
|
|
const leftLegMesh = new Mesh(leftLegBox, layer1MaterialBiased);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-10-03 14:42:22 +02:00
|
|
|
const leftLeg2Box = new BoxGeometry(4.5, 12.5, 4.5);
|
2020-10-09 10:45:08 +02:00
|
|
|
setSkinUVs(leftLeg2Box, 0, 48, 4, 12, 4);
|
2020-08-31 01:38:19 +02:00
|
|
|
const leftLeg2Mesh = new Mesh(leftLeg2Box, layer2MaterialBiased);
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
const leftLegPivot = new Group();
|
2018-10-20 09:32:56 +02:00
|
|
|
leftLegPivot.add(leftLegMesh, leftLeg2Mesh);
|
2017-10-01 14:00:45 +02:00
|
|
|
leftLegPivot.position.y = -6;
|
2018-10-20 09:32:56 +02:00
|
|
|
|
|
|
|
|
this.leftLeg = new BodyPart(leftLegMesh, leftLeg2Mesh);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.leftLeg.name = "leftLeg";
|
2017-10-01 14:00:45 +02:00
|
|
|
this.leftLeg.add(leftLegPivot);
|
2020-10-03 18:43:21 +02:00
|
|
|
this.leftLeg.position.x = 1.9;
|
2020-10-03 16:59:59 +02:00
|
|
|
this.leftLeg.position.y = -12;
|
2020-10-03 18:43:21 +02:00
|
|
|
this.leftLeg.position.z = -.1;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.leftLeg);
|
2018-07-02 09:46:48 +02:00
|
|
|
|
2020-01-26 20:39:29 +01:00
|
|
|
this.modelType = "default";
|
2018-07-02 09:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-26 20:39:29 +01:00
|
|
|
get modelType(): ModelType {
|
|
|
|
|
return this.slim ? "slim" : "default";
|
2018-07-21 05:07:52 +02:00
|
|
|
}
|
2018-07-02 09:46:48 +02:00
|
|
|
|
2020-01-26 20:39:29 +01:00
|
|
|
set modelType(value: ModelType) {
|
|
|
|
|
this.slim = value === "slim";
|
2018-07-21 05:41:12 +02:00
|
|
|
this.modelListeners.forEach(listener => listener());
|
2018-07-21 05:07:52 +02:00
|
|
|
}
|
2018-10-20 09:32:56 +02:00
|
|
|
|
2020-02-01 12:13:46 +01:00
|
|
|
private getBodyParts(): Array<BodyPart> {
|
2018-10-20 09:40:52 +02:00
|
|
|
return this.children.filter(it => it instanceof BodyPart) as Array<BodyPart>;
|
2018-10-20 09:32:56 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-01 12:13:46 +01:00
|
|
|
setInnerLayerVisible(value: boolean): void {
|
2018-10-20 09:32:56 +02:00
|
|
|
this.getBodyParts().forEach(part => part.innerLayer.visible = value);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-01 12:13:46 +01:00
|
|
|
setOuterLayerVisible(value: boolean): void {
|
2018-10-20 09:32:56 +02:00
|
|
|
this.getBodyParts().forEach(part => part.outerLayer.visible = value);
|
|
|
|
|
}
|
2017-10-02 15:29:41 +02:00
|
|
|
}
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
export class CapeObject extends Group {
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
readonly cape: Mesh;
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2020-01-18 15:54:54 +01:00
|
|
|
constructor(texture: Texture) {
|
2017-10-01 14:00:45 +02:00
|
|
|
super();
|
|
|
|
|
|
2020-08-18 09:37:02 +02:00
|
|
|
const capeMaterial = new MeshBasicMaterial({
|
|
|
|
|
map: texture,
|
|
|
|
|
side: DoubleSide,
|
|
|
|
|
transparent: true,
|
|
|
|
|
alphaTest: 1e-5
|
|
|
|
|
});
|
2020-01-18 15:54:54 +01:00
|
|
|
|
2020-10-09 10:12:13 +02:00
|
|
|
// +z (front) - inside of cape
|
|
|
|
|
// -z (back) - outside of cape
|
2020-08-31 01:56:13 +02:00
|
|
|
const capeBox = new BoxGeometry(10, 16, 1);
|
2020-10-09 10:45:08 +02:00
|
|
|
setCapeUVs(capeBox, 0, 0, 10, 16, 1);
|
2020-01-01 10:18:06 +01:00
|
|
|
this.cape = new Mesh(capeBox, capeMaterial);
|
2017-10-01 14:00:45 +02:00
|
|
|
this.cape.position.y = -8;
|
2020-10-09 10:12:13 +02:00
|
|
|
this.cape.position.z = .5;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.cape);
|
|
|
|
|
}
|
2017-10-02 15:29:41 +02:00
|
|
|
}
|
2017-10-01 14:00:45 +02:00
|
|
|
|
2020-06-08 22:32:54 +02:00
|
|
|
export class ElytraObject extends Group {
|
|
|
|
|
|
|
|
|
|
readonly leftWing: Group;
|
|
|
|
|
readonly rightWing: Group;
|
|
|
|
|
|
|
|
|
|
constructor(texture: Texture) {
|
|
|
|
|
super();
|
|
|
|
|
|
2020-09-11 01:11:31 +02:00
|
|
|
const elytraMaterial = new MeshBasicMaterial({
|
|
|
|
|
map: texture,
|
|
|
|
|
side: DoubleSide,
|
|
|
|
|
transparent: true,
|
2018-09-22 17:37:23 +02:00
|
|
|
alphaTest: 1e-5
|
2020-06-08 22:32:54 +02:00
|
|
|
});
|
|
|
|
|
|
2018-09-22 17:37:23 +02:00
|
|
|
const leftWingBox = new BoxGeometry(12, 22, 4);
|
|
|
|
|
setCapeUVs(leftWingBox, 22, 0, 10, 20, 2);
|
2020-06-08 22:32:54 +02:00
|
|
|
const leftWingMesh = new Mesh(leftWingBox, elytraMaterial);
|
|
|
|
|
leftWingMesh.position.x = -5;
|
|
|
|
|
leftWingMesh.position.y = -10;
|
|
|
|
|
leftWingMesh.position.z = -1;
|
|
|
|
|
this.leftWing = new Group();
|
|
|
|
|
this.leftWing.add(leftWingMesh);
|
|
|
|
|
this.add(this.leftWing);
|
|
|
|
|
|
2018-09-22 17:37:23 +02:00
|
|
|
const rightWingBox = new BoxGeometry(12, 22, 4);
|
|
|
|
|
setCapeUVs(rightWingBox, 22, 0, 10, 20, 2);
|
2020-06-08 22:32:54 +02:00
|
|
|
const rightWingMesh = new Mesh(rightWingBox, elytraMaterial);
|
2018-09-22 17:37:23 +02:00
|
|
|
rightWingMesh.scale.x = -1;
|
2020-06-08 22:32:54 +02:00
|
|
|
rightWingMesh.position.x = 5;
|
|
|
|
|
rightWingMesh.position.y = -10;
|
|
|
|
|
rightWingMesh.position.z = -1;
|
|
|
|
|
this.rightWing = new Group();
|
|
|
|
|
this.rightWing.add(rightWingMesh);
|
|
|
|
|
this.add(this.rightWing);
|
2018-09-22 17:37:23 +02:00
|
|
|
|
|
|
|
|
this.leftWing.position.x = 5;
|
|
|
|
|
this.leftWing.rotation.x = .2617994;
|
|
|
|
|
this.leftWing.rotation.y = .01; // to avoid z-fighting
|
|
|
|
|
this.leftWing.rotation.z = .2617994;
|
|
|
|
|
this.updateRightWing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Mirrors the position & rotation of left wing,
|
|
|
|
|
* and apply them to the right wing.
|
|
|
|
|
*/
|
|
|
|
|
updateRightWing(): void {
|
|
|
|
|
this.rightWing.position.x = -this.leftWing.position.x;
|
|
|
|
|
this.rightWing.position.y = this.leftWing.position.y;
|
|
|
|
|
this.rightWing.rotation.x = this.leftWing.rotation.x;
|
|
|
|
|
this.rightWing.rotation.y = -this.leftWing.rotation.y;
|
|
|
|
|
this.rightWing.rotation.z = -this.leftWing.rotation.z;
|
2020-06-08 22:32:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-26 01:00:10 +02:00
|
|
|
export class EarsObject extends Group {
|
|
|
|
|
|
|
|
|
|
readonly leftEar: Mesh;
|
|
|
|
|
readonly rightEar: Mesh;
|
|
|
|
|
|
|
|
|
|
constructor(texture: Texture) {
|
|
|
|
|
super();
|
|
|
|
|
|
2020-09-11 00:59:12 +02:00
|
|
|
const earMaterial = new MeshBasicMaterial({
|
|
|
|
|
map: texture,
|
|
|
|
|
side: DoubleSide,
|
|
|
|
|
transparent: true,
|
|
|
|
|
alphaTest: 1e-5
|
|
|
|
|
});
|
2020-04-26 01:00:10 +02:00
|
|
|
|
|
|
|
|
// back = outside
|
|
|
|
|
// front = inside
|
2020-09-11 00:59:12 +02:00
|
|
|
const earBox = new BoxGeometry(6, 6, 1);
|
2020-04-26 01:00:10 +02:00
|
|
|
//x1: number, y1: number, x2: number, y2: number
|
|
|
|
|
setVertices(earBox,
|
|
|
|
|
//from look at back
|
|
|
|
|
toEarVertices(1, 0, 7, 1), //top
|
|
|
|
|
toEarVertices(7, 0, 13, 1), //bottom
|
|
|
|
|
toEarVertices(0, 1, 1, 7), //right
|
|
|
|
|
toEarVertices(1, 1, 7, 7), //front
|
|
|
|
|
toEarVertices(0, 1, 1, 7), //left
|
|
|
|
|
toEarVertices(8, 1, 14, 7) //back
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this.leftEar = new Mesh(earBox, earMaterial);
|
|
|
|
|
this.leftEar.position.x = -5.5;
|
2020-06-08 22:32:54 +02:00
|
|
|
this.leftEar.scale.x = 1.3;
|
|
|
|
|
this.leftEar.scale.y = 1.3;
|
|
|
|
|
this.leftEar.scale.z = 1.3;
|
2020-04-26 01:00:10 +02:00
|
|
|
this.add(this.leftEar);
|
|
|
|
|
|
|
|
|
|
this.rightEar = new Mesh(earBox, earMaterial);
|
|
|
|
|
this.rightEar.position.x = 5.5;
|
2020-06-08 22:32:54 +02:00
|
|
|
this.rightEar.scale.x = 1.3;
|
|
|
|
|
this.rightEar.scale.y = 1.3;
|
|
|
|
|
this.rightEar.scale.z = 1.3;
|
2020-04-26 01:00:10 +02:00
|
|
|
this.add(this.rightEar);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-10 04:22:17 +02:00
|
|
|
export type BackEquipment = "cape" | "elytra";
|
|
|
|
|
|
2020-01-01 10:18:06 +01:00
|
|
|
export class PlayerObject extends Group {
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2018-08-17 06:56:13 +02:00
|
|
|
readonly skin: SkinObject;
|
|
|
|
|
readonly cape: CapeObject;
|
2020-06-08 22:32:54 +02:00
|
|
|
readonly elytra: ElytraObject;
|
2020-04-26 01:00:10 +02:00
|
|
|
readonly ears: EarsObject
|
2018-07-17 20:49:00 +02:00
|
|
|
|
2020-04-26 01:00:10 +02:00
|
|
|
constructor(skinTexture: Texture, capeTexture: Texture, earTexture: Texture) {
|
2017-10-01 14:00:45 +02:00
|
|
|
super();
|
|
|
|
|
|
2020-01-18 15:54:54 +01:00
|
|
|
this.skin = new SkinObject(skinTexture);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.skin.name = "skin";
|
2020-04-26 01:19:59 +02:00
|
|
|
this.skin.position.y = -2
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.skin);
|
|
|
|
|
|
2020-01-18 15:54:54 +01:00
|
|
|
this.cape = new CapeObject(capeTexture);
|
2019-04-20 16:08:49 +02:00
|
|
|
this.cape.name = "cape";
|
2017-10-01 14:00:45 +02:00
|
|
|
this.cape.position.z = -2;
|
2020-09-16 11:29:23 +02:00
|
|
|
this.cape.rotation.x = 10.8 * Math.PI / 180;
|
2020-10-09 10:12:13 +02:00
|
|
|
this.cape.rotation.y = Math.PI;
|
2017-10-01 14:00:45 +02:00
|
|
|
this.add(this.cape);
|
2020-04-26 01:00:10 +02:00
|
|
|
|
2020-06-08 22:32:54 +02:00
|
|
|
this.elytra = new ElytraObject(capeTexture);
|
2020-07-12 18:52:08 +02:00
|
|
|
this.elytra.name = "elytra";
|
2020-06-08 22:32:54 +02:00
|
|
|
this.elytra.position.z = -2;
|
|
|
|
|
this.elytra.visible = false;
|
|
|
|
|
this.add(this.elytra);
|
|
|
|
|
|
2020-04-26 01:00:10 +02:00
|
|
|
this.ears = new EarsObject(earTexture);
|
|
|
|
|
this.ears.name = "ears";
|
2020-04-26 01:19:59 +02:00
|
|
|
this.ears.position.y = 3.5;
|
2020-04-26 01:00:10 +02:00
|
|
|
this.add(this.ears);
|
2017-10-01 14:00:45 +02:00
|
|
|
}
|
2020-10-10 04:22:17 +02:00
|
|
|
|
|
|
|
|
get backEquipment(): BackEquipment | null {
|
|
|
|
|
if (this.cape.visible) {
|
|
|
|
|
return "cape";
|
|
|
|
|
} else if (this.elytra.visible) {
|
|
|
|
|
return "elytra";
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set backEquipment(value: BackEquipment | null) {
|
|
|
|
|
this.cape.visible = value === "cape";
|
|
|
|
|
this.elytra.visible = value === "elytra";
|
|
|
|
|
}
|
2017-10-02 15:29:41 +02:00
|
|
|
}
|