The main focus in this post is to just simply create textures using raw color channel data, and then use the resulting texture with say a map property of a material. There is then a lot more to read about when it comes to the various options with material maps, but also just as much if not more when it comes to the buffer geometry class. I will then not be getting into great detail with things like the uv attribute of buffer geometry, as well as how to go about setting up a groups property along with material index values when using an array of materials.
If you think that you still need to read more about materials you might want to check out my main blog post on the subject of materials in general in threejs. However that is a very long deep dive top post on the subject so if you just want to get started with data textures there is just starting with say that map option of the basic material. This is a good starting point and also depending on the over all style that you want to follow it might even be a done deal when it comes to this.
I have wrote a number of posts on the use of canvas elements, and also a post on using canvas elements as a way to create textures for the materials that are used for mesh objects in threejs. For the most part I prefer to use canvas elements as I have the whole 2d drawing context to work with that can be used to make quick work of creating textures.
Data tetxures extend from the base Texture Class that applies to data textures of course.
The source code examples that I am writing about in this post can be found in my test threejs repository on Github. This is also where I park the source code for my many other blog posts on threejs as well.
The version of threejs that I was using when I first wrote this post was r135, and the last time I came around to do some editing I was using r146. Still code breaking changes might be made at some point in the future so one should always be mindful of the version of threejs that they are using when reading about and using threejs source code examples on the open web.
To start this post off I will want to cover a few basic examples of data textures. I will be trying to keep these examples fairly simple but even then there is a lot to be aware of when it comes to making textures this way.
For a starting simple example of this data texture thing in threejs I made this quick example that involves starting at a value of 32 for the red channel and adding 128 over the length of the total number of pixels for the image. I am then also doing something similar for the green channel just subtracting rather than adding.
I start out by making my usual scene object along with a camera and web gl renderer just like with any other threejs project. After that I will want to create an instance of a unit8Array where the length is equal to the number of pixels times four. So I just need to figure out that the width and height of the texture should be and then multiply that to get a size in terms of a total number of pixels. I can then use this size value times four to set the length of the typed array, and also use it as a way to know if I should stop looping or not when it comes to setting the values for this array.
I then have a loop in which I am figuring out what the values should be for each red, green, blue, and alpha channel value for each pixel. I can have an index for each pixel and then just figure out what the actual index value in the array is by just multiplying by four and then adding fro there for each channel value. Once I have my array in the state that I want it for the texture the next step is to then pass that array as an argument when calling the THREE.DataTexture constructor function.
For this example I am doing more or less the same thing as in the basic example, but now I am using the distance to method of the Vector2 class as a way to get a distance value from a current pixel location to that of the center of the texture. I can then use this as a main to come up with different color channel values for each pixel in the texture.
Now for a quick example using the math random method to create color channel values. There are of course a great number of ways that I could go about doing this sort of thing, but for this example I just went with creating a single value that will be used for each color channel. So in other words I am doing a kind of random gray scale color effect here.
I just also wrote a new post on the math utils object in threejs, and one interesting method in there is a seeded random method that will work like math random, with one little difference. Each time I reload the page I see the same texture rather than a new one. So then this seeded random method is a way to get an effect like that of what happens when using the math random method, but in a deterministic kind of way which is cool.
Now that I have some basic examples out of the way it is time to go over at least one if not more examples of animated data textures. This is where things can get a little involved and confusing when first starting out. Also I have found that just with buffer geometry it is a good idea to think more in terms of updating a texture rather than creating a new one on each frame update. By reusing the same texture objects over and over agian, but just updating the data from them, this not only results in better performance but I have also run into problems with a loss of context when going in the direction of creating new textures objects over and over again.
Thus far all of these data texture examples are just blocks of code that create a single texture. When it comes to making a real project with data textures I will likely want to make a number of them, and do so in different ways. To keep myself from repeating the same code over and over again each time I want to make a data texture I can then make some kind of helper function and pass some values that will result in the kind of texture that I want. When doing so the first feature that comes to mind that I would want to have in this kind of helper function would be an option that I can use to define the logic that is used to create the texture. In other words a kind of for pixel function that would have some kind of hard coded value.
So when it comes to the helper functions of this example I have a create data helper function that will just create and return an array that I can in turn use to create a new data texture, or update an existing one. With that said I then have both a create data texture helper as well as an update data texture helper as well. When it comes to this create data texture helper I have a built in for pix method, but I also created a number of additional functions that can be used to create and return such a method.
In my animation loop I am then using the update texture method passing option objects with custom for pixel methods which results in the kind of outcome that I would like so far with this sort of thing. I am sue that I might still need to refine things a bit with what I have here but the core idea is there for sure I mainly just need to expand the collection of methods that are used ti create the texture data.
The use of data textures to create textures for threejs geometries can then prove to be a little useful here and there then. However I am not sure if this is what I will want to always use, even when it comes to this sort of thing. For the most part I do still like to use canvas elements to create textures as there are a lot of useful methods to work with in the 2d drawing context.
When it comes to really working out modules I, and also uv wrapping while doing so I sometimes think the best way to go would be external image files when it comes to working with dae files for a project.