WPF 3D 加载局部模型

这篇主要介绍如何实现局部加载模型。阅读这篇博客前,需要参考我的另一篇博文,动态加载模型:http://www.cnblogs.com/enjoyeclipse/archive/2012/03/21/2410439.html

 

1.效果:

    如图所示,因为整个沙盘场景太大,因此需要将桥墩加载并进行放大。不知道大家玩过实况足球没有,选择某个球员就有这种效果。

   

2.思路:

     1). 首先需要构造一个容器,这个容器有ViewPort元素;

     2). 从大沙盘中选取需要的局部模型,并克隆一份(因为WPF中模型对象的Tree关系,因此不能直接将Add(model),必须Add(model.Clone()),

     3). 将局部模型添加到容器的ViewPort中。

 

3.实现:

    1). 首先需要构造一个容器,这个容器有ViewPort元素。

 

         创建容器(UserControl):PartModelControl,最重要的里面要包含ViewPort,并提前把光照,摄像机什么的设置好

         xaml代码如下:

         <UserControl x:Class="UI.Common.UserControls.PartModelControl"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:UI.Common.Converters"
    Background="Transparent" 
    SnapsToDevicePixels="True"
    x:Name="modelPartControl" PreviewMouseDoubleClick="modelPartControl_MouseDoubleClick">
        ....
        <Viewport3D x:Name="_partViewPort">
            <Viewport3D.Camera>
                <!--<PerspectiveCamera x:Name="camera" FieldOfView="45" FarPlaneDistance="1782.5084757839907" LookDirection="0,0,-607.743292014972" NearPlaneDistance="0.1" Position="-0.0207443237299856,-2.1316282072803E-14,407.743292014972" UpDirection="0,1,0"/>-->
                <PerspectiveCamera x:Name="camera" FieldOfView="30" FarPlaneDistance="102122.68952517369" LookDirection="292.292480468755,-0.00048828125,-2204.4668208912" Position="-292.292480468755,0.00048828125,2204.4668208912" NearPlaneDistance="0.1"  UpDirection="0,1,0"/>
            </Viewport3D.Camera>
            <ModelVisual3D x:Name="World">
                <ModelVisual3D x:Name="AmbientLightContainer">
                    <ModelVisual3D.Content>
                        <AmbientLight x:Name="AmbientLight" Color="#FF7F7F7F"/>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
                <ModelVisual3D x:Name="DirectionalLightContainer">
                    <ModelVisual3D.Content>
                        <DirectionalLight x:Name="DirectionalLight" Color="#FF3F3F3F" Direction="0,0,-1">
                            <DirectionalLight.Transform>
                                <TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="3"/>
                            </DirectionalLight.Transform>
                        </DirectionalLight>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
                <ModelVisual3D.Transform>
                    <TranslateTransform3D x:Name="transform" OffsetX="0" OffsetY="0" OffsetZ="0" />
                </ModelVisual3D.Transform>
            </ModelVisual3D>
        </Viewport3D>
        <!--END Viewport-->
        ....

</UserControl> 

 

2). 从大沙盘中选取需要的局部模型,并克隆一份 

 

  • 从沙盘中选取模型:首先不能用WPF默认的方法制作3D,必须用第三方库WaveFrontObjLoader动态加载模型,因为这时候他会将3D的名字和模型形成Dictionary,就可以用Find(string Name)方法加载模型了。具体参考我的博客:http://www.cnblogs.com/enjoyeclipse/archive/2012/03/21/2410439.html 
  • 实现ModelVisual3DWithName的Clone方法:

 

        [ContentProperty("Children")]

    public class ModelVisual3DWithName : ModelVisual3D, ICloneable
    {
        public string Name { getset; }

        public object Tag { getset; }

        public object Clone()
        {
            var model = new ModelVisual3DWithName { Content = Content.Clone(), 
                                                    Name = Name, 
                                                    Tag = Tag
                                                   };
            model.SetColor(Brushes.DefaultSectionBrush);
            return model;
        }

        public void SetMaterial(Material material)
        {
            var geometrymodel = Content as GeometryModel3D;
            if (geometrymodel != null)
            {
                geometrymodel.Material = material;
            }
            else
            {
             
            }
        }

        public Material GetMaterial()
        {
            var geometrymodel = Content as GeometryModel3D;
            if (geometrymodel == null)
            {
                return null;
            }
            return geometrymodel.Material;
        }

        public void SetColor(Brush color)
        {
            var geometrymodel = Content as GeometryModel3D;

            if (geometrymodel.Material is MaterialGroup)
            {
                var materialGroup = geometrymodel.Material as MaterialGroup;
                SetMaterialGroupColor(materialGroup, color);
            }
            else
            {
                DiffuseMaterial material = geometrymodel.Material as DiffuseMaterial;
                if (material != null && !material.IsFrozen)
                {
                    material.Brush = color;
                }
            }
        }


        private  void SetMaterialGroupColor(MaterialGroup materialGroup, Brush color)
        {
            foreach (var groupItem in materialGroup.Children)
            {
                if (groupItem is DiffuseMaterial && !groupItem.IsFrozen)
                {
                    var tmpItem = groupItem as DiffuseMaterial;
                    tmpItem.Brush = color;
                }
            }
        }
    }

 

 3). 将刚才克隆的模型添加到容器中。

      调用world.children.Add()方法添加模型到容器中,逻辑如下:

      var findModel = _baseModel.Find(modelName) as ModelVisual3DWithName;

if (findModel != null)
{
                         model.Children.Add(findModel.Clone() as ModelVisual3DWithName);
}
world.Children.Add(findModel);

posted on 2012-09-27 20:59  enjoyeclipse  阅读(3788)  评论(3编辑  收藏  举报