// returns instance index or -1 if instance not found private int GetHitInstanceIndex(RayMeshGeometry3DHitTestResult rayHitResult) { var modelHit = rayHitResult.ModelHit; // When WPF GeometryModel3D objects are crated with InstancedMeshGeometryVisual3D, // each GeometryModel3D has a InstancedMeshGeometryVisual3D.InstanceIndexProperty set to an int value // that represent an index of the instance. int hitInstanceIndex = (int)modelHit.GetValue(InstancedMeshGeometryVisual3D.InstanceIndexProperty); if (hitInstanceIndex == -1) // If InstanceIndexProperty was not set, then we get a default value of -1. { // In this case we need to use the slower path // of finding the instance index from the bounds of the hit Model3D. // InstanceData.GetHitInstanceIndex method gets the instance index in the _instancedData array that has the bounds set to hitBounds // The last parameter (useOnlyMatrixTranslation) can be set to true when the InstanceData define only translation (OffsetX, OffsetY, OffsetZ) and no scale or rotation. // In this case a faster code path can be taken. When useOnlyMatrixTranslation is false (by default) a full matrix transformation is executed on each position. Rect3D hitBounds = rayHitResult.ModelHit.Bounds; hitInstanceIndex = InstanceData.GetHitInstanceIndex(hitBounds, _instanceMeshGeometry3D.Bounds, _instancedData, useOnlyMatrixTranslation: false); // If not found then hitInstanceIndex is -1 } return(hitInstanceIndex); }
private InstancedMeshGeometryVisual3D AddInstancedTubePath(Point3DCollection spiralPositionCollection, Color4 tubeColor) { // Setup InstanceData var instanceData = new InstanceData[spiralPositionCollection.Count]; // Convert to list of Vector3 var dxCurvePositions = spiralPositionCollection.Select(p => p.ToVector3()).ToList(); // NOTE: // When a tube path is created from a lot of positions, // then it is worth to transform the following loop into Parallel.For loop. var startPosition = dxCurvePositions[0]; for (int i = 1; i < dxCurvePositions.Count; i++) { var endPosition = dxCurvePositions[i]; var direction = endPosition - startPosition; var length = direction.Length(); // length will be used for x scale var scale = new Vector3(length, 1, 1); //direction.Normalize(); // Because we already have length, we can quickly normalize with simply dividing by length direction /= length; instanceData[i].World = Common.MatrixUtils.GetMatrixFromNormalizedDirection(direction, startPosition, scale); instanceData[i].DiffuseColor = Color4.White; startPosition = endPosition; } // Create tube mesh with normalized radius (=1) and from (0,0,0) to (1,0,0). // This mesh is then transformed to connect positions along the path var tubeLineMesh3D = new Ab3d.Meshes.TubeLineMesh3D(startPosition: new Point3D(0, 0, 0), endPosition: new Point3D(1, 0, 0), radius: 1, segments: 8, generateTextureCoordinates: false).Geometry; // Create InstancedMeshGeometryVisual3D var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(tubeLineMesh3D); instancedMeshGeometryVisual3D.InstancesData = instanceData; // Set IsSolidColorMaterial to render tube instances with solid color without any shading based on lighting instancedMeshGeometryVisual3D.IsSolidColorMaterial = true; // Add instancedMeshGeometryVisual3D to the scene MainViewport.Children.Add(instancedMeshGeometryVisual3D); return(instancedMeshGeometryVisual3D); }
private InstanceData[] CreateInstancesData(Point3D center, Size3D size, int xCount, int yCount, int zCount) { var instancedData = new InstanceData[xCount * yCount * zCount]; float xStep = (float)(size.X / xCount); float yStep = (float)(size.Y / yCount); float zStep = (float)(size.Z / zCount); int i = 0; for (int z = 0; z < zCount; z++) { float zPos = (float)(center.Z - (size.Z / 2.0) + (z * zStep)); for (int y = 0; y < yCount; y++) { float yPos = (float)(center.Y - (size.Y / 2.0) + (y * yStep)); for (int x = 0; x < xCount; x++) { float xPos = (float)(center.X - (size.X / 2.0) + (x * xStep)); instancedData[i].World = SharpDX.Matrix.Translation(xPos, yPos, zPos); // If we would also need to scale the mesh, we could create the matrix with the following code: //instancedData[i].World = new SharpDX.Matrix(xScale, 0, 0, 0, // 0, yScale, 0, 0, // 0, 0, zScale, 0, // xPos, yPos, zPos, 1); //instancedData[i].DiffuseColor = new SharpDX.Color4(new SharpDX.Color3(0.3f + ((float)x / (float)xCount) * 0.7f, // 0.3f + ((float)y / (float)yCount) * 0.7f, // 0.3f + ((float)y / (float)yCount) * 0.7f)); instancedData[i].DiffuseColor = new SharpDX.Color4(new SharpDX.Color3(0.1f + ((float)y / (float)yCount) * 0.9f, (float)Math.Abs(0.5 - ((float)x / (float)xCount)) * 2.0f, 0.1f + ((float)(yCount - y) / (float)yCount) * 0.9f)); // Use WPF's Orange color: //instancedData[i].Color = Colors.Orange.ToColor4(); i++; } } } return(instancedData); }
private void CreateInstancedTubePath() { // Create curve through those points var controlPoints = new Point3D[] { new Point3D(-200, 50, 150), new Point3D(0, 50, 20), new Point3D(150, 50, 0), new Point3D(150, 50, 200), new Point3D(250, 50, 200) }; // To create curve through specified points we must first convert the points into a bezierCurve (curve that has tangents defined for each point). // The curve is created with 10 points per segments - 10 points between two control points. var bezierCurve = Ab3d.Utilities.BezierCurve.CreateFromCurvePositions(controlPoints); var curvePositions = bezierCurve.CreateBezierCurve(positionsPerSegment: 10); // Convert Point3D to Vector3 var dxCurvePositions = curvePositions.Select(p => p.ToVector3()).ToList(); // Setup InstanceData var instanceData = new InstanceData[curvePositions.Count]; // NOTE: // When a tube path is created from a lot of positions, // then it is worth to transform the following loop into Parallel.For loop. var startPosition = dxCurvePositions[0]; for (int i = 1; i < dxCurvePositions.Count; i++) { var endPosition = dxCurvePositions[i]; var direction = endPosition - startPosition; var length = direction.Length(); // length will be used for x scale var scale = new Vector3(length, 1, 1); //direction.Normalize(); // Because we already have length, we can quickly normalize with simply dividing by length direction /= length; instanceData[i].World = Common.MatrixUtils.GetMatrixFromNormalizedDirection(direction, startPosition, scale); instanceData[i].DiffuseColor = Color4.White; startPosition = endPosition; } // Create tube mesh with normalized radius (=1) and from (0,0,0) to (1,0,0). // This mesh is then transformed to connect positions along the path var tubeLineMesh3D = new Ab3d.Meshes.TubeLineMesh3D(startPosition: new Point3D(0, 0, 0), endPosition: new Point3D(1, 0, 0), radius: 1, segments: 8, generateTextureCoordinates: false).Geometry; // Create InstancedMeshGeometryVisual3D var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(tubeLineMesh3D); instancedMeshGeometryVisual3D.InstancesData = instanceData; // Set IsSolidColorMaterial to render tube instances with solid color without any shading based on lighting instancedMeshGeometryVisual3D.IsSolidColorMaterial = true; // Add instancedMeshGeometryVisual3D to the scene MainViewport.Children.Add(instancedMeshGeometryVisual3D); }