一、About primitives
在Balder中,有很多已经创建好了的基本体,你只要直接调用就可以了,这和3DMax等软件类似,里面也提供了一系列的基本体,给设计者扩展使用。目前,Balder的Geometries命名空间下已经有Box,Cylinder,Ring等等基本体。在之前的文章中,我们已经使用过了其中的Box,也就是那个立方体。当然,如果就这么些基本体,对于越来越复杂的需求,是不够的,因此Balder提供更大的扩展性。那么,该如何实现呢?请往下看...
二、How to create your own primitives
想要创建自定义的基本体,其实很简单,基本体,说到底其实就是一个Geometry(几何体)。而在Balder中,每个Geometry拥有一个实现了IGeometryContext 接口的GeometryContext类的属性,通过GeometryContext就可以创建被称为GeometryDetailLevel的东西。那么GeometryDetailLevel又是什么东西呢?它其实就是按照Balder想要进行渲染的细分级别来被渲染的一个对象。在大部分情况下,balder使用full detail level来进行渲染。在Geometry中有一个FullDetailLevel 属性,通过它,我们就可以方便的来产生一个几何体了。
三、a demo for creating a primitive
接下来,通过一个实例,来示范下基本体的创建过程,这里,我们通过创建一个三棱锥来作为例子:
首先,你需要创建一个你自己的基本体类继承自Geometry类
using
Balder.Objects.Geometries;
namespace
MeshDemo
{
public
class
MyMesh:Geometry
{
}
}
这样,你就可以把该对象加到页面中去了,就像这样:
1
<
UserControl
x:Class
="MeshDemo.MainPage"
2
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
4
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
5
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
6
xmlns:Execution
="clr-namespace:Balder.Execution;assembly=Balder"
7
xmlns:View
="clr-namespace:Balder.View;assembly=Balder"
8
xmlns:Lighting
="clr-namespace:Balder.Lighting;assembly=Balder"
9
xmlns:Local
="clr-namespace:MeshDemo"
10
mc:Ignorable
="d"
11
d:DesignHeight
="300"
d:DesignWidth
="400"
>
12
13
<
Grid
x:Name
="LayoutRoot"
>
14
<
Execution:Game
Width
="640"
Height
="480"
>
15
<
Execution:Game.Camera
>
16
<
View:Camera
Position
="-10,5,-10"
/>
17
</
Execution:Game.Camera
>
18
<
Local:MyMesh
/>
<!--
加进去的基本体对象
-->
19
</
Execution:Game
>
20
</
Grid
>
21
</
UserControl
>
但是,你此时编译运行它,在浏览器中,什么都看不到。因为,现在在几何体类中,没有创建任何的几何数据,为了创建这些,你需要实现重载Prepare()方法:
1
public
override
void
Prepare(Viewport viewport)
2
{
3
}
4
通过该方法,我们将加入3D网格数据,以创建基本体三棱锥,这里主要由三部分组成:
1.Vertices( 顶点)
2.Lines (线)
3.Face(面)
为了使得结构更清晰,我们把它们分别封装在三函数中:
private void GenerateVertices() //创建顶点
private void GenerateLines() //创建线
private void GenerateFaces() //创建面
接下来,我们一个个来分别完成,首先是创建顶点的:
1
private
void
GenerateVertices()
2
{
3
var dimensionAsVector
=
new
Vertex(5f, 5f, 5f);
4
var halfDimension
=
new
Vertex(
2.5f
,
2.5f
,
2.5f
);
5
var Top
=
new
Vertex(0f, dimensionAsVector.Y, 0f);
6
var backBottomLeft
=
new
Vertex(
-
(halfDimension.X
/
2
)
*
sqt, 0f, halfDimension.Z
/
2
);
7
var backBottomRight
=
new
Vertex(halfDimension.X
/
2
*
sqt, 0f, halfDimension.Z
/
2
);
8
var frontBottom
=
new
Vertex(0f, 0f,
-
halfDimension.Z);
9
FullDetailLevel.AllocateVertices(
4
);
10
FullDetailLevel.SetVertex(
0
, Top);
11
FullDetailLevel.SetVertex(
1
, backBottomLeft);
12
FullDetailLevel.SetVertex(
2
, backBottomRight);
13
FullDetailLevel.SetVertex(
3
, frontBottom);
14
15
16
}
在balder中的3D点是通过Vertex(x,y,z)对象生成的,其参数代表在所在坐标。前面两行只是实例化了两个Vertex对象,在后面可以通过其的X,Y,Z属性进行初始化三棱锥顶点坐标位置。三棱锥一共有4个顶点,所以FullDetailLevel.AllocateVertices(4);分配了4个顶点。其中的sqt是一个常量,为了控制在空间中的位置,不必理会,你可以自己定义基本体的空间位子。
对于线的函数,与之类似,就不详细介绍,直接看代码:
1
private
void
GenerateLines()
2
{
3
FullDetailLevel.AllocateLines(
6
);
4
FullDetailLevel.SetLine(
0
,
new
Line(
0
,
1
));
5
FullDetailLevel.SetLine(
1
,
new
Line(
1
,
3
));
6
FullDetailLevel.SetLine(
2
,
new
Line(
0
,
2
));
7
FullDetailLevel.SetLine(
3
,
new
Line(
3
,
2
));
8
FullDetailLevel.SetLine(
4
,
new
Line(
1
,
2
));
9
FullDetailLevel.SetLine(
5
,
new
Line(
0
,
3
));
10
11
12
}
完成这两个函数,我们在 Prepare函数中调用它们,运行后你会看到这样的结果:
这样一个基本体就创建好了,当然,如果想要看到实体的话,就还需要完成面的组成函数:
private
void
GenerateFaces()
{
FullDetailLevel.AllocateFaces(
4
);
FullDetailLevel.SetFace(
0
,
new
Face(
3
,
1
,
0
));
FullDetailLevel.SetFace(
1
,
new
Face(
2
,
3
,
0
));
FullDetailLevel.SetFace(
2
,
new
Face(
2
,
0
,
1
));
FullDetailLevel.SetFace(
3
,
new
Face(
3
,
2
,
1
));
}
在创建面的时候需要注意,就是顶点的连接顺序,每个面由三个顶点组成的,依次连接它们,在balder中连接顺序是按照顺时针方向的(这和Opengl正好相反),而且是你必须在几何体的外面来观察它。自己画个图形,应该容易理解,弄好后,别忘了加入到Prepare函数,运行,看结果:
你会发现,怎么是黑的?主要有两个原因:一是还没有给场景添加灯光照亮,二是需要法向量。balder中提供了一个 GeometryHelper对象,通过它,就可以方便的创建法向量:
在创建好顶点和面后加入: GeometryHelper.CalculateNormals(FullDetailLevel);
然后我们在修改xaml文件:
1
<
Grid
x:Name
="LayoutRoot"
>
2
<
Execution:Game
Width
="640"
Height
="480"
>
3
<
Execution:Game.Camera
>
4
<
View:Camera
Position
="-10,5,-10"
/>
5
</
Execution:Game.Camera
>
6
<
Lighting:OmniLight
Position
="10,20,-15"
/>
7
<
Local:MyMesh
InteractionEnabled
="True"
Color
="Blue"
/>
8
</
Execution:Game
>
9
</
Grid
>
加入灯光和物体颜色,ok,搞定,看看最后效果: