2015年5月14日 星期四

UnityPaint (Unity C#)

Pain (C#): 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Painter : MonoBehaviour 
{

    public Texture2D sourceBaseTex;
    private Texture2D baseTex;

    void Start()
    {
        baseTex = (Texture2D)Instantiate(sourceBaseTex);
    }


    private Vector2 dragStart;
    private Vector2 dragEnd;
    public enum Tool
    {
        None,
        Line,
        Brush,
        Eraser,
        Vector
    }
    private int tool2 = 1;
    public Drawing.Samples AntiAlias;
    public Tool tool = Tool.Brush;
    public Texture[] toolimgs;
    public Texture2D colorCircle;
    public float lineWidth = 1;
    public float strokeWidth = 1;
    public Color col = Color.white;
    public Color col2 = Color.white;
    public GUISkin gskin;
public LineTool lineTool = new LineTool();   //http://catlikecoding.com/unity/tutorials/curves-and-splines/
    public BrushTool brush = new BrushTool();
    public EraserTool eraser = new EraserTool();
    public Stroke stroke = new Stroke();
    public int zoom = 1;
    Drawing.BezierPoint[] BezierPoints;
    
void OnGUI()
    {
        GUI.skin = gskin;

        GUILayout.BeginArea(new Rect(5, 5, 100 + baseTex.width * zoom, baseTex.height * zoom), "", "Box");
        GUILayout.BeginArea(new Rect(0, 0, 100, baseTex.height * zoom));
        tool2 = GUILayout.Toolbar(tool2, toolimgs, "Tool");
        // FIXME: Defaults to brush tool, fix enum parse above.
        tool = Tool.Brush;


        GUILayout.Label("Drawing Options");
        GUILayout.Space(10);
        switch (tool)
        {
            case Tool.Line:
                GUILayout.Label("Size " + Mathf.Round(lineTool.width * 10) / 10);
                lineTool.width = GUILayout.HorizontalSlider(lineTool.width, 0, 40);
                col = GUIControls.RGBCircle(col, "", colorCircle);
                break;
            case Tool.Brush:
                GUILayout.Label("Size " + Mathf.Round(brush.width * 10) / 10);
                brush.width = GUILayout.HorizontalSlider(brush.width, 0, 40);
                GUILayout.Label("Hardness " + Mathf.Round(brush.hardness * 10) / 10);
                brush.hardness = GUILayout.HorizontalSlider(brush.hardness, 0.1f, 50);
                col = GUIControls.RGBCircle(col, "", colorCircle);
                break;
            case Tool.Eraser:
                GUILayout.Label("Size " + Mathf.Round(eraser.width * 10) / 10);
                eraser.width = GUILayout.HorizontalSlider(eraser.width, 0, 50);
                GUILayout.Label("Hardness " + Mathf.Round(eraser.hardness * 10) / 10);
                eraser.hardness = GUILayout.HorizontalSlider(eraser.hardness, 1, 50);
                break;
        }

        if (tool == Tool.Line)
        {
            stroke.enabled = GUILayout.Toggle(stroke.enabled, "Stroke");
            GUILayout.Label("Stroke Width " + Mathf.Round(stroke.width * 10) / 10);
            stroke.width = GUILayout.HorizontalSlider(stroke.width, 0, lineWidth);
            GUILayout.Label("Secondary Color");
            col2 = GUIControls.RGBCircle(col2, "", colorCircle);
        }

        GUILayout.EndArea();
        GUI.DrawTexture(new Rect(100, 0, baseTex.width * zoom, baseTex.height * zoom), baseTex);
        GUILayout.EndArea();
    }

private Vector2 preDrag;
    
void Update()
    {
        Rect imgRect = new Rect(5 + 100, 5, baseTex.width * zoom, baseTex.height * zoom);
        Vector2 mouse = Input.mousePosition;
        mouse.y = Screen.height - mouse.y;

        if (Input.GetKeyDown("t"))
        {
            test();
        }
        if (Input.GetKeyDown("mouse 0"))
        {

            if (imgRect.Contains(mouse))
            {
                if (tool == Tool.Vector)
                {
                    var m2 = mouse - new Vector2(imgRect.x, imgRect.y);
                    m2.y = imgRect.height - m2.y;
                    var bz = new ArrayList(BezierPoints);
                    bz.Add(new Drawing.BezierPoint(m2, m2 - new Vector2(50, 10), m2 + new Vector2(50, 10)));
                    BezierPoints = (Drawing.BezierPoint[])bz.ToArray();
                    Drawing.DrawBezier(BezierPoints, lineTool.width, col, baseTex);
                }

                dragStart = mouse - new Vector2(imgRect.x, imgRect.y);
                dragStart.y = imgRect.height - dragStart.y;
                dragStart.x = Mathf.Round(dragStart.x / zoom);
                dragStart.y = Mathf.Round(dragStart.y / zoom);

                dragEnd = mouse - new Vector2(imgRect.x, imgRect.y);
                dragEnd.x = Mathf.Clamp(dragEnd.x, 0, imgRect.width);
                dragEnd.y = imgRect.height - Mathf.Clamp(dragEnd.y, 0, imgRect.height);
                dragEnd.x = Mathf.Round(dragEnd.x / zoom);
                dragEnd.y = Mathf.Round(dragEnd.y / zoom);
            }
            else
            {
                dragStart = Vector3.zero;
            }

        }
        if (Input.GetKey("mouse 0"))
        {
            if (dragStart == Vector2.zero)
            {
                return;
            }
            dragEnd = mouse - new Vector2(imgRect.x, imgRect.y);
            dragEnd.x = Mathf.Clamp(dragEnd.x, 0, imgRect.width);
            dragEnd.y = imgRect.height - Mathf.Clamp(dragEnd.y, 0, imgRect.height);
            dragEnd.x = Mathf.Round(dragEnd.x / zoom);
            dragEnd.y = Mathf.Round(dragEnd.y / zoom);

            if (tool == Tool.Brush)
            {
                Brush(dragEnd, preDrag);
            }
            if (tool == Tool.Eraser)
            {
                Eraser(dragEnd, preDrag);
            }

        }
        if (Input.GetKeyUp("mouse 0") && dragStart != Vector2.zero)
        {
            if (tool == Tool.Line)
            {
                dragEnd = mouse - new Vector2(imgRect.x, imgRect.y);
                dragEnd.x = Mathf.Clamp(dragEnd.x, 0, imgRect.width);
                dragEnd.y = imgRect.height - Mathf.Clamp(dragEnd.y, 0, imgRect.height);
                dragEnd.x = Mathf.Round(dragEnd.x / zoom);
                dragEnd.y = Mathf.Round(dragEnd.y / zoom);
                Debug.Log("Draw Line");
                Drawing.NumSamples = AntiAlias;
                if (stroke.enabled)
                {
                    baseTex = Drawing.DrawLine(dragStart, dragEnd, lineTool.width, col, baseTex, true, col2, stroke.width);
                }
                else
                {
                    baseTex = Drawing.DrawLine(dragStart, dragEnd, lineTool.width, col, baseTex);
                }
            }
            dragStart = Vector2.zero;
            dragEnd = Vector2.zero;
        }
        preDrag = dragEnd;
    }

    void Brush(Vector2 p1, Vector2 p2)
    {
        Drawing.NumSamples = AntiAlias;
        if (p2 == Vector2.zero)
        {
            p2 = p1;
        }
        Drawing.PaintLine(p1, p2, brush.width, col, brush.hardness, baseTex);
        baseTex.Apply();
    }

    void Eraser(Vector2 p1, Vector2 p2)
    {
        Drawing.NumSamples = AntiAlias;
        if (p2 == Vector2.zero)
        {
            p2 = p1;
        }
        Drawing.PaintLine(p1, p2, eraser.width, Color.white, eraser.hardness, baseTex);
        baseTex.Apply();
    }

    void test()
    {
        float startTime = Time.realtimeSinceStartup;
        var w = 100;
        var h = 100;
        var p1 = new Drawing.BezierPoint(new Vector2(10, 0), new Vector2(5, 20), new Vector2(20, 0));
        var p2 = new Drawing.BezierPoint(new Vector2(50, 10), new Vector2(40, 20), new Vector2(60, -10));
        var c = new Drawing.BezierCurve(p1.main, p1.control2, p2.control1, p2.main);
        p1.curve2 = c;
        p2.curve1 = c;
        Vector2 elapsedTime = new Vector2((Time.realtimeSinceStartup - startTime) * 10, 0);
        float startTime2 = Time.realtimeSinceStartup;
        for (var i = 0; i < w * h; i++)
        {
            Mathfx.IsNearBezier(new Vector2(Random.value * 80, Random.value * 30), p1, p2, 10);
        }

        Vector2 elapsedTime2 = new Vector2((Time.realtimeSinceStartup - startTime2) * 10, 0);
        Debug.Log("Drawing took " + elapsedTime.ToString() + "  " + elapsedTime2.ToString());

    }

    public class LineTool
    {
        public float width = 1;
    }
    public class EraserTool
    {
        public float width = 1;
        public float hardness = 1;
    }
    public class BrushTool
    {
        public float width = 1;
        public float hardness = 0;
        public float spacing = 10;
    }
    public class Stroke
    {
        public bool enabled = false;
        public float width = 1;
    }
}

--------------------------------------------------

Drawing(C#) :

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Drawing
{

    public enum Samples
    {
        None,
        Samples2,
        Samples4,
        Samples8,
        Samples16,
        Samples32,
        RotatedDisc
    }

    public static Samples NumSamples = Samples.Samples4;

    public static Texture2D DrawLine(Vector2 from, Vector2 to, float w, Color col, Texture2D tex)
    {
        return DrawLine(from, to, w, col, tex, false, Color.black, 0);
    }

    public static Texture2D DrawLine(Vector2 from, Vector2 to, float w, Color col, Texture2D tex, bool stroke, Color strokeCol, float strokeWidth)
    {
        w = Mathf.Round(w);//It is important to round the numbers otherwise it will mess up with the texture width
        strokeWidth = Mathf.Round(strokeWidth);

        var extent = w + strokeWidth;
        var stY = Mathf.Clamp(Mathf.Min(from.y, to.y) - extent, 0, tex.height);//This is the topmost Y value
        var stX = Mathf.Clamp(Mathf.Min(from.x, to.x) - extent, 0, tex.width);
        var endY = Mathf.Clamp(Mathf.Max(from.y, to.y) + extent, 0, tex.height);
        var endX = Mathf.Clamp(Mathf.Max(from.x, to.x) + extent, 0, tex.width);//This is the rightmost Y value

        strokeWidth = strokeWidth / 2;
        var strokeInner = (w - strokeWidth) * (w - strokeWidth);
        var strokeOuter = (w + strokeWidth) * (w + strokeWidth);
        var strokeOuter2 = (w + strokeWidth + 1) * (w + strokeWidth + 1);
        var sqrW = w * w;//It is much faster to calculate with squared values

        var lengthX = endX - stX;
        var lengthY = endY - stY;
        var start = new Vector2(stX, stY);
        Color[] pixels = tex.GetPixels((int)stX, (int)stY, (int)lengthX, (int)lengthY, 0);//Get all pixels

        for (int y = 0; y < lengthY; y++)
        {
            for (int x = 0; x < lengthX; x++)
            {//Loop through the pixels
                var p = new Vector2(x, y) + start;
                var center = p + new Vector2(0.5f, 0.5f);
                float dist = (center - Mathfx.NearestPointStrict(from, to, center)).sqrMagnitude;//The squared distance from the center of the pixels to the nearest point on the line
                if (dist <= strokeOuter2)
                {
                    var samples = Sample(p);
                    var c = Color.black;
                    var pc = pixels[y * (int)lengthX + x];
                    for (int i = 0; i < samples.Length; i++)
                    {//Loop through the samples
                        dist = (samples[i] - Mathfx.NearestPointStrict(from, to, samples[i])).sqrMagnitude;//The squared distance from the sample to the line
                        if (stroke)
                        {
                            if (dist <= strokeOuter && dist >= strokeInner)
                            {
                                c += strokeCol;
                            }
                            else if (dist < sqrW)
                            {
                                c += col;
                            }
                            else
                            {
                                c += pc;
                            }
                        }
                        else
                        {
                            if (dist < sqrW)
                            {//Is the distance smaller than the width of the line
                                c += col;
                            }
                            else
                            {
                                c += pc;//No it wasn't, set it to be the original colour
                            }
                        }
                    }
                    c /= samples.Length;//Get the avarage colour
                    pixels[y * (int)lengthX + x] = c;
                }
            }
        }
        tex.SetPixels((int)stX, (int)stY, (int)lengthX, (int)lengthY, pixels, 0);
        tex.Apply();
        return tex;
    }

    public static Texture2D Paint(Vector2 pos, float rad, Color col, float hardness, Texture2D tex)
    {
        var start = new Vector2(Mathf.Clamp(pos.x - rad, 0, tex.width), Mathf.Clamp(pos.y - rad, 0, tex.height));
        var width = rad * 2;
        var end = new Vector2(Mathf.Clamp(pos.x + rad, 0, tex.width), Mathf.Clamp(pos.y + rad, 0, tex.height));
        var widthX = Mathf.Round(end.x - start.x);
        var widthY = Mathf.Round(end.y - start.y);
        var sqrRad = rad * rad;
        var sqrRad2 = (rad + 1) * (rad + 1);
        Color[] pixels = tex.GetPixels((int)start.x, (int)start.y, (int)widthX, (int)widthY, 0);

        for (var y = 0; y < widthY; y++)
        {
            for (var x = 0; x < widthX; x++)
            {
                var p = new Vector2(x, y) + start;
                var center = p + new Vector2(0.5f, 0.5f);
                float dist = (center - pos).sqrMagnitude;
                if (dist > sqrRad2)
                {
                    continue;
                }
                var samples = Sample(p);
                var c = Color.black;
                for (var i = 0; i < samples.Length; i++)
                {
                    dist = Mathfx.GaussFalloff(Vector2.Distance(samples[i], pos), rad) * hardness;
                    if (dist > 0)
                    {
                        c += Color.Lerp(pixels[y * (int)widthX + x], col, dist);
                    }
                    else
                    {
                        c += pixels[y * (int)widthX + x];
                    }
                }
                c /= samples.Length;

                pixels[y * (int)widthX + x] = c;
            }
        }

        tex.SetPixels((int)start.x, (int)start.y, (int)widthX, (int)widthY, pixels, 0);
        return tex;
    }

    public static Texture2D PaintLine(Vector2 from, Vector2 to, float rad, Color col, float hardness, Texture2D tex)
    {
        var width = rad * 2;

        var extent = rad;
        var stY = Mathf.Clamp(Mathf.Min(from.y, to.y) - extent, 0, tex.height);
        var stX = Mathf.Clamp(Mathf.Min(from.x, to.x) - extent, 0, tex.width);
        var endY = Mathf.Clamp(Mathf.Max(from.y, to.y) + extent, 0, tex.height);
        var endX = Mathf.Clamp(Mathf.Max(from.x, to.x) + extent, 0, tex.width);

        var lengthX = endX - stX;
        var lengthY = endY - stY;

        var sqrRad = rad * rad;
        var sqrRad2 = (rad + 1) * (rad + 1);
        Color[] pixels = tex.GetPixels((int)stX, (int)stY, (int)lengthX, (int)lengthY, 0);
        var start = new Vector2(stX, stY);
        //Debug.Log (widthX + "   "+ widthY + "   "+ widthX*widthY);
        for (int y = 0; y < (int)lengthY; y++)
        {
            for (int x = 0; x < (int)lengthX; x++)
            {
                var p = new Vector2(x, y) + start;
                var center = p + new Vector2(0.5f, 0.5f);
                float dist = (center - Mathfx.NearestPointStrict(from, to, center)).sqrMagnitude;
                if (dist > sqrRad2)
                {
                    continue;
                }
                dist = Mathfx.GaussFalloff(Mathf.Sqrt(dist), rad) * hardness;
                //dist = (samples[i]-pos).sqrMagnitude;
                Color c;
                if (dist > 0)
                {
                    c = Color.Lerp(pixels[y * (int)lengthX + x], col, dist);
                }
                else
                {
                    c = pixels[y * (int)lengthX + x];
                }

                pixels[y * (int)lengthX + x] = c;
            }
        }
        tex.SetPixels((int)start.x, (int)start.y, (int)lengthX, (int)lengthY, pixels, 0);
        return tex;
    }

    public class BezierPoint
    {
        internal Vector2 main;
        internal Vector2 control1;//Think of as left
        internal Vector2 control2;//Right
        //Rect rect;
        internal BezierCurve curve1;//Left
        internal BezierCurve curve2;//Right

        internal BezierPoint(Vector2 m, Vector2 l, Vector2 r)
        {
            main = m;
            control1 = l;
            control2 = r;
        }
    }

    public class BezierCurve
    {
        internal Vector2[] points;
        internal float aproxLength;
        internal Rect rect;
        internal Vector2 Get(float t)
        {
            int t2 = (int)Mathf.Round(t * (points.Length - 1));
            return points[t2];
        }

        void Init(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
        {

            Vector2 topleft = new Vector2(Mathf.Infinity, Mathf.Infinity);
            Vector2 bottomright = new Vector2(Mathf.NegativeInfinity, Mathf.NegativeInfinity);

            topleft.x = Mathf.Min(topleft.x, p0.x);
            topleft.x = Mathf.Min(topleft.x, p1.x);
            topleft.x = Mathf.Min(topleft.x, p2.x);
            topleft.x = Mathf.Min(topleft.x, p3.x);

            topleft.y = Mathf.Min(topleft.y, p0.y);
            topleft.y = Mathf.Min(topleft.y, p1.y);
            topleft.y = Mathf.Min(topleft.y, p2.y);
            topleft.y = Mathf.Min(topleft.y, p3.y);

            bottomright.x = Mathf.Max(bottomright.x, p0.x);
            bottomright.x = Mathf.Max(bottomright.x, p1.x);
            bottomright.x = Mathf.Max(bottomright.x, p2.x);
            bottomright.x = Mathf.Max(bottomright.x, p3.x);

            bottomright.y = Mathf.Max(bottomright.y, p0.y);
            bottomright.y = Mathf.Max(bottomright.y, p1.y);
            bottomright.y = Mathf.Max(bottomright.y, p2.y);
            bottomright.y = Mathf.Max(bottomright.y, p3.y);

            rect = new Rect(topleft.x, topleft.y, bottomright.x - topleft.x, bottomright.y - topleft.y);


            var ps = new List<Vector2>();

            var point1 = Mathfx.CubicBezier(0, p0, p1, p2, p3);
            var point2 = Mathfx.CubicBezier(0.05f, p0, p1, p2, p3);
            var point3 = Mathfx.CubicBezier(0.1f, p0, p1, p2, p3);
            var point4 = Mathfx.CubicBezier(0.15f, p0, p1, p2, p3);

            var point5 = Mathfx.CubicBezier(0.5f, p0, p1, p2, p3);
            var point6 = Mathfx.CubicBezier(0.55f, p0, p1, p2, p3);
            var point7 = Mathfx.CubicBezier(0.6f, p0, p1, p2, p3);

            aproxLength = Vector2.Distance(point1, point2) + Vector2.Distance(point2, point3) + Vector2.Distance(point3, point4) + Vector2.Distance(point5, point6) + Vector2.Distance(point6, point7);

            Debug.Log(Vector2.Distance(point1, point2) + "     " + Vector2.Distance(point3, point4) + "   " + Vector2.Distance(point6, point7));
            aproxLength *= 4;

            float a2 = 0.5f / aproxLength;//Double the amount of points since the approximation is quite bad
            for (float i = 0; i < 1; i += a2)
            {
                ps.Add(Mathfx.CubicBezier(i, p0, p1, p2, p3));
            }

            points = ps.ToArray();
        }

        internal BezierCurve(Vector2 main, Vector2 control1, Vector2 control2, Vector2 end)
        {
            Init(main, control1, control2, end);
        }
    }

    public static void DrawBezier(BezierPoint[] points, float rad, Color col, Texture2D tex)
    {
        rad = Mathf.Round(rad);//It is important to round the numbers otherwise it will mess up with the texture width

        if (points.Length <= 1)
            return;

        Vector2 topleft = new Vector2(Mathf.Infinity, Mathf.Infinity);
        Vector2 bottomright = new Vector2(0, 0);

        for (int i = 0; i < points.Length - 1; i++)
        {
            Vector2 main = points[i].main;
            Vector2 control2 = points[i].control2;
            Vector2 control1 = points[i + 1].control1;
            Vector2 main2 = points[i + 1].main;
            BezierCurve curve = new BezierCurve(main, control2, control1, main2);
            points[i].curve2 = curve;
            points[i + 1].curve1 = curve;

            topleft.x = Mathf.Min(topleft.x, curve.rect.x);

            topleft.y = Mathf.Min(topleft.y, curve.rect.y);

            bottomright.x = Mathf.Max(bottomright.x, curve.rect.x + curve.rect.width);

            bottomright.y = Mathf.Max(bottomright.y, curve.rect.y + curve.rect.height);
        }

        topleft -= new Vector2(rad, rad);
        bottomright += new Vector2(rad, rad);

        var start = new Vector2(Mathf.Clamp(topleft.x, 0, tex.width), Mathf.Clamp(topleft.y, 0, tex.height));
        var width = new Vector2(Mathf.Clamp(bottomright.x - topleft.x, 0, tex.width - start.x), Mathf.Clamp(bottomright.y - topleft.y, 0, tex.height - start.y));

        Color[] pixels = tex.GetPixels((int)start.x, (int)start.y, (int)width.x, (int)width.y, 0);

        for (var y = 0; y < width.y; y++)
        {
            for (var x = 0; x < width.x; x++)
            {
                var p = new Vector2(x + start.x, y + start.y);
                if (!Mathfx.IsNearBeziers(p, points, rad + 2))
                {
                    continue;
                }

                var samples = Sample(p);
                var c = Color.black;
                var pc = pixels[y * (int)width.x + x];//Previous pixel color
                for (var i = 0; i < samples.Length; i++)
                {
                    if (Mathfx.IsNearBeziers(samples[i], points, rad))
                    {
                        c += col;
                    }
                    else
                    {
                        c += pc;
                    }
                }

                c /= samples.Length;

                pixels[y * (int)width.x + x] = c;
            }
        }

        tex.SetPixels((int)start.x, (int)start.y, (int)width.x, (int)width.y, pixels, 0);
        tex.Apply();
    }

    public static void AddP(List<Vector2> tmpList, Vector2 p, float ix, float iy)
    {
        var x = p.x + ix;
        var y = p.y + iy;
        tmpList.Add(new Vector2(x, y));
    }

    public static Vector2[] Sample(Vector2 p)
    {
        List<Vector2> tmpList = new List<Vector2>(32);

        switch (NumSamples)
        {
            case Samples.None:
                AddP(tmpList, p, 0.5f, 0.5f);
                break;

            case Samples.Samples2:
                AddP(tmpList, p, 0.25f, 0.5f);
                AddP(tmpList, p, 0.75f, 0.5f);
                break;

            case Samples.Samples4:
                AddP(tmpList, p, 0.25f, 0.5f);
                AddP(tmpList, p, 0.75f, 0.5f);
                AddP(tmpList, p, 0.5f, 0.25f);
                AddP(tmpList, p, 0.5f, 0.75f);
                break;

            case Samples.Samples8:
                AddP(tmpList, p, 0.25f, 0.5f);
                AddP(tmpList, p, 0.75f, 0.5f);
                AddP(tmpList, p, 0.5f, 0.25f);
                AddP(tmpList, p, 0.5f, 0.75f);

                AddP(tmpList, p, 0.25f, 0.25f);
                AddP(tmpList, p, 0.75f, 0.25f);
                AddP(tmpList, p, 0.25f, 0.75f);
                AddP(tmpList, p, 0.75f, 0.75f);
                break;
            case Samples.Samples16:
                AddP(tmpList, p, 0, 0);
                AddP(tmpList, p, 0.3f, 0);
                AddP(tmpList, p, 0.7f, 0);
                AddP(tmpList, p, 1, 0);

                AddP(tmpList, p, 0, 0.3f);
                AddP(tmpList, p, 0.3f, 0.3f);
                AddP(tmpList, p, 0.7f, 0.3f);
                AddP(tmpList, p, 1, 0.3f);

                AddP(tmpList, p, 0, 0.7f);
                AddP(tmpList, p, 0.3f, 0.7f);
                AddP(tmpList, p, 0.7f, 0.7f);
                AddP(tmpList, p, 1, 0.7f);

                AddP(tmpList, p, 0, 1);
                AddP(tmpList, p, 0.3f, 1);
                AddP(tmpList, p, 0.7f, 1);
                AddP(tmpList, p, 1, 1);
                break;

            case Samples.Samples32:
                AddP(tmpList, p, 0, 0);
                AddP(tmpList, p, 1, 0);
                AddP(tmpList, p, 0, 1);
                AddP(tmpList, p, 1, 1);

                AddP(tmpList, p, 0.2f, 0.2f);
                AddP(tmpList, p, 0.4f, 0.2f);
                AddP(tmpList, p, 0.6f, 0.2f);
                AddP(tmpList, p, 0.8f, 0.2f);

                AddP(tmpList, p, 0.2f, 0.4f);
                AddP(tmpList, p, 0.4f, 0.4f);
                AddP(tmpList, p, 0.6f, 0.4f);
                AddP(tmpList, p, 0.8f, 0.4f);

                AddP(tmpList, p, 0.2f, 0.6f);
                AddP(tmpList, p, 0.4f, 0.6f);
                AddP(tmpList, p, 0.6f, 0.6f);
                AddP(tmpList, p, 0.8f, 0.6f);

                AddP(tmpList, p, 0.2f, 0.8f);
                AddP(tmpList, p, 0.4f, 0.8f);
                AddP(tmpList, p, 0.6f, 0.8f);
                AddP(tmpList, p, 0.8f, 0.8f);

                AddP(tmpList, p, 0.5f, 0);
                AddP(tmpList, p, 0.5f, 1);
                AddP(tmpList, p, 0, 0.5f);
                AddP(tmpList, p, 1, 0.5f);

                AddP(tmpList, p, 0.5f, 0.5f);
                break;
            case Samples.RotatedDisc:
                AddP(tmpList, p, 0, 0);
                AddP(tmpList, p, 1, 0);
                AddP(tmpList, p, 0, 1);
                AddP(tmpList, p, 1, 1);

                Vector2 pq = new Vector2(p.x + 0.5f, p.y + 0.5f);
                AddP(tmpList, pq, 0.258f, 0.965f);//Sin (75°) && Cos (75°)
                AddP(tmpList, pq, -0.965f, -0.258f);
                AddP(tmpList, pq, 0.965f, 0.258f);
                AddP(tmpList, pq, 0.258f, -0.965f);
                break;
        }

        return tmpList.ToArray();
    }
}

--------------------------------------------------

GUIControls(C#) :

using UnityEngine;
using System.Collections;

public class GUIControls 
{

    public static Color RGBSlider(Color c, string label)
    {
        GUI.color = c;
        GUILayout.Label(label);
        GUI.color = Color.red;
        c.r = GUILayout.HorizontalSlider(c.r, 0, 1);
        GUI.color = Color.green;
        c.g = GUILayout.HorizontalSlider(c.g, 0, 1);
        GUI.color = Color.blue;
        c.b = GUILayout.HorizontalSlider(c.b, 0, 1);
        GUI.color = Color.white;
        return c;
    }

    public static Color RGBCircle(Color c, string label, Texture2D colorCircle)
    {
        var r = GUILayoutUtility.GetAspectRect(1);
        r.height = r.width -= 15;
        var r2 = new Rect(r.x + r.width + 5, r.y, 10, r.height);
        var hsb = new HSBColor(c);//It is much easier to work with HSB colours in this case


        var cp = new Vector2(r.x + r.width / 2, r.y + r.height / 2);

        if (Input.GetMouseButton(0))
        {
            var InputVector = Vector2.zero;
            InputVector.x = cp.x - Event.current.mousePosition.x;
            InputVector.y = cp.y - Event.current.mousePosition.y;

            var hyp = Mathf.Sqrt((InputVector.x * InputVector.x) + (InputVector.y * InputVector.y));
            if (hyp <= r.width / 2 + 5)
            {
                hyp = Mathf.Clamp(hyp, 0, r.width / 2);
                float a = Vector3.Angle(new Vector3(-1, 0, 0), InputVector);

                if (InputVector.y < 0)
                {
                    a = 360 - a;
                }

                hsb.h = a / 360;
                hsb.s = hyp / (r.width / 2);
            }
        }

        var hsb2 = new HSBColor(c);
        hsb2.b = 1;
        var c2 = hsb2.ToColor();
        GUI.color = c2;
        hsb.b = GUI.VerticalSlider(r2, hsb.b, 1.0f, 0.0f, "BWSlider", "verticalsliderthumb");

        GUI.color = Color.white * hsb.b;
        GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1);
        GUI.Box(r, colorCircle, GUIStyle.none);

        var pos = (new Vector2(Mathf.Cos(hsb.h * 360 * Mathf.Deg2Rad), -Mathf.Sin(hsb.h * 360 * Mathf.Deg2Rad)) * r.width * hsb.s / 2);

        GUI.color = c;
        GUI.Box(new Rect(pos.x - 5 + cp.x, pos.y - 5 + cp.y, 10, 10), "", "ColorcirclePicker");
        GUI.color = Color.white;

        c = hsb.ToColor();
        return c;
    }
}

--------------------------------------------------

Mathfx (C#) : 

Unity Mathfx API : http://docs.unity3d.com/ScriptReference/Mathf.html

using UnityEngine;
using System.Collections;

public class Mathfx : MonoBehaviour 
{

    public static float Hermite(float start, float end, float value)
    {
        return Mathf.Lerp(start, end, value * value * (3.0f - 2.0f * value));
    }

    public static float Sinerp(float start, float end, float value)
    {
        return Mathf.Lerp(start, end, Mathf.Sin(value * Mathf.PI * 0.5f));
    }

    public static float Coserp(float start, float end, float value)
    {
        return Mathf.Lerp(start, end, 1.0f - Mathf.Cos(value * Mathf.PI * 0.5f));
    }

    public static float Berp(float start, float end, float value)
    {
        value = Mathf.Clamp01(value);
        value = (Mathf.Sin(value * Mathf.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow(1 - value, 2.2f) + value) * (1 + (1.2f * (1 - value)));
        return start + (end - start) * value;
    }

    public static float SmoothStep(float x, float min, float max)
    {
        x = Mathf.Clamp(x, min, max);
        var v1 = (x - min) / (max - min);
        var v2 = (x - min) / (max - min);
        return -2 * v1 * v1 * v1 + 3 * v2 * v2;
    }

    public static float Lerp(float start, float end, float value)
    {
        return ((1.0f - value) * start) + (value * end);
    }

    public static Vector3 NearestPoint(Vector3 lineStart, Vector3 lineEnd, Vector3 point)
    {
        var lineDirection = Vector3.Normalize(lineEnd - lineStart);
        var closestPoint = Vector3.Dot((point - lineStart), lineDirection) / Vector3.Dot(lineDirection, lineDirection);
        return lineStart + (closestPoint * lineDirection);
    }

    public static Vector3 NearestPointStrict(Vector3 lineStart, Vector3 lineEnd, Vector3 point)
    {
        var fullDirection = lineEnd - lineStart;
        var lineDirection = Vector3.Normalize(fullDirection);
        var closestPoint = Vector3.Dot((point - lineStart), lineDirection) / Vector3.Dot(lineDirection, lineDirection);
        return lineStart + (Mathf.Clamp(closestPoint, 0.0f, Vector3.Magnitude(fullDirection)) * lineDirection);
    }

    public static Vector2 NearestPointStrict(Vector2 lineStart, Vector2 lineEnd, Vector2 point)
    {
        var fullDirection = lineEnd - lineStart;
        var lineDirection = Normalize(fullDirection);
        var closestPoint = Vector2.Dot((point - lineStart), lineDirection) / Vector2.Dot(lineDirection, lineDirection);
        return lineStart + (Mathf.Clamp(closestPoint, 0.0f, fullDirection.magnitude) * lineDirection);
    }



    public static float Bounce(float x)
    {
        return Mathf.Abs(Mathf.Sin(6.28f * (x + 1) * (x + 1)) * (1 - x));
    }

    // test for value that is near specified float (due to floating point inprecision)
    // all thanks to Opless for this!
    public static bool Approx(float val, float about, float range)
    {
        return ((Mathf.Abs(val - about) < range));
    }

    // test if a Vector3 is close to another Vector3 (due to floating point inprecision)
    // compares the square of the distance to the square of the range as this
    // avoids calculating a square root which is much slower than squaring the range
    public static bool Approx(Vector3 val, Vector3 about, float range)
    {
        return ((val - about).sqrMagnitude < range * range);
    }

    public static float GaussFalloff(float distance, float inRadius)
    {
        return Mathf.Clamp01(Mathf.Pow(360.0f, -Mathf.Pow(distance / inRadius, 2.5f) - 0.01f));
    }
    // CLerp - Circular Lerp - is like lerp but handles the wraparound from 0 to 360.
    // This is useful when interpolating eulerAngles and the object
    // crosses the 0/360 boundary.  The standard Lerp function causes the object
    // to rotate in the wrong direction and looks stupid. Clerp fixes that.
    public static float Clerp(float start, float end, float value)
    {
        var min = 0.0f;
        var max = 360.0f;
        var half = Mathf.Abs((max - min) / 2.0f);//half the distance between min and max
        var retval = 0.0f;
        var diff = 0.0f;

        if ((end - start) < -half)
        {
            diff = ((max - start) + end) * value;
            retval = start + diff;
        }
        else if ((end - start) > half)
        {
            diff = -((max - end) + start) * value;
            retval = start + diff;
        }
        else retval = start + (end - start) * value;

        return retval;
    }


    //======= NEW =========//


    public static Vector2 RotateVector(Vector2 vector, float rad)
    {
        rad *= Mathf.Deg2Rad;
        var res = new Vector2((vector.x * Mathf.Cos(rad)) - (vector.y * Mathf.Sin(rad)), (vector.x * Mathf.Sin(rad)) + (vector.y * Mathf.Cos(rad)));
        return res;
    }

    public static Vector2 IntersectPoint(Vector2 start1, Vector2 start2, Vector2 dir1, Vector2 dir2)
    {
        if (dir1.x == dir2.x)
        {
            return Vector2.zero;
        }

        var h1 = dir1.y / dir1.x;
        var h2 = dir2.y / dir2.x;

        if (h1 == h2)
        {
            return Vector2.zero;
        }

        var line1 = new Vector2(h1, start1.y - start1.x * h1);
        var line2 = new Vector2(h2, start2.y - start2.x * h2);

        var y1 = line2.y - line1.y;
        var x1 = line1.x - line2.x;

        var x2 = y1 / x1;

        var y2 = line1.x * x2 + line1.y;
        return new Vector2(x2, y2);
    }

    public static Vector2 ThreePointCircle(Vector2 a1, Vector2 a2, Vector2 a3)
    {
        var dir = a2 - a1;
        dir /= 2;
        var b1 = a1 + dir;
        dir = RotateVector(dir, 90);
        var l1 = dir;

        dir = a3 - a2;
        dir /= 2;
        var b2 = a2 + dir;
        dir = RotateVector(dir, 90);
        var l2 = dir;
        var p = IntersectPoint(b1, b2, l1, l2);
        return p;
    }

    //===== Bezier ====== //

    public static Vector2 CubicBezier(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
    {
        // FIXME: fix bezier curve algorithm.
        /*      t = Mathf.Clamp01 (t);
                var t2 = 1-t;
            return Mathf.Pow(t2, 3) * p0 + 3 * Mathf.Pow(t2, 2) * t * p1 + 3 * t2 * Mathf.Pow(t, 2) * p2 + Mathf.Pow(t, 3) * p3;
         */
        return Vector2.zero;
    }

    public static Vector2 NearestPointOnBezier(Vector2 p, Drawing.BezierCurve c, float accuracy, bool doubleAc)
    {
        float minDist = Mathf.Infinity;
        float minT = 0;
        Vector2 minP = Vector2.zero;
        for (float i = 0; i < 1; i += accuracy)
        {
            var point = c.Get(i);
            float d = (p - point).sqrMagnitude;
            if (d < minDist)
            {
                minDist = d;
                minT = i;
                minP = point;
            }
        }

        if (!doubleAc)
        {
            return minP;
        }

        float st = Mathf.Clamp01(minT - accuracy);
        float en = Mathf.Clamp01(minT + accuracy);


        for (var i = st; i < en; i += accuracy / 10)
        {
            var point = c.Get(i);
            float d = (p - point).sqrMagnitude;
            if (d < minDist)
            {
                minDist = d;
                minT = i;
                minP = point;
            }
        }

        return minP;
    }

    public static bool IsNearBezierTest(Vector2 p, Drawing.BezierCurve c, float accuracy, float maxDist)
    {
        Vector2 prepoint = c.Get(0);
        for (float i = accuracy; i < 1; i += accuracy)
        {
            var point = c.Get(i);
            float d = (p - point).sqrMagnitude;
            float d2 = (prepoint - point + new Vector2(maxDist, maxDist)).sqrMagnitude;
            if (d <= d2 * 2)
                return true;
        }

        return false;
    }

    public static Vector2 NearestPointOnBezier(Vector2 p, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
    {
        float minDist = Mathf.Infinity;
        float minT = 0;
        Vector2 minP = Vector2.zero;
        for (float i = 0; i < 1; i += 0.01f)
        {
            var point = CubicBezier(i, p0, p1, p2, p3);
            float d = (p - point).sqrMagnitude;
            if (d < minDist)
            {
                minDist = d;
                minT = i;
                minP = point;
            }
        }

        float st = Mathf.Clamp01(minT - 0.01f);
        float en = Mathf.Clamp01(minT + 0.01f);

        for (var i = st; i < en; i += 0.001f)
        {
            var point = CubicBezier(i, p0, p1, p2, p3);
            var d = (p - point).sqrMagnitude;
            if (d < minDist)
            {
                minDist = d;
                minT = i;
                minP = point;
            }
        }

        return minP;

    }

    public static bool IsNearBezier(Vector2 p, Drawing.BezierPoint point1, Drawing.BezierPoint point2, float rad)
    {
        if (point1.curve2 != point2.curve1)
        {
            Debug.LogError("Curves Not The Same");
            return false;
        }

        Drawing.BezierCurve curve = point1.curve2;

        var r = curve.rect;
        r.x -= rad;
        r.y -= rad;
        r.width += rad * 2;
        r.height += rad * 2;

        if (!r.Contains(p))
        {
            return false;
        }

        var nearest = NearestPointOnBezier(p, curve, 0.1f, false);

        var sec = point1.curve2.aproxLength / 10;

        if ((nearest - p).sqrMagnitude >= (sec * 3) * (sec * 3))
        {
            return false;
        }

        nearest = NearestPointOnBezier(p, curve, 0.01f, true);

        if ((nearest - p).sqrMagnitude <= rad * rad)
        {
            return true;
        }

        return false;
    }

    public static bool IsNearBeziers(Vector2 p, Drawing.BezierPoint[] points, float rad)
    {
        for (var i = 0; i < points.Length - 1; i++)
        {
            if (IsNearBezier(p, points[i], points[i + 1], rad))
            {
                return true;
            }
        }
        return false;
    }

    //====== End Bezier ========//

    public static Vector2 NearestPointOnCircle(Vector2 p, Vector2 center, float w)
    {
        Vector2 dir = p - center;
        dir = Normalize(dir);
        dir *= w;
        return center + dir;
    }

    public static Vector2 Normalize(Vector2 p)
    {
        float mag = p.magnitude;
        return p / mag;
    }
}

--------------------------------------------------

HSBColor(C#) : 

Unity HSBColor wiki:  http://wiki.unity3d.com/index.php?title=HSBColor

using UnityEngine;

[System.Serializable]
public struct HSBColor
{
    public float h;
    public float s;
    public float b;
    public float a;

    public HSBColor(float h, float s, float b, float a)
    {
        this.h = h;
        this.s = s;
        this.b = b;
        this.a = a;
    }
    
    public HSBColor(float h, float s, float b)
    {
        this.h = h;
        this.s = s;
        this.b = b;
        this.a = 1f;
    }
    
    public HSBColor(Color col)
    {
        HSBColor temp = FromColor(col);
        h = temp.h;
        s = temp.s;
        b = temp.b;
        a = temp.a;
    }
    
    public static HSBColor FromColor(Color color)
    {
        HSBColor ret = new HSBColor(0f, 0f, 0f, color.a);

        float r = color.r;
        float g = color.g;
        float b = color.b;

        float max = Mathf.Max(r, Mathf.Max(g, b));

        if (max <= 0)
        {
            return ret;
        }

        float min = Mathf.Min(r, Mathf.Min(g, b));
        float dif = max - min;

        if (max > min)
        {
            if (g == max)
            {
                ret.h = (b - r) / dif * 60f + 120f;
            }
            else if (b == max)
            {
                ret.h = (r - g) / dif * 60f + 240f;
            }
            else if (b > g)
            {
                ret.h = (g - b) / dif * 60f + 360f;
            }
            else
            {
                ret.h = (g - b) / dif * 60f;
            }
            if (ret.h < 0)
            {
                ret.h = ret.h + 360f;
            }
        }
        else
        {
            ret.h = 0;
        }

        ret.h *= 1f / 360f;
        ret.s = (dif / max) * 1f;
        ret.b = max;

        return ret;
    }

    public static Color ToColor(HSBColor hsbColor)
    {
        float r = hsbColor.b;
        float g = hsbColor.b;
        float b = hsbColor.b;
        if (hsbColor.s != 0)
        {
            float max = hsbColor.b;
            float dif = hsbColor.b * hsbColor.s;
            float min = hsbColor.b - dif;

            float h = hsbColor.h * 360f;

            if (h < 60f)
            {
                r = max;
                g = h * dif / 60f + min;
                b = min;
            }
            else if (h < 120f)
            {
                r = -(h - 120f) * dif / 60f + min;
                g = max;
                b = min;
            }
            else if (h < 180f)
            {
                r = min;
                g = max;
                b = (h - 120f) * dif / 60f + min;
            }
            else if (h < 240f)
            {
                r = min;
                g = -(h - 240f) * dif / 60f + min;
                b = max;
            }
            else if (h < 300f)
            {
                r = (h - 240f) * dif / 60f + min;
                g = min;
                b = max;
            }
            else if (h <= 360f)
            {
                r = max;
                g = min;
                b = -(h - 360f) * dif / 60 + min;
            }
            else
            {
                r = 0;
                g = 0;
                b = 0;
            }
        }

        return new Color(Mathf.Clamp01(r),Mathf.Clamp01(g),Mathf.Clamp01(b),hsbColor.a);
    }

    public Color ToColor()
    {
        return ToColor(this);
    }
    
    public override string ToString()
    {
        return "H:" + h + " S:" + s + " B:" + b;
    }
    
    public static HSBColor Lerp(HSBColor a, HSBColor b, float t)
    {
        // works around bug with LerpAngle
        float angle = Mathf.LerpAngle(a.h * 360f, b.h * 360f, t);
        while (angle < 0f)
            angle += 360f;
        while (angle > 360f)
            angle -= 360f;
        
        return new HSBColor(angle / 360f, Mathf.Lerp(a.s, b.s, t), Mathf.Lerp(a.b, b.b, t), Mathf.Lerp(a.a, b.a, t));
    }
    
    public static void Test()
    {
        HSBColor color;
        
        color = new HSBColor(Color.red);
        Debug.Log("red: " + color);
        
        color = new HSBColor(Color.green);
        Debug.Log("green: " + color);
        
        color = new HSBColor(Color.blue);
        Debug.Log("blue: " + color);
        
        color = new HSBColor(Color.grey);
        Debug.Log("grey: " + color);
        
        color = new HSBColor(Color.white);
        Debug.Log("white: " + color);
        
        color = new HSBColor(new Color(0.4f, 1f, 0.84f, 1f));
        Debug.Log("0.4, 1f, 0.84: " + color);
        
        Debug.Log("164,82,84   .... 0.643137f, 0.321568f, 0.329411f  :" + ToColor(new HSBColor(new Color(0.643137f, 0.321568f, 0.329411f))));
    }
}


結果圖 :  


File Download : http://pan.baidu.com/s/1gdH6Yvp

沒有留言:

張貼留言