【愚公系列】2023年12月 WEBGL专题-着色器

举报
愚公搬代码 发表于 2023/12/31 22:06:10 2023/12/31
【摘要】 🏆 作者简介,愚公搬代码🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,51CTO博客专家等。🏆《近期荣誉》:2023年华为云十佳博主,2022年CSDN博客之星TOP2,2022年华为云十佳博主等。🏆《博客内容》:.NET、Java、...

🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2023年华为云十佳博主,2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏

🚀一、什么是着色器

着色器(Shader)是一种编程语言,用于描述如何对场景中的对象进行渲染。它们被用于计算每个像素的颜色、亮度、反射、阴影、透明度等可视化效果。着色器可以被应用于3D模型、2D图形和视频动画中,以创建各种不同的效果和动画。着色器可以被绑定到渲染管道中的不同阶段,如顶点着色器、像素着色器、几何着色器等,以产生各种不同的效果。它们通常使用专门的编程语言,如OpenGL Shading Language(GLSL)或高级着色语言(HLSL)。

简而言之,着色器就是让开发者自己去编写一段程序,用来代替固定渲染管线,来处理图像的渲染。

🔎1.顶点着色器

顶点着色器是一种着色器类型,它是用于3D图形渲染管线中的第一个阶段。它是一个自定义程序,它以每个顶点为输入,并且计算每个顶点的最终屏幕位置。它还对每个顶点执行各种变换和变形,例如旋转、缩放和平移。它还可以对每个顶点进行颜色、纹理和材质属性的计算。顶点着色器通常被用于创建各种特殊效果,如动态几何变换、实时阴影和变形动画。它通常使用着色语言编写,如OpenGL Shading Language(GLSL)或高级着色语言(HLSL)。

在这里插入图片描述

🔎2.片元着色器

片元着色器(也称为像素着色器)是在渲染管线中的一个阶段,用于在像素级别上对三维图形进行着色和渲染。它的作用是确定在屏幕上显示的每个像素的颜色和位置,并且可以实现各种效果,如光照、纹理、阴影等。片元着色器会对每个像素进行处理并将其颜色显示在屏幕上,因此它对于图形的最终呈现效果至关重要。

在这里插入图片描述

🔎3.着色器工作流程

WebGL着色器工作流程如下:

  1. 准备数据:WebGL通过缓冲区对象(Buffer Object)来存储着色器需要处理的数据,包括顶点坐标、纹理坐标、法线向量等,这些数据需通过JavaScript传入程序。

  2. 编写顶点着色器:顶点着色器负责处理顶点数据,将顶点坐标和其他数据转换为可渲染的形式,并传递给片元着色器,每个顶点被处理一次。

  3. 编写片元着色器:片元着色器负责处理像素的颜色值,将纹理贴图、光照和材质属性等应用到像素上,每个像素被处理一次。

  4. 编译着色器程序:将顶点着色器和片元着色器编译成着色器程序,并将它们链接起来。

  5. 传递数据:将准备好的数据传递给着色器程序。

  6. 渲染图形:使用着色器程序渲染图形,WebGL根据顶点着色器和片元着色器的指令来处理数据,并输出渲染结果。

以上就是WebGL着色器的工作流程,它可以帮助开发者实现各种复杂的3D图形效果。
在这里插入图片描述
在这里插入图片描述

🔎4.案例

🦋4.1 静态版

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>绘制一个点</title>
    <!-- //顶点着色器  shader  vertex-->
    <script type='x-shader/x-vertex' id='shader-vs'>
        void main(){
            gl_Position=vec4(0.5,0.0,1.0,1.0); 
            gl_PointSize=20.0; 
        }
    </script>
    <!-- //  范围: 0 - 1  -->
    <!-- 片元着色器 -->
    <script type='x-shader/x-fragment' id='shader-fs'>
        void main(){ 
            gl_FragColor=vec4(0.5,0.0,0.0,1.0);  
        }
    </script>

</head>

<body>
    <!-- style="width:400px;height:400px"  不要这样-->
    <canvas id="webgl" width="400" height="400"></canvas>
    <script>
        //1. 获取webgl
        var canvas = document.getElementById('webgl');
        var gl = canvas.getContext('webgl');
        gl.clearColor(0.5, 0.5, 0.5, 1.0); //rgba - 0 - 0    1 - 255
        gl.clear(gl.COLOR_BUFFER_BIT);
        //1. 初始化着色器 ,方式一
        var vs_source = document.getElementById('shader-vs').innerHTML,
            fs_source = document.getElementById('shader-fs').innerHTML;
        //方式二:
        // var vs_source = `
        //     void main(){
        //         gl_Position=vec4(0.5,0.0,1.0,1.0); 
        //         gl_PointSize=80.0; 
        //     }
        // `;
        // var fs_source = `
        //     void main(){ 
        //         gl_FragColor=vec4(0.0,0.0,0.0,1.0);  
        //     }
        // `;
        //2 创建顶点着色器
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        //绑定资源
        gl.shaderSource(vertexShader, vs_source);
        //编译顶点着色器
        gl.compileShader(vertexShader);
        //. 2 创建片段着色器
        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        // 绑定资源
        gl.shaderSource(fragmentShader, fs_source);
        // 编译片段着色器
        gl.compileShader(fragmentShader);
        // 3.创建一个着色器程序
        var glProgram = gl.createProgram();
        gl.attachShader(glProgram, vertexShader); //把顶点着色器添加到着色器程序 
        gl.attachShader(glProgram, fragmentShader); //把片元着色器添加到着色器程序 
        // 4.把着色器程序链接成一个完整的程序
        gl.linkProgram(glProgram);
        gl.useProgram(glProgram);
        gl.drawArrays(gl.POINTS, 0, 1);
    </script>
