65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 颜色渐变控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.54/5 (22投票s)

2015 年 5 月 21 日

CPOL

3分钟阅读

viewsIcon

31362

downloadIcon

1768

C# 颜色渐变控制的实现,以及一个应用于程序化地形生成的用例。

引言

在我之前已经接触过的程序化纹理生成中 这里,以及我参与的 这里,拥有一个管理颜色渐变的工具可能会很有用。在网上搜索后,我没有找到一个 C# 控件来实现我所需要的。我决定自己动手。

背景

我遇到了两个可能有用到的颜色控制渐变的情况,第一个是在 gdi+ .net 库中 (这里),第二个在纹理生成中。在第二种情况下,你从一个噪声函数开始生成一个高度图,然后你可能希望将一个高度值与一个颜色相关联;在这里,颜色渐变就派上用场了。

让我们假设我们生成以下噪声

应用一个像这样的颜色渐变:

我们得到以下的 (类似景观的) 位图

从相同的起始噪声应用不同的颜色渐变,我们可以得到一个 (天空) 位图,像这样

使用代码

在设计中使用控件

要在设计时添加控件 ColGradCtr,将其拖到你的表单上并调整它的大小。它包含两个默认颜色白色(开始)和黑色(结束)。

然后你可以在控件的 load 事件(或表单的 load 事件)中重置两个起始颜色。同时你也可以添加其他颜色。

        private void colGradCtr1_Load_1(object sender, EventArgs e)
        {
            colGradCtr1.reset(Color.Blue, Color.White); //redefine start and end color
            colGradCtr1.addColor(Color.FromArgb(0, 128, 128), 0.06f); //put a color in position 0.06
            colGradCtr1.addColor(Color.FromArgb(0, 0, 159), 0.60f);
            colGradCtr1.addColor(Color.FromArgb(6, 20, 203), 0.70f); 
            colGradCtr1.addColor(Color.FromArgb(146, 96, 53), 0.75f);
            colGradCtr1.addColor(Color.FromArgb(0, 100, 0), 0.80f);
            colGradCtr1.addColor(Color.FromArgb(64, 0, 0), 0.90f);
        }

控件至少需要两种颜色(开始和结束),分别位于位置 0 和 1。所有其他颜色都在位置 >0 和 <1。

ColGradCtr 获取样本颜色。如果你提供一个 float 输入 >=0 和 <=1,你将得到相应的颜色。

让我们看看景观生成例程

//paints Picturebox pct according to heightmap and ColGradCtr col
private void reColor(PictureBox pct, ColGradCtr col){
            Bitmap b2 = new Bitmap(pct.Width, pct.Height);
            for (int i = 0; i < pct.Width; i++)
                for (int j = 0; j < pct.Height; j++)
                {
                    b2.SetPixel(i, j, col.getColor(heightMap[i, j]));                    
                }
            pct.Image = b2;
}

其中 heightMap 是一个 float 矩阵,包含 0 到 1 之间的样本(高度)。

gdi+ 方法。如果你需要线性渐变,你可以从 ColGradCtr 以这种方式获得它:

LinearGradientBrush br = new LinearGradientBrush(this.pictureBox1.ClientRectangle, Color.Black
, Color.Black,LinearGradientMode.BackwardDiagonal);
ColorBlend cb = BackGradCtr.getColorBlend();//here i get the blend from ctrl
br.InterpolationColors = cb;

offScreenDC.FillRectangle(br, this.pictureBox1.ClientRectangle);

在运行时使用控件。在手柄上按鼠标左键,你可以移动它,改变颜色位置。如果你将手柄拖出控件(到右边),你将擦除该颜色。在手柄附近按鼠标右键可以修改颜色值,在空白处按鼠标右键可以添加新颜色。起始颜色和结束颜色不能移动或擦除,但你可以更改它们。

事件管理:我实现了两个事件,ColorChangedColorChanging。第一个事件在你移动颜色时触发,第二个事件在你释放鼠标按钮并提交更改(修改颜色、添加颜色、擦除颜色)时触发。以下是我在示例应用程序中如何使用 ColorChanged 事件的示例

        private void colGradCtr1_ColorChanged(object sender, EventArgs e)
        {
            reColor(pictureBox2, colGradCtr1);
        }

示例应用程序

点击 "generate new noise" 测试带有新噪声的渐变。

点击 gdi+ 示例获取第二个示例表单:

关注点

ColGradCtr 并不是 gdi+ ColrBlend 的 "包装器",它是我创建的类的 "包装器"

class Wgrad<T>

我创建的; 它是一个“有序”的对象列表

    public class gradObj<T>
    {
        public T ele { get; set; }
        public float w {get;set;}
        public gradObj(T e, float p)
        {
            ele = e;
            //clamp
            if (p > 1f)
                p = 1f;
            if (p < 0f)
                p = 0f;
            w = p;
        }        
    }

其中 T 在本例中是 Color,w 是在 0..1 范围内的位置。

以下是颜色渐变背后数据结构的解释

Wgrad<T> 管理一个对象 T(在本例中为 Color)的 List,根据一个介于 0 和 1 之间的 float 值保持它们排序。

Wgrad<T> 的一些方法

public void addEle(T ele , float p) //Adds a Color in position p (0..1)

public gradObj<T> delNearest(float p) //Deletes the nearest Color to p (0..1)

public gradObj<T>[] getEle(float p) //Gets the 2 colors before and after p (0..1)

最后,noiseGen 是我开发的用于管理噪声函数的类。它包含 2d Perlin 噪声的 C# 实现。

历史

添加了 Wgrad<T> 解释。

 

© . All rights reserved.