Windows的API里有B样条曲线的函数吗?顺便谈谈WPF的动画技术

jameshooo 2011-02-12 02:25:57
我希望有API,能直接根据X算出B样条曲线的Y值,不想要GDI+的,最好是API,或者开源的函数。

最近实现了WPF中的From/To/By动画技术、关键帧动画技术和属性动画技术,可以通过XML或者脚本直接创建2D/3D动画,在时间线的控制上还缺乏样条控制功能(意思是时间值不一定均匀分布,而是通过样条决定时间快慢),只是还未找到轻量级的样条曲线函数,有经验的朋友帮忙提供一点线索。

WPF中还有路径动画技术,这个比较简单,只是现在还没有实现,留待以后吧。WPF的动画依赖高效定时器,我也实现了一个多线程的高精度定时器,效率很高。

动画都是相通的。WPF的动画功能很全,据我观察,在3DSMAX中支持的动画技术都能在WPF中实现,所以对于我而言,WPF是一个非常好的参照平台,可以少走很多弯路,我会尽可能把WPF的特性都COPY过来,并非求全,但是精髓一定要有。同时,因为有专用设计工具,XAML文件看起来很庞大且过于复杂,不利于手写,但我没设计工具,只好在用XML描述时尽量减少大小。

描述一段动画的例子:
WPF用XAML描述:

<!-- 这是From/To/By动画例子 -->
<Rectangle Name="fromToAnimatedRectangle"
Height="10" Width="100" HorizontalAlignment="Left"
Fill="Black">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard>
<!-- Demonstrates the From and To properties used together.
Animates the rectangle's Width property from 50 to 300 over 10 seconds. -->
<DoubleAnimation
Storyboard.TargetName="fromToAnimatedRectangle"
Storyboard.TargetProperty="Width"
From="50" To="300" Duration="0:0:10" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>

<!-- 这是关键帧动画例子 -->
<Border Background="#99FFFFFF" BorderThickness="28"
Margin="0,60,0,20" Padding="20" >
<Border.BorderBrush>
<SolidColorBrush x:Name="MyAnimatedBrush" Color="Green" />
</Border.BorderBrush>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>

<!-- Animate from green to red using a linear key frame, from red to
yellow using a discrete key frame, and from yellow back to green with
a spline key frame. This animation repeats forever. -->
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="Color"
Storyboard.TargetName="MyAnimatedBrush"
Duration="0:0:6" FillBehavior="HoldEnd" RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames.KeyFrames>

<!-- Go from green to red in the first 2 seconds. LinearColorKeyFrame creates
a smooth, linear animation between values. -->
<LinearColorKeyFrame Value="Red" KeyTime="0:0:2" />

<!-- In the next half second, go to yellow. DiscreteColorKeyFrame creates a
sudden jump between values. -->
<DiscreteColorKeyFrame Value="Yellow" KeyTime="0:0:2.5" />

<!-- In the final 2 seconds of the animation, go from yellow back to green. SplineColorKeyFrame
creates a variable transition between values depending on the KeySpline property. In this example,
the animation starts off slow but toward the end of the time segment, it speeds up exponentially.-->
<SplineColorKeyFrame Value="Green" KeyTime="0:0:4.5" KeySpline="0.6,0.0 0.9,0.00" />
</ColorAnimationUsingKeyFrames.KeyFrames>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>

<TextBlock>
This example shows how to use the ColorAnimationUsingKeyFrames to create
an animation on the BorderBrush property of a Border.
</TextBlock>
</Border>


我用XML描述:

<!-- From/To/By 动画XML描述例子 -->
<StoryBoard>
<FrameSet TargetType="Int" Target="myimg" TargetAttribute="left" Reverse="true" Repeat="forever"
From="0" To="125" Duration="0:0:5" />
<FrameSet TargetType="Int" Target="myimg" TargetAttribute="top" Reverse="true" Repeat="forever"
From="20" To="120" Duration="0:0:8.2" />
</StoryBoard>

