implement first person item in hand rendering
(cherry picked from commit 647b7dc98e1fa80c5ba72a560b03cf447fc65bd4)
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 217 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 212 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 168 KiB |
@@ -36,6 +36,8 @@ Click [here](https://labystudio.github.io/js-minecraft/) for a demo!
|
|||||||
- Underwater fog
|
- Underwater fog
|
||||||
- Dynamic FOV
|
- Dynamic FOV
|
||||||
- Third person
|
- Third person
|
||||||
|
- First person hand
|
||||||
|
- First person item in hand
|
||||||
- GUI
|
- GUI
|
||||||
- Screens
|
- Screens
|
||||||
- Loading Screen
|
- Loading Screen
|
||||||
|
|||||||
@@ -287,6 +287,9 @@ export default class Minecraft {
|
|||||||
// Place block
|
// Place block
|
||||||
this.world.setBlockAt(x, y, z, typeId);
|
this.world.setBlockAt(x, y, z, typeId);
|
||||||
|
|
||||||
|
// Swing player arm
|
||||||
|
this.player.swingArm();
|
||||||
|
|
||||||
// Handle block abilities
|
// Handle block abilities
|
||||||
let block = Block.getById(typeId);
|
let block = Block.getById(typeId);
|
||||||
block.onBlockPlaced(this.world, x, y, z, hitResult.face);
|
block.onBlockPlaced(this.world, x, y, z, hitResult.face);
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ export default class GuiControls extends GuiScreen {
|
|||||||
let settings = this.minecraft.settings;
|
let settings = this.minecraft.settings;
|
||||||
|
|
||||||
let scope = this;
|
let scope = this;
|
||||||
this.buttonList.push(new GuiKeyButton("Crouch", settings.crouching, this.width / 2 - 100, this.height / 2 - 20, 200, 20, function (key) {
|
this.buttonList.push(new GuiKeyButton("Crouch", settings.crouching, this.width / 2 - 100, this.height / 2 - 30, 200, 20, function (key) {
|
||||||
settings.crouching = key;
|
settings.crouching = key;
|
||||||
scope.init();
|
scope.init();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.buttonList.push(new GuiKeyButton("Sprint", settings.sprinting, this.width / 2 - 100, this.height / 2 + 5, 200, 20, function (key) {
|
this.buttonList.push(new GuiKeyButton("Sprint", settings.sprinting, this.width / 2 - 100, this.height / 2 - 5, 200, 20, function (key) {
|
||||||
settings.sprinting = key;
|
settings.sprinting = key;
|
||||||
scope.init();
|
scope.init();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.buttonList.push(new GuiKeyButton("Toggle Perspective", settings.togglePerspective, this.width / 2 - 100, this.height / 2 + 30, 200, 20, function (key) {
|
this.buttonList.push(new GuiKeyButton("Toggle Perspective", settings.togglePerspective, this.width / 2 - 100, this.height / 2 + 20, 200, 20, function (key) {
|
||||||
settings.togglePerspective = key;
|
settings.togglePerspective = key;
|
||||||
scope.init();
|
scope.init();
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -287,6 +287,25 @@ export default class BlockRenderer {
|
|||||||
mesh.scale.z = 6;
|
mesh.scale.z = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderBlockInFirstPerson(group, block, brightness) {
|
||||||
|
this.tessellator.startDrawing();
|
||||||
|
|
||||||
|
// Render block
|
||||||
|
this.renderBlock(null, block, 0, 0, 0);
|
||||||
|
|
||||||
|
// Change brightness
|
||||||
|
this.tessellator.transformBrightness(brightness);
|
||||||
|
|
||||||
|
// Create mesh
|
||||||
|
let mesh = this.tessellator.draw(group);
|
||||||
|
mesh.geometry.center();
|
||||||
|
|
||||||
|
// Scale
|
||||||
|
mesh.scale.x = 16;
|
||||||
|
mesh.scale.y = 16;
|
||||||
|
mesh.scale.z = 16;
|
||||||
|
}
|
||||||
|
|
||||||
renderGuiBlock(group, block, x, y, size, brightness) {
|
renderGuiBlock(group, block, x, y, size, brightness) {
|
||||||
this.tessellator.startDrawing();
|
this.tessellator.startDrawing();
|
||||||
|
|
||||||
|
|||||||
@@ -347,11 +347,15 @@ export default class WorldRenderer {
|
|||||||
renderHand(partialTicks) {
|
renderHand(partialTicks) {
|
||||||
// Hide hand before rendering
|
// Hide hand before rendering
|
||||||
let player = this.minecraft.player;
|
let player = this.minecraft.player;
|
||||||
let stack = player.renderer.handGroup;
|
let stack = player.renderer.firstPersonGroup;
|
||||||
stack.visible = false;
|
stack.visible = false;
|
||||||
|
|
||||||
|
let firstPerson = this.minecraft.settings.thirdPersonView === 0;
|
||||||
|
let itemId = firstPerson ? this.itemToRender : player.inventory.getItemInSelectedSlot();
|
||||||
|
let hasItem = itemId !== 0;
|
||||||
|
|
||||||
// Hide in third person
|
// Hide in third person
|
||||||
if (this.minecraft.settings.thirdPersonView !== 0) {
|
if (!firstPerson) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,14 +373,6 @@ export default class WorldRenderer {
|
|||||||
let pitchArm = player.prevRenderArmPitch + (player.renderArmPitch - player.prevRenderArmPitch) * partialTicks;
|
let pitchArm = player.prevRenderArmPitch + (player.renderArmPitch - player.prevRenderArmPitch) * partialTicks;
|
||||||
let yawArm = player.prevRenderArmYaw + (player.renderArmYaw - player.prevRenderArmYaw) * partialTicks;
|
let yawArm = player.prevRenderArmYaw + (player.renderArmYaw - player.prevRenderArmYaw) * partialTicks;
|
||||||
|
|
||||||
let factor = 0.8;
|
|
||||||
let zOffset = Math.sin(swingProgress * Math.PI);
|
|
||||||
let yOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI * 2.0);
|
|
||||||
let xOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI);
|
|
||||||
|
|
||||||
let yRotation = Math.sin(Math.sqrt(swingProgress) * Math.PI);
|
|
||||||
let zRotation = Math.sin(swingProgress * swingProgress * Math.PI);
|
|
||||||
|
|
||||||
// Bobbing animation
|
// Bobbing animation
|
||||||
if (this.minecraft.settings.viewBobbing) {
|
if (this.minecraft.settings.viewBobbing) {
|
||||||
let walked = -(player.prevDistanceWalked + (player.distanceWalked - player.prevDistanceWalked) * partialTicks);
|
let walked = -(player.prevDistanceWalked + (player.distanceWalked - player.prevDistanceWalked) * partialTicks);
|
||||||
@@ -393,31 +389,55 @@ export default class WorldRenderer {
|
|||||||
stack.rotateX(MathHelper.toRadians(pitch));
|
stack.rotateX(MathHelper.toRadians(pitch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let factor = 0.8;
|
||||||
|
let zOffset = Math.sin(swingProgress * Math.PI);
|
||||||
|
let yOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI * 2.0);
|
||||||
|
let xOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI);
|
||||||
|
|
||||||
|
let sqrtRotation = Math.sin(Math.sqrt(swingProgress) * Math.PI);
|
||||||
|
let powRotation = Math.sin(swingProgress * swingProgress * Math.PI);
|
||||||
|
|
||||||
// Camera rotation movement
|
// Camera rotation movement
|
||||||
stack.rotateX(MathHelper.toRadians((player.rotationPitch - pitchArm) * 0.1));
|
stack.rotateX(MathHelper.toRadians((player.rotationPitch - pitchArm) * 0.1));
|
||||||
stack.rotateY(MathHelper.toRadians((player.rotationYaw - yawArm) * 0.1));
|
stack.rotateY(MathHelper.toRadians((player.rotationYaw - yawArm) * 0.1));
|
||||||
|
|
||||||
// Initial offset on screen
|
if(hasItem) {
|
||||||
this.translate(stack, -xOffset * 0.3, yOffset * 0.4, -zOffset * 0.4);
|
// Initial offset on screen
|
||||||
this.translate(stack, 0.8 * factor, -0.75 * factor - (1.0 - equipProgress) * 0.6, -0.9 * factor);
|
this.translate(stack, -xOffset * 0.4, yOffset * 0.2, -zOffset * 0.2);
|
||||||
|
this.translate(stack, 0.7 * factor, -0.65 * factor - (1.0 - equipProgress) * 0.6, -0.9 * factor);
|
||||||
|
|
||||||
// Rotation of hand
|
// Rotation of hand
|
||||||
stack.rotateY(MathHelper.toRadians(45));
|
stack.rotateY(MathHelper.toRadians(45));
|
||||||
stack.rotateY(MathHelper.toRadians(yRotation * 70));
|
stack.rotateY(MathHelper.toRadians(-powRotation * 20));
|
||||||
stack.rotateZ(MathHelper.toRadians(-zRotation * 20));
|
stack.rotateZ(MathHelper.toRadians(-sqrtRotation * 20));
|
||||||
|
stack.rotateX(MathHelper.toRadians(-sqrtRotation * 80));
|
||||||
|
|
||||||
// Post transform
|
// Scale down
|
||||||
this.translate(stack, -1, 3.6, 3.5);
|
stack.scale.x *= 0.4;
|
||||||
stack.rotateZ(MathHelper.toRadians(120));
|
stack.scale.y *= 0.4;
|
||||||
stack.rotateX(MathHelper.toRadians(200));
|
stack.scale.z *= 0.4;
|
||||||
stack.rotateY(MathHelper.toRadians(-135));
|
|
||||||
this.translate(stack, 5.6, 0.0, 0.0);
|
|
||||||
|
|
||||||
if (this.itemToRender === 0) {
|
|
||||||
// Render hand
|
|
||||||
player.renderer.renderRightArm(player, partialTicks);
|
|
||||||
} else {
|
|
||||||
// Render item
|
// Render item
|
||||||
|
player.renderer.updateFirstPerson(player);
|
||||||
|
} else {
|
||||||
|
// Initial offset on screen
|
||||||
|
this.translate(stack, -xOffset * 0.3, yOffset * 0.4, -zOffset * 0.4);
|
||||||
|
this.translate(stack, 0.8 * factor, -0.75 * factor - (1.0 - equipProgress) * 0.6, -0.9 * factor);
|
||||||
|
|
||||||
|
// Rotation of hand
|
||||||
|
stack.rotateY(MathHelper.toRadians(45));
|
||||||
|
stack.rotateY(MathHelper.toRadians(sqrtRotation * 70));
|
||||||
|
stack.rotateZ(MathHelper.toRadians(-powRotation * 20));
|
||||||
|
|
||||||
|
// Post transform
|
||||||
|
this.translate(stack, -1, 3.6, 3.5);
|
||||||
|
stack.rotateZ(MathHelper.toRadians(120));
|
||||||
|
stack.rotateX(MathHelper.toRadians(200));
|
||||||
|
stack.rotateY(MathHelper.toRadians(-135));
|
||||||
|
this.translate(stack, 5.6, 0.0, 0.0);
|
||||||
|
|
||||||
|
// Render hand
|
||||||
|
player.renderer.renderRightHand(player, partialTicks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ export default class EntityRenderer {
|
|||||||
|
|
||||||
fillMeta(entity, meta) {
|
fillMeta(entity, meta) {
|
||||||
meta.brightness = entity.getEntityBrightness();
|
meta.brightness = entity.getEntityBrightness();
|
||||||
meta.itemInHand = entity.inventory.getItemInSelectedSlot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isRebuildRequired(entity) {
|
isRebuildRequired(entity) {
|
||||||
|
|||||||
@@ -16,33 +16,52 @@ export default class PlayerRenderer extends EntityRenderer {
|
|||||||
|
|
||||||
// First person right-hand holder
|
// First person right-hand holder
|
||||||
this.handModel = null;
|
this.handModel = null;
|
||||||
this.handGroup = new THREE.Object3D();
|
this.firstPersonGroup = new THREE.Object3D();
|
||||||
this.worldRenderer.overlay.add(this.handGroup);
|
this.worldRenderer.overlay.add(this.firstPersonGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuild(entity) {
|
rebuild(entity) {
|
||||||
this.tessellator.bindTexture(this.textureCharacter);
|
let firstPerson = this.worldRenderer.minecraft.settings.thirdPersonView === 0;
|
||||||
super.rebuild(entity);
|
let itemId = firstPerson ? this.worldRenderer.itemToRender : entity.inventory.getItemInSelectedSlot();
|
||||||
|
let hasItem = itemId !== 0;
|
||||||
|
|
||||||
// Render item in hand
|
if (firstPerson && hasItem) {
|
||||||
let group = this.model.rightArm.bone;
|
super.rebuild(entity);
|
||||||
let id = entity.inventory.getItemInSelectedSlot();
|
|
||||||
if (id !== 0 && this.worldRenderer.minecraft.settings.thirdPersonView !== 0) {
|
// Create new item group and add it to the hand
|
||||||
let block = Block.getById(id);
|
this.firstPersonGroup.clear();
|
||||||
this.worldRenderer.blockRenderer.renderBlockInHandThirdPerson(group, block, entity.getEntityBrightness());
|
let itemGroup = new THREE.Object3D();
|
||||||
|
this.firstPersonGroup.add(itemGroup);
|
||||||
|
|
||||||
|
// Render item in hand in first person
|
||||||
|
let block = Block.getById(itemId);
|
||||||
|
this.worldRenderer.blockRenderer.renderBlockInFirstPerson(itemGroup, block, entity.getEntityBrightness());
|
||||||
|
|
||||||
|
// Copy material and update depth test of the item to render it always in front
|
||||||
|
let mesh = itemGroup.children[0];
|
||||||
|
mesh.material = mesh.material.clone();
|
||||||
|
mesh.material.depthTest = false;
|
||||||
|
} else {
|
||||||
|
this.tessellator.bindTexture(this.textureCharacter);
|
||||||
|
super.rebuild(entity);
|
||||||
|
|
||||||
|
// Render item in hand in third person
|
||||||
|
if (hasItem) {
|
||||||
|
let block = Block.getById(itemId);
|
||||||
|
let group = this.model.rightArm.bone;
|
||||||
|
this.worldRenderer.blockRenderer.renderBlockInHandThirdPerson(group, block, entity.getEntityBrightness());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create first person right hand and attach it to the holder
|
||||||
|
this.firstPersonGroup.clear();
|
||||||
|
this.handModel = this.model.rightArm.clone();
|
||||||
|
this.firstPersonGroup.add(this.handModel.bone);
|
||||||
|
|
||||||
|
// Copy material and update depth test of the hand to render it always in front
|
||||||
|
let mesh = this.handModel.bone.children[0];
|
||||||
|
mesh.material = mesh.material.clone();
|
||||||
|
mesh.material.depthTest = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create first person right hand and attach it to the holder
|
|
||||||
this.handGroup.clear();
|
|
||||||
this.handModel = this.model.rightArm.clone();
|
|
||||||
this.handGroup.add(this.handModel.bone);
|
|
||||||
|
|
||||||
// Copy material and update depth test of the hand
|
|
||||||
let mesh = this.handModel.bone.children[0];
|
|
||||||
mesh.renerOrder = 999;
|
|
||||||
mesh.material = mesh.material.clone();
|
|
||||||
mesh.material.depthTest = false;
|
|
||||||
mesh.material.depthWrite = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(entity, partialTicks) {
|
render(entity, partialTicks) {
|
||||||
@@ -57,10 +76,17 @@ export default class PlayerRenderer extends EntityRenderer {
|
|||||||
super.render(entity, partialTicks);
|
super.render(entity, partialTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRightArm(player, partialTicks) {
|
updateFirstPerson(player) {
|
||||||
// Make sure the model is created
|
// Make sure the model is created
|
||||||
this.prepareModel(player);
|
this.prepareModel(player);
|
||||||
|
|
||||||
|
// Make the group visible
|
||||||
|
this.firstPersonGroup.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRightHand(player, partialTicks) {
|
||||||
|
this.updateFirstPerson(player);
|
||||||
|
|
||||||
// Set transform of renderer
|
// Set transform of renderer
|
||||||
this.model.swingProgress = 0;
|
this.model.swingProgress = 0;
|
||||||
this.model.hasItemInHand = false;
|
this.model.hasItemInHand = false;
|
||||||
@@ -68,14 +94,17 @@ export default class PlayerRenderer extends EntityRenderer {
|
|||||||
this.model.setRotationAngles(player, 0, 0, 0, 0, 0, 0);
|
this.model.setRotationAngles(player, 0, 0, 0, 0, 0, 0);
|
||||||
this.handModel.copyTransformOf(this.model.rightArm);
|
this.handModel.copyTransformOf(this.model.rightArm);
|
||||||
|
|
||||||
// Render the model
|
// Render hand model
|
||||||
this.handGroup.visible = true;
|
|
||||||
this.handModel.render();
|
this.handModel.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
fillMeta(entity, meta) {
|
fillMeta(entity, meta) {
|
||||||
super.fillMeta(entity, meta);
|
super.fillMeta(entity, meta);
|
||||||
meta.itemInHand = entity.inventory.getItemInSelectedSlot();
|
|
||||||
|
let firstPerson = this.worldRenderer.minecraft.settings.thirdPersonView === 0;
|
||||||
|
|
||||||
|
meta.firstPerson = firstPerson;
|
||||||
|
meta.itemInHand = firstPerson ? this.worldRenderer.itemToRender : entity.inventory.getItemInSelectedSlot();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ export default class ItemRenderer {
|
|||||||
// Create item camera
|
// Create item camera
|
||||||
this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, 0, 300);
|
this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, 0, 300);
|
||||||
this.camera.near = 0;
|
this.camera.near = 0;
|
||||||
this.camera.far = 100;
|
this.camera.far = 15;
|
||||||
this.camera.rotation.order = 'ZYX';
|
this.camera.rotation.order = 'ZYX';
|
||||||
this.camera.up = new THREE.Vector3(0, 1, 0);
|
this.camera.up = new THREE.Vector3(0, 1, 0);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user