WPF 3D: MeshGeometry3D纹理坐标的正确定义TextureCoordinates



3D物体的一个表面称为一个网格(mesh)。一个网格被定义为许多3D点。这些点成为顶点(vertices)。这些顶点通过环绕方式连接起来来形成三角形。每一个三角形有个正面和反面,只有正面才会被渲染。三角形的正面可以通过点的环绕顺序来确定。WPF采用逆时针的环绕方式。你可以通过一个简单的“ 右手定则”来帮助记忆。也就是说,如果合上你的右手并且竖起大拇指,让你的四指顺着逆时针方向,那么大拇指指示方向便是三角形的正面。

WPF 采用右手坐标系系统。也就是说,如果你伸出你的手指如下图所示,各手指指示的是三条坐标轴的正向。

3D场景中的元素


1.Viewport3D


这个viewport是建立连接2D和3D世界大门的一个控件。


2.Camera


每一个3D场景都有一个摄像机。摄像机定义了Position,LookDirection和UpDirection属性。WPF支持正交(orthographical )和透视(perspective )摄像机。


3.3D Models


一个3D模型定义了场景中的一个物体。它包含一个Geometry对象,这个对象是一个网格,和一个材质(Material )对象,材质具有漫反射(diffuse),镜面(specular )或放射(emmisive )几种类型。材质本身具有一个画刷。


4.Lights


没有光源你将什么也看不到。因此我们需要在我们的场景当中至少放置一个光源来照亮我们的模型。WPF支持各种不同的光源,比如:


AmbientLight (自然光)


DirectionalLight (方向光)


PointLight (点光源)


SpotLight (聚光源)


为了使基于2D的纹理显示在3D对象中,我们必须定义3D Mesh对象的纹理贴图坐标。在WPF中,此项功能则通过MeshGeometry3D.TextureCoordinates属性。

 

2D纹理的对应坐标和WPF的LinearGradientBrush的StartPoint和EndPoint一样。

下图来自MSDN关于LinearGradientBrush的StartPoint的说明:

 

(0,0)代表整个图形的左上角,(1,1)则代表右下角。(0,1)则代表左下角……当然单位是相对的,可以用0到1之间的小数来代表中间的相对位置。

 

对于最简单的没有共享顶点的Mesh定义(MeshGeometry3D.Positions属性没有共享点),TextureCoordinates则对应Mesh中的每一个三角形的坐标相对应,这个和MeshGeometry3D.TriangleIndices相关,当然默认TriangleIndices从Positions的第一个点到最后一个点。

 

比如定义一个简单的3D平面矩形,首先一次根据三角形分布定义MeshGeometry的外壳。此时纹理坐标要根据三角形的分布位置来定义纹理坐标位置,比如第一个点是0, 0, 0,显然对应3D空间内矩形的左下角,那么第一个对应的TextureCoordinates是0 1,以此类推,这样定义好整个平面。

<MeshGeometry3D Positions="0 0 0, 5 5 0, 0 5 0, 0 0 0, 5 0 0, 5 5 0"

               TriangleIndices="0 1 2 3 4 5"

               TextureCoordinates="0 1, 1 0, 0 0,

                                    0 1, 1 1, 1 0"/>

 

最终纹理被正确显示:

 

 

如果我把上面的三角形的材质定义翻转一下(由于是逆时针定义,翻转可以通过调换前两个点)

<MeshGeometry3D Positions="0 0 0, 5 5 0, 0 5 0, 0 0 0, 5 0 0, 5 5 0"

               TriangleIndices="0 1 2 3 4 5"

               TextureCoordinates="1 0, 0 1, 0 0,

                                    0 1, 1 1, 1 0"/>

 

结果就是:

 

对于有共享顶点的Mesh定义(MeshGeometry3D.TriangleIndices属性来指定顶点),纹理坐标则直接对应每个定义在3D图形中的位置,还是上面那个例子,定义一个3D平面矩形,四个点,则四个对应的纹理位置相对坐标。

 

如下代码:

<MeshGeometry3D Positions="0 0 0, 5 0 0, 5 5 0, 0 5 0"

               TriangleIndices="0 1 2 0 2 3"

               TextureCoordinates="0 1, 1,1 1,0 0,0"/>

 

输出结果和上面的一致!

 

当然上面的一切都为了简单易懂而在3D空间内做平面图形,下面用上述知识在一个3D的带纹理的锥形(用LinearGradientBrush):

 

或者ImageBrush:

 

 

完整代码:

<Viewport3D>

        <Viewport3D.Camera>

            <PerspectiveCamera Position="0 0 20" LookDirection="0 0 -2"/>

        Viewport3D.Camera>

        <ModelVisual3D>

            <ModelVisual3D.Content>

                <Model3DGroup>

                   

                    <AmbientLight Color="#555555"/>

                    <DirectionalLight Direction="1,0,-7"

                                     Color="White"/>

                    <GeometryModel3D>

                        <GeometryModel3D.Geometry>

                            <MeshGeometry3D Positions="0,5,0 -5,-5,0 0,0,5 -5,-5,0 5,-5,0 0,0,5 0,0,5 5,-5,0 0,5,0"

                                           TextureCoordinates="0,0 0,1 1,1 0,0 0,1 1,1 0,0 0,1 1,1"/>

                        GeometryModel3D.Geometry>

                        <GeometryModel3D.Material>

                            <DiffuseMaterial>

                                <DiffuseMaterial.Brush>

                                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">

                                        <GradientStop Color="YellowGreen" Offset="0"/>

                                        <GradientStop Color="Green" Offset="1"/>

                                    LinearGradientBrush>

                                DiffuseMaterial.Brush>

                            DiffuseMaterial>

                        GeometryModel3D.Material>

                    GeometryModel3D>

                Model3DGroup>

            ModelVisual3D.Content>

        ModelVisual3D>

    Viewport3D>

 

通过替换DiffuseMaterial的Brush属性,读者可以使用其他纹理。

:D

作者:Mgen出处:www.cnblogs.com/mgen


你可能感兴趣的:(WPF 3D: MeshGeometry3D纹理坐标的正确定义TextureCoordinates)