I am trying to wrap an object with texture. The object is Quadrilateral with different side lengths. But when I wrap the object with texture, the texture is not stretching equally.
const canvas = document.querySelector('canvas');
canvas.width = 600;
canvas.height = 400;
const gl = canvas.getContext('webgl');
const mat4 = glMatrix.mat4
if (!gl) {
throw new Error('WebGL not supported');
}
xf = .5
ot = 1.2
const vertexData = [
// Front
-ot, xf, xf, // top left
ot, xf, xf, // top right
-xf, -xf, xf, // bottom left
-xf, -xf, xf, // bottom left
ot, xf, xf, // top right
xf, -xf, xf, // bottom right
];
const uvData = [
0, 0, ot,
ot, 0, ot,
0, xf, xf,
0, xf, xf,
ot, 0, ot,
xf, xf, xf,
];
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
const uvBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvData), gl.STATIC_DRAW);
// RESOURCE LOADING
// ================
function loadTexture(url) {
const texture = gl.createTexture();
const image = new Image();
requestCORSIfNotSameOrigin(image, url)
image.onload = e => {
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);
};
image.src = url;
return texture;
}
const brick = loadTexture(`https://i.ibb.co/z7YGMdK/rsz-1rsz-11uv-maptemplate.jpg`);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, brick);
// SHADER PROGRAM
// ==============
let uniformLocations;
(function shaderProgram() {
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
precision mediump float;
attribute vec3 position;
attribute vec3 uv;
varying vec3 vUV;
uniform mat4 matrix;
void main() {
gl_Position = matrix * vec4(position, 1);
vUV = uv;
}
`);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
precision mediump float;
varying vec3 vUV;
uniform sampler2D textureID;
void main() {
gl_FragColor = texture2DProj(textureID, vUV);
}
`);
gl.compileShader(fragmentShader);
console.log(gl.getShaderInfoLog(fragmentShader));
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const positionLocation = gl.getAttribLocation(program, `position`);
gl.enableVertexAttribArray(positionLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
const uvLocation = gl.getAttribLocation(program, `uv`);
gl.enableVertexAttribArray(uvLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
gl.vertexAttribPointer(uvLocation, 3, gl.FLOAT, false, 0, 0);
gl.useProgram(program);
gl.enable(gl.DEPTH_TEST);
uniformLocations = {
matrix: gl.getUniformLocation(program, `matrix`),
textureID: gl.getUniformLocation(program, 'textureID'),
};
gl.uniform1i(uniformLocations.textureID, 0);
})();
// MATRICES
// ========
const modelMatrix = mat4.create();
const viewMatrix = mat4.create();
const projectionMatrix = mat4.create();
mat4.perspective(projectionMatrix,
75 * Math.PI / 240, // vertical field-of-view (angle, radians)
canvas.width / canvas.height, // aspect W/H
1e-4, // near cull distance
1e4 // far cull distance
);
const mvMatrix = mat4.create();
const mvpMatrix = mat4.create();
mat4.translate(viewMatrix, viewMatrix, [0, 0.1, 2]);
mat4.invert(viewMatrix, viewMatrix);
// ANIMATION LOOP
// ==============
function animate() {
requestAnimationFrame(animate);
mat4.rotateX(modelMatrix, modelMatrix, 0);
mat4.rotateY(modelMatrix, modelMatrix, 0);
mat4.multiply(mvMatrix, viewMatrix, modelMatrix);
mat4.multiply(mvpMatrix, projectionMatrix, mvMatrix);
gl.uniformMatrix4fv(uniformLocations.matrix, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, vertexData.length / 3);
}
animate();
function requestCORSIfNotSameOrigin(img, url) {
if ((new URL(url, window.location.href)).origin !== window.location.origin) {
img.crossOrigin = "";
}
}
<canvas id="canvas"></canvas>
<!--
for most samples webgl-utils only provides shader compiling/linking and
canvas resizing because why clutter the examples with code that's the same in every sample.
See https://webgl2fundamentals.org/webgl/lessons/webgl-boilerplate.html
and https://webgl2fundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
for webgl-utils, m3, m4, and webgl-lessons-ui.
-->
<script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3/gl-matrix.js"></script>
This is the correct formula for the snippet above. And working well as expected.
xf = .5
ot = 1.2
const vertexData = [
// Front
-ot, xf, xf, // top left
ot, xf, xf, // top right
-xf, -xf, xf, // bottom left
-xf, -xf, xf, // bottom left
ot, xf, xf, // top right
xf, -xf, xf, // bottom right
];
const uvData = [
0, 0, 1 * ot,
1 * ot, 0, 1 * ot,
0, 1 * xf, 1 * xf,
0, 1 * xf, 1 * xf,
1 * ot, 0, ot,
1* xf, 1 * xf, 1 * xf,
];
But when I use a different shaped object I could not find a general formula for different shape objects. The example below for a different shape object.
The texture must be wrapped like this
Instead, it's wrapping like this
I used texture2Dproj and gave the z-axis. But I could not find the general formula and failed to project it correctly
Is there a general formula for different shaped objects like this Thank you in advance.