WebGL 实践篇(一)—— 绘制一个三角形

一 绘制webGL独特的黑色背景(其他颜色的背景也ok)

1. 首先创建一个canvas标签,获取其DOM元素。

2. 建立视口,并且清除颜色缓存:

  const canvas = document.getElementById('canvas');
  webgl = canvas.getContext('webgl');
  webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
  webgl.clearColor(0, 0, 0, 1);
  webgl.clear(webgl.COLOR_BUFFER_BIT);

canvas.clientWidth与webgl.canvas.width之间有什么区别?

二 绘制三角形

1.顶点着色器代码的编写(其中type可以写为 type = "x-shader/x-vertex")

  <script id="vertex-shader" type="nojs">
    attribute vec4 a_position;
    void main(){
      gl_Position = a_position;
    }
  </script>

2.片元着色器代码的编写(其中type可以写为 type = "x-shader/x-fragment")

  <script id="fragment-shader" type="nojs">
    precision medium float;
    void main(){
      gl_FragColor = vec4(1,0,0.5,1);
    }

3.编译着色器代码并将其与着色程序链接起来(以下代码可封装成为一个函数)

(1)获取着色器代码并创建一个着色器对象,将着色器代码作为源放入该对象中以便后期的编译操作:

  //获取着色器代码
  var vertexShaderSource = document.getElementById("vertex-shader").text;
  var fragmentShaderSource = document.getElementById("fragment-shader").text;

  //创建一个着色器对象
  var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
  var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);

  webgl.shaderSource(vertexShader, vertexShaderSource);
  webgl.shaderSource(fragmentShader, fragmentShaderSource);

(2)编译着色器代码,并获取编译状态(成功或失败)

  webgl.compileShader(vertexShader)
  webgl.compileShader(fragmentShader)

  var vertexSuccess = webgl.getShaderParameter(vertexShader, webgl.COMPILE_STATUS);
  var fragmentSuccess = webgl.getShaderParameter(fragmentShader, webgl.COMPILE_STATUS);

  if (!vertexSuccess) {
    console.log("erro:vertexShader", webgl.getShaderInfoLog(vertexShader));
  }

  if (!fragmentSuccess) {
    console.log("erro:fragmentShader", webgl.getShaderInfoLog(fragmentShader));
  }

(3)创建一个着色程序作为连接,并获取连接状态:

  var program = webgl.createProgram();
  webgl.attachShader(program, vertexShader);
  webgl.attachShader(program, fragmentShader);
  webgl.linkProgram(program);

  var programSuccess = webgl.getProgramParameter(program, webgl.LINK_STATUS);
  if (!programSuccess) {
    console.log("erro:programlink", webgl.getProgramInfoLog(program));
  }

4.为创建好的着色程序提供数据(即顶点着色器中的变量,一般attribute,uniform需要传值)

(1)获得着色器数据中数据槽的位置(此时只有一个变量位置,没有值)

  var positionAttributeLocation = webgl.getAttribLocation(program, "a_position");

(2)数据值一般存在于缓冲当中,即缓冲是存放数据的地方,也是取数据的地方(算是一个中间载体)。创建缓冲,并将其与数据源进行绑定,确定取数据的具体位置。

  var positionBuffer = webgl.createBuffer();
  webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);

(3)向缓冲中存放数据

  var positions = [
    0, 0,
    0, 0.5,
    0.7, 0
  ]
  webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(positions), webgl.STATIC_DRAW);

5.着色程序以及缓冲创建绑定完后,需要进行下一步的操作也就是渲染。渲染前要记得清除颜色缓冲。

(1)渲染开始就需要使用着色程序

  webgl.useProgram(program)

(2)需要从缓冲当中读取相应的数据:先启用对应的属性(获取位置),其次需要获取具体到哪个缓冲去取值,最后设置读取数据的方式。

  webgl.enableVertexAttribArray(positionAttributeLocation);
  webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
  webgl.vertexAttribPointer(positionAttributeLocation, 2, webgl.FLOAT, false, 0, 0);

(3)绘制操作

  webgl.drawArrays(webgl.TRIANGLES, 0, 3)

这样绘制就基本完成啦。让我们看一下效果:

 ps:还记得刚开始那个问题吗?(canvas.clientWidth与webgl.canvas.width之间有什么区别?具体的解释还是去扒理论吧)

实测代码:

// webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
  webgl.viewport(0, 0, webgl.canvas.width, webgl.canvas.height);//区别在这里,用上面那行代码三角形无法显示

