在 webgl 中绘制树的问题

这次又出现了更多错误,只不过这次是在 webgl 端而不是 mathy 算法端。

我之前的帖子只是关于绘制一个简单的 2d 递归树。我现在要做的事情是在鼠标单击的位置绘制一棵树,如果左键单击,则为红线,如果右击则为蓝色。我解决了之前的问题,并且能够让树显示在我之前的程序版本中。但是,现在当我单击画布时,树甚至不会出现。然而,当我控制台记录存储点的数组时,所有的点似乎都在那里。我想我遗漏了一些东西,但我对 webgl 的了解还不够多,无法知道那可能是什么。

我已经制作了一个工作程序,它可以根据鼠标单击在鼠标位置绘制不同的颜色点,但我仍然没有足够的经验来弄清楚我在该程序中拥有什么使其能够工作以及为什么这个当前程序无法显示任何内容。

我敢打赌,我在主要功能或点击功能中遗漏了一些东西,但我发布了所有内容,因为我不是 100% 确定。


慕容3067478
浏览 406回答 1
1回答

呼唤远方

您发布的代码仅gl.drawXXX在 main 中调用一次,因此它永远不会再绘制任何内容。你已经设置好了,所以当按下鼠标时click将被调用但从click不调用gl.drawXXX此外,每次click调用时,您都会使用一组新的点创建一个新缓冲区。这不是使用 WebGL 的正常方式。通常的方法是设置你的点一次(每个你想画的东西一次),然后使用矩阵来改变位置、方向、比例。我建议你阅读一些关于 WebGL 的其他教程。这一种做你现在正在做的事情,但它会跟进如何改变位置、方向和比例,然后是如何用矩阵来做以获得更大的灵活性。它还涵盖了绘制多个事物在任何情况下,要按原样修复您的代码,您都需要在更改顶点后进行绘制// Vertex shader programvar VSHADER_SOURCE =&nbsp;&nbsp; &nbsp; 'attribute vec4 a_Position;\n' +&nbsp; &nbsp; 'void main() {\n' +&nbsp; &nbsp; '&nbsp; gl_Position = a_Position;\n' +&nbsp; &nbsp; '}\n';// Fragment shader programvar FSHADER_SOURCE =&nbsp; &nbsp; 'precision mediump float;\n' +&nbsp; &nbsp; 'uniform vec4 u_FragColor;\n' +&nbsp; &nbsp; 'void main() {\n' +&nbsp; &nbsp; '&nbsp; gl_FragColor = u_FragColor;\n' +&nbsp; &nbsp; '}\n';var m = 0;function main() {&nbsp; &nbsp; var canvas = document.getElementById('webgl');&nbsp; &nbsp; // Get the rendering context for WebGL&nbsp; &nbsp; var uniform1i = 0;&nbsp; &nbsp; var gl = canvas.getContext('webgl');&nbsp; &nbsp; if (!gl) {&nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to get the rendering context for WebGL');&nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; }&nbsp; &nbsp; // Initialize shaders&nbsp; &nbsp; if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {&nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to intialize shaders.');&nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; }&nbsp; &nbsp; // // Get the storage location of a_Position&nbsp; &nbsp; var a_Position = gl.getAttribLocation(gl.program, 'a_Position');&nbsp; &nbsp; if (a_Position < 0) {&nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to get the storage location of a_Position');&nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; }&nbsp; &nbsp; // Get the storage location of u_FragColor&nbsp; &nbsp; var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');&nbsp; &nbsp; if (!u_FragColor) {&nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to get the storage location of u_FragColor');&nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; }&nbsp; &nbsp; // Register function (event handler) to be called on a mouse press&nbsp; &nbsp; canvas.onmousedown = function (ev) { click(ev, gl, canvas, a_Position, u_FragColor) };}function click(ev, gl, canvas, a_Position, u_FragColor) {&nbsp; &nbsp; var x = ev.clientX; // x coordinate of a mouse pointer&nbsp; &nbsp; var y = ev.clientY; // y coordinate of a mouse pointer&nbsp; &nbsp; var rect = ev.target.getBoundingClientRect();&nbsp; &nbsp; x = ((x - rect.left) - canvas.width / 2) / (canvas.width / 2);&nbsp; &nbsp; y = (canvas.height / 2 - (y - rect.top)) / (canvas.height / 2);&nbsp; &nbsp; if (ev.button == 0) {&nbsp; &nbsp; &nbsp; &nbsp; var depth = 4;&nbsp; &nbsp; &nbsp; &nbsp; gl.uniform4f(u_FragColor, 1.0, 0, 0, 1.0);// Red&nbsp; &nbsp; &nbsp; &nbsp; //red tree, 4 steps, length 50, halved each step&nbsp; &nbsp; &nbsp; &nbsp; // Write the positions of vertices to a vertex shader&nbsp; &nbsp; &nbsp; &nbsp; var n = initVertexBuffers(gl, x, y);&nbsp; &nbsp; &nbsp; &nbsp; if (n < 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to set the positions of the vertices');&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; m = n;&nbsp; &nbsp; }&nbsp; &nbsp; if (ev.button == 2) {&nbsp; &nbsp; &nbsp; &nbsp; var depth = 6;&nbsp; &nbsp; &nbsp; &nbsp; //blue tree, 6 steps, length 40, halved each step&nbsp; &nbsp; &nbsp; &nbsp; gl.uniform4f(u_FragColor, 0, 0, 1.0, 1.0);// Blue&nbsp; &nbsp; &nbsp; &nbsp; // Write the positions of vertices to a vertex shader&nbsp; &nbsp; &nbsp; &nbsp; var n = initVertexBuffers(gl, x, y);&nbsp; &nbsp; &nbsp; &nbsp; if (n < 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to set the positions of the vertices');&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; m = n;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; // Specify the color for clearing <canvas>&nbsp; &nbsp; gl.clearColor(1.0, 1.0, 1.0, 1.0);&nbsp; &nbsp; // Clear <canvas>&nbsp; &nbsp; gl.clear(gl.COLOR_BUFFER_BIT);&nbsp; &nbsp; gl.drawArrays(gl.LINES, 0, m);&nbsp; &nbsp;&nbsp;}function initVertexBuffers(gl, x, y) {&nbsp; &nbsp; let start = [];&nbsp; &nbsp; let points = createPoints(x, y, 0.4, 4, Math.PI / 2, start);&nbsp; &nbsp; console.log(points);&nbsp; &nbsp; var vertices = new Float32Array(points);&nbsp; &nbsp; let n = points.length / 2; // The number of vertices&nbsp; &nbsp; // Create a buffer object&nbsp; &nbsp; var vertexBuffer = gl.createBuffer();&nbsp; &nbsp; if (!vertexBuffer) {&nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to create the buffer object');&nbsp; &nbsp; &nbsp; &nbsp; return -1;&nbsp; &nbsp; }&nbsp; &nbsp; // Bind the buffer object to target&nbsp; &nbsp; gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);&nbsp; &nbsp; // Write date into the buffer object&nbsp; &nbsp; gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);&nbsp; &nbsp; var a_Position = gl.getAttribLocation(gl.program, 'a_Position');&nbsp; &nbsp; if (a_Position < 0) {&nbsp; &nbsp; &nbsp; &nbsp; console.log('Failed to get the storage location of a_Position');&nbsp; &nbsp; &nbsp; &nbsp; return -1;&nbsp; &nbsp; }&nbsp; &nbsp; // Assign the buffer object to a_Position variable&nbsp; &nbsp; gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);&nbsp; &nbsp; // Enable the assignment to a_Position variable&nbsp; &nbsp; gl.enableVertexAttribArray(a_Position);&nbsp; &nbsp; return n;}//var points = [x, y];//var angle = 0;//var prevPoints = [];//var prevPointIndex = 0;function createPoints(x, y, length, depth, angle, points) {&nbsp; &nbsp; if (depth > 0) {&nbsp; &nbsp; &nbsp; &nbsp; //draws line&nbsp; &nbsp; &nbsp; &nbsp; let x2 = x + length * Math.cos(angle);&nbsp; &nbsp; &nbsp; &nbsp; let y2 = y + length * Math.sin(angle);&nbsp; &nbsp; &nbsp; &nbsp; points.push(x, y, x2, y2);&nbsp; &nbsp; &nbsp; &nbsp; //draw left branch;&nbsp; &nbsp; &nbsp; &nbsp; createPoints(x2, y2, length / 2, depth - 1, angle + Math.PI / 4, points);&nbsp; &nbsp; &nbsp; &nbsp; //goes back&nbsp; &nbsp; &nbsp; &nbsp; //points.push(x2, y2);&nbsp; &nbsp; &nbsp; &nbsp; //draw right branch&nbsp; &nbsp; &nbsp; &nbsp; createPoints(x2, y2, length / 2, depth - 1, angle - Math.PI / 4, points);&nbsp; &nbsp; &nbsp; &nbsp; //goes back&nbsp; &nbsp; &nbsp; &nbsp; //points.push(x2, y2);&nbsp; &nbsp; &nbsp; &nbsp; //console.log(points);&nbsp; &nbsp; &nbsp; &nbsp; return points;&nbsp; &nbsp; }&nbsp; &nbsp; return;}main();//----function initShaders(gl, vSrc, fSrc) {&nbsp; const program = twgl.createProgram(gl, [vSrc, fSrc]);&nbsp; gl.program = program; // THIS IS EXTREMELY BAD AND WRONG CODE!!!&nbsp; gl.useProgram(program); // THIS IS ALSO WRONG!&nbsp; return program;}canvas { border: 1px solid black; }<canvas id="webgl"></canvas><script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>代码有很多问题gl.program不是一回事。无论你从中学到什么书或教程,都是一件可怕的、糟糕的和错误的事情。WebGL 程序通常有多个着色器程序,因此一个函数initShaders需要返回创建的程序,以便您可以使用不同的顶点着色器源和片段着色器源多次调用它来制作多个程序。它不应该将一个创建的程序破解到它不属于的 webgl 上下文。注意:即使我实现了initShaders因为你没有提供它从你的代码中可以清楚地看出它在做什么gl.program = gl.createProgram。那是无意义的代码。有多个程序是很常见的。通话gl.useProgram中initShaders也可以说是错误的。(再次清楚,因为它没有在您的代码中的任何地方调用您的版本initShaders正在这样做。同样,这没有意义,因为在普通的 WebGL 页面中,您有多个着色器,因此您需要gl.useProgram多次调用。您正在阅读的教程看起来很旧,因为它为 GLSL 连接字符串。制作 GLSL 的最简单方法是使用多行模板文字var&nbsp;VSHADER_SOURCE&nbsp;=&nbsp;` &nbsp;&nbsp;&nbsp;&nbsp;attribute&nbsp;vec4&nbsp;a_Position; &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;main()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gl_Position&nbsp;=&nbsp;a_Position; &nbsp;&nbsp;&nbsp;&nbsp;} `;容易多了它正在调用一些函数getWebGLContext。不需要那样的东西。只需使用canvas.getContext('webgl')调用gl.drawArrays有m错了地方。正确的调用方式gl.drawArrays是gl.drawArrays(primitiveType, offset, vertexCount)。偏移量几乎是 0。没有第四个参数。请考虑阅读一些更好的教程,例如上面链接的教程。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript