2D 图形学简介——基于WPF

第二章 2D 图形学简介——基于WPF

2.1 引言

选择具体的图形学平台:微软的 Window Presentation Foundation(WPF)
WPF 是同时支持 2D 和 3D应用的现代图形学平台

2.2 2D图形流水线概述

  • 2D图形平台是应用程序和显示硬件的中介,提供的功能与输入和输出相关联。
  • 应用通常是将某些数据(称为 应用模型 (Application Modle), AM) 转化为图像
  • 应用程序开设客户区域有两个目的:
    • 一部分用于应用程序的用户界面(UI)控制
    • 其余部分为 视图,用来显示 场景 绘制的结果。显示内容由 应用程序的 场景生成器 模块从 AM 中提取或导出

2.3 2D图形平台的演变

  • 从整数坐标到浮点数坐标
    • 早期的2D光栅图形平台采用整数坐标
      • 应用程序并非对单个像素进行着色,而是通过调用绘制 基元 的程序来绘制场景。基于可以是 几何形状 或 预先读入的矩形图像(通常叫做位图)。每一个几何基元的外观由具体的属性参数控制。
      • 应用程序采用整数坐标,可一对一地直接映射屏幕像素。
        • 原点 (0, 0) 置于画布的左上角,x 值按从左至右的方向,y值按从上到下的方向
      • 应用程序通过函数对每个基元进行设置
      • 采用整数坐标系,显示大小取决于输出设备的分辨率。同样的图形,如果输出设备的分辨率更大,则输出的图形会更小
    • 之后图形平台采用 浮点数坐标系将详细的几何数据与具体设备的特性分离开。 整数坐标系对应 物理坐标系统 浮点数坐标系对应 抽象坐标系统

  • 即时模式与保留模式
  • 基于整数的数据 和 基于浮点数数据这两种表示 最终形成了 两种不同目标和功能的架构:即时模式(IM) 和 保留模式(RM)
    • 即时模式当绘制函数被调用时,立即执行任务,将几何基元的坐标映射为设备坐标,并在显示缓冲器中对相关像素进行着色,然后将控制权返回给应用程序。
      • 在即时模式下,程序员的工作就是:对绘制图像做任何修改时,让场景生成器遍历 AM,重新生成表示场景的基元集合
    • 保留模式在一个专用数据库中保留了需绘制或观看的场景的表示,我们称之场景图。
      • 应用程序的 UI 和 场景生成器 使用 RM平台的 API 构建场景图。可通过编辑场景图对场景进行增量式修改。任何增量式修改都会导致 RM平台的同步显示器自动更新客户区域的绘制结果。
      • RM平台除了承担显示任务外,还可以承担许多与用户交互相关的任务

  • 过程语言 与 描述语言

  • 为了给出对用户接口和场景的详细描述,图形平台提供以下两种技术:

    • 面向过程的代码:采用命令式编程语言编写(通常是面向对象的,但并非必须如此),可通过大量的图形 API 与显示设备进行交互。例如,Java Swing、WPF、DirectX 等
    • 描述性语言:通过标记语言表达,例如 SVG 或 XAML
  • 最底层:面向对象的 API

    • 核心层是一组提供所有 WPF 功能的类,程序员可以在这一层使用 .Net 语言来定义应用的对外接口和行为。仅通过这一层就可以创建一个 WPF 应用程序。但另外两层可以提高开发效率。
  • 中间层:XAML

    • 中间层 提供了定义 API 大部分功能的另一种途径,它使用描述语言 XAML,其语法与 HTML 和 XML 类似。可通过对描述性语言的解释性执行程序支持应用的快速原型实现。
  • 最高层:工具

    • WPF 的最高层集成了设计师和工程师用于生成 XAML 的实用程序包括 绘图工具、3D建模工具、创建复杂用户界面的工具

2.4 使用 WPF 定义 2D场景

在 2.4 节中,我们将构造一个简单的 XAML 应用程序,来显示一个模拟时钟

  • 像 HTML 一样,XAML 也给出元素的层次化结构,但其元素类型不同,它包含:

    • 布局面板(例如,负责对紧密安放在一起的控件或菜单进行空间布局的 Stack Panel)
    • 用户界面控件(例如,按钮 和 文本输入框)
    • 用于绘制场景的 Canvas(画布)
  • 第一个例子,用 XAML 创建一个Canvas(画布):

