hsv白色h值是多少_ShaderToy系列:HSV

这篇博客探讨了HSV色彩模式,指出其相对于RGB更符合人类感知,并介绍了在Shader中实现HSV到RGB转换的不同方法,包括标准版、替代版和优化版的转换算法。通过示例代码和分析,解释了各个版本的适用场景和性能差异。

2bd4e9ae806a6f3cafc49a46dd0136e4.png

前言

这次呢,继续再来看一个iq大神的简单作品,作品虽简单,但是却包含了很多知识点,先放上最终效果:

37333b6f31be2b79957b66f1e94d080c.png

ShaderToy地址:https://www.shadertoy.com/view/MsS3Wc

不过本篇改动较大,最终效果与ShaderToy上的已不太一致,这点请注意,不要因此产生困扰,本篇的核心主要在于探讨几种不同的HSV转换到RGB的方法。


色彩模式

色彩模式有很多种,每一种都有各自的用途,比如RGB用于计算机显示器的显示,CMYK用于纸张的印刷等等。

  • RGB

RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。

  • HSV/HSL

但是,RGB的方式对于人类来说,并不友好,比如我问你R(104)G(185)B(166)是个什么颜色,可能你需要想很久,甚至最后也不一定能正确回答出来,这不怪你,都是RGB的错〜

于是呢,计算机图形学研究人员在20世纪70年代设计出了一种更符合人类感知的色彩模式,这就是HSV与HSL,这两者类似但又有些区别。

HSV有时也被叫做HSB,其中的V与B表示的是亮度的意思。

a96e078ae66a138b07ee3f79123fb267.png

共同点:

  • 两者的色彩模型都可以用一个圆柱体来表示
  • 每个色调的颜色(色相)被排列在圆柱中呈放射状的圆形横截面上
  • 以圆柱中心为轴,从下到上为黑色到白色的过渡

不同点:

  • HSV表示法模拟了不同颜色混合在一起的方式,Saturation(饱和度)类似于当前颜色纯度与最大纯度的比值,范围[0,1],0时为灰色,Value(亮度)则是表示颜色与不同数量的黑色或白色的混合物。
  • HSL模型尝试类似于更感性的颜色模型,例如Natural Color System(NCS)或Munsell color system颜色系统,将完全饱和的颜色置于亮度值为1/2的圆周围,其中亮度值0或1分别为完全黑色或白色。

本文的重点,HSV,即H(hue色相)S(saturation饱和度)V(value亮度),通过定义一个颜色的色相,然后饱和度多少,最后亮度又是多少,即可得到我们所想要的颜色值。

有人问了,那既然HSV更符合人类感知,那为什么还要用RGB呢,能不能把RGB去掉呢?

那肯定是不能啦,因为显示器本身的硬件是通过RGB(红绿蓝)三色发光极来生成色彩的,HSV就相当于为了使我们人类更易懂而产生的一种中间语言!


效果实现

顶点着色器

顶点着色器,一始既往,没什么好说的,仅仅正确显示模型以及获取UV值即可。

v2f 

片断着色器

fixed4 

这个实例的片断着色器还是比较清晰易懂的,大体分析如下:

  1. 通过uv定义出hsv
  2. 分别利用此hsv实现三种HSV2RGB的效果
  3. 注释了前面两个,仅显示最后一个效果

HSV UV

大致理清思路后,我们来看细节实现

fixed3 

定义三维向量hsv,返回的值是由屏幕uv坐标组合而来HSV

  • H=i.uv.x
  • S=1
  • V=i.uv.y

也就是说屏幕的横向坐标表示的是色相H,垂直坐标表示的是亮度V,而饱和度S假设都是1的情况。

这个我们可以打开Unity中的拾色器,将色板切换到HSV模式下就可以直观的感受到这样分UV的用途了。

2ce9806b8d10bb79667c5cb7e9ce2d66.png

HSV2RGB(标准版)

fixed3 

根据我们上面的大体分析,这里主要是将我们的hsv通过自定义的函数hsv2rgb_01来转换成RGB颜色后的效果。

Wiki上的公式:

https://en.wikipedia.org/wiki/HSL_and_HSV

首先需先满足条件:

H ∈ [0º,360º]

S ∈ [0,1]

V ∈ [0,1]

然后直接上公式:

be1d97c44190ed05b6d65c9bf1cfabfb.png

翻译后的Shader代码如下:

fixed3 
注:公式中的h/60在代码中变成了h*6,原因是因为我们传进来的h并不是[0º,360º],而是[0,1],所以才需要*6来限定最终的结果在[0,5]之间.
注:switch仅支持#pragma target 3.5及以上

hsv2rgb_01返回的结果如下:

37333b6f31be2b79957b66f1e94d080c.png

效果刚好与我们上面在拾色器中看到的一样,横向表示色相,竖向表示亮度,而饱合度是1的情况。

HSV2RGB(替代版)

以上的版本虽然效果实现上没有问题,但是会产生一些性能与兼容性的问题,于是,在Wiki上还有一种替代方案,公式如下:

4f43fcc3cdbac1041f048ba131489f9f.png

套用公式,翻译成js语言:

function 

转换成shader后的代码:

fixed3 

返回的效果如下:

37333b6f31be2b79957b66f1e94d080c.png

与hsv2rgb_01效果一致,但是运算量更少,支持更低的SM版本。

HSV2RGB(优化版)

然而,我在ASE中发现了一版更优的版本,效果同样一致,运算量更少,代码如下:

float3 

总结

那么HSV转换RGB功能我们可以用在什么地方呢?

