@
目录
- 目标
- WebGL原理示意图
- 着色器
- 顶点着色器:
- 片元着色器:
- 着色器代码如下
- web端(js)
- js代码
- 代码结构梳理
- 流程图
- 完整代码(可直接在浏览器中查看)
- 运行效果
目标
- 使用WebgL绘制一个点
- 了解整个绘制的编写流程并进行梳理和记录
WebGL原理示意图
- 在示意图中,我们看到程序分为两个部分,一个部分是浏览器端,一个部分是GPU端。
- 因此我们需要编写两个地方的代码,一个是js代码,一个是着色器代码(shader 编程)。
着色器
顶点着色器:
位置:js给顶点着色器传入一个位置数据,即一个二维的向量(x,y),着色器中将这个位置信息连同两个写死的数据,设置给gl_Position,这里需要attribute变量来接收,并赋值给gl_Position。
大小:本次采用直接在着色器中写死数据,也就是设置gl_PointSize = 10.0
片元着色器:
颜色:片元着色器中需要对颜色进行指定,我们也是采取写死的方式,即:gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
需要注意颜色是一个四维向量,前三个数据分别代表红、绿、蓝光学三原色。
着色器代码如下
<!-- 顶点着色器源码 -->
<script id="vertexShader" type="x-shader/x-vertex">attribute vec2 a_position;void main() {gl_Position = vec4(a_position, 0.0, 1.0);gl_PointSize = 10.0;}
</script>
<!-- 片元着色器源码 -->
<script id="fragmentShader" type="x-shader/x-fragment">void main() {gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}
</script>
web端(js)
- webgl:在js代码中,我们需要获取三维的画笔,也就是webgl,函数我们命名为initWebGL
- 位置:需要准备顶点数据,因为我们只需要画一个点,所以准备一个2维的向量,也就是(x,y)
- 大小:和一个点的大小,点本来没有大小,但我们需要看到它,所以给设置一个大小,事实上画的是一个面,但不纠结这些。
- 颜色:还需要准备一个颜色的数据,这一次我们直接在着色器中写死数据。
js代码
<script>let canvasElementlet glfunction init() {// 初始化webglinitWebGL()// 初始化shadersinitShaders()// 初始化buffer,这里暂时没有用到buffer,我们在buffer中直接通过attribute设置了位置的值initBuffers()// 绘制draw()}function initWebGL() {// 在这个函数执行的过程中,输入、输出,没有,过程:canvasElement gl// 获取canvas元素canvasElement = document.getElementById('canvasId')// 获取WebGL上下文gl = canvasElement.getContext('webgl')}function initShaders() {// 获取着色器源码const vsSource = document.getElementById('vertexShader').innerTextconst fsSource = document.getElementById('fragmentShader').innerText// 初始化着色器initShader(gl, vsSource, fsSource)}function initBuffers() {setPointPosition(0.5, 0.5)}function setPointPosition(x, y) {// 获取位置属性const a_position = gl.getAttribLocation(gl.program, 'a_position')// 设置位置属性gl.vertexAttrib2f(a_position, x, y)}function draw() {// 清空画布颜色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 清空画布gl.clear(gl.COLOR_BUFFER_BIT)// 绘制gl.drawArrays(gl.POINTS, 0, 1)}// -----------------这些代码之后需要单独封装,因此gl需要传递过来---------------------function initShader(gl, vsSource, fsSource) {// 创建着色器对象const vShader = loadShader(gl, gl.VERTEX_SHADER, vsSource)const fShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)// 创建程序对象const program = gl.createProgram()// 将着色器对象分配给程序对象gl.attachShader(program, vShader)gl.attachShader(program, fShader)// 链接程序对象gl.linkProgram(program)// 使用程序对象gl.useProgram(program)// 将程序对象分配给gl.programgl.program = program}function loadShader(gl, type, source) {// 创建着色器const shader = gl.createShader(type)// 加载着色器源码gl.shaderSource(shader, source)// 编译着色器gl.compileShader(shader)return shader}
</script>
代码结构梳理
下图为对代码的一个视图化展示,使其分类清晰,并且层次感更强。
流程图
graph TDA([初始化WebGL]) --> B[初始化Shaders]B --> C[初始化Buffers]C --> D([draw])style A fill:#e1f5festyle B fill:#c8e6c9style C fill:#fff3e0style D fill:#f3e5f5
完整代码(可直接在浏览器中查看)
<!doctype html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>画一个点</title><!-- 需要:位置,color --><!-- 顶点着色器源码 --><script id="vertexShader" type="x-shader/x-vertex">attribute vec2 a_position;void main() {gl_Position = vec4(a_position, 0.0, 1.0);gl_PointSize = 10.0;}</script><!-- 片元着色器源码 --><script id="fragmentShader" type="x-shader/x-fragment">void main() {gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}</script><script>let canvasElementlet glfunction init() {// 初始化WebGLinitWebGL()// 初始化着色器initShaders()// 初始化缓冲区initBuffers()// 绘制draw()}function initWebGL() {// 在这个函数执行的过程中,输入、输出,没有,过程:canvasElement gl// 获取canvas元素canvasElement = document.getElementById('canvasId')// 获取WebGL上下文gl = canvasElement.getContext('webgl')}function initShaders() {// 获取着色器源码const vsSource = document.getElementById('vertexShader').innerTextconst fsSource = document.getElementById('fragmentShader').innerText// 初始化着色器initShader(gl, vsSource, fsSource)}function initBuffers() {setPointPosition(0.5, 0.5)}function setPointPosition(x, y) {// 获取位置属性const a_position = gl.getAttribLocation(gl.program, 'a_position')// 设置位置属性gl.vertexAttrib2f(a_position, x, y)}function draw() {// 清空画布颜色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 清空画布gl.clear(gl.COLOR_BUFFER_BIT)// 绘制gl.drawArrays(gl.POINTS, 0, 1)}// --------------------------------------function initShader(gl, vsSource, fsSource) {// 创建着色器对象const vShader = loadShader(gl, gl.VERTEX_SHADER, vsSource)const fShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource)// 创建程序对象const program = gl.createProgram()// 将着色器对象分配给程序对象gl.attachShader(program, vShader)gl.attachShader(program, fShader)// 链接程序对象gl.linkProgram(program)// 使用程序对象gl.useProgram(program)// 将程序对象分配给gl.programgl.program = program}function loadShader(gl, type, source) {// 创建着色器const shader = gl.createShader(type)// 加载着色器源码gl.shaderSource(shader, source)// 编译着色器gl.compileShader(shader)return shader}</script></head><body onload="init()"><canvas id="canvasId"></canvas></body>
</html>
运行效果
总结:本文主要梳理了在Webgl中如何绘制一个点,也就是提供了位置,大小,颜色等信息之后,我们使用shader绘制出一个红色的点,旨在掌握基本的编程流程,下次我们从绘制线和面开始,逐步更深入代码,力求在前三次把代码中的细节走一遍。
上一篇:WebGL学习及项目实战(第01期:原理篇)
下一篇:WebGL学习及项目实战(第03期:绘制多个点,线,面)
返回系列首页