Vue JS - Как получить WebGL для рендеринга через Vue, не исчезая? - PullRequest
2 голосов
/ 27 марта 2019

Вопрос

Я пытаюсь использовать Vue JS для отображения очень простого WebGL.Я использую вызов метода Vue внутри элемента canvas, чтобы запустить функцию, которая визуализирует WebGL.Все работает нормально, за исключением того, что визуализированное изображение мигает на экране во вспышке, а затем исчезает.Изображение представляет собой простой треугольник, который должен находиться на экране после рендеринга.Я не могу найти решение?

Поскольку я очень новичок, я мог допустить некоторые очевидные ошибки, которые могут быть причиной проблемы, может быть, я предполагаю какой-то стандартизированный способ включения простого,базовый WebGl в HTML через Vue, но я просто не смог его найти?

Каковы возможные решения?К сожалению, я должен использовать только базовый WebGL (не Three.js или что-то еще), а через базовый Vue JS.

Ниже я объясню детали.

Фон


Я довольно новичок в Vue JS и очень плохо знаком с WebGL.Я следую этой серии учебных пособий на YouTube для моего первого вступления в WebGL, где приведено связанное с ним конкретное видео, содержащее код, за которым я следовал для этой проблемы.В отличие от видео, которое я делал, было, конечно, использовать Vue JS в качестве инфраструктуры пользовательского интерфейса, а не писать простые файлы HTML и Javascript, а затем вручную использовать узел js для настройки сервера.

В учебнике онссылки через тег в HTML отдельный файл .js, содержащий код WebGL.В этом сценарии Javascript просто использует селектор запросов, чтобы захватить холст и его контекст, и назначить его в качестве места для вывода рендера.

Внутри Vue JS я не был уверен, как сказать Vue просто запуститьвнешний сценарий, который не был методом, не был вычислен и т. д., поэтому я поместил код WebGL в метод и вывел его на экран, вызвав метод внутри тега canvas в шаблоне vue:

<template>
<div id="app">

<canvas> {{runWebGL()}} </canvas>

</div>
</template>
export default{

methods: {

 runWebGL(){
   . 
   .
   //All the WebGLCode from the video - which for brevity I've pasted right at the bottom.
   .
   .
 }

}

}

Теперь это действительно работает, и маленький красный треугольник фактически визуализируется - за исключением того, что, как только он отображается на экране, он исчезает.


Мои мысли о том, почему

* 1032Вот что, я думаю, происходит: когда компонент vue загружается впервые, он запускает метод runWebGL (), который я там поместил, создает и затем отображает красный холст на холсте.Однако когда метод завершился, он больше не работает, поэтому все в нем уничтожено и WebGL не выводится.

Если я добавлю функцию оповещения, например, в конец runWebGL (), чтобы предотвратить еепосле автоматического завершения вы можете видеть, как треугольник остается выведенным на экран, пока пользователь не закроет предупреждение.

Я предполагаю, что когда, как парень сделал в видео, вы присоединяете какой-то сценарийнепосредственно к html через теги, будь то локальные сценарии или сценарии с внешними ссылками, после завершения они не закрываются.Таким образом, данные и т.д. в них все еще доступны, даже если они были проанализированы до конца?

Как мне решить эту проблему в Vue JS, тогда?Должен ли я реализовать какой-либо способ поддержания «работы» методов Vue JS даже после того, как код в них завершится?Или есть какой-то другой, более стандартизированный метод для объединения WebGL и Vue JS?

Я знаю, что есть некоторые фреймворки WebGL, и есть некоторые, которые пытаются смешать Vue и WebGL, но, к сожалению,Я не должен их использовать - я должен получить его как можно ближе к VueJS и простому WebGL.

Большое спасибо за вашу помощь!


Код Javascript и WebGL, который идентичен коду из видео, который я поместил в runWebGL (), находится здесь:

const canvas = document.querySelector(`canvas`); 
const gl = canvas.getContext(`webgl`); 
if (!gl) { throw new Error(`webGL not supported`); } 
/* ***OUTLINE**** */ // load vertexData into Buffer // create vertex SharedArrayBuffer // create program // attach shaders to program // enable vertex attributes // draw 
console.log(`Starting...`); 
// create a triangle, x,y,z. WebGL uses OpenGL uses Float32 Arrays. // Typically don't use Float32 arrays in JS as per: // https://stackoverflow.com/questions/15823021/when-to-use-float32array-instead-of-array-in-javascript
// changing these points will alter where the corners of your triangle are. max is 1, min is -1 
const vertexData = new Float32Array([ 0, 1, 0, 1, -1, 0, -1, -1, 0, ]); const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
// bind this buffer as the current buffer; as an array of vertices 
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); 
// STATIC_DRAW if not rewriting (optomise) common alternative is DYNAMIC_DRAW // Creates the vertex-shader; a mini program that runs on the GPU // this uses the GL shading language (not JS), hence the typed return for the function (ie 'void') // gl_position is the output of the shader; an array of 4 components from the buffer // vec3 indicates the three parts of x,y,z; this is converted to a vec4 by adding "1" to 'position' 
const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, ` attribute vec3 position; void main() { gl_Position = vec4(position, 1); } `); gl.compileShader(vertexShader); 
// create a fragment-shader // a fragment shader shades the pixels between vertices // the vec4 is in format RGB-A // try changing some of these numbers and see what happens // eg vec4(0,1,0,.5) gives a transparent green triangle 
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, ` void main(){ gl_FragColor = vec4(1, 0, 0, 1); } `); gl.compileShader(fragmentShader); 
// create a program that links the two shaders (vertex and fragment) // to the actual vertices 
const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); 
// load the attributes. // Currently we just have a single attribute `position` created with the vertex shader // Attributes are disabled by default - so we have to enable it 
const positionLocation = gl.getAttribLocation(program, `position`); gl.enableVertexAttribArray(positionLocation); 
// how webgl should retrieve data from the currently bound buffer // what is being retrieved? positionLocation // how many elements to read at a time? 3 (x,y,z) // what type are the elements? floating point numbers (from Float32Array) // remaining arguments are not used ('normalise' is an advanced optomisation, not needed here) 
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0); 
// create an excutable program on the graphics card // drawArrays, 2nd argument is which vertex to start at, how many to draw? (in this case there are 3 vertices all with 3 attributes (x,y,z)) 
gl.useProgram(program); 