</body>

</html>

在这里插入图片描述

🦋4.2 动态版

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>绘制一个点</title>

</head>

<body>
    <!-- style="width:400px;height:400px"  不要这样-->
    <canvas id="webgl" width="400" height="400"></canvas>

    <script>
        //1. 获取webgl
        var canvas = document.getElementById('webgl');
        var gl = canvas.getContext('webgl');
        // gl.clearColor(0.5,0.5,0.5,1.0);  //rgba - 0 - 0    1 - 255
        // gl.clear(gl.COLOR_BUFFER_BIT);
        //1. 初始化着色器 ,方式一
        //方式二:
        //顶点
        var vs_source = `
        attribute vec4 a_Position;
        attribute float a_PointSize;
        void main(){
            gl_Position=a_Position; 
            gl_PointSize=a_PointSize; 
        }
    `;
        // vec4(0.5,0.0,1.0,1.0)
        //片元
        var fs_source = `
        void main(){ 
            gl_FragColor=vec4(0.5,0.0,0.0,1.0);  
        }
    `;
        //2 创建顶点着色器
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        //绑定资源
        gl.shaderSource(vertexShader, vs_source);
        //编译顶点着色器
        gl.compileShader(vertexShader);
        //. 2 创建片段着色器
        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        // 绑定资源
        gl.shaderSource(fragmentShader, fs_source);
        // 编译片段着色器
        gl.compileShader(fragmentShader);
        // 3.创建一个着色器程序
        var glProgram = gl.createProgram();
        gl.attachShader(glProgram, vertexShader); //把顶点着色器添加到着色器程序 
        gl.attachShader(glProgram, fragmentShader); //把片元着色器添加到着色器程序 
        // 4.把着色器程序链接成一个完整的程序
        gl.linkProgram(glProgram);
        gl.useProgram(glProgram);
        // 获取attribute变量的存储位置 , 返回对应的地址信息
        var aPosition = gl.getAttribLocation(glProgram, 'a_Position');
        //给变量赋值
        gl.vertexAttrib3f(aPosition, 0.0, 0.5, 0.0); //位置
        // vertexAttrib函数功能,3:对应需要传3个参数,或者是几维向量,
        // f:表示参数是float类型,
        var aPointSize = gl.getAttribLocation(glProgram, 'a_PointSize');
        gl.vertexAttrib1f(aPointSize, 50.0); //大小
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clear(gl.COLOR_BUFFER_BIT);
        //绘制
        gl.drawArrays(gl.POINTS, 0, 1);
    </script>
</body>

</html>

在这里插入图片描述

🦋4.3 最终版

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
</head>
<body>
  <canvas id="canvas" width="400" height="400">
    此浏览器不支持canvas
  </canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')


  // 着色器
  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    // 必须要存在 main 函数
    void main() {
      // 要绘制的点的坐标
      gl_Position = vec4(0.0,0.0,0.0,1.0);
      // 点的大小
      gl_PointSize = 30.0;
    }
  `; // 顶点着色器

  //  gl_Position vec4(0.0,0.0,0.0,1.0)  x, y, z, w齐次坐标 (x/w, y/w, z/w)

  // gl_FragColor vec4(1.0,0.0,0.0,1.0) r, g, b, a
  const FRAGMENT_SHADER_SOURCE = `
    void main() {
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }
  `; // 片元着色器


  // 创建着色器
  // const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  // const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  //
  // gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE) // 指定顶点着色器的源码
  // gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE) // 指定片元着色器的源码
  //
  // // 编译着色器
  // gl.compileShader(vertexShader)
  // gl.compileShader(fragmentShader)
  //
  // // 创建一个程序对象
  // const program = gl.createProgram();
  //
  // gl.attachShader(program, vertexShader)
  // gl.attachShader(program, fragmentShader)
  //
  // gl.linkProgram(program)
  //
  // gl.useProgram(program)

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  // 执行绘制

  // 要绘制的图形是什么, 从哪个开始,   使用几个顶点
  gl.drawArrays(gl.POINTS, 0, 1);
  gl.drawArrays(gl.LINES, 0, 1); // 最少需要有两个点,
  gl.drawArrays(gl.TRIANGLES, 0, 1); // 3个点

  // 3个顶点
  // 0.0, 0.0, 0.0
  // 0.2, 0.0, 0.0
  // 0.4, 0.0, 0.0
  gl.drawArrays(gl.POINTS, 0, 1);
  gl.drawArrays(gl.LINES, 1, 2);
</script>

initShader函数的封装

function initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) {
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

  gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE) // 指定顶点着色器的源码
  gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE) // 指定片元着色器的源码

  // 编译着色器
  gl.compileShader(vertexShader)
  gl.compileShader(fragmentShader)

  // 创建一个程序对象
  const program = gl.createProgram();

  gl.attachShader(program, vertexShader)
  gl.attachShader(program, fragmentShader)

  gl.linkProgram(program)

  gl.useProgram(program)

  return program;
}

在这里插入图片描述

🚀备注

vec4表示四维向量。它由四个分量组成:x, y, z 和 w。w 的意义取决于 vec4 被用于何种目的:

  • 用于表示点的四维坐标时,w = 1. 这时 vec4 表示三维空间中的一个点加上一个额外的维度。
  • 用于表示方向的四维向量时,w = 0. 这时 vec4 表示一个三维方向加上一个零的第四维分量。
  • 用于表示四元数时,w 为实部,x、y、z 为虚部。四元数可以用来表示旋转和方向。
  • 用于表示仿射变换(例如平移、缩放、旋转)的矩阵时,w 用于指定平移分量。

🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。

在这里插入图片描述

再次感谢您的阅读和支持!

最诚挚的问候, “愚公搬代码”

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。