mc.roleplayhub.com

players online

[Devlog #3] Writing a website to.. view 3D SRP resourcepack models?

Laplace64

Level 2
1736251360761.png



[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
This post is made only for
  • 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)
1736251190107.png

1736249775269.png1736251141938.png

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

1736249833713.png

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
                    ]
                },
Notice that it's a full 1 to 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.

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!
 

Attachments

  • 1736243702185.png
    1736243702185.png
    65.3 KB · Views: 0
  • 1736249104504.png
    1736249104504.png
    185.4 KB · Views: 4
  • 1736249350390.png
    1736249350390.png
    226.8 KB · Views: 1

Users who are viewing this thread

Top