[Devlog #3]
I would like to quickly preface a few very important things
- I have no plans to release this website. It's not published anywhere, and all the model data it loads is from my local drive
- I have no plans to re-distribute any work done by the SRP modelers. I have immense respect in what they do, and this project is only done because I want to see all the cool work that they've done
- Even if I were to release this, you will have to upload the texturepack folder on your own. It will be a general website that can display any texturepack models and will not hold the SRP texturepack in any way shape or form.
- In addition to this, there are IC jobs specifically for cosplayers. Until I know that this would not impact cosplayers, this will be another reason for me to keep it as a small project that lives in my computer
- I have no plans to re-distribute any work done by the SRP modelers. I have immense respect in what they do, and this project is only done because I want to see all the cool work that they've done
- Talking about how minecraft models work, and how these are loaded
- And crediting the (incredibly based) person that actually wrote the code behind this
With that over with, let's start by showing what I got! I managed to "make" (well, attempted to and gave up, then repurposed some absolute unit of a programmer's code)
That's right, it's a website that.. displays all the models on SRP! But.. how? To answer that, let me take you into the deep rabbit hole of.. web development and UV mapping.
What is a UV mapping?
Okay, so, to understand, let's take a look at minecraft's cake texture
Wait.. what? The cake is made out of 4 cakes. That's because a cake is actually made out of the top part, surrounding by 4 sides, and a bottom part!
Our cake is actually... a JSON file! It looks like this
JSON:
{
"textures": {
"bottom": "blocks/cake_bottom",
"top": "blocks/cake_top",
"side": "blocks/cake_side"
},
"elements": [
{
"from": [
1,
0,
1
],
"to": [
15,
8,
15
],
"faces": {
"down": {
"texture": "#bottom",
"uv": [
1,
1,
15,
15
],
"cullface": "down"
},
"up": {
"texture": "#top",
"uv": [
1,
1,
15,
15
]
},
"north": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
},
"south": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
},
"west": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
},
"east": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
}
}
}
]
}
Now, I am NOT qualified to explain UV maps, at all. So if this intrigued you, please delve into your own rabbit hole for this. But for now, let's dissect that thing up there
JSON:
"textures": {
"bottom": "blocks/cake_bottom",
"top": "blocks/cake_top",
"side": "blocks/cake_side"
},
This is it defining what each part of the texture is. You can name this anything, but for cake, it's named "bottom", "top" and "side". For each face respectively.
But now we come to.. the scary part. Let's go from the least scary thing first
JSON:
"from": [
1,
0,
1
],
"to": [
15,
8,
15
],
This part says how "big" the block is. It's a 16x16. We can see that the cake is 8 blocks tall (remember, it's [x y z]!).
We know that a cake is a cube. Well, a cuboid to be exact (since not every edges are of the same length).
It has 6 faces, as all cubes do. It has the up, down, and 4 sides. The JSON file describes how each part should be drawn! And notice something very interesting, we know that the top and bottom part are full-sized (technically padded at each side by 1)
So the uv for them are:
JSON:
"down": {
"texture": "#bottom",
"uv": [
1,
1,
15,
15
],
"cullface": "down"
},
"up": {
"texture": "#top",
"uv": [
1,
1,
15,
15
]
},
However, the sides of the cake are short. So our UV mapping is actually half the size
JSON:
"north": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
},
"south": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
},
"west": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
},
"east": {
"texture": "#side",
"uv": [
1,
8,
15,
16
]
}
Notice that it only spans (1, 15) to (8, 16)! Because one side is full length (the x part) and the upper part (z part) is half-sized. If someone is actually mathematically inclined and understand UV mappings, I beseech you, make a reply to this post and explain it. I genuinely don't get it, there's almost no resources explaining the math or magic behind this.
How did this thing get on a website?
If you've ever written a website (and if you haven't, take my word for it), loading a 3d object with complex geometry and allowing it to be spun around is hard.
And by hard, I mean I would be willing to sleep on a bed of nails than do it.
Luckily, someone else has already beat me to the punch.
GitHub - vberlier/json-model-viewer: A 3d model viewer for minecraft json models.
A 3d model viewer for minecraft json models. Contribute to vberlier/json-model-viewer development by creating an account on GitHub.
github.com
I would like to dedicate a small paragraph just to gush about how insanely based the person behind this repository is.
They wrote this 9 years ago, not a single package manager or framework. They came in, put this thing on MIT license (extremely based license), documented the whole thing and have the actual website running. This is a dangerous level of based.
But back on topic: how did they do it? Well, they used this amazing thing called three.js. This thing is downright ridiculous, it's a game engine inside of your web browser.
People have made full blown games and really impressive things out of it.
Like, what is this nonsense?
JavaScript:
var geometry = new THREE.BoxGeometry(width + fix, height + fix, length + fix)
geometry.faceVertexUvs[0] = []
// assign materials
if (element.hasOwnProperty('faces')) {
var faces = ['east', 'west', 'up', 'down', 'south', 'north']
for (var i = 0; i < 6; i++) {
var face = faces[i]
if (element.faces.hasOwnProperty(face)) {
// check properties
if (!element.faces[face].hasOwnProperty('texture'))
throw new Error('Couldn\'t find "texture" property for "' + face + '" face in element "' + index + '".')
if (!element.faces[face].hasOwnProperty('uv'))
throw new Error('Couldn\'t find "uv" property for "' + face + '" face in element "' + index + '".')
if (element.faces[face].uv.length != 4)
throw new Error('The "uv" property for "' + face + '" face in element "' + index + '" is invalid (got "' + element.faces[face].uv + '").')
// get texture index
var ref = element.faces[face].texture
var textureIndex = references.indexOf(ref[0] == '#' ? ref.substring(1) : ref)
// check if texture has been registered
if (textureIndex < 0)
throw new Error('The "texture" property for "' + face + '" face in element "' + index + '" is invalid (got "' + ref + '").')
geometry.faces[i*2].materialIndex = textureIndex
geometry.faces[i*2+1].materialIndex = textureIndex
// uv map
var uv = element.faces[face].uv
If someone gets it, please impart your knowledge onto my mortal soul. This thing feels like pure black magic. In any case, I've just modified the main `index.html` to support texturepack uploads and added the ability to look up items.
Closing thoughts
It's really fun to go into random rabbit holes to make things. I never knew about how minecraft models work, or how SRP managed to make all these cool 3d items. I also did not know such a based programmer exists, if you have a github account, please go star their repository.
If you want to make something similar, you definitely can. All I ask is to be mindful on giving it public access. Thank you for reading through my unhinged 3am fueled rant, and wishing everyone a wonderful day ahead!