通过单击鼠标使用 webgl 创建一个圆圈

creating a circle with webgl with mouse clicks

我在网上找到了这个程序。我如何修改以下程序以在每次用户用鼠标单击时创建圆圈?那么可以创建多个圈子吗?我是 webgl 的新手,我迷路了,非常感谢您的帮助

<!DOCTYPE html>

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body onload="onLoad()">
        <script id="vertex-shader" type="x-shader/x-vertex">
    uniform vec2 u_resolution;
    attribute vec2 a_position;

    void main(void) {
      vec2 clipspace = a_position / u_resolution * 2.0 - 1.0;
      gl_Position = vec4(clipspace * vec2(1, -1), 0, 1);
    }

</script>

<script id="fragment-shader" type="x-shader/x-fragment">
    precision mediump float;

    void main(void) {
        gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
    }
</script>
<script>
    function onLoad () {
   var canvas = document.getElementById("canvas");
    gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");//   
            //gl.viewport(0, 0, canvas.width, canvas.height);
            gl.clearColor(0.8, 0.0, 0.3, 1.0);//
            gl.clear(gl.COLOR_BUFFER_BIT);//

        
            var v = document.getElementById("vertex-shader").firstChild.nodeValue;//
            var f = document.getElementById("fragment-shader").firstChild.nodeValue;//

            var vs = gl.createShader(gl.VERTEX_SHADER);//
            gl.shaderSource(vs, v);//
            gl.compileShader(vs);//

            var fs = gl.createShader(gl.FRAGMENT_SHADER);//
            gl.shaderSource(fs, f);//
            gl.compileShader(fs);//

            var program = gl.createProgram();//
            gl.attachShader(program, vs);//
            gl.attachShader(program, fs);//
            gl.linkProgram(program);//
            
            gl.useProgram(program);

    var circle = {x: 50, y: 50, r: 15};
    var ATTRIBUTES = 2;
    var numFans = 16;
    var degreePerFan = (2 * Math.PI) / numFans;
    var vertexData = [circle.x, circle.y];
    
    for(var i = 0; i <= numFans; i++) {
      var index = ATTRIBUTES * i + 2; // there is already 2 items in array
      var angle = degreePerFan * (i+1);
      vertexData[index] = circle.x + Math.cos(angle) * circle.r;
      vertexData[index + 1] = circle.y + Math.sin(angle) * circle.r;
    }

    var vertexDataTyped = new Float32Array(vertexData);

    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, vertexDataTyped, gl.STATIC_DRAW);
    
    var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
    gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

    gl.enableVertexAttribArray(positionLocation);

    var positionLocation = gl.getAttribLocation(program, "a_position");
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 0);
    gl.drawArrays(gl.TRIANGLE_FAN, 0, vertexData.length/ATTRIBUTES);
  }
onLoad();
</script>

<canvas id="canvas" style="border: none;" width="300" height="150"></canvas>
    </body>
</html>
           

谢谢

答案是:当然可以有多个圈子。

但是您可以从像 http://learningwebgl.com/blog/?p=28 这样的简单教程开始。在了解了每一部分代码的基本功能后,您可以更改结构以轻松绘制多个圆圈。

我会推荐一些 webgl 教程,例如 http://webglfundamentals.org

Here's an article on drawing multiple things

但具体而言,WebGL 只是一个光栅化库。它没有直接的圈子概念。如果你想画多个圆,你需要决定你想如何表示你的圆(纹理、点、一些花哨的着色器),然后你想如何画它们(每个圆一个绘制调用,每个四边形一个圆,多个圆每次绘制调用)。由你决定。

连你发的代码选项也太多了。该代码绘制一个圆圈。在绘制一个圆圈的代码周围放置一个循环,它将绘制 N 个圆圈。另一方面,您也可以生成一个圆圈和 use various matrix transforms to scale and position it

通过单击鼠标,您已添加了多个问题。

默认情况下,canvas 在 WebGL 中的每一帧都会被清除。因此,您在用户单击鼠标的位置绘制,但下次绘制时,先前的圆圈将被擦除。

最简单的解决方案是告诉 webgl 不要用

清除 canvas
gl = someCanvas.getContext("webgl", { preserveDrawingBuffer: true });

但这通常不是一个好的解决方案,因为如果您想调整 canvas 的大小,它在您调整大小时仍会被清除。

相反,您需要保留所有鼠标点击的列表,然后为每次点击绘制一个圆圈。但这带来了一个新问题,即在点击太多之后它会变得太慢。这意味着您需要结合以上两件事。

不要清除 canvas,只需在单击时绘制新圆圈,如果您需要在调整大小后调整 canvas 的大小,请绘制所有旧圆圈。

如您所见,事实证明这是一个比听起来更大的话题。