public Vector3 CalculateSpin(Vector3 position) { // Combine transverse movement about center and pivot. // First project center onto position vector to get an orthogonal spin vector. Vector3 spin = Math2.ProjectOnVector(Traits.Center, position) - Traits.Center; if (spin.Length > 0.0001f) { Vector3 tangent = Vector3.Cross(spin, position); tangent.Normalize(); tangent *= spin.Length * (float)Math.Tan(Traits.CenterRotation); return(tangent); } return(Vector3.Zero); }
static Stress calculateStress(Vector3 movement0, Vector3 movement1, Vector3 boundaryVector, Vector3 boundaryNormal) { var relativeMovement = movement0 - movement1; var pressureVector = Math2.ProjectOnVector(relativeMovement, boundaryNormal); var pressure = pressureVector.Length; if (Vector3.Dot(pressureVector, boundaryNormal) > 0) { pressure = -pressure; } var shear = Math2.ProjectOnVector(relativeMovement, boundaryVector).Length; return(new Stress(2.0f / (1.0f + (float)Math.Exp(-pressure / 30.0f)) - 1.0f, 2.0f / (1.0f + (float)Math.Exp(-shear / 30.0f)) - 1.0f)); }
public Geometry <Vertex3DColor> GenerateDistanceDebugGeom() { List <Vertex3DColor> verts = new List <Vertex3DColor>(); List <uint> indices = new List <uint>(); for (int plateIndex = 0; plateIndex < plates.Length; ++plateIndex) { Vector3 center = plates[plateIndex].Traits.Center; int cornerIndex = 0; foreach (int corner in plates[plateIndex].Corners) { float hue = (float)cornerIndex / (float)plates[plateIndex].Corners.Count; Vector3 color3 = Math2.HSV2RGB(new Vector3(hue, 0.7f, 0.5f)); Vector4 color = new Vector4(color3.X, color3.Y, color3.Z, 1.0f); Centroid centroid = geometry.Topology.Centroids[corner]; Vector3 cornerPos = centroid.position; Vector3 direction = cornerPos - center; direction.Normalize(); float theta = centroid.PlateDistances[plateIndex]; float distance = 2.0f * (float)Math.Sin(theta * 0.5f); direction *= distance; cornerPos = center + direction; cornerPos.Normalize(); int vertexStart = verts.Count; GeometryFactory.AddArcVerts(verts, center, cornerPos, 1.001f, color); for (int vertexIndex = vertexStart; vertexIndex < verts.Count - 1; ++vertexIndex) { indices.Add((uint)vertexIndex); indices.Add((uint)vertexIndex + 1); } ++cornerIndex; } } Mesh <Vertex3DColor> mesh = new Mesh <Vertex3DColor>(verts.ToArray()); Geometry <Vertex3DColor> geom = new Geometry <Vertex3DColor>(mesh, indices.ToArray()); geom.PrimitiveType = OpenTK.Graphics.OpenGL.PrimitiveType.Lines; return(geom); }
public Scene(World world, float width, float height) { this.world = world; camera = new Camera { Position = Vector3.UnitZ * 2.0f, Width = width, Height = height }; ambientColor = Math2.ToVec3(Color.Aquamarine) * 0.25f; Shader quadShader = new Shader(SHADER_PATH + "quadVertShader.glsl", SHADER_PATH + "texFragShader.glsl"); Shader shader = new Shader(SHADER_PATH + "Vert3DColorUVShader.glsl", SHADER_PATH + "shadedFragShader.glsl"); Shader pointShader = new Shader(SHADER_PATH + "pointVertShader.glsl", SHADER_PATH + "pointFragShader.glsl"); Shader lineShader = new Shader(SHADER_PATH + "pointColorVertShader.glsl", SHADER_PATH + "pointFragShader.glsl"); Shader texShader2 = new Shader(SHADER_PATH + "Vert3DColorUVShader.glsl", SHADER_PATH + "texFragShader.glsl"); Shader borderShader = new Shader(SHADER_PATH + "Vert3DColorShader.glsl", SHADER_PATH + "pointFragShader.glsl"); Texture cellTexture = new Texture("Edge.png"); Texture arrowTexture = new Texture("Arrow.png"); var node = new Node { Position = new Vector3(0, 0, -3) }; node.Model = Matrix4.CreateTranslation(node.Position); nodes.Add(node); worldRenderGeometry = world.geometry.GenerateDualMesh <Vertex3DColorUV>(); worldRenderer = new Renderer(worldRenderGeometry, shader); worldRenderer.AddUniform(new UniformProperty("lightPosition", lightPosition)); worldRenderer.AddUniform(new UniformProperty("ambientColor", ambientColor)); worldRenderer.AddTexture(cellTexture); worldRenderer.CullFaceFlag = true; node.Add(worldRenderer); borderGeometry = world.plates.GenerateBorderGeometry <Vertex3DColor>(); borderGeometry.PrimitiveType = PrimitiveType.Triangles; borderRenderer = new Renderer(borderGeometry, borderShader) { DepthTestFlag = true, CullFaceFlag = true, CullFaceMode = CullFaceMode.Back }; node.Add(borderRenderer); worldVertsDebugRenderer = new Renderer(world.geometry, pointShader); worldVertsDebugRenderer.AddUniform(new UniformProperty("color", new Vector4(0, 0.2f, 0.7f, 1))); worldVertsDebugRenderer.AddUniform(new UniformProperty("pointSize", 3f)); //node.Add(worldVertsDebugRenderer); Geometry <Vertex3D> centroidGeom = new Geometry <Vertex3D>(world.geometry.GenerateCentroidPointMesh()) { PrimitiveType = PrimitiveType.Points }; worldCentroidDebugRenderer = new Renderer(centroidGeom, pointShader) { DepthTestFlag = false, CullFaceFlag = false }; worldCentroidDebugRenderer.AddUniform(new UniformProperty("color", new Vector4(0.5f, 0.5f, 0.5f, 1))); worldCentroidDebugRenderer.AddUniform(new UniformProperty("pointSize", 3f)); worldCentroidDebugRenderer.AddUniform(new UniformProperty("zCutoff", -2.8f)); //node.Add(worldCentroidDebugRenderer); var spinGeom = world.plates.GenerateSpinDriftDebugGeom(true); worldPlateSpinDebugRenderer = new Renderer(spinGeom, texShader2) { DepthTestFlag = false, CullFaceFlag = false, BlendingFlag = true }; worldPlateSpinDebugRenderer.AddTexture(arrowTexture); worldPlateSpinDebugRenderer.AddUniform(new UniformProperty("color", new Vector4(1, 1, 1, 1.0f))); node.Add(worldPlateSpinDebugRenderer); var driftGeom = world.plates.GenerateSpinDriftDebugGeom(false); worldPlateDriftDebugRenderer = new Renderer(driftGeom, texShader2) { DepthTestFlag = false, CullFaceFlag = false, BlendingFlag = true }; worldPlateDriftDebugRenderer.AddTexture(arrowTexture); worldPlateDriftDebugRenderer.AddUniform(new UniformProperty("color", new Vector4(.75f, 0.75f, 0.0f, 1.0f))); node.Add(worldPlateDriftDebugRenderer); var equatorGeom = GeometryFactory.GenerateCircle(Vector3.Zero, Vector3.UnitY, 1.001f, new Vector4(1.0f, 0, 0, 1.0f)); var equatorRenderer = new Renderer(equatorGeom, lineShader); equatorRenderer.AddUniform(new UniformProperty("zCutoff", -2.8f)); node.Add(equatorRenderer); //var plateDistanceGeom = world.plates.GenerateDistanceDebugGeom(); //var plateDistanceRenderer = new Renderer(plateDistanceGeom, lineShader) //{ // DepthTestFlag = true; //} //plateDistanceRenderer.AddUniform(new UniformProperty("zCutoff", -2.8f)); //node.Add(plateDistanceRenderer); }
public float RelaxTriangles(float multiplier) { NeedsUpdate = true; double totalSurfaceArea = 4.0 * Math.PI; double idealFaceArea = totalSurfaceArea / (indices.Length / 3); double idealEdgeLength = Math.Sqrt(idealFaceArea * 4.0 / Math.Sqrt(3.0)); double idealDistanceToCentroid = idealEdgeLength * Math.Sqrt(3) / 3.0 * 0.9; Vector3[] shiftPositions = new Vector3[mesh.vertices.Length]; for (int i = 0; i < mesh.vertices.Length; ++i) { shiftPositions[i] = new Vector3(Vector3.Zero); } int numIndices = indices.Length; TVertex[] centroidVerts = new TVertex[numIndices / 3]; TVertex centroidVertex = new TVertex(); for (int i = 0; i < numIndices; i += 3) { Vector3 centroid = Topology.CalculateCentroid(i / 3); centroid.Normalize(); MeshAttr.SetPosition(ref centroidVertex, ref centroid); Vector3[] oldPositions = new Vector3[3] { new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i]])), new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 1]])), new Vector3(MeshAttr.GetPosition(ref mesh.vertices[indices[i + 2]])), }; for (int j = 0; j < 3; ++j) { Vector3 midLine = centroid - oldPositions[j]; float midLength = midLine.Length; midLine *= (float)(multiplier * (midLength - idealDistanceToCentroid) / midLength); shiftPositions[indices[i + j]] += midLine; } } var origin = Vector3.Zero; Plane p = new Plane(Vector3.UnitY, Vector3.Zero); for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 vertexPosition = MeshAttr.GetPosition(ref mesh.vertices[i]); p.Redefine(vertexPosition, origin); shiftPositions[i] = vertexPosition + p.ProjectPoint(shiftPositions[i]); shiftPositions[i].Normalize(); } // Stop poylgons rotating about their centroid. // Doesn't stop triangles flipping. float[] rotationSuppressions = new float[mesh.vertices.Length]; rotationSuppressions.Initialize(); Topology.GenerateEdges(); float minEdgeLength = (float)idealEdgeLength * 0.8f; float maxEdgeLength = (float)idealEdgeLength * 1.2f; foreach (var iter in Topology.Edges) { Int64 key = iter.Key; int index1 = (int)(key & 0xffffffff); int index2 = (int)((key >> 32) & 0xffffffff); Vector3 oldPos1 = MeshAttr.GetPosition(ref mesh.vertices[index1]); Vector3 oldPos2 = MeshAttr.GetPosition(ref mesh.vertices[index2]); Vector3 newPos1 = shiftPositions[index1]; Vector3 newPos2 = shiftPositions[index2]; Vector3 oldEdge = oldPos2 - oldPos1; Vector3 newEdge = newPos2 - newPos1; if (newEdge.Length < minEdgeLength) { // Move shift positions back out to ensure that the edge is never too small. Vector3 midPt = newPos1 + 0.5f * newEdge; newEdge.Normalize(); newEdge *= minEdgeLength * 0.5f; shiftPositions[index1] = midPt - newEdge; shiftPositions[index2] = midPt + newEdge; newEdge = shiftPositions[index2] - shiftPositions[index1]; } if (newEdge.Length > maxEdgeLength) { // Move shift positions back in to ensure that the edge is never too large. Vector3 midPt = newPos1 + 0.5f * newEdge; newEdge.Normalize(); newEdge *= (maxEdgeLength * 0.5f); shiftPositions[index1] = midPt - newEdge; shiftPositions[index2] = midPt + newEdge; newEdge = shiftPositions[index2] - shiftPositions[index1]; } oldEdge.Normalize(); newEdge.Normalize(); float suppression = (1.0f - Vector3.Dot(oldEdge, newEdge)) * 0.5f; rotationSuppressions[index1] = Math.Max(suppression, rotationSuppressions[index1]); rotationSuppressions[index2] = Math.Max(suppression, rotationSuppressions[index2]); } for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 pos = MeshAttr.GetPosition(ref mesh.vertices[i]); Vector3 delta = pos; pos = Math2.Lerp(pos, shiftPositions[i], (float)(1.0f - Math.Sqrt(rotationSuppressions[i]))); pos.Normalize(); shiftPositions[i] = pos; } float totalShift = 0; for (int i = 0; i < mesh.vertices.Length; ++i) { Vector3 delta = MeshAttr.GetPosition(ref mesh.vertices[i]); MeshAttr.SetPosition(ref mesh.vertices[i], ref shiftPositions[i]); delta -= shiftPositions[i]; totalShift += delta.Length; } Topology.Regenerate(); return(totalShift); }
public Geometry <AltVertex> GenerateBorderGeometry <AltVertex>() where AltVertex : struct, IVertex { if (borders == null || borders.Count == 0) { return(null); } else { List <AltVertex> vertices = new List <AltVertex>(); List <uint> newIndices = new List <uint>(); const float h = 0.1f; foreach (var iter in borders) { Int64 borderKey = iter.Key; int v1index = (int)(borderKey & 0xffffffff); int v2index = (int)((borderKey >> 32) & 0xffffffff); Border border = iter.Value; // The border lies along an edge in the dual geometry. int plateIndex1 = border.plate0; int plateIndex2 = border.plate1; Vector3 v1Pos = geometry.Mesh.GetPosition(v1index); Vector3 v2Pos = geometry.Mesh.GetPosition(v2index); Vector3 centroid1 = geometry.Topology.Centroids[border.c1Index].position; Vector3 centroid2 = geometry.Topology.Centroids[border.c2Index].position; Vector3 v1g1prime = Math2.BaseProjection(v1Pos, centroid1, centroid2, h); Vector3 v1g2prime = Math2.BaseProjection(v1Pos, centroid2, centroid1, h); Vector3 v2g1prime = Math2.BaseProjection(v2Pos, centroid1, centroid2, h); Vector3 v2g2prime = Math2.BaseProjection(v2Pos, centroid2, centroid1, h); centroid1 *= 1.01f; // Project the centroids out of the sphere slightly centroid2 *= 1.01f; bool edgeOrderIsAnticlockwise = false; for (int i = 0; i < 3; i++) { if (geometry.Indices[border.c1Index * 3 + i] == v1index) { if (geometry.Indices[border.c1Index * 3 + (i + 1) % 3] == v2index) { edgeOrderIsAnticlockwise = true; } break; } } int index = vertices.Count; geometry.AddTriangle(ref vertices, ref newIndices, ref v1g2prime, ref centroid2, ref centroid1, edgeOrderIsAnticlockwise); geometry.AddTriangle(ref vertices, ref newIndices, ref v1g2prime, ref centroid1, ref v1g1prime, edgeOrderIsAnticlockwise); geometry.AddTriangle(ref vertices, ref newIndices, ref v2g1prime, ref centroid1, ref centroid2, edgeOrderIsAnticlockwise); geometry.AddTriangle(ref vertices, ref newIndices, ref v2g1prime, ref centroid2, ref v2g2prime, edgeOrderIsAnticlockwise); float p1 = Math2.Clamp(Math.Abs(borderCorners[border.c1Index].stress.pressure) * 1000.0f, 0, 1.0f); float p2 = Math2.Clamp(Math.Abs(borderCorners[border.c2Index].stress.pressure) * 1000.0f, 0, 1.0f); float hue1 = borderCorners[border.c1Index].stress.pressure > 0 ? 0 : 0.5f; float hue2 = borderCorners[border.c2Index].stress.pressure > 0 ? 0 : 0.5f; Vector3 rgb1 = Math2.HSV2RGB(new Vector3(hue1, p1, 1.0f - p1)); Vector3 rgb2 = Math2.HSV2RGB(new Vector3(hue2, p2, 1.0f - p2)); Vector4 c1Color = new Vector4(rgb1.X, rgb1.Y, rgb1.Z, 1); Vector4 c2Color = new Vector4(rgb2.X, rgb2.Y, rgb2.Z, 1); AltVertex v; for (int i = 0; i < 12; ++i) { Vector4 color = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); if (i == 0 || i == 1 || i == 3 || i == 8 || i == 10 || i == 11) { color = c2Color; } else if (i == 2 || i == 4 || i == 5 || i == 6 || i == 7 || i == 9) { color = c1Color; } v = vertices[index + i]; MeshAttr.SetColor(ref v, ref color); vertices[index + i] = v; } } Mesh <AltVertex> newMesh = new Mesh <AltVertex>(vertices.ToArray()); return(new Geometry <AltVertex>(newMesh, newIndices.ToArray())); } }