<!-- 关键帧动画XML描述例子 -->
<StoryBoard>
<KeyFrameSet TargetType="Int" Target="myimg2" TargetAttribute="left" Reverse="true" Repeat="forever">
<KeyFrame KeyTime="0" KeyValue="120" />
<KeyFrame KeyTime="2" KeyValue="160" />
<KeyFrame KeyTime="0:3" KeyValue="210" />
<KeyFrame KeyTime="0:0:5.0" KeyValue="250" />
</KeyFrameSet>
<KeyFrameSet TargetType="Int" Target="myimg2" TargetAttribute="top" Reverse="true" Repeat="forever">
<KeyFrame KeyTime="0" KeyValue="120" />
<KeyFrame KeyTime="3" KeyValue="170" />
<KeyFrame KeyTime="10.0" KeyValue="200" />
<KeyFrame KeyTime="0:0:13" KeyValue="250" />
</KeyFrameSet>
</StoryBoard>

...全文
281 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
fishion 2011-02-20
  • 打赏
  • 举报
回复
。。没看懂是什么。。。
pclili 2011-02-20
  • 打赏
  • 举报
回复
B样条曲线的算法已发给你.收分来的.dui群.tristar.
jackson35296 2011-02-14
  • 打赏
  • 举报
回复
楼主是用C++实现了类似WPF的动画?
sjdev 2011-02-14
  • 打赏
  • 举报
回复
呃.这个合并后的语句看起来很新颖,不过我觉得有点怪异。
c#中有类似下面这样的代码, 我觉得还可以. (我不是很熟悉js, 不知道js的习惯是什么样的)


var frameset = new FrameSet
{
TargetType = "float",
Target = "myimg",
TargetAttribute = "left",
Reverse = true,
Repeat = 3,
From = 20.0f,
To = 58.6f
};

jameshooo 2011-02-14
  • 打赏
  • 举报
回复
我的js用在XML文件中,放在<script>标签内即可,或者放在独立的js文件中,用法跟HTML一样。不需要VC环境。

js的用法我改进过,就是为了把多个语句合并到一个语句中完成(这个特点只能用在DOM对象上,普通的JS对象不行),需要赋值的语句都可以合并,像下面这样:

// 普通的JS赋值代码
var frameset = new FrameSet();
frameset.targetType = "float";
frameset.target = "myimg"; // 或者 直接用 = myimg
frameset.targetAttribute = "left";
frameset.reverse = true;
frameset.repeat = 3;
frameset.from = 20.0f;
frameset.to = 58.6f;

// 合并的JS赋值代码,一个语句完成所有赋值,跟上面的代码完全等效
var frameset = new FrameSet().targetType("float").target("myimg").targetAttribute("left")
.reverse(true).repeat(3).from(20.0f).to(58.6f);
sjdev 2011-02-14
  • 打赏
  • 举报
回复
单独用cs或单独用xaml写wpf代码都挺费劲的,我一般是两者结合起来.

我看你的js挺精炼的, 怎么用? 配合vc使用吗?
jameshooo 2011-02-14
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 jackson35296 的回复:]

楼主是用C++实现了类似WPF的动画?
[/Quote]

对,参照WPF实现的,功能基本相同。
jameshooo 2011-02-14
  • 打赏
  • 举报
回复
js中有 with 语句,但只能用于读取,不能用于写入:

with (obj) {
abc = def; // 等效于 var abc = obj.def;
}


C#这种用法是属于成员初始化,不知道是不是存在类似 VB 中的针对已存在对象的一次性赋值:
with obj
.abc = 1
.def = True;
end with

受限于JS的语法限制,我只能设计成这样。
jameshooo 2011-02-12
  • 打赏
  • 举报
回复
WPF不适合做游戏,MSDN也说得很清楚了,它的目标是UI,只是用DX作为渲染工具,并且有很多影响性能的因素。

[Quote=引用 7 楼 sjdev 的回复:]

贝塞尔曲线,GDI+就可以。
[/Quote]
就是不想用GDI+的

[Quote=引用 8 楼 sjdev 的回复:]

你的东西,现在搞的很不错了。忘记网站了,贴个我去膜拜一下。
[/Quote]
别去网站了,还没时间更新版本,等3D全部完成再说,已经完成2/3了,需要再等几个月。到时直接上3D效果的应用,DEMO就不做了。
sjdev 2011-02-12
  • 打赏
  • 举报
回复
你的东西,现在搞的很不错了。忘记网站了,贴个我去膜拜一下。
sjdev 2011-02-12
  • 打赏
  • 举报
