如何在WebGL中实现亮度+对比度?

时间:2016-06-20 12:53:09

标签: opengl-es webgl

我正在尝试应用类似于this example的窗口级别,将鼠标拖到图像上以查看亮度+对比度效果。

但我希望使用WebGL实现相同目标,因为GPU将比CPU更快地处理它们。

这就是我所做的:

顶点着色器:

attribute vec3 attrVertexPos;
attribute vec2 attrTextureCoord;

varying highp vec2 vTextureCoord;

void main(void) {
    gl_Position = vec4(attrVertexPos, 0.81);
    vTextureCoord = attrTextureCoord;
}

Fragment Shader:

#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);
}

但根据上面给出的链接,它无法正常工作。

这是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);
    }
};

1 个答案:

答案 0 :(得分:3)

不同之处在于像素操作。你只是乘以一个系数(也就是你使用的系数的名称是不正确的),就像在链接的例子中那样,发生了一些更复杂的事情。源图像的某些颜色范围(由其中心和宽度描述)扩展到完整[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;
    }
};

旧答案:

  

问题在于,根据您的代码,您不会重绘   mousemove事件后的图片。只需插入一个绘制调用(或几个   设置制服后,使用适当的参数绘制调用。对于   例如,它可能如下所示:

document.getElementById('canvas').onmousemove = function(e) {
    if (isMouseDown) {
        // your code

        gl.drawArrays(/* params, e.g gl.TRIANGLES, 0 and vertex count */); 
    }
};
     

更好的方法是使用requestAnimationFrame回调   重绘。为此,请定义一个draw函数,该函数将进行绘制   打电话给你并使用requestAnimationFrame回调:

function draw () {
    /* your draw calls here */
}

document.getElementById('canvas').onmousemove = function(e) {
    if (isMouseDown) {
        // your code

        requestAnimationFrame(draw);
    }
};

P.S。另外,我很有兴趣,这个#ifdef GL_ES来自哪里? 不正确根据highp宏设置GL_ES精度。硬件不必根据标准支持它。正确的方法是:

#ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
#else
    precision mediump float;
#endif