WebGL绘制三角形以一次筛选一个点



>我是WebGL的新手,并且一直在尝试创建一个程序,该程序将通过鼠标单击在画布上绘制颜色滑块中指定的颜色点,并在绘制三个点后,它们将连接到三角形中。我创建了一个名为"points"的数组,用于在单击时传入鼠标位置的数据,然后将其展平为"vertexData"以发送到缓冲区和着色器。但是,我目前无法获得任何东西。任何帮助将不胜感激。提前谢谢。

"使用严格";

// 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);
};

上面的代码有很多问题

首先,您创建一个名为points的空数组,然后将其展平,它是空的,因此平展版本为空,然后创建一个空的 WebGL 缓冲区。将点推送到 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

此外,您将 2d 值添加到pointsgetMouseClickPosition但根据创建 WebGL 缓冲区的代码,您已经对其进行了设置,因此它期望每个点具有 3 个值,而不是 2 个,然后需要 3 个颜色值。换句话说,您正在[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
...

此外,您调用points是一个JavaScript数组,因此此代码

this.pointCount = points.size();

毫无意义,并且可能会崩溃,因为JavaScript数组没有size函数。数组的长度array.lengthpoints.length和更进一步,如果您为每个点输入 2 个 vec3 值,一个用于位置,一个用于颜色,则 pointCountpoints.length / 2

我也看不到this.points在哪里分配,即使它被引用了。

这只是其中的一些问题。

  • 如果你想画点和三角形,你需要 2 次调用才能gl.drawArrays。一个用于点,一个用于三角形。

  • 未定义this.mouseXthis.mouseY

  • getSliderColor 返回一个 vec3 数组,而不是 vec3

  • 添加点后不调用渲染

  • 其他。。。

而且你没有显示你的着色器。当您传入像素坐标时,代码似乎不太可能按原样工作,但着色器可以使用剪辑空间坐标。代码中没有用于处理该转换的设置。它可能在您的着色器中进行了硬编码,但这并不正常。更常见的是以一种或另一种形式传入画布分辨率、投影矩阵,或者在 JavaScript 中转换为剪辑空间(不太常见(,但代码中不会出现任何类似内容。

我建议您学习如何使用调试器,因为它会显示代码某些问题的错误。

我还建议这些文章获得更多的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="c-r-slider"><span id="c-r-value"></span><br>
<input type="range" min="0" max="1" step="0.01"  id="c-g-slider"><span id="c-g-value"></span><br>
<input type="range" min="0" max="1" step="0.01"  id="c-b-slider"><span id="c-b-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>

最新更新