implement entity model rendering
(cherry picked from commit a0e5d51290cf521d511f90e23445206a14c4a772)
This commit is contained in:
@@ -49,7 +49,8 @@ window.Minecraft = class {
|
||||
this.soundManager = new SoundManager();
|
||||
|
||||
// Create player
|
||||
this.player = new Player(this, this.world);
|
||||
this.player = new PlayerEntity(this, this.world);
|
||||
this.world.addEntity(this.player);
|
||||
this.inventory = new Inventory();
|
||||
|
||||
this.displayScreen(this.loadingScreen);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
window.Entity = class {
|
||||
|
||||
constructor() {
|
||||
this.group = new THREE.Object3D();
|
||||
}
|
||||
|
||||
}
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
window.Player = class {
|
||||
window.PlayerEntity = class extends Entity {
|
||||
|
||||
static name = "PlayerEntity";
|
||||
|
||||
constructor(minecraft, world) {
|
||||
super();
|
||||
|
||||
this.minecraft = minecraft;
|
||||
this.world = world;
|
||||
|
||||
@@ -25,6 +25,9 @@ window.WorldRenderer = class {
|
||||
// Block Renderer
|
||||
this.blockRenderer = new BlockRenderer(this);
|
||||
|
||||
// Entity render manager
|
||||
this.entityRenderManager = new EntityRenderManager();
|
||||
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
@@ -85,6 +88,11 @@ window.WorldRenderer = class {
|
||||
// Render target block
|
||||
this.renderBlockHitBox(player, partialTicks);
|
||||
|
||||
// Render entities
|
||||
for (let entity of this.minecraft.world.entities) {
|
||||
this.renderEntity(entity);
|
||||
}
|
||||
|
||||
// Render actual scene
|
||||
this.webRenderer.render(this.scene, this.camera);
|
||||
}
|
||||
@@ -287,4 +295,9 @@ window.WorldRenderer = class {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderEntity(entity) {
|
||||
let entityRenderer = this.entityRenderManager.getEntityRendererByEntity(entity);
|
||||
entityRenderer.render(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
window.EntityRenderManager = class {
|
||||
|
||||
constructor() {
|
||||
this.renderers = [];
|
||||
this.push(PlayerEntity, new PlayerRenderer());
|
||||
}
|
||||
|
||||
push(entityType, entityRenderer) {
|
||||
this.renderers[entityType.name] = entityRenderer;
|
||||
}
|
||||
|
||||
getEntityRendererByEntity(entity) {
|
||||
return this.renderers[entity.constructor.name];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
window.EntityRenderer = class {
|
||||
|
||||
constructor(model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
rebuild(tessellator, entity) {
|
||||
this.model.rebuild(tessellator, entity);
|
||||
}
|
||||
|
||||
render(entity) {
|
||||
this.model.render(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
window.PlayerRenderer = class extends EntityRenderer {
|
||||
|
||||
constructor() {
|
||||
super(new ModelPlayer());
|
||||
|
||||
// Load character texture
|
||||
this.textureCharacter = new THREE.TextureLoader().load('src/resources/char.png');
|
||||
this.textureCharacter.magFilter = THREE.NearestFilter;
|
||||
this.textureCharacter.minFilter = THREE.NearestFilter;
|
||||
}
|
||||
|
||||
rebuild(tessellator, entity) {
|
||||
tessellator.bindTexture(this.textureCharacter);
|
||||
super.rebuild(tessellator, entity);
|
||||
}
|
||||
|
||||
render(entity) {
|
||||
super.render(entity);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
window.ModelBase = class {
|
||||
|
||||
/**
|
||||
* Rebuild the model
|
||||
*
|
||||
* @param tessellator Tessellator to render vertices
|
||||
*/
|
||||
rebuild(tessellator, entity) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model
|
||||
*
|
||||
* @param time Animation offset
|
||||
*/
|
||||
render(time) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
window.ModelPlayer = class extends ModelBase {
|
||||
|
||||
/**
|
||||
* Create cubes for the zombie model
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// Create head ModelRenderer
|
||||
this.head = new ModelRenderer(0, 0)
|
||||
.setBox(-4.0, -8.0, -4.0, 8, 8, 8);
|
||||
|
||||
// Create body ModelRenderer
|
||||
this.body = new ModelRenderer(16, 16)
|
||||
.setBox(-4.0, 0.0, -2.0, 8, 12, 4);
|
||||
|
||||
// Right arm ModelRenderer
|
||||
this.rightArm = new ModelRenderer(40, 16)
|
||||
.setBox(-3.0, -2.0, -2.0, 4, 12, 4);
|
||||
this.rightArm.setPosition(-5.0, 2.0, 0.0);
|
||||
|
||||
// Left arm ModelRenderer
|
||||
this.leftArm = new ModelRenderer(40, 16)
|
||||
.setBox(-1.0, -2.0, -2.0, 4, 12, 4);
|
||||
this.leftArm.setPosition(5.0, 2.0, 0.0);
|
||||
|
||||
// Right Legs ModelRenderer
|
||||
this.rightLeg = new ModelRenderer(0, 16)
|
||||
.setBox(-2.0, 0.0, -2.0, 4, 12, 4);
|
||||
this.rightLeg.setPosition(-2.0, 12.0, 0.0);
|
||||
|
||||
// Left leg ModelRenderer
|
||||
this.leftLeg = new ModelRenderer(0, 16)
|
||||
.setBox(-2.0, 0.0, -2.0, 4, 12, 4);
|
||||
this.leftLeg.setPosition(2.0, 12.0, 0.0);
|
||||
}
|
||||
|
||||
rebuild(tessellator, entity) {
|
||||
this.head.rebuild(tessellator, entity);
|
||||
this.body.rebuild(tessellator, entity);
|
||||
this.leftArm.rebuild(tessellator, entity);
|
||||
this.rightArm.rebuild(tessellator, entity);
|
||||
this.leftLeg.rebuild(tessellator, entity);
|
||||
this.rightLeg.rebuild(tessellator, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model
|
||||
*
|
||||
* @param time Animation offset
|
||||
*/
|
||||
render(entity, time) {
|
||||
// Set rotation of cubes
|
||||
this.head.yRotation = Math.sin(time * 0.83);
|
||||
this.head.xRotation = Math.sin(time) * 0.8;
|
||||
this.rightArm.xRotation = Math.sin(time * 0.6662 + Math.PI) * 2.0;
|
||||
this.rightArm.zRotation = (Math.sin(time * 0.2312) + 1.0);
|
||||
this.leftArm.xRotation = Math.sin(time * 0.6662) * 2.0;
|
||||
this.leftArm.zRotation = (Math.sin(time * 0.2812) - 1.0);
|
||||
this.rightLeg.xRotation = Math.sin(time * 0.6662) * 1.4;
|
||||
this.leftLeg.xRotation = Math.sin(time * 0.6662 + Math.PI) * 1.4;
|
||||
|
||||
// Render cubes
|
||||
this.head.render(entity);
|
||||
this.body.render(entity);
|
||||
this.rightArm.render(entity);
|
||||
this.leftArm.render(entity);
|
||||
this.rightLeg.render(entity);
|
||||
this.leftLeg.render(entity);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
window.ModelRenderer = class {
|
||||
|
||||
/**
|
||||
* Create cube object
|
||||
*
|
||||
* @param textureOffsetX x offset position on the texture
|
||||
* @param textureOffsetY y offset position on the texture
|
||||
*/
|
||||
constructor(textureOffsetX, textureOffsetY) {
|
||||
this.textureOffsetX = textureOffsetX;
|
||||
this.textureOffsetY = textureOffsetY;
|
||||
|
||||
this.xRotation = 0;
|
||||
this.yRotation = 0;
|
||||
this.zRotation = 0;
|
||||
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the texture offset position of the cube
|
||||
*
|
||||
* @param textureOffsetX Offset position x
|
||||
* @param textureOffsetY Offset position y
|
||||
*/
|
||||
setTextureOffset(textureOffsetX, textureOffsetY) {
|
||||
this.textureOffsetX = textureOffsetX;
|
||||
this.textureOffsetY = textureOffsetY;
|
||||
|
||||
this.xRotation = 0;
|
||||
this.yRotation = 0;
|
||||
this.zRotation = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create box using offset position and width, height and depth
|
||||
*
|
||||
* @param offsetX X offset of the render position
|
||||
* @param offsetY Y offset of the render position
|
||||
* @param offsetZ Z offset of the render position
|
||||
* @param width Cube width
|
||||
* @param height Cube height
|
||||
* @param depth Cube depth
|
||||
*/
|
||||
setBox(offsetX, offsetY, offsetZ, width, height, depth) {
|
||||
this.polygons = [];
|
||||
|
||||
let x = offsetX + width;
|
||||
let y = offsetY + height;
|
||||
let z = offsetZ + depth;
|
||||
|
||||
// Create bottom vertex points of cube
|
||||
let vertexBottom1 = new Vertex(offsetX, offsetY, offsetZ, 0.0, 0.0);
|
||||
let vertexBottom2 = new Vertex(x, offsetY, offsetZ, 0.0, 8.0);
|
||||
let vertexBottom3 = new Vertex(offsetX, offsetY, z, 0.0, 0.0);
|
||||
let vertexBottom4 = new Vertex(x, offsetY, z, 0.0, 8.0);
|
||||
|
||||
// Create top vertex points of cube
|
||||
let vertexTop1 = new Vertex(x, y, z, 8.0, 8.0);
|
||||
let vertexTop2 = new Vertex(offsetX, y, z, 8.0, 0.0);
|
||||
let vertexTop3 = new Vertex(x, y, offsetZ, 8.0, 8.0);
|
||||
let vertexTop4 = new Vertex(offsetX, y, offsetZ, 8.0, 0.0);
|
||||
|
||||
// Create polygons for each cube side
|
||||
this.polygons[0] = new Polygon(
|
||||
[vertexBottom4, vertexBottom2, vertexTop3, vertexTop1],
|
||||
this.textureOffsetX + depth + width,
|
||||
this.textureOffsetY + depth,
|
||||
this.textureOffsetX + depth + width + depth,
|
||||
this.textureOffsetY + depth + height
|
||||
);
|
||||
|
||||
this.polygons[1] = new Polygon(
|
||||
[vertexBottom1, vertexBottom3, vertexTop2, vertexTop4],
|
||||
this.textureOffsetX,
|
||||
this.textureOffsetY + depth,
|
||||
this.textureOffsetX + depth,
|
||||
this.textureOffsetY + depth + height
|
||||
);
|
||||
|
||||
this.polygons[2] = new Polygon(
|
||||
[vertexBottom4, vertexBottom3, vertexBottom1, vertexBottom2],
|
||||
this.textureOffsetX + depth,
|
||||
this.textureOffsetY,
|
||||
this.textureOffsetX + depth + width,
|
||||
this.textureOffsetY + depth
|
||||
);
|
||||
|
||||
this.polygons[3] = new Polygon(
|
||||
[vertexTop3, vertexTop4, vertexTop2, vertexTop1],
|
||||
this.textureOffsetX + depth + width,
|
||||
this.textureOffsetY,
|
||||
this.textureOffsetX + depth + width + width,
|
||||
this.textureOffsetY + depth
|
||||
);
|
||||
|
||||
this.polygons[4] = new Polygon(
|
||||
[vertexBottom2, vertexBottom1, vertexTop4, vertexTop3],
|
||||
this.textureOffsetX + depth,
|
||||
this.textureOffsetY + depth,
|
||||
this.textureOffsetX + depth + width,
|
||||
this.textureOffsetY + depth + height
|
||||
);
|
||||
|
||||
this.polygons[5] = new Polygon(
|
||||
[vertexBottom3, vertexBottom4, vertexTop1, vertexTop2],
|
||||
this.textureOffsetX + depth + width + depth,
|
||||
this.textureOffsetY + depth,
|
||||
this.textureOffsetX + depth + width + depth + width,
|
||||
this.textureOffsetY + depth + height
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the absolute position of the cube
|
||||
*
|
||||
* @param x Absolute x position of cube
|
||||
* @param y Absolute y position of cube
|
||||
* @param z Absolute z position of cube
|
||||
*/
|
||||
setPosition(x, y, z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
rebuild(tessellator, entity) {
|
||||
// Start drawing
|
||||
tessellator.startDrawing();
|
||||
|
||||
// Render polygons
|
||||
for (let i = 0; i < 6; i++) {
|
||||
let polygon = this.polygons[i];
|
||||
polygon.render(tessellator);
|
||||
}
|
||||
|
||||
// Finish drawing
|
||||
tessellator.draw(entity.group);
|
||||
}
|
||||
|
||||
render(entity) {
|
||||
entity.group.position.setX(this.x);
|
||||
entity.group.position.setY(this.y);
|
||||
entity.group.position.setZ(this.z);
|
||||
|
||||
entity.group.rotation.order = 'ZYX';
|
||||
entity.group.rotation.x = this.xRotation;
|
||||
entity.group.rotation.y = this.yRotation;
|
||||
entity.group.rotation.z = this.zRotation;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
window.Polygon = class {
|
||||
|
||||
/**
|
||||
* Bind UV mappings on the vertices
|
||||
*
|
||||
* @param vertices Vertex array
|
||||
* @param minU Minimum U coordinate
|
||||
* @param minV Minimum V coordinate
|
||||
* @param maxU Maximum U coordinate
|
||||
* @param maxV Maximum V coordinate
|
||||
*/
|
||||
constructor(vertices, minU, minV, maxU, maxV) {
|
||||
this.vertices = vertices;
|
||||
this.vertexCount = vertices.length;
|
||||
|
||||
// Map UV on vertices
|
||||
vertices[0] = vertices[0].remap(maxU, minV);
|
||||
vertices[1] = vertices[1].remap(minU, minV);
|
||||
vertices[2] = vertices[2].remap(minU, maxV);
|
||||
vertices[3] = vertices[3].remap(maxU, maxV);
|
||||
}
|
||||
|
||||
render(tessellator) {
|
||||
// Set color of polygon
|
||||
tessellator.setColor(1, 1, 1);
|
||||
|
||||
// Render all vertices
|
||||
for (let i = 3; i >= 0; i--) {
|
||||
let vertex = this.vertices[i];
|
||||
|
||||
// Bind UV mappings and render vertex
|
||||
tessellator.addVertexWithUV(
|
||||
vertex.position.x,
|
||||
vertex.position.y,
|
||||
vertex.position.z,
|
||||
vertex.u / 64.0,
|
||||
vertex.v / 32.0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
window.Vertex = class {
|
||||
|
||||
/**
|
||||
* A vertex contains a 3 float vector position and UV coordinates
|
||||
*
|
||||
* @param x X position
|
||||
* @param y Y position
|
||||
* @param z Z position
|
||||
* @param u U mapping
|
||||
* @param v V mapping
|
||||
*/
|
||||
constructor(x, y, z, u, v) {
|
||||
this.position = new Vector3(x, y, z);
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new vertex of the current one with different UV mappings
|
||||
*
|
||||
* @param u New U mapping
|
||||
* @param v New V mapping
|
||||
* @return New vertex with the vector position of the current one
|
||||
*/
|
||||
remap(u, v) {
|
||||
return new Vertex(this.position.x, this.position.y, this.position.z, u, v);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@ window.World = class {
|
||||
constructor(minecraft) {
|
||||
this.minecraft = minecraft;
|
||||
|
||||
this.entities = [];
|
||||
|
||||
this.group = new THREE.Object3D();
|
||||
this.group.matrixAutoUpdate = false;
|
||||
|
||||
@@ -500,4 +502,31 @@ window.World = class {
|
||||
}
|
||||
return Math.floor(level * 11);
|
||||
}
|
||||
|
||||
addEntity(entity) {
|
||||
this.entities.push(entity);
|
||||
this.group.add(entity.group);
|
||||
|
||||
let tessellator = new Tessellator();
|
||||
|
||||
// Rebuild entity model
|
||||
let worldRenderer = this.minecraft.worldRenderer;
|
||||
let renderer = worldRenderer.entityRenderManager.getEntityRendererByEntity(entity);
|
||||
renderer.rebuild(tessellator, entity);
|
||||
}
|
||||
|
||||
removeEntityById(id) {
|
||||
let entity = this.getEntityById(id);
|
||||
this.entities.remove(entity);
|
||||
this.group.remove(entity.group);
|
||||
}
|
||||
|
||||
getEntityById(id) {
|
||||
for (let entity of this.entities) {
|
||||
if (entity.id === id) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ window.Vector3 = class {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
|
||||
addVector(x, y, z) {
|
||||
return new Vector3(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
@@ -69,4 +68,19 @@ window.Vector3 = class {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an interpolated vector from the current vector position to the given one
|
||||
*
|
||||
* @param vector The end vector
|
||||
* @param partialTicks Interpolation progress
|
||||
* @return Interpolated vector between the two positions
|
||||
*/
|
||||
interpolateTo(vector, partialTicks) {
|
||||
let interpolatedX = this.x + (vector.x - this.x) * partialTicks;
|
||||
let interpolatedY = this.y + (vector.y - this.y) * partialTicks;
|
||||
let interpolatedZ = this.z + (vector.z - this.z) * partialTicks;
|
||||
|
||||
return new Vector3(interpolatedX, interpolatedY, interpolatedZ);
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
+12
-2
@@ -75,7 +75,8 @@ loadTexture([
|
||||
"gui/icons.png",
|
||||
"terrain/terrain.png",
|
||||
"terrain/sun.png",
|
||||
"terrain/moon.png"
|
||||
"terrain/moon.png",
|
||||
"char.png"
|
||||
]).then(() => {
|
||||
// Load scripts
|
||||
loadScripts([
|
||||
@@ -125,7 +126,8 @@ loadTexture([
|
||||
"src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorOctaves.js",
|
||||
"src/js/net/minecraft/client/world/generator/noise/NoiseGeneratorCombined.js",
|
||||
"src/js/net/minecraft/client/world/generator/WorldGenerator.js",
|
||||
"src/js/net/minecraft/client/entity/Player.js",
|
||||
"src/js/net/minecraft/client/entity/Entity.js",
|
||||
"src/js/net/minecraft/client/entity/PlayerEntity.js",
|
||||
"src/js/net/minecraft/client/inventory/Inventory.js",
|
||||
"src/js/net/minecraft/client/GameSettings.js",
|
||||
"src/js/net/minecraft/client/Minecraft.js",
|
||||
@@ -137,6 +139,14 @@ loadTexture([
|
||||
"src/js/net/minecraft/client/render/gui/ScreenRenderer.js",
|
||||
"src/js/net/minecraft/client/render/gui/ItemRenderer.js",
|
||||
"src/js/net/minecraft/client/render/Tessellator.js",
|
||||
"src/js/net/minecraft/client/render/model/ModelBase.js",
|
||||
"src/js/net/minecraft/client/render/model/renderer/Vertex.js",
|
||||
"src/js/net/minecraft/client/render/model/renderer/Polygon.js",
|
||||
"src/js/net/minecraft/client/render/model/renderer/ModelRenderer.js",
|
||||
"src/js/net/minecraft/client/render/model/model/ModelPlayer.js",
|
||||
"src/js/net/minecraft/client/render/entity/EntityRenderer.js",
|
||||
"src/js/net/minecraft/client/render/entity/entity/PlayerRenderer.js",
|
||||
"src/js/net/minecraft/client/render/entity/EntityRenderManager.js",
|
||||
"src/js/net/minecraft/client/render/WorldRenderer.js",
|
||||
"src/js/net/minecraft/client/render/BlockRenderer.js"
|
||||
]).then(() => {
|
||||
|
||||
Reference in New Issue
Block a user