<Canvas
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
    ClipToBounds="True"
>
</Canvas>
  • 通常都将 ClipToBoudns 设为 True,它将保证画布是有界的,即不会再指定的矩形区域之外显示任何数据
  • 我们没有指定画布大小
  • XAML 具有某些语法特性(例如上面提到的 Canvas 标签中奇特的 xmlns 性质),但它们并不会掩盖标签和属性的语义。

  • 采用抽象坐标系定义场景

    • 在图纸上建立 抽象坐标系,在抽象坐标系中我们不需要关心其一个单位的长度的具体物理单位(是 米 还是 厘米 还是 毫米)
      • 原点为 (0, 0) x 从左 到 右 y 从上 到 下
    • 绘制顺序:按从后(离观察者最远处) 到 近 的顺序绘制。即最开始绘制时钟的钟面

    XAML:

    <Canvas
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
        ClipToBounds="True">
        <Ellipse
            Canvas.Left="-10.0" Canvas.Top="-10.0"
            Width="20.0" Height="20.0"
            Fill="LightGray"/>
    </Canvas>
    

在这里插入图片描述

* [ ] 此时会发现抽象坐标系带来的问题
    * 抽象坐标映射到显示设备上后,显示出的灰色圆太小
    * 只能看到 四分之一的圆
* [ ] 这是由于我们的抽象坐标系 并不 适应WPF画布坐标系统。我们希望钟面的半径为 1英寸,而对应 WPF坐标系统,96个单位 = 1英寸。因此,我们需要定义一个 抽象坐标系 到 WPF坐标系 的 显示变换
* [ ] 我们抽象坐标系 20个单位 映射到 WPF坐标系上 希望是其96个单位,那么就是x、y轴都乘上 96/20 即 4.8。可以通过 RenderTransform 实现比例变换

```xml
<Canvas
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
    ClipToBounds="True">
    <Canvas>
        <Ellipse
        Canvas.Left="-10.0" Canvas.Top="-10.0"
        Width="20.0" Height="20.0"
        Fill="LightGray" >
        </Ellipse>
        <Canvas.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="4.8" ScaleY="4.8" CenterX="0" CenterY="0"/>
            </TransformGroup>
        </Canvas.RenderTransform>
    </Canvas>
</Canvas>
```

在这里插入图片描述

* [ ] 坐标系/基原则:始终选择你工作作为方便的坐标系或基,并通过变换使它和不同的坐标系或基关联起来
* [ ] 此时,我们仍是只能看到四分之一圆,我们再添加一条 平移变换:
```xml
<Canvas
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
    ClipToBounds="True">
    <Canvas>
        <Ellipse
        Canvas.Left="-10.0" Canvas.Top="-10.0"
        Width="20.0" Height="20.0"
        Fill="LightGray" >
        </Ellipse>
        <Canvas.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="4.8" ScaleY="4.8" CenterX="0" CenterY="0"/>
                <TranslateTransform X="48" Y="48"/>
            </TransformGroup>
        </Canvas.RenderTransform>
    </Canvas>
</Canvas>
```

在这里插入图片描述

* [ ] 比例变换 和 位移变换的执行顺序不同,结果也不同。即它们是相关联的

  • 构造并使用模块化模板
    • WPF 中 有重用模板(控制模板 Control),对于我们指针的时针和分针,它们的形状是相同的,只是缩放不同,因此我们可以先构造 模板,然后通过 模板 来实例化出具体的元素
    <Canvas
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
        ClipToBounds="True">
        <Canvas>
            <Canvas.Resources>
                <ControlTemplate x:Key="ClockHandTemplate">
                    <Polygon
                        Points="-0.3,-1 -0.2,8  0,9 0.2,8 0.3,-1  "
                        Fill="Navy"/>
                </ControlTemplate>
            </Canvas.Resources>
            <Ellipse
                Canvas.Left="-10.0" Canvas.Top="-10.0"
                Width="20.0" Height="20.0"
                Fill="LightGray" 
            />
            <Ellipse 
                Canvas.Left="-2" Canvas.Top="-10.0"
                Width="4" Height="4"
                Fill="Blue"
            />
            <Control Name="MinuteHand"
                        Template="{StaticResource ClockHandTemplate}"
            />
            <Canvas.RenderTransform>
                <TransformGroup>
                    <ScaleTransform ScaleX="4.8" ScaleY="4.8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值