這篇主要介紹如何實現局部加載模型。閱讀這篇博客前,需要參考我的另一篇博文,動態加載模型: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: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 string Name { get; set; }
public object Tag { get; set; }
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;
{
model.Children.Add(findModel.Clone() as ModelVisual3DWithName);
}
world.Children.Add(findModel);