WPF 3D model - Sphere, Cone, and Cylinder
原文:WPF 3D model - Sphere, Cone, and Cylinder
Extending Visual3D - Sphere, Cone, and Cylinder
http://blogs.msdn.com/b/danlehen/archive/2005/10/16/481597.aspx
He put together a short sample which derives a Sphere, a Cone, and a Cylinder primitive from ModelVisual3D. (Source available
here.)
You will notice that these primitives are directly usable from Xaml:
<Viewport3D Camera=”{Camera}”
>
<my:Sphere3D Transform=”{XForm1}” Material=”{Azul}” />
<my:Cone3D Transform=”{XForm2}” Material=”{Tulips}” />
<my:Cylinder3D Transform=”{XForm3}” Material=”{Autumn}” />
</Viewport3D>
Perspective : Easy 3D programming with WPF
http://www.odewit.net/ArticleContent.aspx?id=Wpf3DIntro&lang=en&format=xaml
[Lieo原创]圆柱体的三角形剖分——使用WPF 3D绘制圆柱体
上个学期在做某个软件时需要使用WPF绘制一些基本的三维物体。找了很多资料,发现大多是介绍球体的,因为这些图形的绘制原理基本类似。
但是在绘制圆柱体时遇到了一个问题,就是不知道空间中任意一个圆的参数方程。凭大学里学的高等数学知识仅能推导出底面与坐标平面平行的圆的参数方程,如果圆与坐标面成任意夹角就无法解决。使用与坐标面平行的圆绘制出的“类圆柱体”已经可以满足我的程序的需求了,但是绘制出来的毕竟不是一个真正的圆柱。向同学请教了参数方程后后,终于解决了这个问题。
【铺垫:使用WPF 3D绘制三维物体的方法概述】
与Direct 3D类似,在WPF中,任何三维物体都是由三角形组成的。MeshGeometry3D对象定义组成图像的各个三角形顶点和这些顶点的连接方式。该对象的Positions属性是一个Point3D类型的集合,用户记录三角形的各顶点坐标,TriangleIndices属性则描述这些顶点的链接方式。
GeometryModel3D对象的Material和BackMaterial属性可以定义三维物体的表面和背面材质。在本程序中,材质只用到了漫反射材质DiffuseMaterial。Geometry属性指定该三维物体的MeshGeometry3D对象。为此,我们可以为每一个原子、键和平面生成各自的GeometryModel3D对象,这样就可以为每一个元素分别进行着色。
每个GeometryModel3D被承载在一个ModelVisual3D对象中。整个三维场景都被定义在一个Viewport3D对象中。该对象的Children属性是ModelVisual3D的集合。将预先设定的三维物体的ModelVisual3D对象添加到集合中,便可以在Viewport3D视图中显示。
【引子:先了解如何绘制一个球面】
一个球体可以表示成由经线和纬线组成的网格,我们可以将每个网格近似地看成由两个三角形组成的平面,如下图所示。
为了依次生成球面上离散的各点坐标,需要将球面写成参数形式。设球心在坐标原点,球体半径为R,则其参数方程为:
使用参数方程,用双重循环即可生成球面的点。代码如下:
'将球面进行三角形拆分。设球面的参数方程为:
' x = - r * cosφ * sinθ
' y = r * sinφ
' z = - r * cos φ * cosθ
'其中,-π/2≤φ≤π/2,-2π≤θ≤2π
Dim mesh As New MeshGeometry3D
Dim x, y, z, theta, phi As Double
Dim normal As Vector3D '组成球面的某个三角形的法向量
For i As Integer = 0 To Stacks '将球面拆分成Stacks个等距离的薄片(纬度,自上向下)
phi = Math.PI / 2 - i * Math.PI / Stacks '计算该纬度位置的phi角
y = R * Math.Sin(phi) '计算该纬度位置的y轴坐标(假设球心在原点)
For j As Integer = 0 To Slices '将球面纵向切成Slices份(经度方向,自西向东)
theta = j * 2 * Math.PI / Slices '计算该经度位置的theta角
'按照参数方程计算出另外两个坐标值
x = -R * Math.Cos(phi) * Math.Sin(theta)
z = -R * Math.Cos(phi) * Math.Cos(theta)
normal = New Vector3D(x, y, z) '当球心在原点时,某点的法向量就是(x,y,z)
mesh.Positions.Add(normal + center) '某点的坐标:指定的球心+当前计算出的坐标
'计算材质对应的二维坐标,点(j / Slices, i / Stacks)是该点在二维平面展开后对应的坐标
mesh.TextureCoordinates.Add(New Windows.Point(j / Slices, i / Stacks))
Next j
Next i
其中Stacks表示纬度剖分数,Slices为经度拆分数。每计算一个顶点的坐标,便将其添加到Positions集合中。mesh.Normals.Add方法由于指定该点的法向量。该点的法向量方向是球心与该点连线的向量方向,即
,而该点的坐标为
,其中c是球心的坐标。
接下来需要考虑的问题是如何为球面着色。设想球面按球面轴展开,就成了如下图所示的二维平面。
与顶点集合对应的TextureCoordinates集合指定了填充三维对象表面时顶点与二维图像之间的关系。WPF定义与三维物体表面对应的二维填充平面的左上顶点和右下顶点分别为(0,0)和(1,1),如上图所示的(i,j),其对应的二维向量为
。mesh.TextureCoordinates.Add(i/stacks,j/slices)就是指定该顶点与二维填充平面的对应关系。
顶点和相关集设置好后,需要指定这些顶点如何构成三角形。具体实现方式请参考Lieo3DModel类中GenerateSphereMesh方法。
【进入正题:圆柱体侧面的三角形剖分】
与球体类似,圆柱体按照其轴展开后也是一个矩形。
可以想象,设n表示从底面圆心指向顶面圆心的向量,将一个底面圆上的按照圆的参数方程等间隔地生成,那么顶面相对应的顶点的坐标可按照向量n平移得到。将这样的两个点连起来,连线与轴平行。按照这个思路,只需要生成底面圆上各点的坐标,即可按照图将圆柱剖分成三角形。
空间中任意一个圆的参数方程为:
其中 为圆的法向量。为了计算这两个与法向量相互正交的向量,可以使用向量的叉积运算。
设M是空间中任意一个不与圆的法向量共线的向量,令
,这样得到的
就是相互垂直的。将向量归一化后,便得到了参数方程所需要的a,b。
参照球面生成的代码,生成圆柱的代码能够很容易写出。具体请下列代码:
''' <summary>
''' 将两底面圆心在 p1、p2 位置,底面半径为 R 的圆柱体进行三角形剖分。
''' </summary>
''' <param name="p1">圆柱上底面圆心的坐标。</param>
''' <param name="p2">圆柱下底面圆心的坐标。</param>
''' <param name="R">圆柱的底面半径。</param>
''' <returns>返回值:代表该圆柱面的MeshGeometry3D对象。</returns>
Public Shared Function GenerateCylinderMesh(ByVal p1 As Point3D, ByVal p2 As Point3D, ByVal R As Double) As MeshGeometry3D
'将圆柱体进行三角形剖分
'空间中圆的参数方程:(x,y,z) = r*(A*cosθ+B*sinθ)+(x0,y0,z0) 【0≤θ≤2π】
' 其中 a、b 是单位向量,且满足 A⊥B⊥n(圆的法向量)
Dim mesh As New MeshGeometry3D
Dim CircleVector As Vector3D = p2 - p1 '从p1点到p2点的3D向量
Dim M As New Vector3D(1, 1, 1)
If Vector3D.AngleBetween(M, CircleVector) < 0.1 Then
M = New Vector3D(1, 0, 0)
End If
Dim A As Vector3D = Vector3D.CrossProduct(CircleVector, M)
Dim B As Vector3D = Vector3D.CrossProduct(CircleVector, A)
A.Normalize()
B.Normalize()
Dim theta As Double
Dim Pos1, Pos2 As Point3D
'设圆与 xz 轴平行
For i As Integer = 0 To Stacks
'计算剖分三角形顶点在参数方程中对应的角度
theta = i / Stacks * Math.PI * 2
Pos1 = R * (A * Math.Cos(theta) + B * Math.Sin(theta)) + p1
Pos2 = R * (A * Math.Cos(theta) + B * Math.Sin(theta)) + p2
mesh.Positions.Add(Pos1)
mesh.Positions.Add(Pos2)
mesh.TextureCoordinates.Add(New Windows.Point(i / Stacks, 0))
mesh.TextureCoordinates.Add(New Windows.Point(i / Stacks, 1))
Next
For i As Integer = 0 To Stacks - 1
mesh.TriangleIndices.Add(i * 2)
mesh.TriangleIndices.Add(i * 2 + 1)
mesh.TriangleIndices.Add(i * 2 + 3)
mesh.TriangleIndices.Add(i * 2)
mesh.TriangleIndices.Add(i * 2 + 3)
mesh.TriangleIndices.Add(i * 2 + 2)
Next
Return mesh
End Function
WPF 3D model - Sphere, Cone, and Cylinder的更多相关文章
- WPF 3D 知识点大全以及实例
引言 现在物联网概念这么火,如果监控的信息能够实时在手机的客服端中以3D形式展示给我们,那种体验大家可以发挥自己的想象. 那生活中我们还有很多地方用到这些,如上图所示的Kinect 在医疗上的应用,当 ...
- 优化WPF 3D性能
Maximize WPF 3D Performance .NET Framework 4.5 As you use the Windows Presentation Foundation (WPF ...
- WPF 3D 模型旋转
原文:WPF 3D 模型旋转 WPF 是 Microsoft 在 Framework3.0 中支持的一种技术,它能作出很绚丽的界面,同时它也支持3D的操作.在3D操作主要包括平移(Translate) ...
- WPF 3D 小小小小引擎 - ·WPF 3D变换应用
原文:WPF 3D 小小小小引擎 - ·WPF 3D变换应用 WPF可以提供的3D模型使我们可以轻松地创建3D实体,虽然目前来看还很有一些性能上的问题,不过对于一些简单的3D应用应该是可取的,毕竟其开 ...
- WPF 3D 常用类(1)
原文:WPF 3D 常用类(1) 几何数据相关类 Geometry3D 抽象类, 用于定义物体的几何数据, 可用于计算HitTest和BoundingBox MeshGeometry3D Geomet ...
- WPF 3D:使用GeometryModel3D的BackMaterial
原文 WPF 3D:使用GeometryModel3D的BackMaterial 使用BackMaterial,我们可以定义3D物体的内部材质(或者说是背面),比如,我们定义一个四方体容器,外面现实的 ...
- WPF 3D:MeshGeometry3D的定义和光照
原文 WPF 3D:MeshGeometry3D的定义和光照 由于WPF计算光照会根据整个平面的方向向量,所以如果在不同面上使用同一个点可能会达到不同的光照效果.让我们用不同的定义Mesh的方法来演示 ...
- WPF 3D: MeshGeometry3D纹理坐标的正确定义
原文 WPF 3D: MeshGeometry3D纹理坐标的正确定义 为了使基于2D的纹理显示在3D对象中,我们必须定义3D Mesh对象的纹理贴图坐标.在WPF中,此项功能则通过MeshGeomet ...
- WPF 3D:使用变换中的TranslateTransform3D
原文:WPF 3D:使用变换中的TranslateTransform3D 程序效果: WPF 3D中的TranslateTransform3D应该是所有3D变换中最简单的变换,使用起来非常简单,先定义 ...
随机推荐
- UCloud上LAMP小型站点搭建与測试
文件夹 介绍 LAMP环境搭建 打开UCloud防火墙 WordPress安装 应用測试 介绍 本篇博客旨在通过介绍搭建一个WordPress博客的过程介绍在UCloud的云主机(UHOST)上搭建单 ...
- javascript运算符应用
下面的代码会输出什么?为什么? console.log(1 + "2" + "2"); console.log(1 + +"2" + &qu ...
- POJ 3132 & ZOJ 2822 Sum of Different Primes(dp)
题目链接: POJ:id=3132">http://poj.org/problem?id=3132 ZOJ:http://acm.zju.edu.cn/onlinejudge/show ...
- Java随机验证吗
<span style="font-size:18px;">package com.java.process.jsp; import java.awt.Color; i ...
- 算法练习--二分搜索哈希表-JS 实现
1. 以哈希KEY的值建立二叉哈希表 2. 依据传入的哈希值使用二分法搜索 详细实现例如以下: function binarySearchTable(comp){ this.comp = comp; ...
- 读Effective Objective-C [提高OC代码质量总结笔记第一篇:熟悉OC]
一.OC特性 OC 为 C 语言添加了面向对象特性,是其超集; OC 使用动态绑定的消息结构,也就是,在运行时才会检查对象类型; 接收一条消息后,究竟应执行何种代码,由运行期环境来决定,而非 编译器; ...
- 安装使用jupyter(原来的notebook)
1.安装pyzmq 使用pip install pyzmq,安装不成功. 使用easy_install.exe pyzmq.成功安装. 2.安装tornado pip tornado 安装完尚不成功. ...
- php求二叉树的深度(1、二叉树就可以递归,因为结构和子结构太相似)(2、谋而后动,算法想清楚,很好过的)
php求二叉树的深度(1.二叉树就可以递归,因为结构和子结构太相似)(2.谋而后动,算法想清楚,很好过的) 一.总结 1.二叉树就可以递归,因为结构和子结构太相似 2.谋而后动,算法想清楚,很好过的 ...
- 微信开发学习日记(六):weiphp框架
最近重点在看weiphp这个开源的第三方微信公众平台框架. 在网上找微信资料,找到了这个.很早之前,就初步学习了Thinkphp和Onethink2个开源框架,当看到weiphp是用这2个框架开发的时 ...
- 微信开发学习日记(五):weiphp开源框架的bug,公众号权限编辑问题
最近在研究weiphp,总体感觉还行,bug据说还挺多. 这不,我就遇到一个比较严重影响使用的.感觉不太应该出现这么严重的bug啊. weiphp的微信公众号等级,权限增加和编辑bug,看不到权限列表 ...