对应《WebGL编程指南》代码:04-ClickPoint
要点:注册js事件
知识点
为何使用匿名函数?
先看示例:
1 2 3 4 canvas.onmousedown = function (event ) { click(event, gl, canvas, a_Position); };
当你要画一个点时,需要传入三个变量(gl、canvas、a_Position),这三个变量是定义在main()
函数中的局部变量。
当用户点击鼠标时,浏览器会自动调用注册到<canvas>
的ommousedown属性上的函数,并传入event
(后面简写为‘e’)参数,通常你会这样写:
1 2 canvas.onmousedown = mousedown function mousedown (e ) { ... }
但是,这样写会出现一个问题,定义在main()函数外部的mousedown()函数就无法获取 main函数中的局部变量,而使用匿名函数就可以解决这个问题。
当用户点击鼠标后,程序先调用匿名函数function(e),再调用匿名函数中的click()传入参数。
当然,这里也可以使用ES6
的箭头函数更加简洁:
1 canvas.onmousedown = ev => click(ev, gl, canvas, a_Position);
坐标转换
区别:
①客户区原点(0,0) :位于浏览器视图区的左上角顶点处
②canvas原点 :位于绘图区左上角顶点处(…)
③WebGL原点 :位于绘图区中心点
1 2 3 4 5 var rect = ev.target.getBoundingClientRect();x = ((x - rect.left) - canvas.height / 2 ) / (canvas.height / 2 ); y = (canvas.width / 2 - (y - rect.top)) / (canvas.width / 2 );
rect.left:原点在客户区中x坐标
使用*{margin:0;padding:0;list-style: none;}清除默认样式后,与客户区原点重和,即(0,0)
rect.top:原点在客户区中y坐标
若不清除默认样式后,canvas原点可能位于(8,8),仅限博主浏览器测试。
x
相对于浏览器左上角顶点处的鼠标横轴位置
y
相对于浏览器左上角顶点处的鼠标纵轴位置
x - rect.left:鼠标点击处相对于canvas原点位置
将(x,y)转换成canvas坐标系的坐标
y - rect.top:鼠标点击处相对于canvas原点位置
将(x,y)转换成canvas坐标系的坐标
canvas.height/width
绘图区的宽高
(canvas.height/width) / 2
绘图区的中心点
(x - rect.left) - canvas.width / 2
WebGL系统的原点
canvas.height / 2 - (y - rect.top)
WebGL系统的原点
((x - rect.left) - canvas.width / 2) / (canvas.width / 2)
将canvas坐标系下的坐标转换为WebGL坐标系中,最终渲染位置
(canvas.height / 2 - (y - rect.top))
将canvas坐标系下的坐标转换为WebGL坐标系中,最终渲染位置
为啥用g_points.push()
因为WebGL系统中的绘制操作实际上是在颜色缓冲区中进行绘制,绘制结束后系统将缓冲区中的内容显示在屏幕上,然后颜色缓冲区就会被重置,其中内容就会丢失。也由此,每次点击后,浏览器会重新绘制之前的并绘制新点击的。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > ClickedPoints</title > <style > /* body { margin :0 ; padding :0 ; } */ </style > </head > <body onload ="main()" > <canvas id ="webgl" width ="400" height ="400" > Please use the browser supporting "canvas". </canvas > <script src ="../lib/webgl-utils.js" > </script > <script src ="../lib/webgl-debug.js" > </script > <script src ="../lib/cuon-utils.js" > </script > <script src ="ClickedPoints.js" > </script > </body > </html >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 var VSHADER_SOURCE = 'attribute vec4 a_Position;' + 'void main(){' + 'gl_Position=a_Position;' + 'gl_PointSize=15.0;' + '}' ; var FSHADER_SOURCE= 'void main(){' + 'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);' + '}' ; function main ( ) { var canvas = document .getElementById("webgl" ); if (!canvas){ console .log("Failed to retrieve the <canvas> element" ); return ; } var gl = getWebGLContext(canvas); if (!gl){ console .log("Failed to get the rendering context for WebGL" ); return ; } if (!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){ console .log("Failed to initialize shaders." ); return ; } var a_Position = gl.getAttribLocation(gl.program, 'a_Position' ); if (a_Position < 0 ){ console .log("Failed to get the storage location of a_Position" ); return ; } canvas.onmousedown = ev => click(ev, gl, canvas, a_Position); gl.clearColor(0.0 , 1.0 , 0.0 , 1.0 ); gl.clear(gl.COLOR_BUFFER_BIT); } var g_points = []; function click (ev, gl, canvas, a_Position ) { var x= ev.clientX; var y = ev.clientY; var rect = ev.target.getBoundingClientRect(); x = ((x - rect.left) - canvas.width / 2 ) / (canvas.width / 2 ); y = (canvas.height / 2 - (y - rect.top)) / (canvas.height / 2 ); g_points.push(x); g_points.push(y); gl.clear(gl.COLOR_BUFFER_BIT); var len = g_points.length; for (var i = 0 ; i < len; i+=2 ){ gl.vertexAttrib3f(a_Position, g_points[i], g_points[i+1 ], 0.0 ); gl.drawArrays(gl.POINTS, 0 , 1 ); } }
优化方案
将计算出来的x、y值以数组方式存入g_points中,简化程序并提高可读性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function click (ev, gl, canvas, a_Position ) { var x= ev.clientX; var y = ev.clientY; var rect = ev.target.getBoundingClientRect(); x = ((x - rect.left) - canvas.width / 2 ) / (canvas.width / 2 ); y = (canvas.height / 2 - (y - rect.top)) / (canvas.height / 2 ); g_points.push([x, y]); gl.clear(gl.COLOR_BUFFER_BIT); var len = g_points.length; for (var i = 0 ; i < len; i+=2 ){ var xy = g_points[i] gl.vertexAttrib3f(a_Position, xy[0 ], xy[1 ], 0.0 ); gl.drawArrays(gl.POINTS, 0 , 1 ); } }
效果
Tips:
Please indicate the source and original author when reprinting or quoting this article.