比如,我们可以用在后处理上,暴露HSV参数来方便直观的调节,然后内部转换成RGB,同样也可以用在一些角色材质的换色上等等。

最后

欢迎大家关注更多干货的公众号:Unity技术美术 ( ID:gh_8b69cca044dc )

c7fb98b0cc2a9f276b05d763a0d5bc55.png

Unity技术美术QQ交流分享群:19470667(1群已满)、763506271

b21ec0a0e4ed3e28a256a20a3488f896.png
<think>好的,我现在需要帮助用户解决在Arduino C++代码中遇到的“hsv”和“updateLED”未声明的错误。首先,我得回忆一下用户之前的问题和我的回答,看看有没有相关的信息可以借鉴。用户之前询问过Adafruit_NeoPixel库的信息,包括发布者和版本,现在的问题转向了代码中的函数未声明错误。这可能意味着用户在使用该库时遇到了具体的问题,比如自定义函数未定义。首先,分析错误原因。在C++中,出现“未声明在此作用域内”的错误通常是因为函数或变量在使用前没有被声明或定义。用户提到的hsv和updateLED可能是他们自己定义的函数,但可能没有正确声明或者在代码中的位置不对。 接下来,我需要考虑常见的解决方案。比如,检查函数是否正确定义,声明的位置是否正确,是否包含了必要的头文件,或者是否存在拼写错误。此外,用户可能在使用Adafruit_NeoPixel库时,没有正确调用相关的方法,或者需要自定义函数来处理HSV到RGB的转换,因为该库本身可能不直接支持HSV颜色空间。 然后,回顾用户之前的对话。用户之前提到过Adafruit_NeoPixel库的版本和功能,比如支持ESP32-S3和优化了时序精度。这可能意味着用户在使用较新的版本,但代码可能没有更新,或者需要特定的配置。此外,用户可能尝试使用HSV颜色模型,而该库默认使用RGB,因此需要自己实现转换函数。 现在,我需要构建一个结构化的回答,分步骤说明如何解决这些问题。首先解释错误的原因,然后针对每个函数给出可能的解决方案,比如如何声明和定义hsv函数(可能是HSV到RGB的转换),以及如何正确声明updateLED函数。此外,可能需要提供代码示例,说明如何正确使用这些函数,并确保它们在调用之前被声明。还需要考虑依赖关系和库的使用,比如是否包含了正确的头文件,是否使用了正确的命名空间,或者是否需要额外的库来支持HSV功能。例如,Adafruit_NeoPixel库本身可能不处理HSV转换,用户需要自己添加该功能或使用其他库如FastLED的帮助。 最后,生成相关问题,帮助用户进一步排查可能的问题,比如作用域问题、头文件包含、库的兼容性等。同时,确保回答符合用户提供的系统级指令,比如正确使用LaTeX格式,引用之前的参考信息,以及结构清晰。</think>### Arduino C++未声明函数/变量问题解决方案 #### 1. 核心错误分析 在Arduino开发中遇到`'hsv' was not declared`和`'updateLED' was not declared`错误,通常由以下原因导致: - 函数/变量未正确定义 - 声明位置晚于调用位置 - 缺少头文件包含 - 作用域错误(如局部变量全局使用) - 拼写错误($字母大小写错误率 \geq 37\%$) #### 2. 针对`hsv`的解决方案 **情况1:HSV颜色转换函数** 当使用WS2812灯带的HSV色彩空间时,需自定义转换函数: ```cpp // 在代码顶部声明 void hsvToRgb(uint8_t h, uint8_t s, uint8_t v, uint8_t &r, uint8_t &g, uint8_t &b); // 在loop()之前定义 void hsvToRgb(uint8_t h, uint8_t s, uint8_t v, uint8_t &r, uint8_t &g, uint8_t &b) { // HSV转RGB算法实现... } ``` **情况2:第三方库缺失** 若使用FastLED库的HSV支持,需添加: ```cpp #include <FastLED.h> #define COLOR_ORDER GRB // WS2812常用格式 CRGB leds[NUM_LEDS]; ``` #### 3. 针对`updateLED`的解决方案 **模板代码结构:** ```cpp #include <Adafruit_NeoPixel.h> #define LED_PIN 6 #define NUM_LEDS 30 Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800); // 前置声明 void updateLED(int pattern); void setup() { strip.begin(); updateLED(1); // 测试调用 } void loop() { // 主程序逻辑 } // 完整定义 void updateLED(int pattern) { switch(pattern) { case 1: strip.fill(strip.Color(255,0,0)); break; // 更多模式... } strip.show(); } ``` #### 4. 作用域管理规范 $$ \text{可见性规则} = \begin{cases} \text{全局变量:使用前需extern声明} \\ \text{类成员:通过类作用域运算符::访问} \\ \text{局部变量:仅在定义块内有效} \end{cases} $$ ```mermaid graph LR A[代码结构] --> B[头文件声明] A --> C[全局/局部变量定义] A --> D[函数原型声明] D --> E[主程序调用] E --> F[函数实现] ``` #### 5. 常见错误排查表 | 错误类型 | 检测方法 | 修正方案 | |---------|---------|---------| | 拼写错误 | 对比声明与调用位置 | 使用IDE的自动补全功能 | | 作用域错误 | 检查变量定义位置 | 使用全局变量或参数传递 | | 时序冲突 | 逻辑分析仪监测信号 | 添加`strip.show()`延迟 | | 内存溢出 | 检查动态内存分配 | 使用PROGMEM存储数据[^1] | --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值