Как нарисовать 3 прямоугольника с помощью WebGL2 - PullRequest
0 голосов
/ 15 марта 2019

Я могу написать полный шаблон для WebGL2 вручную, и это очень хорошо работает.

const canvas = document.createElement('canvas')
document.body.appendChild(canvas)

const gl = canvas.getContext('webgl2', { antialias: true })
const width = 800
const height = 500

canvas.width = width
canvas.height = height

const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)

gl.shaderSource(vertexShader, `#version 300 es

in vec3 position;
in vec4 color;

out vec4 thecolor;

void
main() {
  gl_Position = vec4(position, 1.0);

  thecolor = color;
}
`)

gl.shaderSource(fragmentShader, `#version 300 es
precision mediump float;

in vec4 thecolor;

out vec4 color;

void
main() {
  color = thecolor;
}
`)

gl.compileShader(vertexShader)
var success = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(vertexShader))

gl.compileShader(fragmentShader)
var success = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(fragmentShader))

const program = gl.createProgram()

gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)

gl.linkProgram(program)
gl.useProgram(program)

const positionAttribute = gl.getAttribLocation(program, 'position')
const colorAttribute = gl.getAttribLocation(program, 'color')

gl.viewport(0, 0, width, height)
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

// I don't know what the purpose of this is.
const positionVAO = gl.createVertexArray()
gl.bindVertexArray(positionVAO)

const vertexBuffer = gl.createBuffer()
const indexBuffer = gl.createBuffer()

const vertexArray = [
  // don't know how to structure this on my own.
]

const indexArray = [
  // don't know how to structure this either.
]

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.DYNAMIC_DRAW)

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)

gl.enableVertexAttribArray(positionAttribute)
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0)

gl.enableVertexAttribArray(colorAttribute)
gl.vertexAttribPointer(colorAttribute, 4, gl.FLOAT, false, 0, 0)

gl.drawElements(gl.TRIANGLES, indexArray.length, gl.UNSIGNED_SHORT, 0)

Однако там есть 3 комментария.

  1. Я не знаю, какова цель gl.createVertexArray и gl.bindVertexArray. Это объясняет это.
  2. Не знаю, как структурировать вершины в vertexArray.
  3. Не знаю, как структурировать индексы в indexArray.

Я прошел много уроков, но они обычно затуманивают создание и определение вершин / индексов. Они на самом деле не объясняют, как они их спроектировали или структурировали, или почему это так, поэтому я пока не смог восстановить это самостоятельно. Я хотел бы использовать drawElements с индексами вместо drawArrays.

Хотите знать, можно ли показать, как нарисовать 3 прямоугольника, каждый из которых имеет свой цвет (который пропускается через vertexArray). Я представлял себе чередование позиций / цветов в vertexArray, но я не знаю, как это сделать правильно, а также не знаю, как связать данные с indexArray. Под «должным образом» я имею в виду, что пока не понимаю интуитивно, что входит в Float32Array для вершин и Uint32Array для индексов. Если это x, y, или x, y, r, g, b, a в этом случае, или что. Я не понимаю, как прямоугольник закрывается и его «поверхность» окрашивается. Хотите знать, если кто-то может помочь объяснить и продемонстрировать этот рисунок из 3 прямоугольников разных цветов. Это поможет понять, как рисовать в WebGL!

Моя попытка нарисовать их такова:

const vertexArray = [
  1, 1, 1, 1, 1, 1, // x y r g b a
  0, 1, 1, 1, 1, 1,
  1, 0, 1, 1, 1, 1,
  0, 0, 1, 1, 1, 1
]

const indexArray = [
  1,
  2,
  3,
  4
]

Но это ничего не делает.

1 Ответ

1 голос
/ 15 марта 2019

Ключом к этому являются последние 2 параметра gl.vertexAttribPointer.

5-й параметр указывает смещение байтов между наборами последовательных общих атрибутов вершин.В вашем случае каждый набор атрибутов состоит из 6 значений (xyrgba) с типом float .Таким образом, смещение в байтах равно 6 * 4 = 24.

