着色器的概念
webgl 绘图需要两种着色器:
顶点着色器(Vertex shader):描述顶点的特征,如位置、颜色等。
片元着色器(Fragment shader):进行逐片元处理,如光照。
看了这两个名词的解释,我想很多初学者会是懵的。
给大家举一个更简单、更贴切的例子:
两点决定一条直线,顶点着色器里的顶点就是决定这一条直线的两个点,片元着色器里的片元就是把直线画到画布上后,这两个点之间构成直线的每个像素。
webGL编程指南,有一段话是这么描述着色器的:
顶点着色器 (Vertex shader)∶ 顶点着色器是用来描述顶点特性(如位置、颜色等) 的程序。顶点(vertex)是指二维或三维空间中的一个点,比如二维或三维图形的端点或交点。 绘制一个点
片元着色器(Fragment shader)∶进行逐片元处理过程如光照(见第8章"光照") 的程序。片元(fragment)是一个WebGL术语,你可以将其理解为像素(图像的单元)。
着色器,可以理解为运行在显卡中的指令和数据。
完整的着色器包括顶点着色器和片元着色器。顶点着色器最基本的任务是接收三维空间中点的坐标,将其处理为二维空间中的坐标并输出;片元着色器最基本的任务是对需要处理的屏幕上的每个像素输出一个颜色值;将顶点着色器输出的二维空间中的点坐标,转化为需要处理的像素并传递给片元着色器的过程,称为图元光栅化。
关于概念咱们就说到这,接下来咱们说着色器语言。
着色器语言
webgl 的着色器语言是GLSL ES语言
顶点着色程序,要写在type=“x-shader/x-vertex” 的script中。
<!-- 顶点着色器 --> <script id="vertexShader" type="x-shader/x-vertex"> void main(){ //点位 gl_Position=vec4(0,0,0,1); //尺寸 gl_PointSize=50.0; } </script>
片元着色程序,要写在type=“x-shader/x-fragment” 的script中。
<!-- 片元着色器 --> <script id="fragmentShader" type="x-shader/x-fragment"> void main(){ gl_FragColor=vec4(1,1,0,1); } </script>
void main() {…… } 是主体函数。
在顶点着色器中,gl_Position 是顶点的位置,gl_PointSize 是顶点的尺寸,这种名称都是固定的,不能写成别的。
在片元着色器中,gl_FragColor 是片元的颜色。
vec4() 是一个4维矢量对象。
将vec4() 赋值给顶点点位gl_Position 的时候,其中的前三个参数是x、y、z,第4个参数默认1.0,其含义我们后面会详解;
将vec4() 赋值给片元颜色gl_FragColor 的时候,其中的参数是r,g,b,a。
着色器初始化
初始化着色器的步骤:
建立程序对象,目前这只是一个手绘板的外壳。
const shaderProgram = gl.createProgram();
2.建立顶点着色器对象和片元着色器对象
//创建顶点着色器对象 const vertexShader = this.loaderShader( this.gl.VERTEX_SHADER, this.verSource ) //创建片元着色器对象 const fragmentShader = this.loaderShader( this.gl.FRAGMENT_SHADER, this.fragmentSource )
3.将顶点着色器对象和片元着色器对象装进程序对象中
// 添加预先定义好的顶点着色器和片段着色器 this.gl.attachShader(program, vertexShader) this.gl.attachShader(program, fragmentShader) //连接webgl上下文对象和程序对象 this.gl.linkProgram(program) //启动程序对象,使其开始绘制 this.gl.useProgram(program)
完整代码HTML
<!-- * @Description: * @Author: pang bo * @Date: 2021-05-24 22:19:23 * @LastEditTime: 2021-05-24 22:29:50 * @LastEditors: Do not edit --> <!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> </head> <style> * { margin: 0; padding: 0%; } html, body { width: 100%; height: 100%; overflow: hidden; } </style> <!-- 顶点着色器 --> <script id="vertexShader" type="x-shader/x-vertex"> void main(){ //点位 gl_Position=vec4(0,0,0,1); //尺寸 gl_PointSize=50.0; } </script> <!-- 片元着色器 --> <script id="fragmentShader" type="x-shader/x-fragment"> void main(){ gl_FragColor=vec4(1,1,0,1); } </script> <body> <canvas id="canvas"></canvas> </body> <script type="module"> import { InitShaDer } from './index.js' const canvas = document.getElementById('canvas'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; //获取着色器文本 const verSource = document.getElementById('vertexShader').innerText; const fragmentSource = document.getElementById('fragmentShader').innerText; const gl = canvas.getContext('webgl'); //初始化着色器 console.log(verSource, fragmentSource); let shaderObj = new InitShaDer(gl, verSource, fragmentSource); // 指定将要用来清理绘图区的颜色 gl.clearColor(0., 0.0, 0.0, 1.0); // 清理绘图区 gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.POINTS, 0, 1) </script> </html>
封装解析着色器JS代码
//初始化着色器 /** * @description: * @param {gl canvas实例对象,verSource,顶点着色器片段,fragmentSource片元着色器} * @return {*} */ export class InitShaDer { constructor(gl, verSource, fragmentSource) { this.gl = gl this.verSource = verSource this.fragmentSource = fragmentSource this.init() } init() { // 创建一个程序对象 const program = this.gl.createProgram() //创建顶点着色器对象 const vertexShader = this.loaderShader( this.gl.VERTEX_SHADER, this.verSource ) //创建片元着色器对象 const fragmentShader = this.loaderShader( this.gl.FRAGMENT_SHADER, this.fragmentSource ) // 添加预先定义好的顶点着色器和片段着色器 this.gl.attachShader(program, vertexShader) this.gl.attachShader(program, fragmentShader) //连接webgl上下文对象和程序对象 this.gl.linkProgram(program) //启动程序对象,使其开始绘制 this.gl.useProgram(program) if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) { var info = this.gl.getProgramInfoLog(program) throw 'Could not compile WebGL program. \n\n' + info } } //编译着色器,type代表是片元还是顶点着色器,source代表着色器代码 loaderShader(type, source) { //创建着色器对象 根据着色类型,建立着色器对象 const shader = this.gl.createShader(type) //将着色器源文件传入着色器对象中 this.gl.shaderSource(shader, source) //编译着色器对象 this.gl.compileShader(shader) return shader } }
发表评论
侧栏公告
寄语
譬如朝露博客是一个分享前端知识的网站,联系方式11523518。
热评文章
标签列表
热门文章
友情链接