gl.drawArrays(gl.TRIANGLES, 0, 3);const canvas = document.querySelector(`canvas`); 
const gl = canvas.getContext(`webgl`); 
if (!gl) { throw new Error(`webGL not supported`); } 
/* ***OUTLINE**** */ // load vertexData into Buffer // create vertex SharedArrayBuffer // create program // attach shaders to program // enable vertex attributes // draw 
console.log(`Starting...`); 
// create a triangle, x,y,z. WebGL uses OpenGL uses Float32 Arrays. // Typically don't use Float32 arrays in JS as per: // https://stackoverflow.com/questions/15823021/when-to-use-float32array-instead-of-array-in-javascript
// changing these points will alter where the corners of your triangle are. max is 1, min is -1 
const vertexData = new Float32Array([ 0, 1, 0, 1, -1, 0, -1, -1, 0, ]); const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
// bind this buffer as the current buffer; as an array of vertices 
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW); 
// STATIC_DRAW if not rewriting (optomise) common alternative is DYNAMIC_DRAW // Creates the vertex-shader; a mini program that runs on the GPU // this uses the GL shading language (not JS), hence the typed return for the function (ie 'void') // gl_position is the output of the shader; an array of 4 components from the buffer // vec3 indicates the three parts of x,y,z; this is converted to a vec4 by adding "1" to 'position' 
const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, ` attribute vec3 position; void main() { gl_Position = vec4(position, 1); } `); gl.compileShader(vertexShader); 
// create a fragment-shader // a fragment shader shades the pixels between vertices // the vec4 is in format RGB-A // try changing some of these numbers and see what happens // eg vec4(0,1,0,.5) gives a transparent green triangle 
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, ` void main(){ gl_FragColor = vec4(1, 0, 0, 1); } `); gl.compileShader(fragmentShader); 
// create a program that links the two shaders (vertex and fragment) // to the actual vertices 
const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); 
// load the attributes. // Currently we just have a single attribute `position` created with the vertex shader // Attributes are disabled by default - so we have to enable it 
const positionLocation = gl.getAttribLocation(program, `position`); gl.enableVertexAttribArray(positionLocation); 
// how webgl should retrieve data from the currently bound buffer // what is being retrieved? positionLocation // how many elements to read at a time? 3 (x,y,z) // what type are the elements? floating point numbers (from Float32Array) // remaining arguments are not used ('normalise' is an advanced optomisation, not needed here) 
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0); 
// create an excutable program on the graphics card // drawArrays, 2nd argument is which vertex to start at, how many to draw? (in this case there are 3 vertices all with 3 attributes (x,y,z)) 
gl.useProgram(program); 


gl.drawArrays(gl.TRIANGLES, 0, 3);

Ответы [ 2 ]

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

Вам необходимо больше узнать о жизненном цикле vue-instance.Например, попробуйте the mounted hook:

<template>
<div id="app">
  <canvas></canvas>
</div>
</template>

<script>
export default{
  ...
  mounted () {
    this.runWebGL()
  },
  methods: {
    runWebGL(){
      ...
    }
  }
}
</script>

[https://jsfiddle.net/stdob__/fyojs1vn/]

0 голосов
/ 28 марта 2019

Ответ stdon отлично сработал, чтобы автоматически запустить WebGL и оставаться там при первой загрузке приложения Vue. Спасибо!

Кроме того, в конечном итоге я хотел, чтобы WebGL не запускался автоматически, а включался одним нажатием кнопки. Предполагалось, что его автоматический запуск станет более простой отправной точкой моего развития.

Тогда я сам экспериментировал с этим, и просто нажал кнопку, чтобы активировать метод "runWebGL" при нажатии - таким образом, не нужно помещать {{runWebGL ()}} внутри тега canvas для автоматического вызова метода - и это сработало!

Но ответ stdon об использовании mount был правильным ответом на то, что я изначально просил, и заслуживает положительных отзывов. Спасибо!


Моя новая настройка:

Обратите внимание, код stdon из его ответа работает для настройки автоматического запуска WebGL при загрузке приложения Vue. Мой ниже для настройки кнопки, которую я использовал.

HTML

<template>
<div id="app">

<button @click="runWebGL"> Start WebGL </button>
<canvas></canvas>

</div>
</template>

Javascript

<script>

export default {
      .
      .
   methods: {

   runWebGL(){

     //The Javascript & WebGL code from my original question

     }
   }
    .
    .

}

</script>
...