回复
贝塞尔曲线,GDI+就可以。
zzz_zou 2011-02-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 jameshooo 的回复:]
引用 2 楼 eyey1 的回复:

完全不懂。顶下!


不懂就看看MSDN中关于WPF动画的部分内容,你会发现做一个动画原来这么简单。
[/Quote]

我去看看 是不是真的这么简单!
手机写程序 2011-02-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 jameshooo 的回复:]
引用 2 楼 eyey1 的回复:

完全不懂。顶下!


不懂就看看MSDN中关于WPF动画的部分内容,你会发现做一个动画原来这么简单。
[/Quote]
多谢lz栽培。
据说用WPF后就可以放弃DX了,而且实现了很多特效。只是感觉推广不力啊。以后游戏开发会转到这个平台上吗?希望lz开示。
[Quote=引用 4 楼 visualeleven 的回复:]
围观大牛~
[/Quote]
围观两条大牛。
Eleven 2011-02-12
  • 打赏
  • 举报
回复
围观大牛~
jameshooo 2011-02-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 eyey1 的回复:]

完全不懂。顶下!
[/Quote]

不懂就看看MSDN中关于WPF动画的部分内容,你会发现做一个动画原来这么简单。
jameshooo 2011-02-12
  • 打赏
  • 举报
回复

用开发语言创建动画的例子:
C#创建动画的例子:

// C# 创建From/To/By 动画的例子
NameScope.SetNameScope(this, new NameScope());

Rectangle myRectangle = new Rectangle();

// Assign the Rectangle a name so that
// it can be targeted by a Storyboard.
this.RegisterName(
"fromToAnimatedRectangle", myRectangle);
myRectangle.Height = 10;
myRectangle.Width = 100;
myRectangle.HorizontalAlignment = HorizontalAlignment.Left;
myRectangle.Fill = Brushes.Black;

// Demonstrates the From and To properties used together.
// Animates the rectangle's Width property from 50 to 300 over 10 seconds.
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 50;
myDoubleAnimation.To = 300;
myDoubleAnimation.Duration =
new Duration(TimeSpan.FromSeconds(10));

Storyboard.SetTargetName(myDoubleAnimation, "fromToAnimatedRectangle");
Storyboard.SetTargetProperty(myDoubleAnimation,
new PropertyPath(Rectangle.WidthProperty));
Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);

// Use an anonymous event handler to begin the animation
// when the rectangle is clicked.
myRectangle.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs args)
{
myStoryboard.Begin(myRectangle);

};

// C# 创建关键帧动画的例子
Background = Brushes.White;
Margin = new Thickness(20);

// Create a NameScope for this page so that
// Storyboards can be used.
NameScope.SetNameScope(this, new NameScope());

StackPanel myStackPanel = new StackPanel();
myStackPanel.Orientation = Orientation.Vertical;
myStackPanel.HorizontalAlignment = HorizontalAlignment.Center;

// Create the Border that is the target of the animation.
SolidColorBrush animatedBrush = new SolidColorBrush();
animatedBrush.Color = Color.FromArgb(255, 0, 255, 0);
Border myBorder = new Border();

// Set the initial color of the border to green.
myBorder.BorderBrush = animatedBrush;
myBorder.BorderThickness = new Thickness(28);
myBorder.Padding = new Thickness(20);
myStackPanel.Children.Add(myBorder);

// Create a TextBlock to host inside the Border.
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "This example shows how to use the ColorAnimationUsingKeyFrames"
+ " to create an animation on the BorderBrush property of a Border.";
myBorder.Child = myTextBlock;

// Assign the Brush a name so that
// it can be targeted by a Storyboard.
this.RegisterName(
"AnimatedBrush", animatedBrush);

// Create a ColorAnimationUsingKeyFrames to
// animate the BorderBrush property of the Button.
ColorAnimationUsingKeyFrames colorAnimation
= new ColorAnimationUsingKeyFrames();
colorAnimation.Duration = TimeSpan.FromSeconds(6);

// Create brushes to use as animation values.
Color redColor = new Color();
redColor = Color.FromArgb(255, 255, 0, 0);
Color yellowColor = new Color();
yellowColor = Color.FromArgb(255, 255, 255, 0);
Color greenColor = new Color();
greenColor = Color.FromArgb(255, 0, 255, 0);

