WebGL学习【焕新计划】

作者 : admin 本文共4477个字,预计阅读时间需要12分钟 发布时间: 2024-06-17 共1人阅读

WebGL基础

在正式进入webgl之前,我想有必要简单了解一下渲染管线,毕竟它贯穿webgl学习的整个过程。

渲染管线流程图:

WebGL学习【焕新计划】插图

webgl着色器简单语法:

在GLSL(OpenGL Shading Language)中,常见的变量类型可以归纳为以下几种,并根据提供的参考文章进行详细的解释:

  1. 基本数据类型
    • 整型(int):用于存放自然数的变量。
    • 浮点型(float):用于存放小数点数值的变量。
    • 布尔型(bool):用于存放0值或非0值,0代表false,1代表true。
  2. 向量(vec)
    • GLSL中的向量类型可以是2维(vec2)、3维(vec3)或4维(vec4)。
    • 向量中的数据类型可以是整数、浮点数或布尔值。
    • 向量在GLSL中常用于描述颜色、坐标和纹理等。
  3. GLSL内置变量
    • 顶点属性(attribute):指顶点的信息,如顶点坐标、纹理坐标、颜色等。GLSL会为这些传统的顶点属性设置内置变量与之对应,以便在需要时可以在顶点或片元着色器中直接引用。
    • 一致变量(uniform):是外部应用程序传递给(顶点和片元)着色器的变量。它在着色器程序内部是不可修改的,通常用于表示变换矩阵、材质、光照参数和颜色等信息。
    • 易变变量(varying):由顶点程序向片元程序插值传递的变量。这些变量在顶点着色器中定义,并在片元着色器中使用,用于传递从顶点计算得到的插值数据。
    • 其他内置变量:如gl_ModelViewMatrix(模型视图变换矩阵)、gl_ProjectMatrix(投影矩阵)等,这些变量描述了OpenGL的状态,并在着色器之间共享。
  4. 特殊变量
    • gl_Position:在顶点着色器中用于写顶点位置,其类型是highp vec4
    • gl_FragColor:在片元着色器中用于写片元颜色,其类型是mediump vec4
    • gl_PointSize:在顶点着色器中用于写光栅化后的点大小,其类型是mediump float

向量与矩阵

常见内置变量

常见数据类型

常见修饰符

vec3

gl_PointSize

float

attribute

vec4

gl_Position

int

uniform

mat3

gl_FragColor

bool

varying

mat4

gl_FragCoord

sampler2D

gl_ModelViewMatrix
gl_ProjectMatrix

说明:

  • in和out

   glsl版本不同,attribute和uniform在glsl 新本本对应着inout是两种特殊的变量限定符,它们用于在着色器阶段之间传递数据。

  • in限定符
  • 用途in用于在着色器阶段之间输入数据。在顶点着色器中,in变量通常表示从CPU传入的顶点数据,如顶点位置、纹理坐标等。在片元着色器中,in变量表示从顶点着色器插值传递过来的数据。

  • 示例

// 顶点着色器示例  
#version 330 core  
layout(location = 0) in vec3 aPos;    // aPos是一个in变量,表示顶点位置  
out vec4 vertexColor;                 // vertexColor是一个out变量,用于将颜色数据传递给片元着色器  
  
void main() {  
    gl_Position = vec4(aPos, 1.0);    // 设置顶点位置  
    vertexColor = vec4(1.0, 0.0, 0.0, 1.0); // 设置顶点颜色为红色  
}
  •  out限定符
  • 用途out用于在着色器阶段之间输出数据。在顶点着色器中,out变量用于将计算得到的数据传递给下一个着色器阶段(通常是片元着色器)。在片元着色器中,out变量表示最终的像素颜色或其他输出数据。

  • 示例

// 片元着色器示例  
#version 330 core  
in vec4 vertexColor;    // vertexColor是一个in变量,从顶点着色器接收颜色数据  
out vec4 FragColor;     // FragColor是一个out变量,表示最终的像素颜色  
  
void main() {  
    FragColor = vertexColor; // 直接将顶点着色器传递过来的颜色作为最终像素颜色  
}
  • 坐标变换:【3D基础】坐标转换——地理坐标投影到平面_将世界地理坐标投影到平面的方法-CSDN博客
  • Three.js和Cesium.js中坐标_threejs 物体缩放后需要更新世界坐标吗-CSDN博客
  • 最后在正式开始前,先大致了解整个流程:
  • 整个流程:

WebGL学习【焕新计划】插图(1)

 WebGL学习【焕新计划】插图(2)

 WebGL学习【焕新计划】插图(3)

 (注:上述内容为搭建一个框架,此外课程学习前可能需一些计算机图形学和线性代数的基本知识,若还未学习相关内容的小伙伴可以去B站学习相关内容,推荐《计算机图形学入门》和《线性代数的本质》两门课程,当然学习webgl还是很推荐郭老师的课程哈!课程+博客!)

了解大致流程后,开始正式webgl入门课程的学习:

