Vue JS-如何使WebGL通过Vue呈现而不会消失?

时间:2019-03-27 20:00:19

标签: javascript vue.js vuejs2 webgl webgl2

问题

我正在尝试使用Vue JS来显示一些非常简单的WebGL。我在我的canvas元素内使用Vue方法调用来启动呈现WebGL的功能。一切工作正常,除了渲染的图像在屏幕上闪烁一次然后消失。图像是一个简单的三角形,渲染后应该仅位于屏幕上。我找不到解决方案?

由于我是个新手,所以我可能犯了一些明显的错误,这就是问题所在,可能是我猜到了通过Vue将简单的基本WebGl合并到HTML中的标准化方法,但是我只是找不到它?

可能的解决方案是什么?不幸的是,我应该只使用基本的WebGL(而不是Three.js或其他任何东西),而是使用基本的Vue JS。

我将在下面解释细节。

背景


我对Vue JS相当陌生,对WebGL也很陌生。我正在YouTube上的this系列教程中首次学习WebGL,其中链接的特定视频包含了我为解决此问题而编写的代码。

与vid唯一的,也许是与众不同的事情当然是使用Vue JS作为UI框架,而不是编写纯HTML和Javascript文件,然后手动使用node js来设置服务器。

在本教程中,他通过html中的标记链接了一个单独的包含WebGL代码的.js文件。在此脚本中,Javascript仅使用查询选择器来获取画布及其上下文,并将其分配为输出渲染的位置。

在Vue JS内,我不确定如何告诉Vue只是运行不是方法或计算方法等外部脚本,因此我将WebGL代码放入方法中,并通过调用将其输出到屏幕上vue模板中canvas标记内的方法:

<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.
   .
   .
 }

}

}

现在这实际上可以工作了,并且实际上已经渲染了红色的小三角形-除非将其渲染到屏幕上,否则它就会消失。


我对为什么的想法

这是我想发生的事情:当vue组件第一次加载时,它将运行我放置在其中的runWebGL()方法,创建并在画布上显示lil红色三角形。但是,该方法完成后,它将不再运行,因此其中的所有内容都将被破坏,并且没有WebGL可以输出。

例如,如果我在runWebGL()的末尾放置了一个警报函数以防止该函数自动结束,则可以看到三角形一直输出到屏幕上,直到用户关闭警报为止。

那我假设的是,当这家伙在视频中做过的时候,您通过标记将一些脚本直接附加到html上,无论它们是本地还是外部引用的脚本,一旦完成,它们就不会关。因此,即使它们已经解析到最后,它们中的数据等仍然可用?

那我该如何在Vue JS中解决这个问题?我应该实现某种方法来使Vue JS方法“运行”,即使其中的代码已经执行完了吗?还是有其他更标准化的方法来对WebGL和Vue JS进行网格划分?

我知道那里有一些WebGL框架,并且有一些试图将Vue和WebGL融合在一起,但是不幸的是我不应该使用它们-我必须尽可能地接近它我可以使用原生VueJS和纯WebGL。

非常感谢您的帮助!


我在runWebGL()中放入的Javascript和WebGL代码与视频中的代码相同:

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 个答案:

答案 0 :(得分:1)

您需要详细了解the life cycle of the 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/]

答案 1 :(得分:0)

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>