• Rendering Transparent 3D Surfaces in WPF with C#(转载)


    Rendering Transparent 3D Surfaces in WPF with C#

    The primary problems that arise when rendering semi-transparent 3d objects in Windows Presentation Foundation have to do with false z-buffer occlusions. Specifically, when a transparent surface or polygon is rendered, it sets the z-buffer depth values to block objects that are behind it from being rendered, even though they should show through the transparent layer.

    In WPF with C#, the z-buffer is not accessible. So, it can not be disabled during transparent rendering. Instead, we must render the transparent objects last so that they are layered over the rest of the scene and the objects behind them show through.

    RotatingTransTetra

    Below, I have a program for the single code file that I used to generate the spinning, transparent tetrahedron shown above. The C# project that I used is a simple Console Application project with the libraries PresentationCore,PresentationFramework, and WindowsBase references added to it as I showed in a prior post: Using WPF in a C# Console Application. The Main() function creates the Window for the program and calls TransparentScene() to do all of the rendering.

    Inside the function TransparentScene(), I create the camera, the light, the animated rotation transformation, the tetrahedron geometry, and then use that geometry to specify three tetrahedrons. The first tetrahedron is called the Inner Tetrahedronbecause it is scaled to fit inside the others. The second tetrahedron is called the Outer Tetrahedron and is semi-transparent. The third tetrahedron is also part of the Outer Tetrahedron, but consists of the opaque back faces. Note that it only makes sense to render the back faces because the front faces are semi-transparent. Otherwise, the back would not be visible.

    At the end the code, I use the following lines to add the tetrahedrons to the scene:

                qModelGroup.Children.Add(qBackGeometry);
                qModelGroup.Children.Add(qInnerGeometry);
                qModelGroup.Children.Add(qOuterGeometry);
    

    Notice that the transparent “Outer Geometry” layer is added last. This is necessary to avoid false occlusions.

    For comparison, I have included the image below with four different arrangements. The first (top-left) shows the scene with the transparent outer layer added before the inner and after the back. The second (top-right) shows the transparent outer layer added before both the inner and the back layers. The third (bottom-left) shows the transparent layer added before the back and after the inner layer. The last (bottom-right) shows the scene with the transparent layer added last as it is in the code.

    TransparentComparison

    Program.cs

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Media.Media3D;
    using System.Windows.Media.Animation;
    
    namespace WpfTransparent {
        class Program {
            [STAThread]
            static void Main(string[] args) {
                Window qWindow = new Window();
                qWindow.Title = "Transparent Rendering";
                qWindow.Width = 400;
                qWindow.Height = 300;
                qWindow.Content = TransparentScene();
                qWindow.ShowDialog();
            }
    
            static Viewport3D TransparentScene() {
                // Define the camera
                PerspectiveCamera qCamera = new PerspectiveCamera();
                qCamera.Position = new Point3D(0, .25, 2.25);
                qCamera.LookDirection = new Vector3D(0, -.05, -1);
                qCamera.UpDirection = new Vector3D(0, 1, 0);
                qCamera.FieldOfView = 60;
    
                // Define a lighting model
                DirectionalLight qLight = new DirectionalLight();
                qLight.Color = Colors.White;
                qLight.Direction = new Vector3D(-0.5, -0.25, -0.5);
    
                // Define the animated rotation transformation
                RotateTransform3D qRotation =
                    new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 1));
                DoubleAnimation qAnimation = new DoubleAnimation();
                qAnimation.From = 1;
                qAnimation.To = 361;
                qAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(5000));
                qAnimation.RepeatBehavior = RepeatBehavior.Forever;
                qRotation.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, qAnimation);
    
                // Define the geometry
                const double kdSqrt2 = 1.4142135623730950488016887242097;
                const double kdSqrt6 = 2.4494897427831780981972840747059;
                // Create a collection of vertex positions
                Point3D[] qaV = new Point3D[4]{
                    new Point3D(0.0, 1.0, 0.0),
                    new Point3D(2.0 * kdSqrt2 / 3.0, -1.0 / 3.0, 0.0),
                    new Point3D(-kdSqrt2 / 3.0, -1.0 / 3.0, -kdSqrt6 / 3.0),
                    new Point3D(-kdSqrt2 / 3.0, -1.0 / 3.0, kdSqrt6 / 3.0)};
                Point3DCollection qPoints = new Point3DCollection();
                // Designate Vertices
                // My Scheme (0, 1, 2), (1, 0, 3), (2, 3, 0), (3, 2, 1)
                for (int i = 0; i < 12; ++i) {
                    if ((i/3) % 2 == 0) {
                        qPoints.Add(qaV[i%4]);
                    } else { 
                        qPoints.Add(qaV[(i*3)%4]);
                    }
                }
                // Designate Triangles
                Int32Collection qTriangles = new Int32Collection();
                for (int i = 0; i < 12; ++i ) {
                    qTriangles.Add(i);
                }
                Int32Collection qBackTriangles = new Int32Collection();
                // Designate Back Triangles in the opposite orientation
                for (int i = 0; i < 12; ++i) {
                    qBackTriangles.Add(3 * (i / 3) + (2 * (i % 3) % 3));
                }
    
                // Inner Tetrahedron: Define the mesh, material and transformation.
                MeshGeometry3D qFrontMesh = new MeshGeometry3D();
                qFrontMesh.Positions = qPoints;
                qFrontMesh.TriangleIndices = qTriangles;
                GeometryModel3D qInnerGeometry = new GeometryModel3D();
                qInnerGeometry.Geometry = qFrontMesh;
                // *** Material ***
                DiffuseMaterial qDiffGreen =
                    new DiffuseMaterial(new SolidColorBrush(Color.FromArgb(255, 0, 128, 0)));
                SpecularMaterial qSpecWhite = new
                    SpecularMaterial(new SolidColorBrush(Color.FromArgb(255, 255, 255, 255)), 30.0);
                MaterialGroup qInnerMaterial = new MaterialGroup();
                qInnerMaterial.Children.Add(qDiffGreen);
                qInnerMaterial.Children.Add(qSpecWhite);
                qInnerGeometry.Material = qInnerMaterial;
                // *** Transformation ***
                ScaleTransform3D qScale = new ScaleTransform3D(new Vector3D(.5, .5, .5));
                Transform3DGroup myTransformGroup = new Transform3DGroup();
                myTransformGroup.Children.Add(qRotation);
                myTransformGroup.Children.Add(qScale);
                qInnerGeometry.Transform = myTransformGroup;
    
                // Outer Tetrahedron (semi-transparent) : Define the mesh, material and transformation.
                GeometryModel3D qOuterGeometry = new GeometryModel3D();
                qOuterGeometry.Geometry = qFrontMesh;
                // *** Material ***
                DiffuseMaterial qDiffTransYellow =
                    new DiffuseMaterial(new SolidColorBrush(Color.FromArgb(64, 255, 255, 0)));
                SpecularMaterial qSpecTransWhite =
                    new SpecularMaterial(new SolidColorBrush(Color.FromArgb(128, 255, 255, 255)), 30.0);
                MaterialGroup qOuterMaterial = new MaterialGroup();
                qOuterMaterial.Children.Add(qDiffTransYellow);
                qOuterMaterial.Children.Add(qSpecTransWhite);
                qOuterGeometry.Material = qOuterMaterial;
                // *** Transformation ***
                qOuterGeometry.Transform = qRotation;
    
                // Outer Tetrahedron (solid back) : Define the mesh, material and transformation.
                MeshGeometry3D qBackMesh = new MeshGeometry3D();
                qBackMesh.Positions = qPoints;
                qBackMesh.TriangleIndices = qBackTriangles;
                GeometryModel3D qBackGeometry = new GeometryModel3D();
                qBackGeometry.Geometry = qBackMesh;
                // *** Material ***
                DiffuseMaterial qDiffBrown =
                    new DiffuseMaterial(new SolidColorBrush(Color.FromArgb(255, 200, 175, 0)));
                qBackGeometry.Material = qDiffBrown;
                // *** Transformation ***
                qBackGeometry.Transform = qRotation;
    
                // Collect the components
                Model3DGroup qModelGroup = new Model3DGroup();
                qModelGroup.Children.Add(qLight);
                qModelGroup.Children.Add(qBackGeometry);
                qModelGroup.Children.Add(qInnerGeometry);
                qModelGroup.Children.Add(qOuterGeometry);
                ModelVisual3D qVisual = new ModelVisual3D();
                qVisual.Content = qModelGroup;
                Viewport3D qViewport = new Viewport3D();
                qViewport.Children.Add(qVisual);
                qViewport.Camera = qCamera;
    
                return qViewport;
            }
        }
    }
  • 相关阅读:
    pom.xml报错web.xml is missing and <failOnMissingWebXml> is set to true
    JDK编译环境和运行环境版本不一致:unsupported major.minor version 52.0
    jdk与eclipse版本不一致导致:java was started but returned exit code=13
    Maven工程配置文件存放路径与读取配置文件路径配置
    maven官网下载bin.tar.gz和bin.zip以及src.tar.gz和src.zip的区别
    SpringBoot如何配置静态地址与访问路径
    好用免费的PPT网站
    executor可实现线程任务的提交与执行解耦的原因
    Maven配置阿里镜像库和本地库的方法
    SpringBoot热加载
  • 原文地址:https://www.cnblogs.com/sigame/p/5654817.html
Copyright © 2020-2023  润新知