如何使用 gl_Position 以编程方式平移纹理
How to pan a texture programatically using gl_Position
我可以在此 fiddle 中轻松缩放纹理,但无法正确平移。
这是着色器的代码片段:
var vertexShader = createVertexShader([
'attribute vec3 attrVertexPos;',
'attribute vec2 attrTextureCoord;',
'varying highp vec2 vTextureCoord;',
'uniform float zoomFactor;',
'uniform vec2 panCoord;',
'void main(void) {',
'\tgl_Position = vec4(attrVertexPos.xy + panCoord.xy, 0, zoomFactor);',
'\tvTextureCoord = attrTextureCoord;',
'}'
].join('\n'));
//create and compile Fragment Shader
var fragmentShader = createFragmentShader([
'#ifdef GL_FRAGMENT_PRECISION_HIGH',
'precision highp float;',
'#else',
'precision mediump float;',
'#endif',
'varying highp vec2 vTextureCoord;',
'uniform sampler2D uImage;',
'void main(void) {',
'\tgl_FragColor = texture2D(uImage, vTextureCoord);',
'}'
].join('\n'));
Javascript代码:
document.getElementById('canvas').onmousedown = function(e) {
if(startX === undefined) {
startX = e.clientX;
startY = e.clientY;
} else {
startX = lastX;
startY = lastY;
}
isMouseDown = true;
};
document.getElementById('canvas').onmouseup = function() {
isMouseDown = false;
previousTranslation[0] = xVal/100*zoomFactor;
previousTranslation[1] = yVal/100*zoomFactor;
};
document.getElementById('canvas').onmouseout = function() {
isMouseDown = false;
};
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
xVal = (lastX-startX)/canvas.width*100;
yVal = (startY-lastY)/canvas.height*100;
console.log(xVal/100*2.0 + ',' +yVal/100*2.0);
gl.uniform2fv(pan, new Float32Array([previousTranslation[0] + xVal/100*zoomFactor, previousTranslation[1] + yVal/100*zoomFactor]));
}
};
我认为 javascript 方面可以做一些事情,因为着色器看起来不错。有什么建议吗?
错误的发生是因为你试图将一个 vec4 写入一个浮点数,但这是行不通的。 float 与 vec4 相乘得到 vec4,因此你有这样的东西:
gl_Position.x = aVertexPosition.x * u_CosB - aVertexPosition.y * u_SinB
float = float * vec4 - float * vec4
编辑
如果这真的是关于平移(移动对象),那么我不完全理解为什么会涉及到 sin 和 cos 项。另外:为什么要根据y坐标修改x坐标?只有在进行一些轮换(不是平移)时才需要这样做。最后,对象根本不可见,因为你将所有顶点的y坐标设置为0,这意味着它们被折叠成一条线。
所以为了实现平移,代码可能看起来像这样:
//Contains offset in normalized device coordinates along x and y direction
uniform vec2 pan;
attribute vec4 aVertexPosition;
void main()
{
gl_Position = vec4(aVertexPosition.xy + pan.xy, 0, 1.0);
}
编辑 2
你在onmousemove
中计算平底锅的方式是错误的。您必须计算到鼠标按下位置的距离(不确定您现在在计算什么):
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
var xVal = (lastX - e.clientX)/canvas.width;
var yVal = (lastY - e.clientY)/canvas.height;
gl.uniform2fv(pan, new Float32Array([xVal, yVal]));
}
};
当你需要的时候faster/slower用一个常数乘以xVal
和yVal
。当平底锅进入错误的方向时,您可能必须反转其中一个方向。
编辑 3
mousedown 功能现在没有多大意义?为什么第一次点击后它的行为会有所不同?唯一的代码应该是:
document.getElementById('canvas').onmousedown = function(e) {
startX = e.clientX;
startY = e.clientY;
isMouseDown = true;
};
此外,第二次调用鼠标弹起函数时,您覆盖了 previousTranslation
的值,而不是向其添加当前翻译。正确:
document.getElementById('canvas').onmouseup = function() {
isMouseDown = false;
if (previousTranslation[0] == undefined)
{
previousTranslation[0] = 0.0;
previousTranslation[1] = 0.0;
}
previousTranslation[0] += xVal/100*zoomFactor;
previousTranslation[1] += yVal/100*zoomFactor;
};
我可以在此 fiddle 中轻松缩放纹理,但无法正确平移。
这是着色器的代码片段:
var vertexShader = createVertexShader([
'attribute vec3 attrVertexPos;',
'attribute vec2 attrTextureCoord;',
'varying highp vec2 vTextureCoord;',
'uniform float zoomFactor;',
'uniform vec2 panCoord;',
'void main(void) {',
'\tgl_Position = vec4(attrVertexPos.xy + panCoord.xy, 0, zoomFactor);',
'\tvTextureCoord = attrTextureCoord;',
'}'
].join('\n'));
//create and compile Fragment Shader
var fragmentShader = createFragmentShader([
'#ifdef GL_FRAGMENT_PRECISION_HIGH',
'precision highp float;',
'#else',
'precision mediump float;',
'#endif',
'varying highp vec2 vTextureCoord;',
'uniform sampler2D uImage;',
'void main(void) {',
'\tgl_FragColor = texture2D(uImage, vTextureCoord);',
'}'
].join('\n'));
Javascript代码:
document.getElementById('canvas').onmousedown = function(e) {
if(startX === undefined) {
startX = e.clientX;
startY = e.clientY;
} else {
startX = lastX;
startY = lastY;
}
isMouseDown = true;
};
document.getElementById('canvas').onmouseup = function() {
isMouseDown = false;
previousTranslation[0] = xVal/100*zoomFactor;
previousTranslation[1] = yVal/100*zoomFactor;
};
document.getElementById('canvas').onmouseout = function() {
isMouseDown = false;
};
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
xVal = (lastX-startX)/canvas.width*100;
yVal = (startY-lastY)/canvas.height*100;
console.log(xVal/100*2.0 + ',' +yVal/100*2.0);
gl.uniform2fv(pan, new Float32Array([previousTranslation[0] + xVal/100*zoomFactor, previousTranslation[1] + yVal/100*zoomFactor]));
}
};
我认为 javascript 方面可以做一些事情,因为着色器看起来不错。有什么建议吗?
错误的发生是因为你试图将一个 vec4 写入一个浮点数,但这是行不通的。 float 与 vec4 相乘得到 vec4,因此你有这样的东西:
gl_Position.x = aVertexPosition.x * u_CosB - aVertexPosition.y * u_SinB
float = float * vec4 - float * vec4
编辑
如果这真的是关于平移(移动对象),那么我不完全理解为什么会涉及到 sin 和 cos 项。另外:为什么要根据y坐标修改x坐标?只有在进行一些轮换(不是平移)时才需要这样做。最后,对象根本不可见,因为你将所有顶点的y坐标设置为0,这意味着它们被折叠成一条线。
所以为了实现平移,代码可能看起来像这样:
//Contains offset in normalized device coordinates along x and y direction
uniform vec2 pan;
attribute vec4 aVertexPosition;
void main()
{
gl_Position = vec4(aVertexPosition.xy + pan.xy, 0, 1.0);
}
编辑 2
你在onmousemove
中计算平底锅的方式是错误的。您必须计算到鼠标按下位置的距离(不确定您现在在计算什么):
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
var xVal = (lastX - e.clientX)/canvas.width;
var yVal = (lastY - e.clientY)/canvas.height;
gl.uniform2fv(pan, new Float32Array([xVal, yVal]));
}
};
当你需要的时候faster/slower用一个常数乘以xVal
和yVal
。当平底锅进入错误的方向时,您可能必须反转其中一个方向。
编辑 3
mousedown 功能现在没有多大意义?为什么第一次点击后它的行为会有所不同?唯一的代码应该是:
document.getElementById('canvas').onmousedown = function(e) {
startX = e.clientX;
startY = e.clientY;
isMouseDown = true;
};
此外,第二次调用鼠标弹起函数时,您覆盖了 previousTranslation
的值,而不是向其添加当前翻译。正确:
document.getElementById('canvas').onmouseup = function() {
isMouseDown = false;
if (previousTranslation[0] == undefined)
{
previousTranslation[0] = 0.0;
previousTranslation[1] = 0.0;
}
previousTranslation[0] += xVal/100*zoomFactor;
previousTranslation[1] += yVal/100*zoomFactor;
};