HSV - RGB 来点实际的
作者:Miracle
- 2025-09-25 四川
本文字数:2135 字
阅读完需:约 7 分钟

现在开始 做点有用的东西了,图形学中最常见的 转换是 HSV <-> RGB
一个高效的算法长这样的
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);
}
复制代码
我们用 Zeta 来实现
K 是个常数,我们首先需要 常数定义的指令 Zeta 是动态类型语言 所以可以 写成这样
我们没必要单独引入 Vec<4> 对于 常量数组 [] 语法足够了
const K = [1.0, 2.0/3.0, 1.0/3.0, 3.0];
让我们增加 const 的解析
let const_stmt = just("const").padded_by(rust_ws()).ignore_then(
super::ident_parser().padded().then(just(':').padded_by(rust_ws())
.ignore_then(type_parser()).padded().or_not()
).then_ignore(just('=').padded_by(rust_ws())).then(expr_parser.clone()).then_ignore(just(';').padded_by(rust_ws()))
).map(|((name, opt_ty), val)| {
let ty = opt_ty.unwrap_or(Type::Void); // 或者进行类型推断
Stmt::Const(name, ty, val)
}).boxed();
复制代码
然后增加 Vec 的加法
if let Self::VecF32(_) = self {
let len = self.len();
let mut ret = Vec::new();
for idx in 0..len {
ret.push(self.get_f32(idx).unwrap() + other.as_f32().unwrap());
}
return Dynamic::from(&ret[..]);
}
if let Self::List(list) = self {
let mut ret = Vec::new();
for item in list {
ret.push(item + other.clone());
}
return Dynamic::List(ret);
}
if let Self::List(list) = other {
let mut ret = Vec::new();
for item in list {
ret.push(self.clone() +item);
}
return Dynamic::List(ret);
}
if let Self::VecF32(_) = other {
let len = other.len();
let mut ret = Vec::new();
for idx in 0..len {
ret.push(other.get_f32(idx).unwrap() + self.as_f32().unwrap());
}
return Dynamic::from(&ret[..]);
}
复制代码
Zeta 写成这样
const K = [1.0f32, 2.0f32/3.0f32, 1.0f32/3.0f32];
fn hsv2rgb(hsv: [f32; 3]) {
let x = (hsv[0] + K).fract();
return x;
}
"#;
复制代码
我们要为 Dynamic 实现 fract 先只实现需要的
impl Dynamic {
pub fn fract(&self) -> Dynamic {
match self {
Self::F32(v) => Dynamic::F32(v.fract()),
Self::List(list) => {
let mut new_list = Vec::with_capacity(list.len());
for item in list {
new_list.push(item.fract());
}
Dynamic::List(new_list)
},
_ => panic!("Unsupported type for fract"),
}
}
}
复制代码
native.rs 加上
"fract"=> {
let val = self.get(&obj);
*self.get_mut(ret_addr).unwrap() = val.fract();
}
复制代码
完美

加上乘法 减法 和绝对值
fn mul(self, other: Self) -> Self::Output {
if let Self::List(list) = self {
let mut ret = Vec::new();
for item in list {
ret.push(item * other.clone());
}
return Dynamic::List(ret);
}
复制代码
然后是 clamp 以及 mix 函数
"clamp"=> {
let val = self.get(&obj);
let min = var_list[0].as_f32().unwrap();
let max = var_list[1].as_f32().unwrap();
return Some(val.my_clamp(min, max));
}
"mix"=> {
if let Dynamic::List(list) = var_list[1].clone() {
let mut v = Vec::new();
for elem in list {
let x = var_list[0].clone() * (Dynamic::F32(1.0) - var_list[2].clone());
let x = x + (elem.clone() * var_list[2].clone());
v.push(x);
}
return Some(Dynamic::List(v));
}
}
复制代码
我们的 Zeta 代码现在长这样
const K = [1.0, 2.0/3.0, 1.0/3.0];
fn hsv2rgb(hsv: [f32; 3]) {
let rgb = (((hsv[0] + K).fract() * 6.0f32 - 3.0f32).abs() - 1.0).clamp(0.0, 1.0);
return mix(1.0f32, rgb, hsv[1]) * hsv[2];
}
复制代码
注意 我们现在明确需要类型了
现在我们的虚拟机上验证执行
测试这几个 HSV 的值

结果是这样的

完美 下一步就是 放在显卡上执行了
划线
评论
复制
发布于: 11 分钟前阅读数: 6

Miracle
关注
三十年资深码农 2019-10-25 加入
还未添加个人简介
评论