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"
No comments yet. Be the first to share your thoughts.