Check out a free preview of the full Advanced Creative Coding with WebGL & Shaders course

The "Texture Mapping" Lesson is part of the full, Advanced Creative Coding with WebGL & Shaders course featured in this preview video. Here's what you'd learn in this lesson:

Matt covers the concept of equirectangular textures and how they're useful in mapping objects in a scene, and introduces types of maps that help debug how light and other properties will affect the texture of an object's mapping.


Transcript from the "Texture Mapping" Lesson

>> So far, we've just been texture mapping spheres with the Earth texture. And there's a couple things to note. One of them is, the way that we described those textures is called equirectangular. So if you wanted to find more images that have that kind of mapping that you can map onto a sphere, you can search equirectangular.

You can also use the term panoramic images, sometimes you'll find this kind of mapping. Sometimes it's also called HDR maps. And that's because when we work with HDR maps, for example, for a game engine or in a rendering engine, it's quite often this sorta spherical texture. So there's lots of different terms that you could search for these, another term would be environment map textures.

And you can find these different textures like this, and then you can drag those in and apply them. Just be aware of licensing, obviously. And then the other thing that came up is just, what about geometries that are not just a sphere? How do we map textures onto those, and how is it a little bit different?

So, here's a demo that I just quickly whipped up. So if we go into the repository and we go into the src/demos, you'll see a few new textures. You'll see brick-diffuse, and that's the texture of this brick. And so when we're actually looking at this output here, which I'll walk through a little bit.

When we're looking at this, it's a seamless texture that's been repeated across the surface of this torus. And so that's the diffuse, diffuse is just another way of saying the the color of the texture. It's kind of the the term that we use for for color. There's another type called normal.

So this is a normal map, which I'll show a little bit about how this works, and how it changes the look of a material. But it's a texture that goes along quite often with diffuse. And it gives us the information of the surface geometry, almost. So this gives us some information about how the surface geometry will react to light as the light hits it and bounces off of it.

And so that can be really useful for adding a little bit more detail and a little bit more reaction to light. And so when you actually go looking for textures for 3D things, generally, you'll look up 3D textures. You'll look up maybe it's called physically based texturing. So you can search physically based texturing or PBR, physically based rendering, PBR textures.

And you can find packs of textures that include diffuse, normal. Sometimes it includes other textures like metalness, which is just like we've been defining metalness as 0 to 1 or roughness as 0 to 1. Sometimes for certain materials, you might have a material that's partly metal and partly rough.

And so for example, if you have chipped paint, and it's in a texture, Or even chipped metal would be a better example. Where part of the surface is really metallic, and then part of it is really rough. And so this is where we would use a sort of metalness map.

So metalness texture map, which would define which areas of the texture are metallic, and which areas are not metallic. But it's hard to sometimes find them just on Google Images, you might have to actually search for things like rock texture pbr or something like that. And then here you might find some stone and rock textures.

So yeah, this is a site I've used before. It has some nice textures for different types of surfaces. So actually getting into the demo, the demo is just here, it's at the bottom, torus-material.js. But I'll just open it up locally, And just walk through a few of the changes.

So the first obvious change is that it's using a torus geometry instead of a sphere geometry. And so the torus geometry, you can specify the outer radius size, and then the inner radius, which is gonna be the thickness of this donut that we're making. And then we specify the segments, the divisions, which is gonna make it less detailed or more detailed, like high poly versus low poly.

And then we actually get into loading some textures, and here is a little bit different. We load a texture just like we did before with the Earth. We do load with the URL, which is, in this case, brick-diffuse which is the color. But here, we're gonna say we want this texture to wrap seamlessly.

So this line that we have here is saying, make it so that along the horizontal and along the vertical, make it so that this texture wraps seamlessly. The default, if we didn't have this, we would see it would start to get sort of stretched in this weird way.

And that's because the texture's just getting stretched, and it starts to look pretty ugly. And so you need repeat wrapping for it to seamlessly repeat across the surface. And then this last thing we're doing here is, we're changing the repeat value. So without this, it's going to just take this texture and try and wrap it around the mesh just as if we've taken wrapping paper.

I don't know, you're wrapping a gift, and you're wrapping it around this object. But what we really want is, we want to get rid of this stretching that's happening in the brick. And so we're gonna say something like map.repeat, which is a vector two, so we can say set.

We can make it repeat twice along the horizontal plane, or twice as much as it is along the vertical plane, or even three times or four times. And there's no exact number we can really choose here that would work across the entire torus. Because you'll see the bricks that are close to the center here are gonna be a little smaller.

And the bricks that are close to the edge here are gonna be a little bigger. So if you really wanted this torus to be perfectly mapped, you might have to open it up in Cinema 4D or Blender, and actually work with these coordinates and things like that. But for now, it's okay just doing something like this.

And then because it's a vector two, you can say multiplyScalar. And you can chain these methods together, because it always returns the vector two. And so now I could say multiplyScalar(4), and that's just gonna make it repeat more or less depending on what number I put in here.

So this is just scaling the repeat vector, which is gonna repeat the texture in two dimensions, in the x and y, and so that's this here. And then the next sorta chunk is the normal map. So we load it in the same way we apply repeat wrapping. And then we copy the vector two so that the normal map matches the same repeat values, so that it's just gonna line up perfectly.

And then the only other thing we really do is, in our MeshStandardMaterial, we can tweak the roughness and metalness, and we pass in the normal map, we pass in the map. And so what you'll actually see, I'll make this a bit bigger so we can see it. But when we look at the light as it hits these rocks, we can really start to see the light sort of bouncing off the edge of the rocks and the edge of the stone and brick and the sort of texture.

And so if I was to take the normal map out of this material, and now we look at it from a glancing angle, we look at it from an edge, it's just a perfectly smooth torus. And that's not what we want, we want to actually start to see the detail of the brick, so that's what the normal map gives us.

One other thing worth mentioning with this kind of approach. Depending on where you get your normal maps, might be set up for a different engine, it might be set up for Unity or something else. And they might be using a slightly different coordinate system. And it might end up looking like this, where we look at our texture, and we're like, well, we can see the detail of the brick, but it looks weird, and it almost looks like it's inverted.

Cuz if we look at this, we would imagine when the light hits the brick from there, we would imagine this side of the brick to be lit up. But in reality, it's like the other side of the brick has lit up. So it's almost there, it almost looks okay, but everything looks a little bit backwards or a little bit inverted.

And that's because maybe some engines will use an inverted y channel for the normal map. And so to change that you just pass in this thing called normalScale, which is a vector two. And you either use a positive or negative value as the y, depending on which one looks more correct.

And you can also use the same value to reduce the overall strength of this map. So by multiplying it by a scalar value, which is what we're doing here, normal strength, we're making it really intense, like trying to make these brick really stand out. Or making it really reduced, so really reducing that effect, so that it's a much more subtle change.

So yeah, that's just a bit of a recap of texturing. But also, how do we texture things that are not just spheres? And if we had an object that's a 3D model, like a physical bust or some sort of maybe a person's character, or a character design or something like that, or an object like a coffee cup.

Then you'd actually have to texture map it in a 3D software like Blender or Cinema 4D, or ask your your 3D artists do the texturing and to do the UV mapping. So that when you load it into three.js, it can just be applied with a texture and it should just all work.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now