public void Slice(DynamicRenderMesh mesh, Camera camera) { slicePointsDictionary.Clear(); verticesDictionary.Clear(); slicePoints.Clear(); vertices.Clear(); texCoords.Clear(); indices.Clear(); triangles.Clear(); ResultMeshes.Clear(); FillVertices(mesh, camera); Vector2 A = new Vector2(99999.0f, 99999.0f), B = new Vector2(-99999.0f, -99999.0f); var tempLine = new Line2d(); var workedIndices = new List <int>(); var tempIndices = new List <int>(); foreach (var line in Lines) { for (var i = 0; i < 2; i++) { if (line.A[i] < A[i]) { A[i] = line.A[i]; } if (line.B[i] > B[i]) { B[i] = line.B[i]; } } } for (var i = 0; i < indices.Count / 3; i++) { var index = i * 3; var point0 = vertices[indices[index]]; var point1 = vertices[indices[index + 1]]; var point2 = vertices[indices[index + 2]]; if (!CheckAABB(ref point0, ref point1, ref point2, ref A, ref B)) { for (var j = 0; j < 3; j++) { tempIndices.Add(indices[index + j]); } continue; } for (var j = 0; j < 3; j++) { workedIndices.Add(indices[index + j]); } } if (workedIndices.Count == 0) { return; } var triangle = new Vector3[3]; var triangleT = new Vector2[3]; var tempCollisions = new List <Vector3>(); var tempTexCoords = new List <Vector2>(); var tempCollisionsEdgeIndices = new List <int>(); var newTriangles = new List <int>(); var info0 = CollisionInfo.Zero; var info1 = CollisionInfo.Zero; for (var i = 0; i < sliceLines.Count; i++) { var line = Lines[i]; var sliceLine = sliceLines[i]; var trianglesCount = workedIndices.Count / 3; for (var j = 0; j < trianglesCount; j++) { var index = j * 3; for (var l = 0; l < 3; l++) { triangle[l] = vertices[workedIndices[index + l]]; triangleT[l] = texCoords[workedIndices[index + l]]; } info0 = CollisionInfo.Zero; info1 = CollisionInfo.Zero; tempCollisions.Clear(); tempTexCoords.Clear(); tempCollisionsEdgeIndices.Clear(); newTriangles.Clear(); //looking for a point / intersection point of the triangle and line for (int k = 0, l = 2; k < 3; l = k, k++) { if (info1.Type != CollisionType.CT_NONE) { break; } var tPoint0 = triangle[l]; var tPoint1 = triangle[k]; var tTexCoord0 = triangleT[l]; var tTexCoord1 = triangleT[k]; tempLine.Point0.X = tPoint0.X; tempLine.Point0.Y = tPoint0.Y; tempLine.Point1.X = tPoint1.X; tempLine.Point1.Y = tPoint1.Y; float ua, ub; if (!GetUaUb(tempLine, line, out ua, out ub)) { //lines coincide? //Verify whether some point belongs line segment tempLine //if find - get result and break. } else { if (ub < 0.0f || ub > 1.0f) { continue; } var collisionPoint = tPoint0 + (tPoint1 - tPoint0) * ub; var collisionTexCoord = tTexCoord0 + (tTexCoord1 - tTexCoord0) * ub; if (tempCollisions.Count == 0 || !PointsCompare.Equals(tempCollisions[0], collisionPoint)) { tempCollisions.Add(collisionPoint); tempTexCoords.Add(collisionTexCoord); tempCollisionsEdgeIndices.Add(l); } if (ua < 0.0f || ua > 1.0f) { continue; } var pointType = CollisionType.CT_VERTEX; Vector3 point; Vector2 texCoord; var pointIndex = -1; var edgeIndex = -1; if (ub > 0.0f) { if (ub < 1.0f) { pointType = CollisionType.CT_EDGE; point = tempCollisions.Last(); texCoord = tempTexCoords.Last(); edgeIndex = l; } else { point = tPoint1; texCoord = tTexCoord1; pointIndex = workedIndices[index + k]; } } else { point = tPoint0; texCoord = tTexCoord0; pointIndex = workedIndices[index + l]; } if (info0.Type == CollisionType.CT_NONE) { info0.PointIndex = pointIndex; info0.Type = pointType; info0.Position = point; info0.TexCoord = texCoord; info0.EdgeIndex = edgeIndex; } else { if (pointIndex == -1 || info0.PointIndex != pointIndex) { info1.PointIndex = pointIndex; info1.Type = pointType; info1.Position = point; info1.TexCoord = texCoord; info1.EdgeIndex = edgeIndex; } } } } if (info1.Type == CollisionType.CT_NONE) { if (tempCollisions.Count == 0) { if (info0.Type == CollisionType.CT_NONE) { continue; } } else { if (tempCollisions.Count > 1) { //Perhaps the point inside the triangle var dir = line.Direction; for (var l = 0; l < 2; l++) { var p = l == 0 ? line.Point0 : line.Point1; if (PointInTriangle(ref triangle[0], ref triangle[1], ref triangle[2], ref p)) { var v0 = tempCollisions[1].Xy - tempCollisions[0].Xy; var v1 = p - tempCollisions[0].Xy; var k = (v1.Length / v0.Length); var z = tempCollisions[0].Z + (tempCollisions[1].Z - tempCollisions[0].Z) * k; var t = tempTexCoords[0] + (tempTexCoords[1] - tempTexCoords[0]) * k; if (info0.Type == CollisionType.CT_NONE) { info0.Type = CollisionType.CT_INSIDE; info0.Position = new Vector3(p.X, p.Y, z); info0.TexCoord = t; if (Vector2.Dot(dir, v0) > 0.0f) { info0.EdgeIndex = tempCollisionsEdgeIndices[0]; } else { info0.EdgeIndex = tempCollisionsEdgeIndices[1]; } tempCollisionsEdgeIndices.Remove(info0.EdgeIndex); } else { info1.Type = CollisionType.CT_INSIDE; info1.Position = new Vector3(p.X, p.Y, z); info1.TexCoord = t; info1.EdgeIndex = tempCollisionsEdgeIndices[0]; } } } } } } if (info0.Type == CollisionType.CT_NONE) { continue; } //Create new triangles, if we have two points of intersection, and they are not vertices int pi1 = 0, pi0 = 0; if (info1.Type != CollisionType.CT_NONE && (info0.Type != CollisionType.CT_VERTEX || info1.Type != CollisionType.CT_VERTEX)) { if (info1.Type == CollisionType.CT_VERTEX || (info1.Type == CollisionType.CT_EDGE && info0.Type == CollisionType.CT_INSIDE) || (info1.Type == CollisionType.CT_EDGE && info0.Type == CollisionType.CT_EDGE && (info0.EdgeIndex + 1) % 3 != info1.EdgeIndex) || (info0.Type == CollisionType.CT_INSIDE && info1.Type == CollisionType.CT_INSIDE && (info0.EdgeIndex + 1) % 3 != info1.EdgeIndex)) { var temp = info1; info1 = info0; info0 = temp; } if (!verticesDictionary.TryGetValue(info1.Position, out pi1)) { pi1 = vertices.Count; vertices.Add(info1.Position); texCoords.Add(info1.TexCoord); verticesDictionary.Add(info1.Position, pi1); } if (info0.Type == CollisionType.CT_VERTEX) //One point of intersection coincides with the vertex { pi0 = info0.PointIndex; int i0 = workedIndices[index], i1 = workedIndices[index + 1], i2 = workedIndices[index + 2]; if (i0 == info0.PointIndex) { i0 = i2; i2 = i1; } else { if (i2 == info0.PointIndex) { i2 = i0; i0 = i1; } } i1 = info0.PointIndex; newTriangles.AddRange(new[] { i0, i1, pi1, i1, i2, pi1 }); if (info1.Type == CollisionType.CT_INSIDE) //The second point inside the triangle { newTriangles.AddRange(new[] { i2, i0, pi1 }); } } else { if (!verticesDictionary.TryGetValue(info0.Position, out pi0)) { pi0 = vertices.Count; vertices.Add(info0.Position); texCoords.Add(info0.TexCoord); verticesDictionary.Add(info0.Position, pi0); } if (info1.Type != info0.Type) //One point crosses the brink, the second inside the triangle { var prev = info0.EdgeIndex == 0 ? 2 : info0.EdgeIndex - 1; prev = workedIndices[index + prev]; var next = info0.EdgeIndex == 2 ? 0 : info0.EdgeIndex + 1; next = workedIndices[index + next]; var curr = workedIndices[index + info0.EdgeIndex]; newTriangles.AddRange(new[] { prev, curr, pi1, curr, pi0, pi1, pi0, next, pi1, next, prev, pi1 }); } else { var c0 = workedIndices[index + info0.EdgeIndex]; var c1 = workedIndices[index + info1.EdgeIndex]; var c2 = workedIndices[index + ((info1.EdgeIndex + 1) % 3)]; if (info0.Type == CollisionType.CT_EDGE) { newTriangles.AddRange(new[] { c0, pi0, pi1, pi0, c1, pi1, pi1, c2, c0 }); } else { newTriangles.AddRange(new[] { c0, c1, pi0, c1, pi1, pi0, c1, c2, pi1, c2, c0, pi1, c0, pi0, pi1 }); } } } } int slicePointIndex; SlicePoint slicePoint; for (var l = 0; l < 2; l++) { if (l == 1 && info1.Type == CollisionType.CT_NONE) { break; } var position = l == 0 ? info0.Position.Xy : info1.Position.Xy; var pointIndex = l == 0 ? pi0 : pi1; if (!slicePointsDictionary.TryGetValue(position, out slicePointIndex)) { slicePoint = new SlicePoint { Coordinate = position }; slicePoint.Lines.Add(sliceLine); slicePoint.PreparePoint(); slicePointIndex = slicePoints.Count; slicePoints.Add(slicePoint); slicePointsDictionary.Add(position, slicePointIndex); } else { slicePoint = slicePoints[slicePointIndex]; } if (!slicePoint.Indices.Contains(pointIndex)) { slicePoint.Indices.Add(pointIndex); } } if (newTriangles.Count > 0) { for (var l = 0; l < 3; l++) { workedIndices[index + l] = newTriangles[l]; } newTriangles.RemoveRange(0, 3); workedIndices.InsertRange(index, newTriangles); var count = (newTriangles.Count / 3); j += count; trianglesCount += count; } } } for (var i = 0; i < workedIndices.Count / 3; i++) { var index = i * 3; var t = new Triangle(); for (var j = 0; j < 3; j++) { t.Indices[j] = workedIndices[index + j]; } triangles.Add(i, new TrianleConnections { Triangle = t }); } var ind = new List <int>(); var tempTriangle = new Triangle(); tempTriangle.Indices[1] = -1; foreach (var point in slicePoints) { point.PreparePoint(); foreach (var index in point.Indices) { ind.Clear(); ind.Add(index); tempTriangle.Indices[0] = index; //Duplicate the verticle several times for (var i = 1; i < point.Directions.Count; i++) { ind.Add(vertices.Count); vertices.Add(vertices[index]); texCoords.Add(texCoords[index]); } foreach (var t in triangles) { var tr = t.Value.Triangle; var id = Triangle.TriangleEquals(ref tempTriangle, ref tr); if (id > -1) { var center = (vertices[tr.Indices[0]].Xy + vertices[tr.Indices[1]].Xy + vertices[tr.Indices[2]].Xy) / 3.0f; var dir = (center - point.Coordinate).Normalized(); var angle = SlicePoint.GetAngle(ref dir); var ii = point.Directions.Count - 1; for (var j = 0; j < point.Directions.Count; j++) { if (angle < point.Directions[j]) { break; } ii = j; } tr.Indices[id] = ind[ii]; } } } } var invTransform = mesh.Transform * camera.ViewMatrix; invTransform.Invert(); for (var i = 0; i < vertices.Count; i++) { vertices[i] = Vector3.Transform(vertices[i], invTransform); } workedIndices.Clear(); foreach (var t in triangles) { foreach (var i in t.Value.Triangle.Indices) { workedIndices.Add(i); } } workedIndices.AddRange(tempIndices); triangleConnections.Clear(); triangles.Clear(); for (var i = 0; i < workedIndices.Count / 3; i++) { var index = i * 3; var t = new Triangle(); for (var j = 0; j < 3; j++) { t.Indices[j] = workedIndices[index + j]; List <int> l; if (!triangleConnections.TryGetValue(t.Indices[j], out l)) { l = new List <int>(); triangleConnections.Add(t.Indices[j], l); } l.Add(i); } triangles.Add(i, new TrianleConnections { Triangle = t }); } var mainMesh = true; while (triangles.Count > 0) { foundedTriangles.Clear(); FillTriangles(triangles.First().Key); if (mainMesh) { mesh.Create(vertices, texCoords, foundedTriangles, mesh.Material.DiffuseTextureMap, mesh.Material.TransparentTextureMap, mesh.TextureAngle, mesh.TextureSize); mainMesh = false; } else { var tmpMesh = new DynamicRenderMesh(MeshType.Hair); tmpMesh.Create(vertices, texCoords, foundedTriangles, mesh.Material.DiffuseTextureMap, mesh.Material.TransparentTextureMap, mesh.TextureAngle, mesh.TextureSize); tmpMesh.Transform = mesh.Transform; tmpMesh.Material.DiffuseColor = mesh.Material.DiffuseColor; tmpMesh.MeshAngle = mesh.MeshAngle; tmpMesh.MeshSize = mesh.MeshSize; var info = tmpMesh.GetMeshInfo(); var center = Vector3.Zero; var scale = PickingController.GetHairScale(ProgramCore.Project.ManType); foreach (var vert in info.Positions) { center.X += vert.X * scale; center.Y += vert.Y * scale; center.Z += vert.Z * scale; } center /= info.Positions.Count; tmpMesh.Position = center; ResultMeshes.Add(tmpMesh); } } }
public void UpdateSelectedFace(int x, int y) { var selectedId = -1; var viewport = new int[4]; var selectBuffer = new uint[BufferSize * 4]; GL.SelectBuffer(BufferSize * 4, selectBuffer); GL.RenderMode(RenderingMode.Select); GL.InitNames(); GL.PushName(-0x01); GL.MatrixMode(MatrixMode.Projection); GL.PushMatrix(); GL.GetInteger(GetPName.Viewport, viewport); var doubleArray = new double[16]; GL.GetDouble(GetPName.ProjectionMatrix, doubleArray); GL.LoadIdentity(); PickMatrix(x, viewport[3] - y, 0.001f, 0.001f, viewport); GL.MultMatrix(doubleArray); camera.PutCamera(); GL.PushMatrix(); GL.Enable(EnableCap.DepthTest); var name = 0; foreach (var mesh in HairMeshes) { if (!mesh.IsVisible) { ++name; continue; } GL.LoadName(++name); GL.PushMatrix(); GL.MultMatrix(ref mesh.Transform); mesh.SimpleDraw(); GL.PopMatrix(); } name = 99999; foreach (var mesh in AccesoryMeshes) { if (!mesh.IsVisible) { ++name; continue; } GL.LoadName(++name); GL.PushMatrix(); GL.MultMatrix(ref mesh.Transform); mesh.SimpleDraw(); GL.PopMatrix(); } GL.PopMatrix(); GL.Flush(); GL.MatrixMode(MatrixMode.Projection); GL.PopMatrix(); GL.MatrixMode(MatrixMode.Modelview); GL.Flush(); var hits = GL.RenderMode(RenderingMode.Render); var closest = uint.MaxValue; for (var i = 0; i < hits; i++) { var distance = selectBuffer[i * 4 + 1]; if (closest >= distance) { closest = distance; selectedId = (int)selectBuffer[i * 4 + 3]; } } if (selectedId > 0) { if (selectedId >= 100000) { SelectedMeshes.Clear(); var mesh = AccesoryMeshes[selectedId - 100000]; SelectedMeshes.Add(mesh); } else { if (SelectedMeshes.Any(z => z.meshType == MeshType.Accessory)) { SelectedMeshes.Clear(); } var mesh = HairMeshes[selectedId - 1]; if (!SelectedMeshes.Contains(mesh)) { SelectedMeshes.Add(mesh); } else { SetPointColor(mesh); SelectedMeshes.Remove(mesh); } } } else { SelectedMeshes.Clear(); } }