在C#中加快了L系统的渲染器/ WPF [英] Speeding up an L-System renderer in C#/WPF

查看:285
本文介绍了在C#中加快了L系统的渲染器/ WPF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

lsys 是一个的超快的的 L-系统渲染写在CoffeeScript的。



下面是一个简单的渲染器在C#和WPF。它是硬编码来呈现的这个例子的。结果当运行如下所示:





点击鼠标将调整 angleGrowth 变量。重新计算 GeometryGroup 以及建设画布通常需要不到十分之一秒少得多。然而,实际的屏幕更新似乎需要更长的时间。



任何关于如何使这个速度更快或更有效的建议吗?这是目前比...的的CoffeeScript / JavaScript版本的方式慢: - )

 使用系统; 
使用System.Collections.Generic;
使用System.Text;使用System.Windows
;使用System.Windows.Controls的
;使用System.Windows.Media
;使用System.Diagnostics程序
;

命名空间WpfLsysRender
{
类DrawingVisualElement:FrameworkElement的
{
公共DrawingVisual视觉;

公共DrawingVisualElement(){视觉=新DrawingVisual(); }

保护覆盖INT VisualChildrenCount {{返回1; }}

保护覆盖视觉GetVisualChild(INT指数){返回视觉; }
}

类国家
{
公共两倍大小;

公共双角;

公共双X;

公共双Y;

公共双DIR;

公共状态的clone(){返回(州)this.MemberwiseClone(); }
}

公共部分类主窗口:窗口
{
静态字符串重写(词典<焦炭,串> TBL,字符串str)
{
变种某人=新的StringBuilder();

的foreach(str中VAR ELT)
{
如果(tbl.ContainsKey(ELT))
sb.Append(TBL [ELT]);
,否则
sb.Append(ELT);
}

返回sb.ToString();
}

公共主窗口()
{
的InitializeComponent();

宽度= 800;
身高= 800;

变种状态=新的堆栈<州及GT;();

无功海峡=L;

{
变种TBL =新词典<焦炭,串>();

tbl.Add(L,| -S大号Y!!);
tbl.Add(S,[F [FF-YS F)G] +);
tbl.Add(Y, - [F - )LT; F-FG] - );
tbl.Add(G,FGF [Y + F]氟化物+ Y);

为(VAR I = 0; I< 12;我++)海峡=重写(TBL,STR);
}

变种帆布=新的Canvas();

含量=帆布;

VAR sizeGrowth = -1.359672;
VAR angleGrowth = -0.138235;

态状态;

无功笔=新朋(新的SolidColorBrush(Colors.Black),0.25);

变种geometryGroup =新GeometryGroup();

行动buildGeometry =()=>
{
状态=新的国家()
{
X = 0,由= 0 $ B $,
DIR = 0,
规格= 14.11,
角= -3963.7485
};

geometryGroup =新GeometryGroup();

的foreach(str中VAR ELT)
{
如果(ELT =='F')
{
变种一个new_x = state.x +状态.size * Math.Cos(state.dir * Math.PI / 180.0);
VAR new_y = state.y + state.size * Math.Sin(state.dir * Math.PI / 180.0);

geometryGroup.Children.Add(
新LineGeometry(
新点(state.x,state.y),
新点(一个new_x,new_y))) ;

state.x =一个new_x;
state.y = new_y;
}
,否则如果(ELT =='+')state.dir + = state.angle;

,否则如果(ELT ==' - ')state.dir - = state.angle;

,否则如果(ELT =='>')state.size * =(1.0 - sizeGrowth);

,否则如果(ELT =='<')state.size * =(1.0 + sizeGrowth);

,否则如果(ELT ==')')state.angle * =(1 + angleGrowth);

,否则如果(ELT =='(')state.angle * =(1 - angleGrowth);

,否则如果(ELT =='[')states.Push (state.Clone());

,否则如果(ELT ==']')状态= states.Pop();

,否则如果(ELT =='! ')state.angle * = -1.0;

,否则如果(ELT =='|')state.dir + = 180.0;
}
};

行动populateCanvas =()=>
{
变种drawingVisualElement =新drawingVisualElement();

Console.WriteLine(。);

canvas.Children.Clear();

canvas.RenderTransform =新TranslateTransform(400.0,400.0);

使用(VAR DC = drawingVisualElement.visual.RenderOpen ())
dc.DrawGeometry(NULL,笔,geometryGroup);

canvas.Children.Add(drawingVisualElement);
};

的MouseDown + =(S,E)=>
{
angleGrowth + = 0.001;
Console.WriteLine(angleGrowth:{0},angleGrowth);

变种SW = Stopwatch.StartNew();

buildGeometry();
populateCanvas();

sw.Stop();

Console.WriteLine(sw.Elapsed);
};

buildGeometry();

populateCanvas();
}
}
}


解决方案

WPF的几何渲染的只是缓慢。如果你想快速渲染使用其他技术,并承办结果WPF。例如,你可以使用渲染Direct3D和托管您呈现的 D3DImage 下面是使用Direct2D的,而不是的一个例子。或者你可以通过在RGB缓冲区手动设置字节值绘制和复制一个的 WriteableBitmap的



