WebGL пытается нарисовать треугольник - PullRequest
0 голосов
/ 15 октября 2018

Я пытался нарисовать треугольник, но он не появляется на холсте

вот мой код функции рисования:

function draw() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)gl.clear(gl.COLOR_BUFFER_BIT)       
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 
                buffer.itemSize, gl.FLOAT, false, 0, 0); 
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute)
      
        //Draw the triangle
    gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
}

вот вся работа:

const vertexShaderText = [
  'attribute vec3 vertexPos;',
  '',
  'void main() {',
  '  gl_Position = vec4(vertexPos, 1.0);',
  '}'
].join('\n')

const fragmentShaderText = [
  'precision mediump float;',
  '',
  'void main() {',
  '  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);',
  '}'
].join('\n')

let gl, shaderProgram, buffer

function startup() {
  const canvas = document.getElementById('myCanvas')
  gl = canvas.getContext('webgl')

  initShader()
  initBuffer()

  gl.clearColor(0.0, 0.0, 0.0, 1.0)

  draw()
}

function initShader() {

  // VERTEX SHADER
  let vertexShader = gl.createShader(gl.VERTEX_SHADER)
  gl.shaderSource(vertexShader, vertexShaderText)
  gl.compileShader(vertexShader)

  if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
    alert('vertex', gl.getShaderInfoLog(vertexShader))
    return
  }

  let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
  gl.shaderSource(fragmentShader, fragmentShaderText)
  gl.compileShader(fragmentShader)

  if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
    alert('fragment', gl.getShaderInfoLog(fragmentShader))
    return
  }


  shaderProgram = gl.createProgram()

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

  gl.linkProgram(shaderProgram)

  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert('Failed to setup shaders')
  }

  gl.useProgram(shaderProgram)

  shaderProgram.vertextPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
  //gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)

}

function initBuffer() {
  buffer = gl.createBuffer()

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)

  const triangleVertices = [
    0.0, 0, 5, 0.0, -0.5, -0.5, 0.0,
    0.5, -0.5, 0.0
  ]

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)

  buffer.itemSize = 3
  buffer.numberOfItems = 3
  console.log(shaderProgram)
}

function draw() {
  gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight) 
  gl.clear(gl.COLOR_BUFFER_BIT)

  gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,
    buffer.itemSize, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute)  
  //Draw the triangle
  gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)
}

startup()
<canvas id="myCanvas" width="500" height="500"></canvas>

Ответы [ 2 ]

0 голосов
/ 15 октября 2018

Некоторые проблемы

Нет такой вещи, как gl.viewportWidth и gl.viewportHeight

Использование gl.canvas.width и gl.canvas.height.

Там есть сайткоторый учит использовать gl.viewportWidth и gl.viewportHeight.Это возможно анти-образец.Эти переменные не являются частью WebGL.Это пользовательские переменные, добавляемые примером в контекст WebGL.Существует абсолютно нулевая причина сделать это, поскольку они всегда должны обновляться вручную, а фактическая ширина и высота всегда доступны.

Опечатка в triangleVertices

Вторая запятая ниже должна бытьточка

плохо

 const triangleVertices = [
    0.0, 0, 5, 0.0, -0.5, -0.5, 0.0,  
    0.5, -0.5, 0.0
  ]

хорошо

 const triangleVertices = [
    0.0, 0.5, 0.0, -0.5, -0.5, 0.0,  
    0.5, -0.5, 0.0
  ]

С этим он работает, но вот еще одна опечатка

vertextPositionAttribute должно быть vertexPositionAttribute

  shaderProgram.vertextPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
  //gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)

При этом есть несколько предложений.

  • Использование литералов многострочных шаблонов для шейдеров

вместо

const vertexShaderText = [
  'attribute vec3 vertexPos;',
  '',
  'void main() {',
  '  gl_Position = vec4(vertexPos, 1.0);',
  '}'
].join('\n')

сделать это

const vertexShaderText = `
  attribute vec3 vertexPos;

  void main() {
    gl_Position = vec4(vertexPos, 1.0);
  }
`;

Намного проще!Используйте кавычки вместо кавычек для многострочных строк

  • Сделайте initShader возврат шейдера вместо того, чтобы назначить глобальный

В WebGL не часто встречается один шейдерпоэтому гораздо полезнее иметь функцию, которая создает шейдеры

  • Не вызывайте gl.useProgram в initShader

Опять же, нередко иметь один шейдер,Вызов gl.useProgram обычно относится к draw

  • Не добавляйте атрибуты к объектам браузера, особенно к объектам WebGL

    bad

    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos');
    

    хорошо (один из многих способов)

    const shaderProgramInfo = {}
    shaderProgramInfo.program = initShader(...)
    shaderProgramInfo.vertexPositionAttribute =
        gl.getAttribLocation(shaderProgramInfo.program, 'vertexPos');
    

    Это потому, что в случае сбоя initShader (например, потеря контекста) ваш gl.createProgram будет иметь значение null, а попытка присвоить свойству значение null приведет к тому, что ваша страницапотерпеть поражение.Та же проблема с буфером

    плохо

     const buffer = gl.createBuffer();
     ...
     buffer.itemSize = 3
     buffer.numberOfItems = 3
    

    хорошо (один из многих способов)

     const bufferInfo = {
       buffer: gl.createBuffer(),
     }
     ...
     bufferInfo.itemSize = 3
     bufferInfo.numberOfItems = 3
    
  • Позвоните gl.bindBuffer перед вызовом gl.vertexAttribPointer

    Ваш код работает, потому что есть только один буфер.Если имеется 2 буфера, он, скорее всего, перестанет работать, потому что gl.vertexAttribPointer ссылается на текущий связанный буфер

  • Рекомендуем прочитать лучшие учебники.

