WebGL学习-夹角的归一化

代码功能解析

这段 GLSL 片元着色器代码的核心功能是:根据像素在 UV 坐标系中的位置,计算该像素相对于中心点的角度,并将角度值映射到 [0,1] 范围,最终用这个值作为灰度色值渲染像素,呈现出从中心点向外辐射的角度渐变效果(类似雷达图的角度色标)。

逐行详细解释

glsl 复制代码
// 兼容 OpenGL ES 环境,指定浮点数精度为中等精度(移动设备常用)
#ifdef GL_ES
precision mediump float;
#endif

// 从顶点着色器传入的 UV 坐标(范围通常是 [0,1])
varying vec2 vUv;

void main(){
    // 将 UV 坐标原点从左下角(0,0)移到画布中心(0.5,0.5),此时 p 的范围是 [-0.5, 0.5]
    vec2 p = vUv - 0.5;
    // 定义圆周率常量
    float PI = 3.1415926;
    
    // 计算像素相对于中心点的角度(atan(y,x) 返回范围是 [-π, π])
    float a = atan(p.y, p.x);
    // 将角度从 [-π, π] 归一化到 [0,1] 范围(GLSL 颜色值要求在 0-1 之间)
    float t = (a + PI) / (2.0 * PI);
    
    // 将归一化后的角度值作为 RGB 通道值(灰度),Alpha 通道为 1(不透明)
    gl_FragColor = vec4(vec3(t), 1.0);
}

关键逻辑说明

  1. UV 坐标转换vUv 是纹理坐标,默认原点在左下角(0,0),vUv - 0.5 后原点移到画布中心,p 的 x/y 分别表示像素相对于中心点的水平/垂直偏移。
  2. 角度计算atan(p.y, p.x) 是 GLSL 中求反正切的函数(注意参数顺序是 y 在前、x 在后),返回值范围是 (左)到 π(右),对应顺时针/逆时针方向的角度。
  3. 归一化(a + PI) 将角度范围从 [-π, π] 平移到 [0, 2π],再除以 得到 [0,1] 的归一化值,刚好匹配 GLSL 颜色通道的取值范围。

效果预览

  • 画布中心点(0.5,0.5)是角度计算的原点;
  • 正右方(x 轴正方向)像素的角度为 0,对应色值 t=0(黑色);
  • 正上方(y 轴正方向)像素的角度为 π/2,对应色值 t=0.25(深灰色);
  • 正左方(x 轴负方向)像素的角度为 π,对应色值 t=0.5(中灰色);
  • 正下方(y 轴负方向)像素的角度为 -π/2,对应色值 t=0.75(浅灰色);
  • 回到正右方完成一圈,色值回到 0,形成连续的角度渐变。

扩展优化建议

如果想让效果更直观(比如彩色角度渐变),可以将归一化的 t 映射到 HSV 颜色空间再转 RGB:

glsl 复制代码
#ifdef GL_ES
precision mediump float;
#endif

varying vec2 vUv;

