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

news2025/1/23 7:50:15

缩放

1 )原理

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


2 )公式

  • 已知

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

在着色器中缩放


1 )核心代码
  • 可以对gl_Position 的x、y、z依次缩放

    <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组成的三维向量,对其进行一次性缩放

    <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 )完整代码

<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变量
      <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 变量
      const u_Scale = gl.getUniformLocation(gl.program, 'u_Scale')
      gl.uniform1f(u_Scale, 1.0)
      
    • 添加动画让其动起来
      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 )完整代码

<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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1279600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

L1-009:N个数求和

目录 ⭐题目描述⭐ ⭐分析 ⭐程序代码 运行结果 ⭐文案分享⭐ ⭐题目描述⭐ 本题的要求很简单&#xff0c;就是求N个数字的和。麻烦的是&#xff0c;这些数字是以有理数分子/分母的形式给出的&#xff0c;你输出的和也必须是有理数的形式。 输入格式&#xff1a; 输入第一行给出…

GAN:PacGAN-生成对抗网络中两个样本的威力

论文&#xff1a;https://arxiv.org/pdf/1712.04086.pdf 代码&#xff1a;GitHub - fjxmlzn/PacGAN: [NeurIPS 2018] [JSAIT] PacGAN: The power of two samples in generative adversarial networks 发表&#xff1a;2016 一、摘要 1&#xff1a;GAN最重大的缺陷是&#xf…

数据库管理-第121期 我为什么写文章(202301203)

数据库管理-第121期 我为什么写文章&#xff08;202301203&#xff09; 其实呢~大周末我不是太想写文章的&#xff0c;周五HaloDB起了个头还有一堆可以做的事情都计划到下周了&#xff0c;但是昨天发生了一件事情&#xff0c;让我很是不开心&#xff1a;强盗逻辑&#xff0c;白…

部署 Draw.io 思维导图工具

1&#xff09;Draw.io 介绍 提到流程图&#xff0c;大家第一时间可能会想到 Visio&#xff0c;不可否认&#xff0c;VIsio 确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。…

分治-归并算法——LCR 170. 交易逆序对的总数

文章目录 &#x1f33c;0. 归并排序&#x1f33b;1. 题目&#x1f33c;2. 算法原理&#x1f337;3. 代码实现 &#x1f33c;0. 归并排序 归并排序是典型的分治&#xff0c;将数组分成若干个子数组&#xff0c;数组两两比较&#xff0c;不是很清楚的&#xff0c;可以查看此篇文…

VUE设计与实现共读系列之ref的实现【响应式原理】

前言 我们先顺一下vue使用响应式数据的流程&#xff1a; vue 是通过 ref 和 reactive 来创建响应式值&#xff0c;改变响应式值&#xff0c;视图跟着发生变化。 我们今天就来看一下ref和reactive是如何实现的 准备 首先&#xff0c;打开ref函数的位置 我们可以看到一个被re…

10行代码实现vue路由最简单的登陆拦截

需求&#xff1a;不涉及任何角色权限&#xff0c;基本实现目标&#xff0c;有token就可查看任何页面&#xff0c;否则就去登陆&#xff0c;来一步步实现 1. 创建你的路由页面&#xff0c;此处略了 2. 导航守卫拦截判断思路 // 创建路由 const router createRouter({history…

Python----字典练习

相关链接&#xff1a;Python---字典的增、删、改、查操作_python中字典的增删改查-CSDN博客 Python---字典---dict-CSDN博客 Python---引用变量与可变、非可变类型-CSDN博客 重点&#xff1a; 字典中的 key &#xff08;就是键&#xff09;可以是很多数据类型&#xff08;…

对比ProtoBuf和JSON的序列化和反序列化能力

1.序列化能力对比验证 在这里让我们分别使用PB与JSON的序列化与反序列化能力&#xff0c;对值完全相同的一份结构化数据进行不同次数的性能测试。 为了可读性&#xff0c;下面这一份文本使用JSON格式展示了需要被进行测试的结构化数据内容: {"age" : 20,"name…

SpringAMQP入门案例——接收消息

依赖 <!--SpringAMQP起步依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> yml配置文件 自行修改 spring:rabbitmq:host: 192.168.220.130 # …

