WebGL笔记:图形缩放的原理和实现

缩放

1 )原理

  • 缩放可以理解为对向量长度的改变,或者对向量坐标分量的同步缩放
    • 如下图,比如
    • 让向量OA 收缩到点B的位置,也就是从OA变成OB,缩放了一半

2 )公式

  • 已知

    • 点A的位置是(ax,ay,az)
    • 点A基于原点內缩了一半
    • 点A內缩了一半后的bx、by、bz位置B
  • js 复制代码
    bx = ax * 0.5
    by = ay * 0.5
    bz = az * 0.5

在着色器中缩放

1 )核心代码

  • 可以对gl_Position 的x、y、z依次缩放

    html 复制代码
    <script id="vertexShader" type="x-shader/x-vertex">
      attribute vec4 a_Position;
      float scale = 1.2; // 注意这里声明了浮点型,一点要用浮点数,否则会导致 UseProgram: program not valid 的警告
      void main() {
        gl_Position.x = a_Position.x * scale;
        gl_Position.y = a_Position.y * scale;
        gl_Position.z = a_Position.z * scale;
        gl_Position.w = 1.0; // 注意 w 的值,默认1.0
      }
    </script>
  • 也可以从a_Position中抽离出由x、y、z组成的三维向量,对其进行一次性缩放

    html 复制代码
    <script id="vertexShader" type="x-shader/x-vertex">
      attribute vec4 a_Position;
      float scale = 1.2;
      void main() {
        gl_Position = vec4(vec3(a_Position) * scale, 1.0);
      }
    </script>

2 )完整代码

html 复制代码
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
  attribute vec4 a_Position;
  float scale = 1.0;
  void main() {
      gl_Position = vec4(vec3(a_Position) * scale, 1.0);
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  void main(){
      gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
</script>
<script type="module">
  import { initShaders } from './utils.js';

  const canvas = document.getElementById('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const gl = canvas.getContext('webgl');
  const vsSource = document.getElementById('vertexShader').innerText;
  const fsSource = document.getElementById('fragmentShader').innerText;
  initShaders(gl, vsSource, fsSource);

  const vertices = new Float32Array([
    0.0, 0.1,
    -0.1, -0.1,
    0.1, -0.1
  ])

  const vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

用js缩放图形

1 )核心代码

  • 同样的我们也可以把缩放系数暴露给js,通过js 缩放图形
    • 建立uniform变量

      html 复制代码
      <script id="vertexShader" type="x-shader/x-vertex">
          attribute vec4 a_Position;
          uniform float u_Scale;
          void main() {
              gl_Position = vec4(vec3(a_Position) * u_Scale, 1.0);
          }
      </script>
    • 使用js获取并修改uniform 变量

      js 复制代码
      const u_Scale = gl.getUniformLocation(gl.program, 'u_Scale')
      gl.uniform1f(u_Scale, 1.0)
    • 添加动画让其动起来

      js 复制代码
      let angle = 0
      !(function animate() {
          angle += 0.05;
          const scale = Math.sin(n) + 1; // 借助三角函数正弦进行缩放 (-1, 1) + 1 => (0, 2)
          gl.uniform1f(u_Scale, scale);
          gl.clear(gl.COLOR_BUFFER_BIT);
          gl.drawArrays(gl.TRIANGLES, 0, 3);
          requestAnimationFrame(animate)
      })()

2 )完整代码

html 复制代码
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
  attribute vec4 a_Position;
  uniform float u_Scale;
  void main() {
      gl_Position = vec4(vec3(a_Position) * u_Scale, 1.0);
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  void main() {
      gl_FragColor = vec4(1.0,1.0,0.0,1.0);
  }
</script>
<script type="module">
  import { initShaders } from './utils.js';

  const canvas = document.getElementById('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const gl = canvas.getContext('webgl');

  const vsSource = document.getElementById('vertexShader').innerText;
  const fsSource = document.getElementById('fragmentShader').innerText;
  initShaders(gl, vsSource, fsSource);
  
  const vertices = new Float32Array([
    0.0, 0.1,
    -0.1, -0.1,
    0.1, -0.1
  ])

  const vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);

  const u_Scale = gl.getUniformLocation(gl.program, 'u_Scale')
  gl.uniform1f(u_Scale, 1);

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLES, 0, 3);

  let angle = 0;
  !(function animate() {
    angle += 0.05;
    const scale = Math.sin(angle) + 1;
    gl.uniform1f(u_Scale, scale);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(animate);
  })()
</script>
相关推荐
IT小白杨5 天前
链上任务与海外社媒多账号:环境隔离工具技术横评
经验分享·webgl·chrome devtools·安全架构·指纹浏览器
AI_AGENT_DEV_AI11 天前
数字孪生项目的开发
webgl
supermapsupport12 天前
SuperMap GIS 基础产品 FAQ 集锦(20260807)
webgl·supermap·idesktopx
supermapsupport12 天前
SuperMap iClient3D for WebGL 如何开启实体对象深度检测
webgl
IT小白杨12 天前
2026Shopee多站点运营的浏览器隔离与移动端云手机方案
经验分享·社交电子·webgl·安全架构·指纹浏览器
echoVic13 天前
同一个 bug,我在 WebGPU 渲染器里犯了两轮:一帧内多次写同一块 buffer
前端·webgl·图形学
用户831348593069816 天前
Vue3+Cesium实现阴天乌云+下雨天气特效
vue.js·webgl·cesium
引山洪0817 天前
Babylon.js 8.x 中文文档整理——Node篇 (上)
前端·webgl
想做后端的前端24 天前
WebGL实现FPS游戏
vue.js·游戏·webgl
ZENERGY-众壹24 天前
延时 5 秒怎么调优:光伏 SCADA 实时画面与 WebGL 拓扑集成的性能复盘
性能优化·webgl·scada·光伏运维·api集成