// Go from green to red in the first 2 seconds. LinearColorKeyFrame creates
// a smooth, linear animation between values.
colorAnimation.KeyFrames.Add(
new LinearColorKeyFrame(
redColor, // Target value (KeyValue)
KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.0))) // KeyTime
);

// In the next half second, go to yellow. DiscreteColorKeyFrame creates a
// sudden jump between values.
colorAnimation.KeyFrames.Add(
new DiscreteColorKeyFrame(
yellowColor, // Target value (KeyValue)
KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.5))) // KeyTime
);

// In the final 2 seconds of the animation, go from yellow back to green. SplineColorKeyFrame
// creates a variable transition between values depending on the KeySpline property. In this example,
// the animation starts off slow but toward the end of the time segment, it speeds up exponentially.
colorAnimation.KeyFrames.Add(
new SplineColorKeyFrame(
greenColor, // Target value (KeyValue)
KeyTime.FromTimeSpan(TimeSpan.FromSeconds(4.5)), // KeyTime
new KeySpline(0.6, 0.0, 0.9, 0.0) // KeySpline
)
);

// Set the animation to repeat forever.
colorAnimation.RepeatBehavior = RepeatBehavior.Forever;

// Set the animation to target the Color property
// of the object named "AnimatedBrush".
Storyboard.SetTargetName(colorAnimation, "AnimatedBrush");
Storyboard.SetTargetProperty(
colorAnimation, new PropertyPath(SolidColorBrush.ColorProperty));

// Create a storyboard to apply the animation.
Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(colorAnimation);

// Start the storyboard when the Border loads.
myBorder.Loaded += delegate(object sender, RoutedEventArgs e)
{
myStoryboard.Begin(this);
};



我用JS创建动画的例子:

// 演示From/To/By动画的函数
function doframe() {
return StoryBoard() // 创建演示板
.addTo(window) // 添加演示板至窗口
// 在演示板中添加两个FROM/TO/BY动画帧
.newFrameSet(
// 此动画帧控制 myimg 控件的 left 属性,类型为整数,在5秒内使其值从0变成120,自动回转,动画不停止
FrameSet.TargetType('int').Target(myimg).TargetAttribute('left').Reverse(true).Repeat('forever').From(0).To(120).Duration(5)
)
.newFrameSet(
// 此动画帧控制 myimg 控件的 top 属性,类型为整数,在8.2秒内使其值从20变成120,自动回转,动画不停止
FrameSet.TargetType('int').Target(myimg).TargetAttribute('top').Reverse(true).Repeat('forever').From(20).To(120).Duration(8.2)
)
.start(); // 启动演示板动画
}

// 演示关键帧动画的函数
function dokeyframe() {
return StoryBoard() // 创建演示板
.addTo(window) // 添加演示板至窗口
// 创建两个关键帧集,分别控制 myimg2 控件的left和top属性
.newFrameSet(
// 此关键帧集控制 myimg2 控件的 left 属性,类型为整数,自动回转,动画不停止
KeyFrameSet.TargetType('int').Target(myimg2).TargetAttribute('left').Reverse(true).Repeat('forever')
// 关键帧集添加 4 个关键帧,时间从 0 到 5 秒,关键帧的值从 120 到 250
.newKeyFrame(KeyFrame.KeyTime(0).KeyValue(120))
.newKeyFrame(KeyFrame.KeyTime(2).KeyValue(160))
.newKeyFrame(KeyFrame.KeyTime(3).KeyValue(210))
.newKeyFrame(KeyFrame.KeyTime(5).KeyValue(250))
)
.newFrameSet(
// 此关键帧集控制 myimg2 控件的 top 属性,类型为整数,自动回转,动画不停止
KeyFrameSet.TargetType('int').Target(myimg2).TargetAttribute('top').Reverse(true).Repeat('forever')
// 关键帧集添加 4 个关键帧,时间从 0 到 13 秒,关键帧的值从 120 到 250
.newKeyFrame(KeyFrame.KeyTime(0).KeyValue(120))
.newKeyFrame(KeyFrame.KeyTime(3).KeyValue(170))
.newKeyFrame(KeyFrame.KeyTime(10).KeyValue(200))
.newKeyFrame(KeyFrame.KeyTime(13).KeyValue(250))
)
.start(); // 启动演示板动画
}

19,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