1.绘制一个点

1.1实现效果:

WebGL学习【焕新计划】插图(4)

1.2实现代码:

 
  
      
      使用WebGL绘制一个点
  
  
  
  



  
  

  
  

  
  
  

1.3解析:刚入门第一个案例较为简单,通过本案例了解代码编写整个流程即可

2. 绘制一个矩形

2.1实现效果:

WebGL学习【焕新计划】插图(5)

2.2实现代码:

 
  
      
      使用WebGL绘制一个矩形
  
  
  
  
  
  

  
  
  
  
  

2.3解析:本案例,在之前案例的基础上,增加了声明变量和为变量传递数据的过程。在webgl中先需创建一个类型化数组存储“顶点”信息,然后在绘制的过程,指定绘制的类型,这时进行图元装配时就会将点按指定要求绘制成几何体。如本案例就是绘制类型gl.LINE_LOOP(闭合线)就会将点连城闭合线(矩形)

3.绘制三角形|投影(UV坐标)

3.1实现效果

WebGL学习【焕新计划】插图(6)

3.2实现代码




  
  绘制三角形|投影



  
  

  
  
  
  
  


3.3解析:本案例将对z轴进行投影,投影为二维平面,所以第一个顶点的1.0,可以取值[-1.0,1.0],效果都一样,若超过1.0或少于-1.0,测试不难发现会有部分被裁掉,因为在webgl中坐标为[-1.0 ,1.0],所以效果左边的图设置三角形顶点1的z值[-1.0,1.0]皆是那个效果,右图为z值为2.0的效果

中级案例:

绘制一个时钟

 1.实现效果:

2.实现代码:




    
    
    
    时针
    
        #myCanvas{
            background-color: rgb(246, 246, 249);
        }
    
    
    
  
  
  


3.核心拆解:

3.1 片元着色器中调用 texture2D(texture,texcoord),方法有两个参数,一个为所需要的纹理,另一部分为纹理坐标。纹理坐标好办,创建类型化数组传递即可。本案例涉及多重纹理叠加,所以最后片源着色器的颜色为两种颜色的和。

       vec4 color1 = texture2D(u_Sampler,v_TexCoord);
       vec4 color2 = texture2D(u_Sampler1,vec2(v_TexCoord.x + u_Ani , v_TexCoord.y));
       gl_FragColor = color1 + color2;

本案例还涉及动态雾,所以需要利用requestAnimationFrame()方法,进行不断绘制。

function tick() {
            requestAnimFrame(tick)
            draw();
        };

下面重点讲述纹理数据的创建与传递,纹理的创建可参考缓冲区的创建:

1.webgl.createTexture创建纹理对象

2.配置纹理对象的属性 .image   .image.src   .image.onload

3.绑定纹理、设置二维纹理、设置纹理属性,将其封装归类到handleLoaderTexture()方法中

4.最后在绘制函数draw()中激活、绑定、传递纹理数据

        function handleLoadedTexture(texture) {


            webgl.bindTexture(webgl.TEXTURE_2D, texture);
            webgl.texImage2D(webgl.TEXTURE_2D, 0, webgl.RGBA, webgl.RGBA, webgl.UNSIGNED_BYTE, texture.image);
            webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_MAG_FILTER, webgl.LINEAR);
            webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_MIN_FILTER, webgl.LINEAR);
            webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_S, webgl.REPEAT);
            webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_T, webgl.REPEAT);

            // webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_S, webgl.CLAMP_TO_EDGE);
            // webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_T, webgl.CLAMP_TO_EDGE);

        }
        function initTexture(imageFile, num) {
            let textureHandle = webgl.createTexture();
            textureHandle.image = new Image();
            textureHandle.image.src = imageFile;
            textureHandle.image.onload = function () {
                handleLoadedTexture(textureHandle, num)
            }
            return textureHandle;
        }
        function draw() {
            webgl.clearColor(0.0, 1.0, 0.0, 1.0);
            webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
            webgl.enable(webgl.DEPTH_TEST);
            //纹理变动
            uniformAnim = webgl.getUniformLocation(webgl.program, "anim");
            count = count + 0.01;
            webgl.uniform1f(uniformAnim, count);
            
            webgl.activeTexture(webgl.TEXTURE0);
            webgl.bindTexture(webgl.TEXTURE_2D, texture0);
            webgl.uniform1i(uniformTexture, 0);

            webgl.activeTexture(webgl.TEXTURE1);
            webgl.bindTexture(webgl.TEXTURE_2D, texture1);
            webgl.uniform1i(uniformTexture1, 1);

            webgl.drawArrays(webgl.TRIANGLES, 0, 6);
        }

(注:在WebGL渲染纹理时,纹理的像素也有要求的,需要为2的幂次方,所以有时用自己的纹理图片去贴图时,明明代码都一样却总出来一个黑色照片,不是代码的问题,是原始数据的问题)

本站无任何商业行为
个人在线分享 » WebGL学习【焕新计划】
E-->