Код, который вы опубликовали, вызывает только gl.drawXXX
один раз в основном, поэтому он никогда не будет ничего рисовать.
У вас есть настройки, поэтому при нажатии мыши будет вызываться click
, ноclick
никогда не вызывает gl.drawXXX
Далее, каждый раз, когда вызывается click
, вы создаете новый буфер с новым набором точек. Это не обычный способ использования WebGL. Обычный способ - настроить точки один раз (один раз для каждой вещи, которую вы хотите нарисовать), а затем использовать матрицы для изменения положения, ориентации и масштаба.
Я предлагаю вам прочитать некоторые другие учебные пособия по WebGL. Этот тип делает то, что вы делаете сейчас, но он описывает, как изменить положение , ориентация и масштаб ,затем как это сделать с матрицами для большей гибкости . Он также охватывает рисование нескольких вещей
В любом случае исправьте свой код так, как вам нужно рисовать после изменения вершин
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
'}\n';
// Fragment shader program
var FSHADER_SOURCE =
'precision mediump float;\n' +
'uniform vec4 u_FragColor;\n' +
'void main() {\n' +
' gl_FragColor = u_FragColor;\n' +
'}\n';
var m = 0;
function main() {
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var uniform1i = 0;
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// // Get the storage location of a_Position
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;
}
// Get the storage location of u_FragColor
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
if (!u_FragColor) {
console.log('Failed to get the storage location of u_FragColor');
return;
}
// Register function (event handler) to be called on a mouse press
canvas.onmousedown = function (ev) { click(ev, gl, canvas, a_Position, u_FragColor) };
}
function click(ev, gl, canvas, a_Position, u_FragColor) {
var x = ev.clientX; // x coordinate of a mouse pointer
var y = ev.clientY; // y coordinate of a mouse pointer
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);
if (ev.button == 0) {
var depth = 4;
gl.uniform4f(u_FragColor, 1.0, 0, 0, 1.0);// Red
//red tree, 4 steps, length 50, halved each step
// Write the positions of vertices to a vertex shader
var n = initVertexBuffers(gl, x, y);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
m = n;
}
if (ev.button == 2) {
var depth = 6;
//blue tree, 6 steps, length 40, halved each step
gl.uniform4f(u_FragColor, 0, 0, 1.0, 1.0);// Blue
// Write the positions of vertices to a vertex shader
var n = initVertexBuffers(gl, x, y);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
m = n;
}
// Specify the color for clearing <canvas>
gl.clearColor(1.0, 1.0, 1.0, 1.0);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINES, 0, m);
}
function initVertexBuffers(gl, x, y) {
let start = [];
let points = createPoints(x, y, 0.4, 4, Math.PI / 2, start);
console.log(points);
var vertices = new Float32Array(points);
let n = points.length / 2; // The number of vertices
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return -1;
}
// Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
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 -1;
}
// Assign the buffer object to a_Position variable
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
return n;
}
//var points = [x, y];
//var angle = 0;
//var prevPoints = [];
//var prevPointIndex = 0;
function createPoints(x, y, length, depth, angle, points) {
if (depth > 0) {
//draws line
let x2 = x + length * Math.cos(angle);
let y2 = y + length * Math.sin(angle);
points.push(x, y, x2, y2);
//draw left branch;
createPoints(x2, y2, length / 2, depth - 1, angle + Math.PI / 4, points);
//goes back
//points.push(x2, y2);
//draw right branch
createPoints(x2, y2, length / 2, depth - 1, angle - Math.PI / 4, points);
//goes back
//points.push(x2, y2);
//console.log(points);
return points;
}
return;
}
main();
//----
function initShaders(gl, vSrc, fSrc) {
const program = twgl.createProgram(gl, [vSrc, fSrc]);
gl.program = program; // THIS IS EXTREMELY BAD AND WRONG CODE!!!
gl.useProgram(program); // THIS IS ALSO WRONG!
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 VSHADER_SOURCE = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
}
`;
намного проще
Вызывает какую-то функцию getWebGLContext
. Ничего такого не нужно. Просто используйте canvas.getContext('webgl')
вызов gl.drawArrays
имеет m
в неправильном месте. Правильный способ вызова gl.drawArrays
- gl.drawArrays(primitiveType, offset, vertexCount)
. Смещение почти равно 0. Нет 4-го параметра.
Пожалуйста, ознакомьтесь с некоторыми лучшими учебниками, подобными тем, которые приведены выше.