完整的代码如下(可直接运行):

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    canvas {
      width: 100%;
      height: 100%;
    }
  </style>
  <!-- 着色器代码 -->
  <script id="vertex-shader" type="nojs">
    attribute vec4 a_position;
    void main(){
      gl_Position = a_position;
    }
  </script>
  <script id="fragment-shader" type="nojs">
    precision mediump float;
    void main(){
      gl_FragColor = vec4(1,0,0.5,1);
    }
  </script>
</head>

<body>
  <canvas id="canvas"></canvas>
</body>

<script>
  var canvas = document.getElementById('canvas');
  webgl = canvas.getContext('webgl');

  if (!webgl) {
    console.log('浏览器不支持webGL');
  }

  var vertexShaderSource = document.getElementById("vertex-shader").text;
  var fragmentShaderSource = document.getElementById("fragment-shader").text;

  var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
  var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);

  webgl.shaderSource(vertexShader, vertexShaderSource);
  webgl.shaderSource(fragmentShader, fragmentShaderSource);

  webgl.compileShader(vertexShader)
  webgl.compileShader(fragmentShader)

  var vertexSuccess = webgl.getShaderParameter(vertexShader, webgl.COMPILE_STATUS);
  var fragmentSuccess = webgl.getShaderParameter(fragmentShader, webgl.COMPILE_STATUS);

  if (!vertexSuccess) {
    console.log("erro:vertexShader", webgl.getShaderInfoLog(vertexShader));
  }

  if (!fragmentSuccess) {
    console.log("erro:fragmentShader", webgl.getShaderInfoLog(fragmentShader));
  }

  var program = webgl.createProgram();
  webgl.attachShader(program, vertexShader);
  webgl.attachShader(program, fragmentShader);
  webgl.linkProgram(program);

  var programSuccess = webgl.getProgramParameter(program, webgl.LINK_STATUS);
  if (!programSuccess) {
    console.log("erro:programlink", webgl.getProgramInfoLog(program));
  }

  var positionAttributeLocation = webgl.getAttribLocation(program, "a_position");
  var positionBuffer = webgl.createBuffer();
  webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);

  var positions = [
    0, 0,
    0, 0.5,
    0.7, 0
  ]
  webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(positions), webgl.STATIC_DRAW);

  // webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
  webgl.viewport(0, 0, webgl.canvas.width, webgl.canvas.height);//区别在这里,用上面那行代码三角形无法显示
  webgl.clearColor(0, 0, 0, 1);
  webgl.clear(webgl.COLOR_BUFFER_BIT);

  webgl.useProgram(program)
  webgl.enableVertexAttribArray(positionAttributeLocation);
  webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
  webgl.vertexAttribPointer(positionAttributeLocation, 2, webgl.FLOAT, false, 0, 0);

  webgl.drawArrays(webgl.TRIANGLES, 0, 3)
</script>

</html>

使用 WebGL 绘制正方形需要进行以下步骤: 1. 获取 WebGL 上下文对象 ```javascript const canvas = document.querySelector('canvas'); const gl = canvas.getContext('webgl'); ``` 2. 设置顶点着色器和片元着色器 ```javascript const vertexShaderSource = ` attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0, 1); } `; const fragmentShaderSource = ` precision mediump float; void main() { gl_FragColor = vec4(1, 0, 0, 1); } `; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); ``` 3. 创建着色器程序并链接顶点着色器和片元着色器 ```javascript const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); ``` 4. 创建缓冲区并绑定数据 ```javascript const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const positions = [ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); ``` 5. 设置顶点属性指针并启用 ```javascript const positionAttributeLocation = gl.getAttribLocation(program, 'a_position'); gl.enableVertexAttribArray(positionAttributeLocation); gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); ``` 6. 清空画布并绘制正方形 ```javascript gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); ``` 完整的 WebGL 绘制正方形的代码如下: ```javascript const canvas = document.querySelector('canvas'); const gl = canvas.getContext('webgl'); const vertexShaderSource = ` attribute vec2 a_position; void main() { gl_Position = vec4(a_position, 0, 1); } `; const fragmentShaderSource = ` precision mediump float; void main() { gl_FragColor = vec4(1, 0, 0, 1); } `; const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderSource); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); const program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.useProgram(program); const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); const positions = [ -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); const positionAttributeLocation = gl.getAttribLocation(program, 'a_position'); gl.enableVertexAttribArray(positionAttributeLocation); gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); ``` 这样就可以在 canvas 中绘制一个红色的正方形了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值