// HSV 转 RGB 辅助函数(GLSL 无内置,需自定义)
vec3 hsv2rgb(vec3 c) {
    vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

void main(){
    vec2 p = vUv - 0.5;
    float PI = 3.1415926;
    float a = atan(p.y, p.x);
    float t = (a + PI) / (2.0 * PI);
    
    // 用角度 t 作为色相(H),饱和度 1,明度 1,转 RGB 彩色
    vec3 color = hsv2rgb(vec3(t, 1.0, 1.0));
    gl_FragColor = vec4(color, 1.0);
}

总结

  1. 核心逻辑:通过 atan(p.y, p.x) 计算像素相对中心点的角度,再将 [-π, π] 的角度归一化为 [0,1] 的颜色值;
  2. 坐标转换:vUv - 0.5 是将计算原点移到画布中心的关键步骤;
  3. 颜色映射:归一化后的角度值可直接作为灰度色值,也可映射到色相实现彩色角度渐变。

扩展基础知识

我纯用大白话讲清楚「夹角」的数学核心概念,不带任何编程相关的内容,保证好理解:

一、夹角的基础定义

简单说,夹角就是平面上两条相交的直线(或向量)之间形成的角 ,咱们平时说的"角"其实大多都是夹角。

比如你张开两根手指,手指之间的那个"开口大小"就是夹角;钟表上时针和分针撞在一起,俩指针之间的角也是夹角。

数学里规定,夹角的取值范围最小是0°(两条线完全重合),最大是180°(两条线成一条直线)。

二、平面直角坐标系里的夹角(重点)

咱们平时用的坐标系(横是x轴、竖是y轴)里,最常用的夹角是「向量与x轴正方向的夹角」:

  1. 先画一个向量(可以理解成"带方向的线段"),比如从坐标原点出发,指向点(3,4)的线段就是一个向量;
  2. 这个向量和x轴正方向(也就是水平朝右的方向)之间形成的角,就是这个向量的"方向夹角";
  3. 这个夹角能精准描述向量的方向:比如指向正右方的向量,夹角是0°;正上方是90°;正左方是180°;正下方是270°(也可以记成-90°,本质一样)。

三、有符号夹角 vs 无符号夹角

  1. 无符号夹角:只看"开口大小",不管方向,范围0°~180°(比如正上方90°、正下方90°,只算大小);
  2. 有符号夹角 :既看大小,也看旋转方向------数学里默认「逆时针旋转」出来的夹角算"正的",「顺时针旋转」算"负的"。
    比如:从x轴正方向逆时针转到正上方,夹角是+90°;顺时针转到正下方,夹角是-90°(也能写成270°,只是计数方式不同)。
    有符号夹角的范围通常是-180°~180°,能更精准地描述向量在坐标系里的具体方向。

四、夹角的计算(核心公式)

如果知道向量的坐标(x,y)(比如从原点指向(x,y)),想算它和x轴正方向的夹角θ,核心公式是:
tanθ = y/x(正切值等于纵坐标除以横坐标)

反过来算夹角就是 θ = arctan(y/x)(反正切运算)。

不过普通的arctan只能算-90°90°的角,所以数学里有"四象限反正切"(专门的计算方法),能算出-180°180°的完整夹角,不管向量在哪个象限都能精准算出来。

总结

  1. 夹角本质是两条相交线/向量之间的"开口大小",基础范围0°~180°;
  2. 坐标系里常用「向量与x轴正方向的夹角」描述方向,分有符号(-180°180°)和无符号(0°180°)两种;
  3. 已知向量坐标(x,y)时,用tanθ=y/x可计算夹角,四象限反正切能精准确定任意方向的夹角。
相关推荐
三品吉他手会点灯3 小时前
C语言学习笔记 - 20.C编程预备计算机专业知识 - 变量为什么必须的初始化【重点】
c语言·笔记·学习
sakiko_3 小时前
UIKit学习笔记1-创建项目(使用UIKit)、使用组件
笔记·学习
生信碱移4 小时前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
星幻元宇VR6 小时前
VR航空航天科普设备【VR时空直升机】
科技·学习·安全·生活·vr
_李小白6 小时前
【android opencv学习笔记】Day 2: Mat类(图片数据结构体)
android·opencv·学习
harder3217 小时前
RMP模式的创新突破
开发语言·学习·ios·swift·策略模式
程序猿乐锅8 小时前
【Tilas|第三篇】多表SQL语句
数据库·经验分享·笔记·学习·mysql
徐某人..8 小时前
基于i.MX6ULL平台的智能网关系统开发
arm开发·c++·单片机·qt·物联网·学习·arm
AOwhisky8 小时前
Kubernetes 学习笔记:集群管理、命名空间与 Pod 基础
linux·运维·笔记·学习·云原生·kubernetes
光影少年9 小时前
大屏页面,一次多个请求,请求加密导致 点击 全局时间选择器 时出现卡顿咋解决(面板收起会延迟1~2秒)
前端·javascript·vue.js·学习·前端框架·echarts·reactjs