WebGL рисует треугольники для скрининга по одной точке за раз - PullRequest
0 голосов
/ 11 февраля 2020

Я действительно новичок в 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);
};

1 Ответ

0 голосов
/ 11 февраля 2020

Есть много проблем с кодом выше

Для начала вы создаете пустой массив с именем 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 значения в points в getMouseClickPosition, но в соответствии с вашим кодом, в котором вы создаете буферы 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();

не имеет смысла и, скорее всего, взломает sh, поскольку для javascript массивов нет функции size. Длина массива равна array.length, как в points.length, и далее, если вы помещаете 2 значения vec3 на точку, одно для позиции, одно для цвета, то pointCount будет points.length / 2

I также не вижу где, где this.points назначается, даже если на него есть ссылка.

И это только некоторые из проблем.

  • Если вы хотите нарисовать как точки, так и треугольники, вам потребуется 2 вызова на gl.drawArrays. Один для точек и один для треугольников.

  • this.mouseX и this.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>
...