您的问题非常广泛,而且这是一个非常复杂的练习,包含大量代码,包括图像渲染、图像格式处理、将文件写入磁盘等。这些不是单个函数的问题。因此,我专注于制作 2 种颜色的任意线性颜色渐变。
线性颜色渐变
您可以通过2 种颜色之间的线性插值来创建线性颜色“渐变” 。然而,简单的线性插值会产生非常刺眼的过渡。为了获得视觉上更吸引人的结果,我建议使用某种S 形插值曲线,例如基于 Hermite 插值的smoothstep。
关于角度,您可以通过颜色渐变的起点 ( p0
) 和终点 ( )定义一条线段。p1
让我们称它们之间的距离d01
,所以d01 = distance(p0, p1)
。然后对于图像的每个像素点p
,您必须计算p2
该段上的最近点。这是一个如何做到这一点的例子。然后计算t = distance(p0, p2) / d01
。这将是 [0, 1] 范围内的lerp参数t
。通过这个在 2 个渐变颜色之间进行插值t
,你就得到了给定点的颜色p
。
This can be implemented multiple ways. You can use OpenGL to render the image, then read the pixel buffer back to the RAM. If you are not familiar with OpenGL or the rendering process, you can write a function which takes a point (the 2D coordinates of a pixel) and returns an RGB color - so you can compute all the pixels of the image. Finally you can write the image to disk using an image format, but that's an another story.
The following are example C++14 implementations of some functions mentioned above.
Simple linear interpolation:
template <typename T, typename U>
T lerp(const T &a, const T &b, const U &t)
{
return (U(1) - t)*a + t*b;
}
, where a
and b
are the two values (colors in this case) you want to interpolate between, and t
is the interpolation parameter in the range [0, 1] representing the transition between a
and b
.
当然,上述函数需要一个T
支持标量乘法的类型。为此,您可以简单地使用任何 3D 矢量类型,因为颜色实际上是颜色空间中的坐标。
两个二维点之间的距离:
#include <cmath>
auto length(const Point2 &p)
{
return std::sqrt(p.x*p.x + p.y*p.y);
}
auto distance(const Point2 &a, const Point2 &b)
{
Point delta = b - a;
return length(delta);
}
图片来自https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient