【愚公系列】2023年08月 WEBGL专题-3D特效-半透明


前言

半透明物体是指在光线透过时,可以看到模糊的影像,但不完全透明的物体。这种物体通常具有一定的透明性,但不完全透明,仍然存在某种程度上的不透明性。

半透明物体的意义在于它可以在不影响视线的情况下,让光线穿过物体,使得我们能够观察到物体背后或者内部的部分。这种特性在许多应用中都非常有用,比如建筑物中的玻璃窗、医疗设备中的透明塑料、以及电子设备中的显示屏。此外,半透明物体还具有一定的艺术效果,可以让物体呈现出半透明的质感和神秘感,增强视觉体验。

一、半透明

1.流程说明

在WebGL中创建半透明物体需要遵循以下步骤:

  1. 在片元着色器中定义透明度属性,并使用gl_FragColor来设置颜色和透明度值。

  2. 使用gl.enable(gl.BLEND)启用混合模式,这样可以将透明物体正确地混合到场景中。

  3. 使用gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)设置混合函数,指定源颜色因子和目标颜色因子,以便正确地混合透明物体。

  4. 在渲染透明物体时,确保先渲染不透明的物体,再渲染半透明的物体。这样可以避免混合时受到前面物体的影响而导致不正确的结果。

2.方法说明

要实现透明,需要开启混合,会使用到下面的两个方法:

  • gl.enable(gl.BLEND):开启混合

  • gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA):源因子和目标因子是可以通过gl.blendFunc函数来进行设置的,gl.blendFunc有两个参数,前者表示源因子,后者表示目标因子。这两个参数可以是多种值,下面介绍比较常用的几种。

    • gl.ZERO:表示使用0.0作为因子,实际上相当于不使用这种颜色参与混合运算。
    • gl.ONE:表示使用1.0作为因子,实际上相当于完全的使用了这种颜色参与混合运算。
    • gl.SRC_ALPHA:表示使用源颜色的alpha值来作为因子。
    • gl.DST_ALPHA:表示使用目标颜色的alpha值来作为因子。
    • gl.ONE_MINUS_SRC_ALPHA:表示用1.0减去源颜色的alpha值来作为因子。
    • gl.ONE_MINUS_DST_ALPHA:表示用1.0减去目标颜色的alpha值来作为因子。

3.案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</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 = `
    attribute vec4 aPosition;
    attribute vec4 aNormal;
    varying vec4 vColor;

    uniform mat4 mat;
    void main() {
      // 定义点光源的颜色
      vec3 uPointLightColor = vec3(1.0,1.0,0.0);

      // 点光源的位置
      vec3 uPointLightPosition = vec3(-5.0,6.0,10.0);

      // 环境光
      vec3 uAmbientLightColor = vec3(0.2,0.2,0.2);

      // 物体表面的颜色
      vec4 aColor = vec4(1.0,0.0,0.0,1.0);

      // 顶点的世界坐标
      vec4 vertexPosition = mat * aPosition;

      // 点光源的方向
      vec3 lightDirection = normalize(uPointLightPosition - vec3(vertexPosition));

      // 环境反射
      vec3 ambient = uAmbientLightColor * vec3(aColor);

      // 计算入射角 光线方向和法线方向的点积
      float dotDeg = dot(lightDirection, vec3(aNormal));

      // 漫反射光的颜色
      vec3 diffuseColor = uPointLightColor * vec3(aColor) * dotDeg;

      gl_Position = vertexPosition;
      vColor = vec4(ambient + diffuseColor, 0.5);
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    precision lowp float;
    varying vec4 vColor;

    void main() {
      gl_FragColor = vColor;
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const aNormal = gl.getAttribLocation(program, 'aNormal');
  const mat = gl.getUniformLocation(program, 'mat');

  const vertices = new Float32Array([
    // 0123
    1, 1, 1,
    -1, 1, 1,
    -1,-1, 1,
    1,-1, 1,
    // 0345
    1, 1, 1,
    1,-1, 1,
    1,-1,-1,
    1, 1,-1,
    // 0156
    1, 1, 1,
    1, 1, -1,
    -1, 1,-1,
    -1, 1,1,
    // 1267
    -1, 1, 1,
    -1,1, -1,
    -1, -1,-1,
    -1,-1,1,
    // 2347
    -1,-1, 1,
    1,-1, 1,
    1,-1,-1,
    -1,-1,-1,
    // 4567
    1,-1,-1,
    1, 1,-1,
    -1, 1,-1,
    -1,-1,-1,
  ])

  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aPosition)

  // 法向量
  const normals = new Float32Array([
    0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,
    0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,
    -1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,
    1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,
    0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,
    0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,
  ])
  const normalBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aNormal)

  const indeces = new Uint8Array([
    0,1,2,0,2,3,
    4,5,6,4,6,7,
    8,9,10,8,10,11,
    12,13,14,12,14,15,
    16,17,18,16,18,19,
    20,21,22,20,22,23,
  ])
  const indexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indeces, gl.STATIC_DRAW);

  gl.enable(gl.BLEND);

  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

  const vm = getViewMatrix(3,3,5,0.0,0.0,0.0,0.0,0.6,0.0);
  const perspective = getPerspective(30, ctx.width / ctx.height, 100, 1);

  gl.uniformMatrix4fv(mat, false, mixMatrix(perspective, vm));
  gl.drawElements(gl.TRIANGLES, indeces.length, gl.UNSIGNED_BYTE, 0);

</script>

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/aa2528877987/article/details/132168378