[英]WebGL draw triangles to screen one point at a time
I am really new to WebGL and have been trying to create a program that will draw points of a color specified in color sliders on the canvas with a mouse click and after three points are drawn, they will be connected into a triangle.我真的是 WebGL 的新手,并且一直在尝试创建一个程序,该程序将通过单击鼠标在画布上的颜色滑块中绘制指定颜色的点,在绘制三个点后,它们将连接成一个三角形。 I created an array called "points" to pass in the data of the mouse position on click and then I flatten that into "vertexData" to be sent to the buffer and shaders.我创建了一个名为“points”的数组,以在单击时传入鼠标位置的数据,然后将其展平为“vertexData”以发送到缓冲区和着色器。 I cant get anything to come up currently however.但是,我目前无法提出任何问题。 Any help would be greatly appreciated.任何帮助将不胜感激。 Thanks in advance.提前致谢。
"use strict"; “严格使用”;
// Constructor
//
// @param canvasID - string containing name of canvas to render.
// Buttons and sliders should be prefixed with this string.
//
function Lab2(canvasID /* name of canvas to render */) {
this.canvasID = canvasID;
this.canvas = document.getElementById(canvasID);
if (!this.canvas) {
alert("Canvas ID '" + canvasID + "' not found.");
return;
}
this.gl = WebGLUtils.setupWebGL(this.canvas);
if (!this.gl) {
alert("WebGL isn't available in this browser");
return;
}
this.init();
}
// Define prototype values common to all Lab2 objects
Lab2.prototype.gl = null;
Lab2.prototype.toString = function () {
return JSON.stringify(this);
};
Lab2.prototype.init = function () {
var canvas = this.canvas;
var gl = this.gl;
var t = this; // make available to event handlers
// WebGL setup
gl.viewport(0, 0, canvas.width, canvas.height);
// Compile and link shaders
this.shaderProgram = initShaders(gl, "vShader.glsl", "fShader.glsl");
if (this.shaderProgram === null)
return;
gl.useProgram(this.shaderProgram);
// Define names for colors
var white = vec3(1.0, 1.0, 1.0);
var red = vec3(1.0, 0.0, 0.0);
var green = vec3(0.0, 1.0, 0.0);
var blue = vec3(0.0, 0.0, 1.0);
var yellow = vec3(1.0, 1.0, 1.0);
// Array of alternating initial vertex coordinates and colors for each vertex
var points = [];
this.vertexData = flatten(points);
// Count of points in vertexData
this.pointCount = points.size();
var floatSize = 4; // size of gl.FLOAT in bytes
// Load vertex data into WebGL buffer
this.vertexCoordBuffer = gl.createBuffer(); // get unique buffer ID
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexCoordBuffer); // make this the active buffer
gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW); // write data to buffer
// Define data layout in buffer for position. Postions are 3 floats,
// interleaved with 3 floats for colors, starting at beginning of buffer.
this.vPosition = gl.getAttribLocation(this.shaderProgram, "vPosition");
gl.vertexAttribPointer(this.vPosition, 3, gl.FLOAT, false, 6 * floatSize, 0);
gl.enableVertexAttribArray(this.vPosition);
// Define data layout in buffer for colors. Colors are 3 floats,
// interleaved with 3 floats for positions, starting after first position in buffer.
this.vColor = gl.getAttribLocation(this.shaderProgram, "vColor");
gl.vertexAttribPointer(this.vColor, 3, gl.FLOAT, false, 6 * floatSize, 3 * floatSize);
gl.enableVertexAttribArray(this.vColor);
// Define callback for change of slider value
var sliderCallback = function (e) {
// Update text display for slider
var color = e.target.value;
e.target.valueDisplay.textContent = color;
// Re-render canvas
requestAnimationFrame(render);
};
// Set up HTML user interface
this.colors = ["r", "g", "b"];
var rgbSliders = []; // array of slider HTML elements
var rgbSliderValues = []; // array of slider value HTML elements
// Set up an object with sliders for the three colors. The sliders are
// accessed using "indices" of "r", "g", and "b".
for (var i in this.colors) {
var color = this.colors[i];
var sliderID = this.canvasID + "-" + color + "-slider";
rgbSliders[color] = document.getElementById(sliderID);
if (rgbSliders[color] === null) {
alert("Slider ID not found: " + sliderID);
return;
}
var valueID = this.canvasID + "-" + color + "-value";
rgbSliderValues[color] = document.getElementById(valueID);
if (rgbSliders[color] === null) {
alert("Slider value ID not found: " + sliderID);
return;
}
rgbSliders[color].valueDisplay = rgbSliderValues[color]; // attach to slider
// Set callback on slider input
rgbSliders[color].addEventListener("input", sliderCallback);
}
this.rgbSliders = rgbSliders;
var resetButton = document.getElementById(this.canvasID + "-reset-button");
if (resetButton === null) {
alert("Reset button ID not found: " + this.canvasID + "-reset-button");
return;
}
// Set up callback to render a frame
var render = function () {
t.Render();
};
// Set up the callback for the reset button
resetButton.addEventListener("click", function () {
// Reset all the sliders to the middle value
for (var i in rgbSliders) {
rgbSliders[i].value = rgbSliders[i].max / 2.0;
rgbSliders[i].valueDisplay.textContent =
rgbSliders[i].valueAsNumber / rgbSliders[i].max;
}
requestAnimationFrame(render);
});
// Set up mouse tracking
var mouseX = document.getElementById(this.canvasID + "-mousex");
var mouseY = document.getElementById(this.canvasID + "-mousey");
var mouseButton = document.getElementById(this.canvasID + "-mousebutton");
this.mouseDown = [ false, false, false ]; // track mouse button state
mouseButton.textContent = this.mouseDown;
if (mouseX === null || mouseY === null || mouseButton === null) {
alert("Mouse output HTML IDs not found");
return;
}
// Add mouse event handlers
canvas.addEventListener("mousedown", function (e) {
t.mouseDown[e.button] = true;
mouseButton.textContent = t.mouseDown;
getMouseClickPosition();
});
canvas.addEventListener("mouseup", function (e) {
t.mouseDown[e.button] = false;
mouseButton.textContent = t.mouseDown;
});
canvas.addEventListener("mousemove", function (e) {
mouseX.textContent = e.pageX - e.target.offsetLeft;
mouseY.textContent = e.pageY - e.target.offsetTop;
});
// Kick things off with an initial rendering
requestAnimationFrame(render);
};
/**
* GetSliderColors - get the current RGB color represented by the sliders
* as a vec3.
*
* @returns {vec3} current slider color
*/
Lab2.prototype.getSliderColor = function () {
// Build an array of color values based on the current slider colors
var colorValues = [];
for (var i in this.colors) {
var color = this.colors[i];
var colorValue = this.rgbSliders[color].valueAsNumber;
colorValues[i] = colorValue;
}
return vec3(colorValues);
};
Lab2.prototype.getMouseClickPosition = function (){
var point = vec2(this.mouseX, this.mouseY);
this.points.push(point);
};
/**
* Render - draw the frame
*
*/
Lab2.prototype.Render = function () {
var gl = this.gl;
gl.clearColor(0.0, 0.0, 0.25, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0, this.pointCount);
};
There are many issues with the code above上面的代码有很多问题
As a start you create an empty array called points
and then flatten it, it's empty so the flattened version is empty, you then make a WebGL buffer that's empty as a result.首先,您创建一个名为points
的空数组,然后将其展平,它是空的,因此展平后的版本是空的,然后您创建了一个空的 WebGL 缓冲区。 Pushing points into the javascript array won't update the buffer in WebGL so at a minimum you need to update the buffer in WebGL each time you add points.将点推入 javascript 数组不会更新 WebGL 中的缓冲区,因此至少每次添加点时都需要更新 WebGL 中的缓冲区。
Lab2.prototype.getMouseClickPosition = function (){
var point = vec2(this.mouseX, this.mouseY);
this.points.push(point);
this.vertexData = flatten(this.points);
// Count of points in vertexData
this.pointCount = this.points.size();
var floatSize = 4; // size of gl.FLOAT in bytes
// Load vertex data into WebGL buffer
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexCoordBuffer); // make this the active buffer
gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW); // write data to buffer
Further you add 2d values to points
in getMouseClickPosition
but according to your code where you create the WebGL buffers you've set it up so it expects points with 3 values each, not 2, and then expects 3 color values.此外,您将 2d 值添加到getMouseClickPosition
points
,但根据您创建 WebGL 缓冲区的代码,您已经设置了它,因此它期望每个点具有 3 个值,而不是 2,然后期望 3 个颜色值。 In other words you're putting [x, y, x, y, x, y]
in points
but based on your setup code it needs to be [x, y, z, r, g, b, x, y, z, r, g, b, x, y, z, r, g, b]
换句话说,您将[x, y, x, y, x, y]
放在points
但根据您的设置代码,它需要是[x, y, z, r, g, b, x, y, z, r, g, b, x, y, z, r, g, b]
Lab2.prototype.getMouseClickPosition = function (){
var point = vec3(this.mouseX, this.mouseY, 0); // no idea what Z value you want
this.points.push(point);
this.points.push(vec3(red, green, blue)); // you need to figure out red, green, and blue
...
further you're calling points
is a javascript array so this code您进一步调用points
是一个 javascript 数组,因此此代码
this.pointCount = points.size();
makes no sense and would likely crash since there is no size
function for javascript arrays.没有意义并且可能会崩溃,因为 javascript 数组没有size
函数。 The length of an array is array.length
as in points.length
and further, if you're putting 2 vec3 values per point, one for position, one for color, then the pointCount is points.length / 2
数组的长度是array.length
如points.length
,此外,如果您为每个点放置2个vec3值,一个用于位置,一个用于颜色,那么pointCount是points.length / 2
I also see no where where this.points
is assigned even though it's referenced.即使引用了this.points
我也看不到它在哪里分配。
And that's just some of the issues.这只是部分问题。
If you want to draw both points and triangles you'll need 2 calls to gl.drawArrays
.如果您想同时绘制点和三角形,则需要调用 2 次gl.drawArrays
。 One for points and one for triangles.一种用于点,一种用于三角形。
this.mouseX
and this.mouseY
are not defined. this.mouseX
和this.mouseY
没有定义。
getSliderColor returns an array of vec3 instead of vec3 getSliderColor 返回一个数组 vec3 而不是 vec3
not calling render after adding a point添加点后不调用渲染
other...其他...
And you didn't show your shaders.而且你没有展示你的着色器。 It seems unlikely the code would work as is as you're passing in pixel coordinates but shaders work with clip space coordinates.当您传入像素坐标时,代码似乎不太可能按原样工作,但着色器使用剪辑空间坐标。 There is no setup in your code to deal with that conversion.您的代码中没有设置来处理该转换。 It's possible it's hard coded in your shaders but that's not normal.它可能在您的着色器中进行了硬编码,但这不正常。 It's more common to pass in the canvas resolution in one form or another, a projection matrix, or to convert to clip space in JavaScript (less common) but nothing like any one of those appears in your code.更常见的是以一种或另一种形式传入画布分辨率、投影矩阵,或者在 JavaScript 中转换为剪辑空间(不太常见),但不会出现在您的代码中。
I'd suggest you learn how to use a debugger as it would show errors for some of the issues with the code.我建议您学习如何使用调试器,因为它会显示代码中某些问题的错误。
I'd also suggest these articles for more WebGL help.我还建议阅读这些文章以获得更多 WebGL 帮助。
// Constructor // // @param canvasID - string containing name of canvas to render. // Buttons and sliders should be prefixed with this string. // function Lab2(canvasID /* name of canvas to render */) { this.canvasID = canvasID; this.canvas = document.getElementById(canvasID); if (!this.canvas) { alert("Canvas ID '" + canvasID + "' not found."); return; } this.gl = WebGLUtils.setupWebGL(this.canvas); if (!this.gl) { alert("WebGL isn't available in this browser"); return; } this.init(); } // Define prototype values common to all Lab2 objects Lab2.prototype.gl = null; Lab2.prototype.toString = function () { return JSON.stringify(this); }; Lab2.prototype.init = function () { var canvas = this.canvas; var gl = this.gl; var t = this; // make available to event handlers // WebGL setup gl.viewport(0, 0, canvas.width, canvas.height); // Compile and link shaders this.shaderProgram = initShaders(gl, "vShader.glsl", "fShader.glsl"); if (this.shaderProgram === null) return; gl.useProgram(this.shaderProgram); this.resolutionLoc = gl.getUniformLocation(this.shaderProgram, 'resolution'); // Define names for colors var white = vec3(1.0, 1.0, 1.0); var red = vec3(1.0, 0.0, 0.0); var green = vec3(0.0, 1.0, 0.0); var blue = vec3(0.0, 0.0, 1.0); var yellow = vec3(1.0, 1.0, 1.0); // Array of alternating initial vertex coordinates and colors for each vertex var points = []; this.points = points; this.vertexData = flatten(points); // Count of points in vertexData this.pointCount = 0; var floatSize = 4; // size of gl.FLOAT in bytes // Load vertex data into WebGL buffer this.vertexCoordBuffer = gl.createBuffer(); // get unique buffer ID gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexCoordBuffer); // make this the active buffer gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW); // write data to buffer // Define data layout in buffer for position. Postions are 3 floats, // interleaved with 3 floats for colors, starting at beginning of buffer. this.vPosition = gl.getAttribLocation(this.shaderProgram, "vPosition"); gl.vertexAttribPointer(this.vPosition, 3, gl.FLOAT, false, 6 * floatSize, 0); gl.enableVertexAttribArray(this.vPosition); // Define data layout in buffer for colors. Colors are 3 floats, // interleaved with 3 floats for positions, starting after first position in buffer. this.vColor = gl.getAttribLocation(this.shaderProgram, "vColor"); gl.vertexAttribPointer(this.vColor, 3, gl.FLOAT, false, 6 * floatSize, 3 * floatSize); gl.enableVertexAttribArray(this.vColor); // Define callback for change of slider value var sliderCallback = function (e) { // Update text display for slider var color = e.target.value; e.target.valueDisplay.textContent = color; // Re-render canvas requestAnimationFrame(render); }; // Set up HTML user interface this.colors = ["r", "g", "b"]; var rgbSliders = []; // array of slider HTML elements var rgbSliderValues = []; // array of slider value HTML elements // Set up an object with sliders for the three colors. The sliders are // accessed using "indices" of "r", "g", and "b". for (var i in this.colors) { var color = this.colors[i]; var sliderID = this.canvasID + "-" + color + "-slider"; rgbSliders[color] = document.getElementById(sliderID); if (rgbSliders[color] === null) { alert("Slider ID not found: " + sliderID); return; } var valueID = this.canvasID + "-" + color + "-value"; rgbSliderValues[color] = document.getElementById(valueID); if (rgbSliders[color] === null) { alert("Slider value ID not found: " + sliderID); return; } rgbSliders[color].valueDisplay = rgbSliderValues[color]; // attach to slider // Set callback on slider input rgbSliders[color].addEventListener("input", sliderCallback); } this.rgbSliders = rgbSliders; var resetButton = document.getElementById(this.canvasID + "-reset-button"); if (resetButton === null) { alert("Reset button ID not found: " + this.canvasID + "-reset-button"); return; } // Set up callback to render a frame var render = function () { t.Render(); }; // Set up the callback for the reset button resetButton.addEventListener("click", function () { // Reset all the sliders to the middle value for (var i in rgbSliders) { rgbSliders[i].value = rgbSliders[i].max / 2.0; rgbSliders[i].valueDisplay.textContent = rgbSliders[i].valueAsNumber / rgbSliders[i].max; } requestAnimationFrame(render); }); // Set up mouse tracking var mouseX = document.getElementById(this.canvasID + "-mousex"); var mouseY = document.getElementById(this.canvasID + "-mousey"); var mouseButton = document.getElementById(this.canvasID + "-mousebutton"); this.mouseDown = [ false, false, false ]; // track mouse button state mouseButton.textContent = this.mouseDown; if (mouseX === null || mouseY === null || mouseButton === null) { alert("Mouse output HTML IDs not found"); return; } // Add mouse event handlers canvas.addEventListener("mousedown", function (e) { t.mouseDown[e.button] = true; mouseButton.textContent = t.mouseDown; t.mouseX = e.pageX - e.target.offsetLeft; t.mouseY = e.pageY - e.target.offsetTop; t.getMouseClickPosition(); requestAnimationFrame(render); }); canvas.addEventListener("mouseup", function (e) { t.mouseDown[e.button] = false; mouseButton.textContent = t.mouseDown; }); canvas.addEventListener("mousemove", function (e) { mouseX.textContent = e.pageX - e.target.offsetLeft; mouseY.textContent = e.pageY - e.target.offsetTop; }); // Kick things off with an initial rendering requestAnimationFrame(render); }; /** * GetSliderColors - get the current RGB color represented by the sliders * as a vec3. * * @returns {vec3} current slider color */ Lab2.prototype.getSliderColor = function () { // Build an array of color values based on the current slider colors var colorValues = []; for (var i in this.colors) { var color = this.colors[i]; var colorValue = this.rgbSliders[color].valueAsNumber; colorValues[i] = colorValue; } return vec3(...colorValues); }; Lab2.prototype.getMouseClickPosition = function (){ var point = vec3(this.mouseX, this.mouseY, 0); this.points.push(point, this.getSliderColor()); this.vertexData = flatten(this.points); // Count of points in vertexData this.pointCount = this.points.length / 2; var floatSize = 4; // size of gl.FLOAT in bytes var gl = this.gl; // Load vertex data into WebGL buffer gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexCoordBuffer); // make this the active buffer gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW); // write data to buffer }; /** * Render - draw the frame * */ Lab2.prototype.Render = function () { var gl = this.gl; gl.clearColor(0.0, 0.0, 0.25, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); if (!this.pointCount) return; gl.useProgram(this.shaderProgram); gl.uniform2f(this.resolutionLoc, gl.canvas.width, gl.canvas.height); gl.drawArrays(gl.POINTS, 0, this.pointCount); gl.drawArrays(gl.TRIANGLES, 0, this.pointCount); }; const WebGLUtils = { setupWebGL(elem) { return elem.getContext('webgl'); }, }; function initShaders(gl, vsHref, fsHref) { // ignore vsHref and fsHref and guess what the shaders are return twgl.createProgram(gl, [` attribute vec4 vPosition; attribute vec3 vColor; uniform vec2 resolution; varying vec3 v_color; void main() { gl_PointSize = 10.0; gl_Position = vec4(vPosition.xy / resolution * vec2(2, -2) + vec2(-1, 1), 0, 1); v_color = vColor; } `, ` precision mediump float; varying vec3 v_color; void main() { gl_FragColor = vec4(v_color, 1); } `]); } const vec3 = (x, y, z) => [x, y, z]; const flatten = a => new Float32Array(a.flat()); const lab = new Lab2('c');
#outer { display: flex; }
<div id="outer"><canvas id='c'></canvas><div> <input type="range" value="1" min="0" max="1" step="0.01" id="cr-slider"><span id="cr-value"></span><br> <input type="range" min="0" max="1" step="0.01" id="cg-slider"><span id="cg-value"></span><br> <input type="range" min="0" max="1" step="0.01" id="cb-slider"><span id="cb-value"></span><br> <button type="button" id="c-reset-button">reset</button> <div id="c-mousex"></div> <div id="c-mousey"></div> <div id="c-mousebutton"></div> </div> </div> <script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.