Я использую холст WebGL2, и мне хотелось бы, чтобы изображение, которое я на нем нарисовал, имело такое же преобразование.
Для достижения этой цели , я считаю, что мне нужен вершинный шейдер, чтобы взять матрицу и умножить ее:
const matrixLocation = gl.getUniformLocation(program, "u_matrix");
gl.uniformMatrix4fv(matrixLocation, false, new Float32Array(matrix));
Сейчас я застрял в выяснении того, каким должно быть значение матрицы в моем коде. Я пытался прочитать, как устроено преобразование Matrix3d, и перестроить матрицу на основе этого, но безуспешно.
Как я могу использовать matrix3d< /code> преобразование в шейдере WebGL2 здесь?
Изменить: полный рабочий пример добавлен по запросу в комментариях.
#image {
transform: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0);
transform-origin: 0 0;
}
img, canvas {
border: 1px solid #000;
}
// Set up matrices
// Based on: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0)
const cssMatrix = new Float32Array([1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0]);
const identityMatrix = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
// identityMatrix works correctly while the cssMatrix does not
const matrixArray = cssMatrix;
// const matrixArray = identityMatrix;
// Set up shaders
const vertexShaderSource = `#version 300 es
in vec2 a_position;
in vec2 a_texCoord;
uniform vec2 u_resolution;
uniform mat4 u_matrix;
out vec2 v_texCoord;
void main() {
vec2 zeroToOne = a_position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = u_matrix*vec4(clipSpace * vec2(1, -1), 0,1);
v_texCoord = a_texCoord;
}`;
const fragmentShaderSource = `#version 300 es
precision highp float;
uniform sampler2D u_image;
in vec2 v_texCoord;
out vec4 outColor;
void main() {
outColor = texture(u_image, v_texCoord);
}`;
// Load the test image
const img = document.getElementById("image");
img.src = "https://i.imgur.com/NIt86ft.png";
img.onload = () => renderImg(img);
// Rest of this code is boilerplate based off of
// https://webgl2fundamentals.org/webgl/lessons/webgl-image-processing.html
function createProgram(
gl, shaders, opt_attribs, opt_locations, opt_errorCallback) {
const errFn = opt_errorCallback || console.error;
const program = gl.createProgram();
shaders.forEach(function(shader) {
gl.attachShader(program, shader);
});
if (opt_attribs) {
opt_attribs.forEach(function(attrib, ndx) {
gl.bindAttribLocation(
program,
opt_locations ? opt_locations[ndx] : ndx,
attrib);
});
}
gl.linkProgram(program);
// Check the link status
const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
// something went wrong with the link
const lastError = gl.getProgramInfoLog(program);
errFn('Error in program linking:' + lastError);
gl.deleteProgram(program);
return null;
}
return program;
}
function loadShader(gl, shaderSource, shaderType, opt_errorCallback) {
const errFn = opt_errorCallback || console.error;
// Create the shader object
const shader = gl.createShader(shaderType);
// Load the shader source
gl.shaderSource(shader, shaderSource);
// Compile the shader
gl.compileShader(shader);
// Check the compile status
const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
// Something went wrong during compilation; get the error
const lastError = gl.getShaderInfoLog(shader);
console.error('*** Error compiling shader \'' + shader + '\':' + lastError + `\n` + shaderSource.split('\n').map((l,i) => `${i + 1}: ${l}`).join('\n'));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgramFromSources(
gl, shaderSources, opt_attribs, opt_locations, opt_errorCallback) {
const shaders = [];
const defaultShaderType = [
'VERTEX_SHADER',
'FRAGMENT_SHADER',
];
for (let ii = 0; ii < shaderSources.length; ++ii) {
shaders.push(loadShader(
gl, shaderSources[ii], gl[defaultShaderType[ii]], opt_errorCallback));
}
return createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback);
}
function resizeCanvasToDisplaySize(canvas, multiplier) {
multiplier = multiplier || 1;
const width = canvas.clientWidth * multiplier | 0;
const height = canvas.clientHeight * multiplier | 0;
if (canvas.width !== width || canvas.height !== height) {
canvas.width = width;
canvas.height = height;
return true;
}
return false;
}
function renderImg(image) {
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl2");
if (!gl)
return;
var program = createProgramFromSources(gl, [vertexShaderSource, fragmentShaderSource]);
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
var texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
var imageLocation = gl.getUniformLocation(program, "u_image");
var matrixLocation = gl.getUniformLocation(program, "u_matrix");
// Create a vertex array object (attribute state)
var vao = gl.createVertexArray();
// and make it the one we're currently working with
gl.bindVertexArray(vao);
// Create a buffer and put a single pixel space rectangle in
// it (2 triangles)
var positionBuffer = gl.createBuffer();
// Turn on the attribute
gl.enableVertexAttribArray(positionAttributeLocation);
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
// provide texture coordinates for the rectangle.
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0,
]), gl.STATIC_DRAW);
// Turn on the attribute
gl.enableVertexAttribArray(texCoordAttributeLocation);
// Tell the attribute how to get data out of texCoordBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
texCoordAttributeLocation, size, type, normalize, stride, offset);
// Create a texture.
var texture = gl.createTexture();
// make unit 0 the active texture uint
// (ie, the unit all other texture commands will affect
gl.activeTexture(gl.TEXTURE0 + 0);
// Bind it to texture unit 0's 2D bind point
gl.bindTexture(gl.TEXTURE_2D, texture);
// Set the parameters so we don't need mips and so we're not filtering
// and we don't repeat at the edges.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
// Upload the image into the texture.
var mipLevel = 0; // the largest mip
var internalFormat = gl.RGBA; // format we want in the texture
var srcFormat = gl.RGBA; // format of data we are supplying
var srcType = gl.UNSIGNED_BYTE; // type of data we are supplying
gl.texImage2D(gl.TEXTURE_2D,
mipLevel,
internalFormat,
srcFormat,
srcType,
image);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
setRectangle(gl, 0, 0, image.width, image.height);
resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(program);
gl.bindVertexArray(vao);
gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height);
gl.uniform1i(imageLocation, 0);
gl.uniformMatrix4fv(matrixLocation, false, matrixArray);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2,
]), gl.STATIC_DRAW);
}
Сейчас у меня есть преобразование CSS Matrix3d, которое мне нравится, скажем, например, следующее: [code]transform: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0); transform-origin: 0 0; [/code] Я использую холст WebGL2, и мне хотелось бы, чтобы изображение, которое я на нем нарисовал, имело такое же преобразование. Для достижения этой цели , я считаю, что мне нужен вершинный шейдер, чтобы взять матрицу и умножить ее: [code]#version 300 es
in vec2 a_position; in vec2 a_texCoord; uniform vec2 u_resolution; out vec2 v_texCoord;
gl_Position = u_matrix*vec4(clipSpace * vec2(1, -1), 0, 1); v_texCoord = a_texCoord; } [/code] Затем я могу передать матрицу шейдеру в моем коде JavaScript: [code]const matrixLocation = gl.getUniformLocation(program, "u_matrix"); gl.uniformMatrix4fv(matrixLocation, false, new Float32Array(matrix)); [/code] Сейчас я застрял в выяснении того, каким должно быть значение матрицы в моем коде. Я пытался прочитать, как устроено преобразование Matrix3d, и перестроить матрицу на основе этого, но безуспешно. Как я могу использовать matrix3d< /code> преобразование в шейдере WebGL2 здесь? Изменить: полный рабочий пример добавлен по запросу в комментариях.
// Based on: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0) const cssMatrix = new Float32Array([1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0]); const identityMatrix = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
// identityMatrix works correctly while the cssMatrix does not const matrixArray = cssMatrix; // const matrixArray = identityMatrix;
// Set up shaders
const vertexShaderSource = `#version 300 es
in vec2 a_position; in vec2 a_texCoord;
uniform vec2 u_resolution; uniform mat4 u_matrix; out vec2 v_texCoord;
// Check the link status const linked = gl.getProgramParameter(program, gl.LINK_STATUS); if (!linked) { // something went wrong with the link const lastError = gl.getProgramInfoLog(program); errFn('Error in program linking:' + lastError);
function renderImg(image) { const canvas = document.getElementById("canvas"); const gl = canvas.getContext("webgl2"); if (!gl) return;
var program = createProgramFromSources(gl, [vertexShaderSource, fragmentShaderSource]);
var positionAttributeLocation = gl.getAttribLocation(program, "a_position"); var texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord"); var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); var imageLocation = gl.getUniformLocation(program, "u_image"); var matrixLocation = gl.getUniformLocation(program, "u_matrix");
// Create a vertex array object (attribute state) var vao = gl.createVertexArray();
// and make it the one we're currently working with gl.bindVertexArray(vao);
// Create a buffer and put a single pixel space rectangle in // it (2 triangles) var positionBuffer = gl.createBuffer();
// Turn on the attribute gl.enableVertexAttribArray(positionAttributeLocation);
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) var size = 2; // 2 components per iteration var type = gl.FLOAT; // the data is 32bit floats var normalize = false; // don't normalize the data var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position var offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( positionAttributeLocation, size, type, normalize, stride, offset);
// provide texture coordinates for the rectangle. var texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, ]), gl.STATIC_DRAW);
// Turn on the attribute gl.enableVertexAttribArray(texCoordAttributeLocation);
// Tell the attribute how to get data out of texCoordBuffer (ARRAY_BUFFER) var size = 2; // 2 components per iteration var type = gl.FLOAT; // the data is 32bit floats var normalize = false; // don't normalize the data var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position var offset = 0; // start at the beginning of the buffer gl.vertexAttribPointer( texCoordAttributeLocation, size, type, normalize, stride, offset);
// Create a texture. var texture = gl.createTexture();
// make unit 0 the active texture uint // (ie, the unit all other texture commands will affect gl.activeTexture(gl.TEXTURE0 + 0);
// Bind it to texture unit 0's 2D bind point gl.bindTexture(gl.TEXTURE_2D, texture);
// Set the parameters so we don't need mips and so we're not filtering // and we don't repeat at the edges. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
// Upload the image into the texture. var mipLevel = 0; // the largest mip var internalFormat = gl.RGBA; // format we want in the texture var srcFormat = gl.RGBA; // format of data we are supplying var srcType = gl.UNSIGNED_BYTE; // type of data we are supplying gl.texImage2D(gl.TEXTURE_2D, mipLevel, internalFormat, srcFormat, srcType, image);
Сейчас у меня есть преобразование CSS Matrix3d, которое мне нравится, скажем, например, следующее:
transform: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0);
transform-origin: 0 0;
Сейчас у меня есть преобразование CSS Matrix3d, которое мне нравится, скажем, например, следующее:
transform: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0);
transform-origin: 0 0;
Сейчас у меня есть преобразование CSS Matrix3d, которое мне нравится, скажем, например, следующее:
transform: matrix3d(1.3453,0.1357,0.0,0.0003,0.2096,1.3453,0.0,0.0003,0.0,0.0,1.0,0.0,-100.0,-100.0,0.0,1.0);
transform-origin: 0 0;
Я пытаюсь вычислить некоторые производные результатов нейронной сети. Если быть точным, мне нужна матрица Якобиана функции, представленной нейронной сетью, и вторая производная функции по ее входным данным.
Я хочу умножить производную якобиана с...
Я пытаюсь вычислить некоторые производные результатов нейронной сети. Если быть точным, мне нужна матрица Якобиана функции, представленной нейронной сетью, и вторая производная функции по ее входным данным.
Я хочу умножить производную якобиана с...