I am trying to map a texture at a cube, but I came across two problems and one question
here is the code for initialize the cube
function init_cube(gl, n)
{
const vertices = new Float32Array([ // Vertex coordinates
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0,-1.0, 1.0, 1.0,-1.0, 1.0,
// v0-v1-v2-v3 front, Pass
1.0, 1.0, 1.0, 1.0,-1.0, 1.0, 1.0,-1.0,-1.0, 1.0, 1.0,-1.0,
// v0-v3-v4-v5 right, No
1.0, 1.0, 1.0, 1.0, 1.0,-1.0, -1.0, 1.0,-1.0, -1.0, 1.0, 1.0,
// v0-v5-v6-v1 up, Pass
-1.0, 1.0, 1.0, -1.0, 1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0, 1.0,
// v1-v6-v7-v2 left, Pass
-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,-1.0, 1.0, -1.0,-1.0, 1.0,
// v7-v4-v3-v2 down, No
1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0, 1.0,-1.0, 1.0, 1.0,-1.0
// v4-v7-v6-v5 back, Pass
]);
const indices = new Uint8Array([ // Indices of the vertices
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
const indexBuffer = gl.createBuffer();
if(!indexBuffer)
{
console.log("Failed to create an index buffer");
return;
}
if(!initArrayBuffer(gl, vertices, 3, gl.FLOAT, loc_aPosition))
{
console.log("Failed to initialize an array buffer for the position");
return;
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
init_texture(gl);
gl.bindVertexArray(null);
return {vao, n:indices.length};
}
and the code for the texture, I referenced this tutorial while I making this code
function init_texture(gl)
{
const UVCoord = new Float32Array
(
[
//First Pass
0, 0.75,
0.25, 0.75,
0.25, 0.5,
0, 0.5,
0, 0.75,
0.25, 0.5,
//Second Pass
0.25, 0.75,
0.5, 0.5,
0.5, 0.75,
0.25, 0.75,
0.25, 0.5,
0.5, 0.5,
//Third Pass
0.5, 0.75,
0.75, 0.75,
0.75, 0.5,
0.5, 0.5,
0.5, 0.75,
0.75, 0.5,
//Fourth Pass
1, 0.5,
0.75, 0.75,
1, 0.75,
1, 0.5,
0.75, 0.5,
0.75, 0.75,
//Sixth No
0.75, 0.25,
0.5, 0.5,
0.5, 0.25,
0.75, 0.25,
0.75, 0.5,
0.5, 0.5,
//Fifth No
0.75, 0.75,
0.5, 1,
0.5, 0.75,
0.75, 0.75,
0.75, 1,
0.5, 1
]
);
let UVCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, UVCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, UVCoord, gl.STATIC_DRAW);
gl.vertexAttribPointer(loc_UVCoord, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(loc_UVCoord);
let texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
new Uint8Array([0, 0, 255, 255]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
let image = new Image();
let url = "https://live.staticflickr.com/65535/49093406911_7d185dba0e_b.jpg";
requestCORSIfNotSameOrigin(image, url);
image.src = url;
image.onload = function()
{
loadTexture(gl, texture, image);
}
}
function loadTexture(gl, texture, image)
{
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.generateMipmap(gl.TEXTURE_2D);
}
....
function requestCORSIfNotSameOrigin(img, url) //https://webgl2fundamentals.org/webgl/lessons/webgl-cors-permission.html
{
if ((new URL(url)).origin !== window.location.origin)
{
img.crossOrigin = "";
}
}
....
The First problem is that the texture is not loaded at the main function this is because the loadTexure
function get started after the main function is finished so, is there anyway to load the texture at the first time of drawing the cube??
These are the pictures for above problem..
After changing the angle by pushing the arrow keys...
The second problem is that the texture is not applied properly at the right side of cube and the bottom..
By changing the texture coordinates I can see the 1, 2, 3, 4 on the cube but no matter how I editted the order of coordinates I still cannot see 5, 6 on the right face of the cube and the bottom face of the cube ... here is the texture image
And the last question is that If I want to change the faces to be mapped, do I have to modify the texture coordinates arrays or indices array or vertices array?
The First problem is that the texture is not loaded at the main function this is because the loadTexure function get started after the main function is finished so, is there anyway to load the texture at the first time of drawing the cube??
Textures are loaded asynchonously so you have about 3 choices
Wait for the texture to load before starting
Create a renderable texture, render continuously using a requestAnimationFrame loop, replace the texture contents it with the image when the image has loaded.
since your render loop would have things rendering contiunously problem solved.
Create a renderable texture, replace the texture contents it with the image when the image has loaded and render again
It looks like you're currently doing #3 but you're not rendering again after the texture loads. Inside your loadTexture
function call your render/draw function.
If you want to do #1 you need to create the Image
and set its onload
outside the rest of your code. Something like
const img = new Image();
img.onload = initRestOfCode;
img.src = urlForImage;
function initRestOfCode() { ...
The second problem is that the texture is not applied properly at the right side of cube and the bottom..
Just checking first you turned on depth test and face culling
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
But otherwise the texture coordinates don't match the vertex positions. There are 4 vertex positions per cube face but the code has 6 texture coordinates per cube face. They need to match, just 4 texture coordinates per face. Attributes in WebGL represent parallel arrays