Spring MVC学习随笔-控制器(Controller)开发详解:接受客户端(Client)请求参数

学习视频&#xff1a;孙哥说SpringMVC&#xff1a;结合Thymeleaf&#xff0c;重塑你的MVC世界&#xff01;&#xff5c;前所未有的Web开发探索之旅 第三章、SpringMVC控制器开发详解 3.1 核心要点 &#x1f4a1; 1. 接受客户端&#xff08;client&#xff09;请求参数[讲解] 2…

Linux脚本awk命令

目录 一. awk命令简介 1. awk版本 2. awk与vim的区别 3. awk与sed的区别 4. awk工作原理 5. awk格式 6. awk常用选项 二. awk基础用法 1. awk基础用法 2. BEGIN和END语句块 3. 指定分隔符 4. 首尾关键字 三. awk内置变量 1. FS变量 2. OFS变量 3. RS变量 4. NF…

【Unity动画】为一个动画片段添加事件Events

动画不管播放到那一帧&#xff0c;我们都可以在这里“埋伏”一个事件&#xff08;调用一个函数并且给函数传递一个参数&#xff0c;参数在外部设置&#xff0c;甚至传递一个物体&#xff09;&#xff01; 嗨&#xff0c;亲爱的Unity小伙伴们&#xff01;你是否曾想过为你的动画…

语言模型文本处理基石:Tokenizer简明概述

编者按&#xff1a;近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大型语言模型的问世&#xff0c;让 AI 写作、聊天等能力有了质的飞跃。如何更好地理解和利用这些生成式 AI&#xff0c;成为许多开发者和用户关心的问题。 今天&#xff0c;我们推出的这篇文章有助…

【小沐学Python】网络爬虫之lxml

文章目录 1、简介2、安装3、基本功能3.1 lxml.etree3.2 解析HTML网页3.3 读取并解析HTML文件3.4 提取所有a标签内的文本信息3.5 树迭代3.6 序列化3.7 元素以字典的形式携带属性3.8 元素包含文本 4、代码测试4.1 lxml解析网页4.2 使用xpath获取所有的文本4.3 使用xpath获取 clas…

TA-Lib学习研究笔记(二)——Overlap Studies上

TA-Lib学习研究笔记&#xff08;二&#xff09;——Overlap Studies 1. Overlap Studies 指标 [BBANDS, DEMA, EMA, HT_TRENDLINE, KAMA, MA, MAMA, MAVP, MIDPOINT, MIDPRICE, SAR, SAREXT, SMA, T3, TEMA, TRIMA, WMA]2.数据准备 get_data函数参数&#xff08;代码&#x…

mongoose学习记录

mongoose安装和连接数据库 npm i mongoose导入mongoose const mongoose require(mongoose) mongoose.set("strictQuery",true)连接数据库 mongoose.connect(mongodb:127.0.0.1:27017/test)设置回调 mongoose.connection.on(open,()>{console.log("连接成…

利用段落检索和生成模型进行开放域问答12.2

利用段落检索和生成模型进行开放域问答 摘要引言2 相关工作3 方法 摘要 事实证明&#xff0c;开放域问答的生成模型具有竞争力&#xff0c;无需借助外部知识。虽然很有希望&#xff0c;但这种方法需要使用具有数十亿个参数的模型&#xff0c;而这些模型的训练和查询成本很高。…

还在Wins 11怀念10的右键单击菜单?别担心,可通过注册表来实现

到目前为止&#xff0c;Windows 11最令人讨厌的新“功能”是右键单击任何内容时会出现截断的上下文菜单。以前版本的Windows显示了你的所有选项&#xff0c;包括可以打开文件的不同程序&#xff0c;而新菜单仅限于少数选项&#xff0c;不一定是你想要的。 例如&#xff0c;当我…

SHAP(五):使用 XGBoost 进行人口普查收入分类

SHAP&#xff08;五&#xff09;&#xff1a;使用 XGBoost 进行人口普查收入分类 本笔记本演示了如何使用 XGBoost 预测个人年收入超过 5 万美元的概率。 它使用标准 UCI 成人收入数据集。 要下载此笔记本的副本&#xff0c;请访问 github。 XGBoost 等梯度增强机方法对于具有…