Skip to main content

Draw a Point at Mouse Click Position_WebGL Notes 3

Free2015-12-22#JS#WebGL#webgl坐标系转换#点击canvas画一个点#canvas获取鼠标位置

canvas coordinate system and WebGL coordinate system are different, need to do coordinate conversion

Preface

In [previous notes](/articles/attribute 变量与顶点着色器-webgl 笔记 2/), we achieved dynamically setting point position through attribute variables. To draw a point at mouse click position, just need to get the coordinates at mouse click position, the biggest problem is coordinate conversion

1. Get canvas Coordinates

Add event handler, then find it from event object, as follows:

// webgl is reference to canvas element
webgl.addEventListener('click', function(e) {
    var x = e.offsetX;
    var y = e.offsetY;
}

Through event object's offsetX/Y attributes can get coordinate values (x, y) of mouse click position in canvas coordinate system, click canvas top-left corner, get (0, 0)

2. canvas Coordinates to WebGL Coordinates

In WebGL origin is at canvas center, x-axis positive to right, y-axis positive upward, z-axis positive from screen pointing to face, conversion method from canvas coordinates to WebGL coordinates is simple calculation, as follows:

var x = (e.offsetX - webgl.width / 2) / (webgl.width / 2);
var y = (webgl.height / 2 - e.offsetY) / (webgl.height / 2);

Simple derivation process as follows:

1. Calculate x'
If point p is on left side of y-axis, then x' = (width/2 - x) * -1 = x - width/2
Then divide by x-axis negative half-axis length to get value in [0-1] range
x' = (x - width/2) / width/2
If p is on right side of y-axis, then x' = x - width/2
Then divide by x-axis positive half-axis length to get value in [0-1] range
x' = (x - width/2) / width/2
So x' = (x - width/2) / width/2
2. Calculate y'
If p is on upper side of x-axis, then y' = height/2 - y
Then divide by y-axis positive half-axis length to get value in [0-1] range
y' = (height/2 - y) / height/2
If p is on lower side of x-axis, then y' = (y - height/2) * -1 = height/2 - y
Then divide by y-axis negative half-axis length to get value in [0-1] range
y' = (height/2 - y) / height/2
So y' = (height/2 - y) / height/2

3. Draw Point

Complete code as follows:

webgl.addEventListener('click', function(e) {
    // Convert coordinates
    var x = (e.offsetX - webgl.width / 2) / (webgl.width / 2);
    var y = (webgl.height / 2 - e.offsetY) / (webgl.height / 2);
    console.log(x, y);

    // 2. Assign value to attribute variable
    // Get storage location of attribute variable
    var a_Position = gl.getAttribLocation(glUtil.program, 'a_Position');
    if (a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return;
    }
    // Pass vertex position to attribute variable
    gl.vertexAttrib3f(a_Position, x, y, 0.0);

    // Clear canvas
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Draw point
    gl.drawArrays(gl.POINTS, 0, 1);
});

Note: Before drawing point each time we perform clear operation, if comment out clear, will find after clicking black background and previous point are both gone, because WebGL uses color buffer, drawing operations in WebGL system are actually performed in color buffer, after drawing completes system displays buffer content on screen, then color buffer will be reset, content in it will be lost, reset color is vec4(0.0, 0.0, 0.0, 0.0), so canvas becomes transparent

P.S. Actually above clearColor can be removed, because gl.clear(gl.COLOR_BUFFER_BIT) will by default use value specified by previous gl.clearColor, if none, use default color vec4(0.0, 0.0, 0.0, 0.0)

4. DEMO

For complete examples containing above code, please see: http://www.ayqy.net/temp/webgl/attribute-clickit/index.html

5. Summary

Currently achieved effect is: click where draw point there, no matter how click, only one point will appear

If want to keep historical points, currently can use array to record historical points, then loop gl.drawArrays(gl.POINTS, 0, 1); to draw all points, but doing this seems too silly, is there a method to draw multiple points at once? Yes, but needs to cooperate with buffer use, is slightly later content

Learned for so long still drawing points, to make it slightly more interesting, next note we introduce something flashier—setting point color, dot dot dot dot out brilliant starry sky:-)

References

  • "WebGL Programming Guide"

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment