WebGL中如何实现亮度+对比度?
How to achieve brightness + contrast in WebGL?
我正在尝试应用类似于 this example 的 window 级别,将鼠标拖到图像上以查看亮度 + 对比度效果。
但我想使用 WebGL 实现相同的效果,因为 GPU 处理它们的速度比 CPU 快。
这是我所做的:
顶点着色器:
attribute vec3 attrVertexPos;
attribute vec2 attrTextureCoord;
varying highp vec2 vTextureCoord;
void main(void) {
gl_Position = vec4(attrVertexPos, 0.81);
vTextureCoord = attrTextureCoord;
}
片段着色器:
#ifdef GL_ES
precision highp float;
#endif
varying highp vec2 vTextureCoord;
uniform sampler2D uImage;
uniform float brightnessFactor;
uniform float contrastFactor;
void main(void) {
gl_FragColor = texture2D(uImage, vTextureCoord) *(brightnessFactor/contrastFactor);
}
但是根据上面给出的link,它并没有像预期的那样工作。
这是 Javascript 代码:
var isMouseDown = false;
document.getElementById('canvas').onmousedown = function() { isMouseDown = true };
document.getElementById('canvas').onmouseup = function() { isMouseDown = false };
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
var intWidth = $('canvas').innerWidth();
var intHeight = $('canvas').innerHeight();
var x = (e.clientX/intWidth)*100;
var y = (e.clientY/intHeight)*100;
console.log(x/10 + ' :: ' + y/10);
brightnessVal = x/10;
gl.uniform1f(gl.getUniformLocation(program, "contrastFactor"), brightnessVal);
contrastVal = y/10;
gl.uniform1f(gl.getUniformLocation(program, "brightnessFactor"), contrastVal);
}
};
区别在于像素操作。您只是乘以一个系数(另外,您使用的系数名称不正确),在链接示例中,发生了一些更复杂的事情。源图像的某些颜色范围(由其中心和宽度描述)扩展到完整的 [0,1] 范围:
newColor = (oldColor - rangeCenter) / rangeWidth + 0.5
我不知道为什么要这样做(该页面是医学影像库的示例,我对此一无所知)。不过,我已经设法将公式移植到您的代码中。一、片段着色器变化:
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
varying highp vec2 vTextureCoord;
uniform sampler2D uImage;
// New uniforms
uniform float rangeCenter;
uniform float rangeWidth;
void main(void) {
vec3 c = texture2D(uImage, vTextureCoord).rgb;
gl_FragColor = vec4(
// The above formula, clamped to [0, 1]
clamp((c - windowCenter) / windowWidth + 0.5, 0.0, 1.0),
// Also, let's not screw alpha
1
);
}
至于 JavaScript,我冒昧地让它更接近链接示例:
var isMouseDown = false,
// Initially we set "equality" colour mapping
rangeCenter = 0.5,
ragneWidth = 1,
lastX, lastY;
document.getElementById('canvas').onmousedown = function(e) {
lastX = e.clientX;
lastY = e.clientY;
isMouseDown = true
};
document.getElementById('canvas').onmouseup = function() {
isMouseDown = false
};
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
var intWidth = $('canvas').innerWidth();
var intHeight = $('canvas').innerHeight();
// Change params according to cursor coords delta
rangeWidth += (e.clientX - lastX) / intWidth;
rangeCenter += (e.clientY - lastY) / intHeight;
gl.uniform1f(
gl.getUniformLocation(program, "rangeWidth"),
rangeWidth
);
gl.uniform1f(
gl.getUniformLocation(program, "rangeCenter"),
rangeCenter
);
lastX = e.clientX;
lastY = e.clientY;
}
};
旧答案:
The problem is that, according to your code, you don't redraw the
picture after mousemove
event. Just insert a draw call (or several
draw calls) with appropriate parameters after setting uniforms. For
example, it may look like this:
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
// your code
gl.drawArrays(/* params, e.g gl.TRIANGLES, 0 and vertex count */);
}
};
A better way would be using requestAnimationFrame
callback to
redraw. To do that, define a draw
function, which will make the draw
call for you and use it a requestAnimationFrame
callback:
function draw () {
/* your draw calls here */
}
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
// your code
requestAnimationFrame(draw);
}
};
P.S。另外,我很感兴趣,这个 #ifdef GL_ES
东西是从哪里来的?根据GL_ES
宏设置highp
精度是不正确。硬件不必根据标准支持它。正确的方法是:
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
我正在尝试应用类似于 this example 的 window 级别,将鼠标拖到图像上以查看亮度 + 对比度效果。
但我想使用 WebGL 实现相同的效果,因为 GPU 处理它们的速度比 CPU 快。
这是我所做的:
顶点着色器:
attribute vec3 attrVertexPos;
attribute vec2 attrTextureCoord;
varying highp vec2 vTextureCoord;
void main(void) {
gl_Position = vec4(attrVertexPos, 0.81);
vTextureCoord = attrTextureCoord;
}
片段着色器:
#ifdef GL_ES
precision highp float;
#endif
varying highp vec2 vTextureCoord;
uniform sampler2D uImage;
uniform float brightnessFactor;
uniform float contrastFactor;
void main(void) {
gl_FragColor = texture2D(uImage, vTextureCoord) *(brightnessFactor/contrastFactor);
}
但是根据上面给出的link,它并没有像预期的那样工作。
这是 Javascript 代码:
var isMouseDown = false;
document.getElementById('canvas').onmousedown = function() { isMouseDown = true };
document.getElementById('canvas').onmouseup = function() { isMouseDown = false };
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
var intWidth = $('canvas').innerWidth();
var intHeight = $('canvas').innerHeight();
var x = (e.clientX/intWidth)*100;
var y = (e.clientY/intHeight)*100;
console.log(x/10 + ' :: ' + y/10);
brightnessVal = x/10;
gl.uniform1f(gl.getUniformLocation(program, "contrastFactor"), brightnessVal);
contrastVal = y/10;
gl.uniform1f(gl.getUniformLocation(program, "brightnessFactor"), contrastVal);
}
};
区别在于像素操作。您只是乘以一个系数(另外,您使用的系数名称不正确),在链接示例中,发生了一些更复杂的事情。源图像的某些颜色范围(由其中心和宽度描述)扩展到完整的 [0,1] 范围:
newColor = (oldColor - rangeCenter) / rangeWidth + 0.5
我不知道为什么要这样做(该页面是医学影像库的示例,我对此一无所知)。不过,我已经设法将公式移植到您的代码中。一、片段着色器变化:
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
varying highp vec2 vTextureCoord;
uniform sampler2D uImage;
// New uniforms
uniform float rangeCenter;
uniform float rangeWidth;
void main(void) {
vec3 c = texture2D(uImage, vTextureCoord).rgb;
gl_FragColor = vec4(
// The above formula, clamped to [0, 1]
clamp((c - windowCenter) / windowWidth + 0.5, 0.0, 1.0),
// Also, let's not screw alpha
1
);
}
至于 JavaScript,我冒昧地让它更接近链接示例:
var isMouseDown = false,
// Initially we set "equality" colour mapping
rangeCenter = 0.5,
ragneWidth = 1,
lastX, lastY;
document.getElementById('canvas').onmousedown = function(e) {
lastX = e.clientX;
lastY = e.clientY;
isMouseDown = true
};
document.getElementById('canvas').onmouseup = function() {
isMouseDown = false
};
document.getElementById('canvas').onmousemove = function(e) {
if (isMouseDown) {
var intWidth = $('canvas').innerWidth();
var intHeight = $('canvas').innerHeight();
// Change params according to cursor coords delta
rangeWidth += (e.clientX - lastX) / intWidth;
rangeCenter += (e.clientY - lastY) / intHeight;
gl.uniform1f(
gl.getUniformLocation(program, "rangeWidth"),
rangeWidth
);
gl.uniform1f(
gl.getUniformLocation(program, "rangeCenter"),
rangeCenter
);
lastX = e.clientX;
lastY = e.clientY;
}
};
旧答案:
The problem is that, according to your code, you don't redraw the picture after
mousemove
event. Just insert a draw call (or several draw calls) with appropriate parameters after setting uniforms. For example, it may look like this:document.getElementById('canvas').onmousemove = function(e) { if (isMouseDown) { // your code gl.drawArrays(/* params, e.g gl.TRIANGLES, 0 and vertex count */); } };
A better way would be using
requestAnimationFrame
callback to redraw. To do that, define adraw
function, which will make the draw call for you and use it arequestAnimationFrame
callback:function draw () { /* your draw calls here */ } document.getElementById('canvas').onmousemove = function(e) { if (isMouseDown) { // your code requestAnimationFrame(draw); } };
P.S。另外,我很感兴趣,这个 #ifdef GL_ES
东西是从哪里来的?根据GL_ES
宏设置highp
精度是不正确。硬件不必根据标准支持它。正确的方法是:
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif