如何将Model3DGroup的某些区域绘制为不同的颜色,以及如何在Model3DGroup上添加视觉形状

本文关键字:Model3DGroup 视觉 添加 区域 绘制 颜色 | 更新日期: 2023-09-27 18:15:48

我可以使用将Model3DGroup绘制成我想要的颜色

Material material = new DiffuseMaterial(new SolidColorBrush(Colors.White));
GeometryModel3D model = new GeometryModel3D(mesh, material);

(遵循本教程(

以设置GeometryModel3Di包含在Model3DGroup中的颜色。

我有一个应用程序,我必须在三维地形上放置地图(地形是完全平坦的(,地图不是图像,我有我想要绘制的形状的点的详细数据,我还有我想要投影在三维表面上的所有形状的DrawingVisual对象。在2D模式下,我在自定义画布上绘制它们(源自canvas(,在那里我使用添加它们

myCanvas.addVisualChild(item);
myCanvas.addLogicvalChild(item);

我的问题是如何在3D物品上"绘画"或绘制形状和线条等?这些形状不能完全覆盖地形。我尝试过使用Viewport2DVisual3D类,并尝试使用以下代码将画布放置在3D表面上(一个带有按钮的简单画布(:

Canvas testCanvas = new Canvas();
testCanvas.Background = Brushes.Green;
Button b1 = new Button();
b1.Content = "Hello there";
Canvas.SetTop(b1, 50);
Canvas.SetLeft(b1, 50);
Canvas.SetZIndex(b1, 2);
testCanvas.Children.Add(b1);
testVisual3d.Visual = testCanvas; // testVisual3d is a Viewport2DVisual3D declared in xaml

但问题是,我无法弄清楚Canvas或任何Visual如何"填充"Viewport2DVisual3D类,因为:

  1. 按钮完全填满了画布
  2. 画布的空白区域(canvas.SetTop(b1,50((不可见
  3. 我不知道画布的大小与Viewport2DVisual3D对象的大小有关,因为按钮总是完全填充对象

此外,我不能到处使用Viewport2DVisual3D,因为当我将地图投影到3D地形时,我还必须创建建筑物等的模型,所以我必须以不同的方式绘制建筑模型(将是Model3DGroup(的区域,以获得逼真的效果,但如果我设法将地图投影在Viewport2DVisual 3D上,它将解决很多问题,因为我将能够直接在Viewport2DVisual3D对象或地形上投影包括网格在内的所有形状。

我使用的是.NET 4.0和C#。

请帮忙。

更新

使用此代码可以解决画布大小和空间的初始问题:

Canvas testCanvas = new Canvas();
testCanvas.Background = Brushes.Green;
Button b1 = new Button();
b1.Width = 120;
b1.Height = 25;
testCanvas.Width = 200;
testCanvas.Height = 200;
b1.Content = "Hello there";
Canvas.SetTop(b1, 50);
Canvas.SetLeft(b1, 50);
Canvas.SetZIndex(b1, 2);
testCanvas.Children.Add(b1);
testVisual3d.Visual = testCanvas;

Viewport2DVisual3D的大小为

Positions="0,0,0 0,0,30 30,0,30 30,0,0"

画布会调整大小以适应Viewport2DVisual3D的边界,但它能与从canvas派生的类一起工作吗?在该类中,使用canvas.AddVisualChild和canvas.AndLogicalChild直接添加了形状,我还没有尝试过。

在Model3DGroup上绘画的最初问题仍然存在,如何做到这一点?

如何将Model3DGroup的某些区域绘制为不同的颜色,以及如何在Model3DGroup上添加视觉形状

这可能有点晚了,但我遇到了一个非常类似的问题。尽管以上方法适用于较小的网格,但一旦进入成百上千(或更多(的三角形,速度就会变慢。我实现的替代方案为所有网格/集合使用统一的材质,但使用lineralgradientbrush为材质指定渐变颜色(根据需要设置停止点和颜色以实现目标(。然后,通过使用纹理坐标,可以设置给定三角形的颜色(如果你想拥有纯色,所有三个纹理坐标都将是同一点(。这种方法效果更好,对于大型网格(10k及以上(更有效,只需要额外的时间来设置笔刷和指定纹理坐标。同样/相似的方法也可以用于通过命中测试或类似的方法来更改三角形的颜色,其中只提供三角形的顶点(索引(和源网格(因此提供了需要更新的纹理坐标的索引(

p>所以这里有一些我使用过的代码(经过一些修改,根据需要进行调整(。这是在VB中,移植到C#应该很容易。请注意,这是从一些现有项目中复制粘贴的,所以有些项目可能没有可能的那么清晰…很抱歉懒惰。。。
Private Sub RefreshRHDisplay()
        'global/input data is RHTris which is a List(of Point3D())
        'updates the data on the display with the available data
        Dim v, f, i As Integer
        'clear geometry
        Group3D_RH.Children.Clear() 'is a Model3DGroup object
        'define lights
        Dim _L As Model3DGroup = GetLighting() 'defines the lighting
        'mesh items
        Dim mesh As New MeshGeometry3D
        'group of items
        Dim geomGroup As New Model3DGroup
        'materials
        Dim mat As MaterialGroup  'the foreground/front material
        Dim bmat As MaterialGroup 'the background/back material
        Dim MatGroup As New MaterialGroup
        Dim ColBrush As Brush = New SolidColorBrush(_bodyCol) : ColBrush.Opacity = 1.0F
        Dim LightBrush As Brush = New SolidColorBrush(Colors.White) : LightBrush.Opacity = 0.3
        Dim _diffuseMaterial As New DiffuseMaterial(ColBrush)
        Dim _specularMaterial As New SpecularMaterial(LightBrush, 300.0F)
        MatGroup.Children.Add(_diffuseMaterial)
        MatGroup.Children.Add(_specularMaterial)
        mat = MatGroup
        MatGroup = New MaterialGroup
        Dim bColBrush As Brush = New SolidColorBrush(Colors.DarkGray) : bColBrush.Opacity = 1.0F
        _diffuseMaterial = New DiffuseMaterial(bColBrush)
        MatGroup.Children.Add(_diffuseMaterial)
        MatGroup.Children.Add(_specularMaterial)
        bmat = MatGroup
        Dim vPts(0) As Point
        'distinguish between direct (uniform color) and colorize mode
        If chkColorize.IsChecked Then 'COLORIZE MODE
'Note: the gradient stop ends at 0.9, this is purely so that I can assign a special color after that.
            Dim gsp As New GradientStopCollection({New GradientStop(Colors.Red, 0.0),
                                                   New GradientStop(Colors.Orange, 0.15),
                                                   New GradientStop(Colors.Yellow, 0.3),
                                                  New GradientStop(Colors.Green, 0.45),
                                                  New GradientStop(Colors.Blue, 0.6),
                                                  New GradientStop(Colors.Indigo, 0.75),
                                                   New GradientStop(Colors.Violet, 0.9)
                                                  })
            Dim lBrsh As New LinearGradientBrush(gsp, New Point(0, 1), New Point(0.9, 1))
            'define random locations for the textures
            ReDim vPts(RHTris.Count - 1)
            Dim rnd As New Random(CInt(Now.Ticks Mod Integer.MaxValue))
            For v = 0 To RHTris.Count - 1
                vPts(v) = New Point(rnd.NextDouble, 1)
            Next
            'replace the default material with the linear gradient
            mat.Children.Clear()
            mat.Children.Add(New DiffuseMaterial(lBrsh))

        End If
        'add all vertices
        For v = 0 To RHTris.Count - 1
            mesh.Positions.Add(RHTris.Item(v)(0))
            mesh.Positions.Add(RHTris.Item(v)(1))
            mesh.Positions.Add(RHTris.Item(v)(2))
        Next
        'add all triangles
        v = 0
        For f = 0 To RHTris.Count - 1
            'If .isVisible Then 'true by def of _visList
            Dim v0, v1, n As Vector3D
            v0 = Point3D.Subtract(RHTris.Item(f)(1), RHTris.Item(f)(0))
            v1 = Point3D.Subtract(RHTris.Item(f)(2), RHTris.Item(f)(0))
            n = Vector3D.CrossProduct(v0, v1)
            mesh.Normals.Add(n)
            mesh.Normals.Add(n)
            mesh.Normals.Add(n)
            mesh.TriangleIndices.Add(v)
            mesh.TriangleIndices.Add(v + 1)
            mesh.TriangleIndices.Add(v + 2)
            v += 3
        Next
        If chkColorize.IsChecked Then 'define the texture coordinates that define the color through the linear gradient brush
            For v = 0 To RHTris.Count - 1
                For i = 0 To 2
                    mesh.TextureCoordinates.Add(vPts(v)) 'add same three points for each location
                Next
            Next
        End If
        'body mesh has been defined, create body and add to visual
        Dim geo As New GeometryModel3D
        geo.Geometry = mesh
        geo.Material = mat
        geo.BackMaterial = bmat

        'combine to group
        geomGroup.Children.Add(geo)
        'add to scene
        Group3D_RH.Children.Add(geomGroup)
        'add lights back in
        Group3D_RH.Children.Add(_L)
    End Sub

一些基本注释如下:数据在RHTris集合中,该集合是List(属于Point3D(((类型的变量,包含三个位置。指定给每个材质的颜色要么是默认材质,要么是随机颜色(如果选中了chkColorize(。Sub还将数据应用于Group3D_RH,它是Model3DGroup对象。该方法使用实心材质或具有渐变颜色的(恒定(纹理(遍历所有可用的颜色(。然后,颜色的指定是将一个点(2D点(定义为纹理坐标。如果三角形的每个点都指定了相同的点,那么三角形最终会具有统一的颜色(基于其沿颜色梯度的坐标(。。。希望这至少说明了方法。。。

经过一点实验,我得到了答案,简单的方法是在定义网格时设置每个三角形的颜色。在WPF中,在定义新的GeometryModel3D时,需要在组合三角形(MeshGeometry3D(和材质时设置材质颜色。

(来自本教程(

Material material = new DiffuseMaterial(
        new SolidColorBrush(Colors.DarkKhaki)); //Set color here
    GeometryModel3D model = new GeometryModel3D(
        mesh, material);

我是3D的初学者,还没有探索过材料的概念。

如果有人知道其他方法,请在这里发帖。