Sliverlight 3D——绘制一个三角形

这篇文章介绍了如何使用Silverlight在Web网页上绘制一个简单的三角形。

XNA Games Studio 4.0的图形库现在已经包含在Silverlight 5中了,如果你有XNA的开发知识,就可以很容易地在Silverlight中创建3D程序。

要创建一个Silverlight 3D应用程序,最佳的方法就是使用Toolkit提供的3D模板,这个模板提供了一个基础框架,添加了必要的引用、一个Content项目和绘制一个立方体动画的代码,你可以很容易地扩展这个框架实现更复杂的效果。

但为了理解原理,这个例子并没有从3D模板生成,而是从更基本的Silverlight应用程序开始。

最小代码

首先,使用Visual Studio创建一个新Silverlight应用程序项目,我命名为Silverlight3D_1

新建项目

生成项目后,右击项目打开属性窗口,设置允许在浏览器外运行应用程序,在下面的浏览器外设置对话框中必须选择使用GPU加速在浏览器之外运行时需要提升的信任

属性设置

你需要在项目中添加以下引用:

添加引用

添加DrawingSurface控件

Silverlight中使用一个新控件DrawingSurface绘制3D图形,DrawingSurface是一个FrameworkElement,所以它可以像其他控件一样组合在Silverlight的visual tree(注:Visual Tree应翻译为视觉树,它是WPF和Silverlight程序组织控件的一种形式,类似于HTML中DOM树)中,它继承了Width,Height,FlowDirection,HorizontalAlignment和VerticalAlignment属性。

DrawingSurface添加了一个新事件:Draw。Draw事件处理3D图形的位置;world,view和projection矩阵的更新,调用DrawPrimitives方法让GraphicsDevice绘制图形。

当系统准备好绘制下一帧时就会引发Draw事件。当DrawingSurface添加到visual tree时会引发第一个事件,后面的Draw事件是在invalidated时引发的。Invalidated可以使用两种方法实现:调用UI线程中的DrawingSurface.Invalidate方法;或从事件处理程序中调用绘制线程中的DrawEventArgs.InvalidateSurface

如果3D内容是静态的,就无需在Draw事件最后调用InvalidateSurface方法。如果3D内容是动态的,例如,如果3D对象具有动画,则需要在事件处理的最后调用InvalidateSurface开始绘制循环。

当DrawingSurface的视口比例发生变化时,可以在DrawingSurface的SizeChanged事件处理程序中添加对应的代码。

如果3D是不可见的,那么DrawingSurface事件不会被调用,当element或parent tree是不可见的或者图形设备被移除时就可能发生这种情况。

DrawEventArgs类提供了两个计时属性用于动画计算。DrawEventArgs.TotalTime 表示程序启动后经历的总时间,DrawEventArgs.DeltaTime表示上一次绘制更新后经历的时间。

在MainPage.xmal中添加DrawingSurface控件:

<Grid x:Name="LayoutRoot" Background="White">
    <DrawingSurface Loaded="DrawingSurface_Loaded" Draw="DrawingSurface_Draw" />
</Grid>

还添加了DrawingSurface加载和绘制事件的处理程序DrawingSurface_LoadedDrawingSurface_Draw

后台代码

后台MainPage.xaml.cs的代码如下:

using System.Windows;
using System.Windows.Controls; 
using System.Windows.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Silverlight3D_1 
{
    public partial class MainPage : UserControl
    {        
        GraphicsDevice graphicsDevice; // 图形设备
        
        public MainPage()
        {
            InitializeComponent();
        }
        
        private void DrawingSurface_Loaded(object sender, RoutedEventArgs e) 
        {
            // 初始化图形设备
            graphicsDevice = GraphicsDeviceManager.Current.GraphicsDevice;
        }
        
        private void DrawingSurface_Draw(object sender, DrawEventArgs e)
        {
            // 清除后备缓冲 
            graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Color(0.2f, 0.2f, 0.2f, 1.0f), 1.0f, 0); 
            // 刷新DrawingSurface控件 
            e.InvalidateSurface(); 
        }
    }
}

很简单!在DrawingSurface的加载过程中获取图形设备,在绘制方法中用灰色刷新视频缓冲。但是要注意:GraphicsDevice的Clear方法中使用的Color位于Microsoft.Xna.Framework命名空间,会和System.Windows.Media.Color冲突,你要么全名定义这个Color,要么在程序文件顶部的using中删除System.Windows.Media命名空间。

运行程序,截图如下,这就是最简单的一个3D程序。

最简单的代码运行截图

绘制一个三角形

创建顶点数据

要绘制三角形,我们需要设定三个顶点的数据,因为这个例子不需要光照,因此顶点格式为VertexPositionColor,但顶点格式位于Microsoft.Xna.Framework.Graphics.Extensions命名空间,你必须首先在项目中添加引用。然后,在DrawingSurface_Loaded方法中添加定义三角形的代码:

private void DrawingSurface_Loaded(object sender, RoutedEventArgs e) 
{
    …
    
    // 定义三角形顶点
    VertexPositionColor[] vertices = new VertexPositionColor[3]; 
    
    vertices[0].Position = new Vector3(-1, -1, 0); // 左边的顶点
    vertices[1].Position = new Vector3(0, 1, 0); // 顶部的顶点
    vertices[2].Position = new Vector3(1, -1, 0); // 右边的顶点
    vertices[0].Color = new Color(255, 0, 0, 255); // 左边顶点为红色
    vertices[1].Color = new Color(0, 255, 0, 255); // 顶部顶点为绿色
    vertices[2].Color = new Color(0, 0, 255, 255); // 右边顶点为蓝色
}

别忘了Vector3位于Microsoft.Xna.Framework.Math命名空间,你还要在项目中添加这个命名空间。

创建顶点缓冲

首先在程序中定义顶点缓冲的全局变量:

VertexBuffer vertexBuffer; // 顶点缓冲 
                

然后在DrawingSurface_Loaded方法中定义顶点数据之后设置顶点缓冲:

private void DrawingSurface_Loaded(object sender, RoutedEventArgs e) 
{
    … 
    // 设置顶点缓冲
    vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), vertices.Length,BufferUsage.WriteOnly); 
    vertexBuffer.SetData(0, vertices, 0, vertices.Length, 0);
}

使用Effect

在这个最简单的例子中,我们使用XNA内置的BasicEffect绘制几何数据,首先需定义这个全局变量:

basicEffect = new BasicEffect(graphicsDevice); 

并在DrawingSurface_Loaded方法中进行初始化:

private void DrawingSurface_Loaded(object sender, RoutedEventArgs e) 
{
    …
    // 初始化Effect 
    basicEffect = new BasicEffect(graphicsDevice); 
}

设置矩阵

你还要在设置相机的矩阵数据,首先定义全局变量:

Matrix view; // 相机视矩阵
Matrix projection; // 相机投影矩阵

并在DrawingSurface_Loaded方法中进行初始化:

private void DrawingSurface_Loaded(object sender, RoutedEventArgs e)
{
    …
    
    // 初始化矩阵
    view = Matrix.CreateLookAt(new Vector3(0, 0, 5.0f), Vector3.Zero, Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4f / 3, 0.01f, 1000.0f); 
}

绘制图形

最后在DrawingSurface_Draw方法中添加以下代码让图形设备调用DrawPrimitives方法绘制顶点缓冲中的数据:

private void DrawingSurface_Draw(object sender, DrawEventArgs e) 
{
    // 清除后备缓冲 
    graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Color(0.2f, 0.2f, 0.2f, 1.0f), 1.0f, 0);
    
    // 设置顶点缓冲
    graphicsDevice.SetVertexBuffer(vertexBuffer); 
    
    // 开始绘制
    basicEffect.CurrentTechnique.Passes[0].Apply();
    // 设置矩阵
    basicEffect.View = view; 
    basicEffect.Projection = projection; 
    // 开启顶点颜色的绘制
    basicEffect.VertexColorEnabled = true; 
    // 绘制几何体
    graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); 
    
    // 刷新DrawingSurface控件 
    e.InvalidateSurface(); 
}

运行程序后的效果如下:

文件下载(已下载 3401 次)

发布时间:2012/1/9 下午12:14:44  阅读次数:12122

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号