Skip to content

Textures

Vinicius Reif Biavatti edited this page Oct 9, 2019 · 10 revisions

Introduction

In the previous tutorial we learned how to show textures on the walls. In this tutorial we will use file textures images to put the image data in the wall. This is not hard, we will use almost all of implemented things we did previously. Here, more functions will be created to get the image data and load it to memory.

Hint: The image data is an array with the pixel values of some image. In HTML5 canvas image data, the pixels are positioned for each index of the array. For example, if we have a 1x1 image, the data of it would has a size of 4. The array would be [R, G, B, Alpha].

Important: If you run the code without use a server, a CORS error will be throwed in the browser because the external images we will import. Check this page for more details. I recommend you to start the project with a server. The server that I used is lite-server. You can use the apache server or XAMPP if you want.

Lite Server

Lite-server: To use it, we will need to install the nodejs. After install it, in the root of our project we will need to execute this shell command:

Shell Command: $ npm install -g lite-server

This command will install the server in our computer. After the installation, we just need to execute this command below to start our apllication in the server:

Shell Command: $ lite-server

Textures

The first thing to do is import the image in the HTML DOM. This will guarantee that the image will be loaded when the page gets opened. The image we will use is the 16x16 image below:

Image: texture.png

The texture will be used for this tutorial

Put this image file on your project folder and load this with this html:

File: raycasting.html

<!-- ... -->
<body>
    <img id="texture" src="texture.png" style="display: none">
</body>
<!-- ... -->

Note: We need to hide the image, otherwise every texture we import in out application will appear in the page.

After it, we will define this image in our attributes. The texture session will be used for it too.

// Data
let data = {
    // ...
    textures: [
        // ...
        {
            width: 16,
            height: 16,
            id: "texture",
            data: null
        }
    ]
}

After it, three new function will be created. Check the table below for understand about these functions:

Function Description
loadTextures() Iterate all textures defined in the textures attributes, and load the data of every texture
getTextureData(texture) Get the pixel array of the texture. For it we will need to create a canvas in memory
parseImageData(imageData) This function will transform the pixel array with the css color syntax

The first function loadTextures() will iterate every texture we have and check the textures that is not in memory and load the data of it. To know if the texture is not in memory, just check the if there is the id property in the texture object.

/**
 * Load textures
 */
function loadTextures() {
    for(let i = 0; i < data.textures.length; i++) {
        if(data.textures[i].id) {
            data.textures[i].data = getTextureData(data.textures[i]);
        }
    }
}

After it, we will create the getTextureData(texture) function. This function requests the texture to get the image element in the DOM, and put this image in a canvas. This canvas is needed to get the pixel data. Directally from image it is not possible. The steps of this function is:

  • Get the image element from DOM by texture.id
  • Create a canvas with the texture dimensions (texture.width and texture.heigth)
  • Get the context of this canvas
  • Draw the image in this canvas with the drawImage function
  • The the image data from the canvas with the getImageData() function
  • Parse this image data with the function we will create after it
/**
 * Get texture data
 * @param {Object} texture 
 */
function getTextureData(texture) {
    let image = document.getElementById(texture.id);
    let canvas = document.createElement('canvas');
    canvas.width = texture.width;
    canvas.height = texture.height;
    let canvasContext = canvas.getContext('2d');
    canvasContext.drawImage(image, 0, 0, texture.width, texture.height);
    let imageData = canvasContext.getImageData(0, 0, texture.width, texture.height).data;
    return parseImageData(imageData);
}

The last function we will need to create is the parseImageData(imageData) function. This function is necessary to parse the image data array format to our format to be better to manipulate. We have to iterate each image data array index and create our array with css color syntax;

/**
 * Parse image data to a css rgb array
 * @param {array} imageData 
 */
function parseImageData(imageData) {
    let colorArray = [];
    for (let i = 0; i < imageData.length; i += 4) {
        colorArray.push(`rgb(${imageData[i]},${imageData[i + 1]},${imageData[i + 2]})`);
    }
    return colorArray;
}

So now, we just need to call the loadTextures() before start our RayCasting logic. We can put the function call after the calculated data session:

// Calculated data
// ...

// Load textures
loadTextures();

// Canvas creation
// ...

Nice! The next thing to do is change the drawTexture() function to check if the image

Clone this wiki locally