6-й параметр указывает смещение в байтах первого компонента первого общего атрибута вершины в массиве (в случае, когда буферный объект именованного массива связан).
Смещение для координат вершины равно 0, поскольку это первые 2 значения.
Смещение для атрибута цвета составляет 2 * 4 = 8, поскольку атрибут цвета начинается с 3-й позиции.

Таким образом, спецификация массива вершин должна быть:

const vertexArray = [
    1, 1, 1, 1, 1, 1, // x y r g b a
    0, 1, 1, 1, 1, 1,
    1, 0, 1, 1, 1, 1,
    0, 0, 1, 1, 1, 1
]

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.DYNAMIC_DRAW)

gl.enableVertexAttribArray(positionAttribute)
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 6*4, 0)

gl.enableVertexAttribArray(colorAttribute)
gl.vertexAttribPointer(colorAttribute, 4, gl.FLOAT, false, 6*4, 2*4)

Вы хотите нарисовать 2 треугольника:

2           0    
  +--------+         0: (1, 1)
  |       /|         1: (0, 1)
  |    /   |         2: (1, 0)
  | /      |         3: (0, 0)
  + -------+
3           1

каждый треугольник состоит из 3 индексов, поэтому массив индексовдолжно быть:

const indexArray = [ 0, 2, 3, 0, 3, 1 ]

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)

Если вы рисуете это, используя примитив тип TRIANGLES,

gl.drawElements(gl.TRIANGLES, indexArray.length, gl.UNSIGNED_SHORT, 0)

, то это формирует 2 треугольника с координатами:

1st : (1, 1) -> (1, 0) -> (0, 0)
2nd : (1, 1) -> (0, 0) -> (0, 1)

Конечно, вместо этого можно нарисовать треугольную полосу (TRIANGLE_STRIP) или треугольный веер (TRIANGLE_FAN):

const indexArray = [ 2, 0, 3, 1 ]
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)
gl.drawElements(gl.TRIANGLE_STRIP, indexArray.length, gl.UNSIGNED_SHORT, 0)
const indexArray = [ 0, 2, 3, 1 ]
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)
gl.drawElements(gl.TRIANGLE_FAN, indexArray.length, gl.UNSIGNED_SHORT, 0)

var canvas = document.getElementById('my_canvas');

const gl = canvas.getContext('webgl2', { antialias: true })
const width = 800
const height = 500

canvas.width = width
canvas.height = height

const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)

gl.shaderSource(vertexShader, `#version 300 es

in vec3 position;
in vec4 color;

out vec4 thecolor;

void
main() {
  gl_Position = vec4(position, 1.0);

  thecolor = color;
}
`)

gl.shaderSource(fragmentShader, `#version 300 es
precision mediump float;

in vec4 thecolor;

out vec4 color;

void
main() {
  color = thecolor;
}
`)

gl.compileShader(vertexShader)
var success = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(vertexShader))

gl.compileShader(fragmentShader)
var success = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(fragmentShader))

const program = gl.createProgram()

gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)

gl.linkProgram(program)
gl.useProgram(program)

const positionAttribute = gl.getAttribLocation(program, 'position')
const colorAttribute = gl.getAttribLocation(program, 'color')

gl.viewport(0, 0, width, height)
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

// I don't know what the purpose of this is.
const positionVAO = gl.createVertexArray()
gl.bindVertexArray(positionVAO)

const vertexBuffer = gl.createBuffer()
const indexBuffer = gl.createBuffer()

const vertexArray = [
   1, 1, 1, 1, 0, 1, // x y r g b a
   0, 1, 1, 0, 1, 1,
   1, 0, 0, 1, 1, 1,
   0, 0, 1, 1, 0, 1
]

const indexArray = [0, 2, 3, 0, 3, 1]

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.DYNAMIC_DRAW)

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)

gl.enableVertexAttribArray(positionAttribute)
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 6*4, 0)

gl.enableVertexAttribArray(colorAttribute)
gl.vertexAttribPointer(colorAttribute, 4, gl.FLOAT, false, 6*4, 2*4)

gl.drawElements(gl.TRIANGLES, indexArray.length, gl.UNSIGNED_SHORT, 0)
<canvas id="my_canvas"></canvas>
...