编辑:作为OP发现,还有一个免费的图书馆,以帮助一个叫做WriteableBitmap的内部图纸 WriteableBitmapEx


lsys is a blazing fast L-System renderer written in CoffeeScript.

Below is a simple renderer in C# and WPF. It is hardcoded to render this example. The result when run looks as follows:

A mouse-click in the window will adjust the angleGrowth variable. The re-calculation of the GeometryGroup as well as building the Canvas usually take much less than a tenth of a second. However, the actual screen update seems to take much longer.

Any suggestions for how to make this faster or more efficient? It's currently way slower than the CoffeeScript/JavaScript version... :-)

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Diagnostics;

namespace WpfLsysRender
{
    class DrawingVisualElement : FrameworkElement
    {
        public DrawingVisual visual;

        public DrawingVisualElement() { visual = new DrawingVisual(); }

        protected override int VisualChildrenCount { get { return 1; } }

        protected override Visual GetVisualChild(int index) { return visual; }
    }

    class State
    {
        public double size;

        public double angle;

        public double x;

        public double y;

        public double dir;

        public State Clone() { return (State) this.MemberwiseClone(); }
    }

    public partial class MainWindow : Window
    {
        static string Rewrite(Dictionary<char, string> tbl, string str)
        {
            var sb = new StringBuilder();

            foreach (var elt in str)
            {
                if (tbl.ContainsKey(elt))
                    sb.Append(tbl[elt]);
                else
                    sb.Append(elt);
            }

            return sb.ToString();
        }

        public MainWindow()
        {
            InitializeComponent();

            Width = 800;
            Height = 800;

            var states = new Stack<State>();

            var str = "L";

            {
                var tbl = new Dictionary<char, string>();

                tbl.Add('L', "|-S!L!Y");
                tbl.Add('S', "[F[FF-YS]F)G]+");
                tbl.Add('Y', "--[F-)<F-FG]-");
                tbl.Add('G', "FGF[Y+>F]+Y");

                for (var i = 0; i < 12; i++) str = Rewrite(tbl, str);
            }

            var canvas = new Canvas();

            Content = canvas;

            var sizeGrowth = -1.359672;
            var angleGrowth = -0.138235;

            State state;

            var pen = new Pen(new SolidColorBrush(Colors.Black), 0.25);

            var geometryGroup = new GeometryGroup();

            Action buildGeometry = () => 
            {
                state = new State()
                {
                    x = 0,
                    y = 0,
                    dir = 0,
                    size = 14.11,
                    angle = -3963.7485
                };

                geometryGroup = new GeometryGroup();

                foreach (var elt in str)
                {
                    if (elt == 'F')
                    {
                        var new_x = state.x + state.size * Math.Cos(state.dir * Math.PI / 180.0);
                        var new_y = state.y + state.size * Math.Sin(state.dir * Math.PI / 180.0);

                        geometryGroup.Children.Add(
                            new LineGeometry(
                                new Point(state.x, state.y),
                                new Point(new_x, new_y)));

                        state.x = new_x;
                        state.y = new_y;
                    }
                    else if (elt == '+') state.dir += state.angle;

                    else if (elt == '-') state.dir -= state.angle;

                    else if (elt == '>') state.size *= (1.0 - sizeGrowth);

                    else if (elt == '<') state.size *= (1.0 + sizeGrowth);

                    else if (elt == ')') state.angle *= (1 + angleGrowth);

                    else if (elt == '(') state.angle *= (1 - angleGrowth);

                    else if (elt == '[') states.Push(state.Clone());

                    else if (elt == ']') state = states.Pop();

                    else if (elt == '!') state.angle *= -1.0;

                    else if (elt == '|') state.dir += 180.0;
                }
            };

            Action populateCanvas = () =>
            {
                var drawingVisualElement = new DrawingVisualElement();

                Console.WriteLine(".");

                canvas.Children.Clear();

                canvas.RenderTransform = new TranslateTransform(400.0, 400.0);

                using (var dc = drawingVisualElement.visual.RenderOpen())
                    dc.DrawGeometry(null, pen, geometryGroup);

                canvas.Children.Add(drawingVisualElement);
            };

            MouseDown += (s, e) =>
                {
                    angleGrowth += 0.001;
                    Console.WriteLine("angleGrowth: {0}", angleGrowth);

                    var sw = Stopwatch.StartNew();

                    buildGeometry();
                    populateCanvas();

                    sw.Stop();

                    Console.WriteLine(sw.Elapsed);
                };

            buildGeometry();

            populateCanvas();
        }
    }
}

解决方案

WPF's geometry rendering is just slow. If you want fast, render using another technology, and host the result in WPF. For example, you could render using Direct3D and host your render target inside a D3DImage. Here's an example using Direct2D instead. Or you could draw by manually setting byte values in a RGB buffer and copy that inside a WriteableBitmap.

EDIT: as the OP found out, there's also a free library to help out with drawing inside a WriteableBitmap called WriteableBitmapEx.

这篇关于在C#中加快了L系统的渲染器/ WPF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