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 加入
还未添加个人简介







评论