I 'буду рекомендовать https://webglfundamentals.org

const vertexShaderText = `
  attribute vec3 vertexPos;
  
  void main() {
    gl_Position = vec4(vertexPos, 1.0);
  }
`;

const fragmentShaderText = `
  precision mediump float;
  
  void main() {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
  }
`;

let gl, shaderProgramInfo, bufferInfo

function startup() {
  const canvas = document.getElementById('myCanvas')
  gl = canvas.getContext('webgl')

  shaderProgramInfo = {
    program: initShader(gl, vertexShaderText, fragmentShaderText),
  };
  shaderProgramInfo.vertexPositionAttribute = gl.getAttribLocation(shaderProgramInfo.program, 'vertexPos');

  bufferInfo = initBuffer()

  gl.clearColor(0.0, 0.0, 0.0, 1.0)

  draw()
}

function initShader(gl, vertexShaderText, fragmentShaderText) {

  // VERTEX SHADER
  let vertexShader = gl.createShader(gl.VERTEX_SHADER)
  gl.shaderSource(vertexShader, vertexShaderText)
  gl.compileShader(vertexShader)

  if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
    alert('vertex', gl.getShaderInfoLog(vertexShader))
    return
  }

  let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
  gl.shaderSource(fragmentShader, fragmentShaderText)
  gl.compileShader(fragmentShader)

  if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
    alert('fragment', gl.getShaderInfoLog(fragmentShader))
    return
  }

  const shaderProgram = gl.createProgram()

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

  gl.linkProgram(shaderProgram)

  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert('Failed to setup shaders')
  }

  return shaderProgram;
}

function initBuffer() {
  buffer = gl.createBuffer()

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer)

  const triangleVertices = [
    0.0, 0.5, 0.0, -0.5, -0.5, 0.0,
    0.5, -0.5, 0.0
  ]

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)

  return {
    buffer,
    itemSize: 3,
    numberOfItems: 3,
  };
}

function draw() {
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 
  gl.clear(gl.COLOR_BUFFER_BIT)

  gl.useProgram(shaderProgramInfo.program)

  gl.bindBuffer(gl.ARRAY_BUFFER, bufferInfo.buffer);
  gl.vertexAttribPointer(shaderProgramInfo.vertexPositionAttribute,
    bufferInfo.itemSize, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(shaderProgramInfo.vertexPositionAttribute)  
  //Draw the triangle
  gl.drawArrays(gl.TRIANGLES, 0, bufferInfo.numberOfItems)
}

startup()
<canvas id="myCanvas" width="500" height="500"></canvas>
0 голосов
/ 15 октября 2018

Есть некоторые проблемы:

Свойства gl.viewportWidth и gl.viewportHeight никогда не устанавливаются:

gl = canvas.getContext('webgl')
gl.viewportWidth = canvas.clientWidth;
gl.viewportHeight = canvas.clientHeight;

В массиве координат вершин вместо ,.

const triangleVertices = [
     0.0,  0,5, 0.0, // <---- this line
    -0.5, -0.5, 0.0, 
     0.5, -0.5, 0.0
]

И есть опечатка, вы написали vertextPositionAttribute вместо vertexPositionAttribute, когда вы получаете индекс атрибута:

shaderProgram.vertextPositionAttribute = // <--- typo
    gl.getAttribLocation(shaderProgram, 'vertexPos') 

Но в целом ваш кодработы:

  const vertexShaderText = [
    'attribute vec3 vertexPos;',
    '',
    'void main() {',
    '  gl_Position = vec4(vertexPos, 1.0);',
    '}'
].join('\n')

const fragmentShaderText = [
    'precision mediump float;',
    '',
    'void main() {',
    '  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);',
    '}'
].join('\n')

let gl, shaderProgram, buffer

function startup() {
    const canvas = document.getElementById('myCanvas')
    gl = canvas.getContext('webgl')

    gl.viewportWidth = canvas.clientWidth;
    gl.viewportHeight = canvas.clientHeight;
      
    initShader()
    initBuffer()

    gl.clearColor(0.0, 0.0, 0.0, 1.0)
    
    draw()
}

function initShader() {
    
    // VERTEX SHADER
    let vertexShader = gl.createShader(gl.VERTEX_SHADER)
    gl.shaderSource(vertexShader, vertexShaderText)
    gl.compileShader(vertexShader)

    if(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
        alert('vertex', gl.getShaderInfoLog(vertexShader))
        return
    }

    let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
    gl.shaderSource(fragmentShader, fragmentShaderText)
    gl.compileShader(fragmentShader)

    if(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
        alert('fragment', gl.getShaderInfoLog(fragmentShader))
        return
    }
    

    shaderProgram = gl.createProgram()

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

    gl.linkProgram(shaderProgram)

    if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert('Failed to setup shaders')
    }

    gl.useProgram(shaderProgram)

    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'vertexPos')
    //gl.enableVertexAttribArray(shaderProgram.vertextPositionAttribute)
  
}

function initBuffer() {
    buffer = gl.createBuffer()

    gl.bindBuffer(gl.ARRAY_BUFFER, buffer)

    const triangleVertices = [
          0.0,  0.5, 0.0,
        -0.5, -0.5, 0.0,
          0.5, -0.5, 0.0
    ]

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW)

    buffer.itemSize = 3
    buffer.numberOfItems = 3
    console.log(shaderProgram)
}

function draw() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight)
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
    
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 
            buffer.itemSize, gl.FLOAT, false, 0, 0); 
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    //Draw the triangle
    gl.drawArrays(gl.TRIANGLES, 0, buffer.numberOfItems)

    requestAnimationFrame(draw);
}

startup()
<canvas id="myCanvas" width="500" height="500"></canvas>
...