diff options
Diffstat (limited to 'OpenSim/Region')
-rw-r--r-- | OpenSim/Region/Physics/Meshing/PrimMesher.cs | 843 |
1 files changed, 10 insertions, 833 deletions
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index 47ce615..c7c9160 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs | |||
@@ -67,11 +67,6 @@ namespace PrimMesher | |||
67 | Normalize(); | 67 | Normalize(); |
68 | } | 68 | } |
69 | 69 | ||
70 | public Quat Identity() | ||
71 | { | ||
72 | return new Quat(0.0f, 0.0f, 0.0f, 1.0f); | ||
73 | } | ||
74 | |||
75 | public float Length() | 70 | public float Length() |
76 | { | 71 | { |
77 | return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); | 72 | return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); |
@@ -660,7 +655,7 @@ namespace PrimMesher | |||
660 | this.faceNumbers = new List<int>(); | 655 | this.faceNumbers = new List<int>(); |
661 | 656 | ||
662 | Coord center = new Coord(0.0f, 0.0f, 0.0f); | 657 | Coord center = new Coord(0.0f, 0.0f, 0.0f); |
663 | bool hasCenter = false; | 658 | //bool hasCenter = false; |
664 | 659 | ||
665 | List<Coord> hollowCoords = new List<Coord>(); | 660 | List<Coord> hollowCoords = new List<Coord>(); |
666 | List<Coord> hollowNormals = new List<Coord>(); | 661 | List<Coord> hollowNormals = new List<Coord>(); |
@@ -727,7 +722,7 @@ namespace PrimMesher | |||
727 | else if (!simpleFace) | 722 | else if (!simpleFace) |
728 | { | 723 | { |
729 | this.coords.Add(center); | 724 | this.coords.Add(center); |
730 | hasCenter = true; | 725 | //hasCenter = true; |
731 | if (this.calcVertexNormals) | 726 | if (this.calcVertexNormals) |
732 | this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); | 727 | this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); |
733 | this.us.Add(0.0f); | 728 | this.us.Add(0.0f); |
@@ -1541,7 +1536,7 @@ namespace PrimMesher | |||
1541 | } | 1536 | } |
1542 | 1537 | ||
1543 | /// <summary> | 1538 | /// <summary> |
1544 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. | 1539 | /// Extrudes a profile along a path. |
1545 | /// </summary> | 1540 | /// </summary> |
1546 | public void Extrude(PathType pathType) | 1541 | public void Extrude(PathType pathType) |
1547 | { | 1542 | { |
@@ -1557,7 +1552,6 @@ namespace PrimMesher | |||
1557 | if (this.calcVertexNormals) | 1552 | if (this.calcVertexNormals) |
1558 | this.normals = new List<Coord>(); | 1553 | this.normals = new List<Coord>(); |
1559 | 1554 | ||
1560 | //int step = 0; | ||
1561 | int steps = 1; | 1555 | int steps = 1; |
1562 | 1556 | ||
1563 | float length = this.pathCutEnd - this.pathCutBegin; | 1557 | float length = this.pathCutEnd - this.pathCutBegin; |
@@ -1579,20 +1573,6 @@ namespace PrimMesher | |||
1579 | if (twistTotalAbs > 0.01f) | 1573 | if (twistTotalAbs > 0.01f) |
1580 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | 1574 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number |
1581 | 1575 | ||
1582 | //float start = -0.5f; | ||
1583 | //float stepSize = length / (float)steps; | ||
1584 | //float percentOfPathMultiplier = stepSize; | ||
1585 | //float xProfileScale = 1.0f; | ||
1586 | //float yProfileScale = 1.0f; | ||
1587 | //float xOffset = 0.0f; | ||
1588 | //float yOffset = 0.0f; | ||
1589 | //float zOffset = start; | ||
1590 | //float xOffsetStepIncrement = this.topShearX / steps; | ||
1591 | //float yOffsetStepIncrement = this.topShearY / steps; | ||
1592 | |||
1593 | //float percentOfPath = this.pathCutBegin; | ||
1594 | //zOffset += percentOfPath; | ||
1595 | |||
1596 | float hollow = this.hollow; | 1576 | float hollow = this.hollow; |
1597 | 1577 | ||
1598 | // sanity checks | 1578 | // sanity checks |
@@ -1662,7 +1642,6 @@ namespace PrimMesher | |||
1662 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | 1642 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; |
1663 | } | 1643 | } |
1664 | 1644 | ||
1665 | |||
1666 | if (initialProfileRot != 0.0f) | 1645 | if (initialProfileRot != 0.0f) |
1667 | { | 1646 | { |
1668 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | 1647 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); |
@@ -1693,24 +1672,6 @@ namespace PrimMesher | |||
1693 | path.stepsPerRevolution = stepsPerRevolution; | 1672 | path.stepsPerRevolution = stepsPerRevolution; |
1694 | 1673 | ||
1695 | path.Create(pathType, steps); | 1674 | path.Create(pathType, steps); |
1696 | /* | ||
1697 | public int twistBegin = 0; | ||
1698 | public int twistEnd = 0; | ||
1699 | public float topShearX = 0.0f; | ||
1700 | public float topShearY = 0.0f; | ||
1701 | public float pathCutBegin = 0.0f; | ||
1702 | public float pathCutEnd = 1.0f; | ||
1703 | public float dimpleBegin = 0.0f; | ||
1704 | public float dimpleEnd = 1.0f; | ||
1705 | public float skew = 0.0f; | ||
1706 | public float holeSizeX = 1.0f; // called pathScaleX in pbs | ||
1707 | public float holeSizeY = 0.25f; | ||
1708 | public float taperX = 0.0f; | ||
1709 | public float taperY = 0.0f; | ||
1710 | public float radius = 0.0f; | ||
1711 | public float revolutions = 1.0f; | ||
1712 | public int stepsPerRevolution = 24; | ||
1713 | */ | ||
1714 | 1675 | ||
1715 | bool needEndFaces = false; | 1676 | bool needEndFaces = false; |
1716 | if (pathType == PathType.Circular) | 1677 | if (pathType == PathType.Circular) |
@@ -1796,7 +1757,6 @@ namespace PrimMesher | |||
1796 | int numVerts = newLayer.coords.Count; | 1757 | int numVerts = newLayer.coords.Count; |
1797 | Face newFace = new Face(); | 1758 | Face newFace = new Face(); |
1798 | 1759 | ||
1799 | //if (step > 0) | ||
1800 | if (nodeIndex > 0) | 1760 | if (nodeIndex > 0) |
1801 | { | 1761 | { |
1802 | int startVert = coordsLen + 1; | 1762 | int startVert = coordsLen + 1; |
@@ -1812,7 +1772,6 @@ namespace PrimMesher | |||
1812 | iNext = startVert; | 1772 | iNext = startVert; |
1813 | 1773 | ||
1814 | int whichVert = i - startVert; | 1774 | int whichVert = i - startVert; |
1815 | //int whichVert2 = i - lastCoordsLen; | ||
1816 | 1775 | ||
1817 | newFace.v1 = i; | 1776 | newFace.v1 = i; |
1818 | newFace.v2 = i - numVerts; | 1777 | newFace.v2 = i - numVerts; |
@@ -1982,809 +1941,27 @@ namespace PrimMesher | |||
1982 | 1941 | ||
1983 | 1942 | ||
1984 | /// <summary> | 1943 | /// <summary> |
1944 | /// DEPRICATED - use Extrude(PathType.Linear) instead | ||
1985 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. | 1945 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. |
1986 | /// </summary> | 1946 | /// </summary> |
1947 | /// | ||
1987 | public void ExtrudeLinear() | 1948 | public void ExtrudeLinear() |
1988 | { | 1949 | { |
1989 | this.coords = new List<Coord>(); | 1950 | this.Extrude(PathType.Linear); |
1990 | this.faces = new List<Face>(); | ||
1991 | |||
1992 | if (this.viewerMode) | ||
1993 | { | ||
1994 | this.viewerFaces = new List<ViewerFace>(); | ||
1995 | this.calcVertexNormals = true; | ||
1996 | } | ||
1997 | |||
1998 | if (this.calcVertexNormals) | ||
1999 | this.normals = new List<Coord>(); | ||
2000 | |||
2001 | int step = 0; | ||
2002 | int steps = 1; | ||
2003 | |||
2004 | float length = this.pathCutEnd - this.pathCutBegin; | ||
2005 | normalsProcessed = false; | ||
2006 | |||
2007 | if (this.viewerMode && this.sides == 3) | ||
2008 | { | ||
2009 | // prisms don't taper well so add some vertical resolution | ||
2010 | // other prims may benefit from this but just do prisms for now | ||
2011 | if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) | ||
2012 | steps = (int)(steps * 4.5 * length); | ||
2013 | } | ||
2014 | |||
2015 | |||
2016 | float twistBegin = this.twistBegin / 360.0f * twoPi; | ||
2017 | float twistEnd = this.twistEnd / 360.0f * twoPi; | ||
2018 | float twistTotal = twistEnd - twistBegin; | ||
2019 | float twistTotalAbs = Math.Abs(twistTotal); | ||
2020 | if (twistTotalAbs > 0.01f) | ||
2021 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | ||
2022 | |||
2023 | float start = -0.5f; | ||
2024 | float stepSize = length / (float)steps; | ||
2025 | float percentOfPathMultiplier = stepSize; | ||
2026 | float xProfileScale = 1.0f; | ||
2027 | float yProfileScale = 1.0f; | ||
2028 | float xOffset = 0.0f; | ||
2029 | float yOffset = 0.0f; | ||
2030 | float zOffset = start; | ||
2031 | float xOffsetStepIncrement = this.topShearX / steps; | ||
2032 | float yOffsetStepIncrement = this.topShearY / steps; | ||
2033 | |||
2034 | float percentOfPath = this.pathCutBegin; | ||
2035 | zOffset += percentOfPath; | ||
2036 | |||
2037 | float hollow = this.hollow; | ||
2038 | |||
2039 | // sanity checks | ||
2040 | float initialProfileRot = 0.0f; | ||
2041 | if (this.sides == 3) | ||
2042 | { | ||
2043 | if (this.hollowSides == 4) | ||
2044 | { | ||
2045 | if (hollow > 0.7f) | ||
2046 | hollow = 0.7f; | ||
2047 | hollow *= 0.707f; | ||
2048 | } | ||
2049 | else hollow *= 0.5f; | ||
2050 | } | ||
2051 | else if (this.sides == 4) | ||
2052 | { | ||
2053 | initialProfileRot = 1.25f * (float)Math.PI; | ||
2054 | if (this.hollowSides != 4) | ||
2055 | hollow *= 0.707f; | ||
2056 | } | ||
2057 | else if (this.sides == 24 && this.hollowSides == 4) | ||
2058 | hollow *= 1.414f; | ||
2059 | |||
2060 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); | ||
2061 | this.errorMessage = profile.errorMessage; | ||
2062 | |||
2063 | this.numPrimFaces = profile.numPrimFaces; | ||
2064 | |||
2065 | int cut1Vert = -1; | ||
2066 | int cut2Vert = -1; | ||
2067 | if (hasProfileCut) | ||
2068 | { | ||
2069 | cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; | ||
2070 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | ||
2071 | } | ||
2072 | |||
2073 | if (initialProfileRot != 0.0f) | ||
2074 | { | ||
2075 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | ||
2076 | if (viewerMode) | ||
2077 | profile.MakeFaceUVs(); | ||
2078 | } | ||
2079 | |||
2080 | Coord lastCutNormal1 = new Coord(); | ||
2081 | Coord lastCutNormal2 = new Coord(); | ||
2082 | float lastV = 1.0f; | ||
2083 | |||
2084 | bool done = false; | ||
2085 | while (!done) | ||
2086 | { | ||
2087 | Profile newLayer = profile.Copy(); | ||
2088 | |||
2089 | if (this.taperX == 0.0f) | ||
2090 | xProfileScale = 1.0f; | ||
2091 | else if (this.taperX > 0.0f) | ||
2092 | xProfileScale = 1.0f - percentOfPath * this.taperX; | ||
2093 | else xProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperX; | ||
2094 | |||
2095 | if (this.taperY == 0.0f) | ||
2096 | yProfileScale = 1.0f; | ||
2097 | else if (this.taperY > 0.0f) | ||
2098 | yProfileScale = 1.0f - percentOfPath * this.taperY; | ||
2099 | else yProfileScale = 1.0f + (1.0f - percentOfPath) * this.taperY; | ||
2100 | |||
2101 | if (xProfileScale != 1.0f || yProfileScale != 1.0f) | ||
2102 | newLayer.Scale(xProfileScale, yProfileScale); | ||
2103 | |||
2104 | float twist = twistBegin + twistTotal * percentOfPath; | ||
2105 | if (twist != 0.0f) | ||
2106 | newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist)); | ||
2107 | |||
2108 | newLayer.AddPos(xOffset, yOffset, zOffset); | ||
2109 | |||
2110 | if (step == 0) | ||
2111 | { | ||
2112 | newLayer.FlipNormals(); | ||
2113 | |||
2114 | // add the top faces to the viewerFaces list here | ||
2115 | if (this.viewerMode) | ||
2116 | { | ||
2117 | Coord faceNormal = newLayer.faceNormal; | ||
2118 | ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); | ||
2119 | int numFaces = newLayer.faces.Count; | ||
2120 | List<Face> faces = newLayer.faces; | ||
2121 | |||
2122 | for (int i = 0; i < numFaces; i++) | ||
2123 | { | ||
2124 | Face face = faces[i]; | ||
2125 | newViewerFace.v1 = newLayer.coords[face.v1]; | ||
2126 | newViewerFace.v2 = newLayer.coords[face.v2]; | ||
2127 | newViewerFace.v3 = newLayer.coords[face.v3]; | ||
2128 | |||
2129 | newViewerFace.coordIndex1 = face.v1; | ||
2130 | newViewerFace.coordIndex2 = face.v2; | ||
2131 | newViewerFace.coordIndex3 = face.v3; | ||
2132 | |||
2133 | newViewerFace.n1 = faceNormal; | ||
2134 | newViewerFace.n2 = faceNormal; | ||
2135 | newViewerFace.n3 = faceNormal; | ||
2136 | |||
2137 | newViewerFace.uv1 = newLayer.faceUVs[face.v1]; | ||
2138 | newViewerFace.uv2 = newLayer.faceUVs[face.v2]; | ||
2139 | newViewerFace.uv3 = newLayer.faceUVs[face.v3]; | ||
2140 | |||
2141 | this.viewerFaces.Add(newViewerFace); | ||
2142 | } | ||
2143 | } | ||
2144 | } | ||
2145 | |||
2146 | // append this layer | ||
2147 | |||
2148 | int coordsLen = this.coords.Count; | ||
2149 | int lastCoordsLen = coordsLen; | ||
2150 | newLayer.AddValue2FaceVertexIndices(coordsLen); | ||
2151 | |||
2152 | this.coords.AddRange(newLayer.coords); | ||
2153 | |||
2154 | if (this.calcVertexNormals) | ||
2155 | { | ||
2156 | newLayer.AddValue2FaceNormalIndices(this.normals.Count); | ||
2157 | this.normals.AddRange(newLayer.vertexNormals); | ||
2158 | } | ||
2159 | |||
2160 | if (percentOfPath < this.pathCutBegin + 0.01f || percentOfPath > this.pathCutEnd - 0.01f) | ||
2161 | this.faces.AddRange(newLayer.faces); | ||
2162 | |||
2163 | // fill faces between layers | ||
2164 | |||
2165 | int numVerts = newLayer.coords.Count; | ||
2166 | Face newFace = new Face(); | ||
2167 | |||
2168 | if (step > 0) | ||
2169 | { | ||
2170 | int startVert = coordsLen + 1; | ||
2171 | int endVert = this.coords.Count; | ||
2172 | |||
2173 | if (sides < 5 || this.hasProfileCut || hollow > 0.0f) | ||
2174 | startVert--; | ||
2175 | |||
2176 | for (int i = startVert; i < endVert; i++) | ||
2177 | { | ||
2178 | int iNext = i + 1; | ||
2179 | if (i == endVert - 1) | ||
2180 | iNext = startVert; | ||
2181 | |||
2182 | int whichVert = i - startVert; | ||
2183 | //int whichVert2 = i - lastCoordsLen; | ||
2184 | |||
2185 | newFace.v1 = i; | ||
2186 | newFace.v2 = i - numVerts; | ||
2187 | newFace.v3 = iNext - numVerts; | ||
2188 | this.faces.Add(newFace); | ||
2189 | |||
2190 | newFace.v2 = iNext - numVerts; | ||
2191 | newFace.v3 = iNext; | ||
2192 | this.faces.Add(newFace); | ||
2193 | |||
2194 | if (this.viewerMode) | ||
2195 | { | ||
2196 | // add the side faces to the list of viewerFaces here | ||
2197 | //int primFaceNum = 1; | ||
2198 | //if (whichVert >= sides) | ||
2199 | // primFaceNum = 2; | ||
2200 | int primFaceNum = profile.faceNumbers[whichVert]; | ||
2201 | |||
2202 | ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); | ||
2203 | ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); | ||
2204 | |||
2205 | float u1 = newLayer.us[whichVert]; | ||
2206 | float u2 = 1.0f; | ||
2207 | if (whichVert < newLayer.us.Count - 1) | ||
2208 | u2 = newLayer.us[whichVert + 1]; | ||
2209 | |||
2210 | if (whichVert == cut1Vert || whichVert == cut2Vert) | ||
2211 | { | ||
2212 | u1 = 0.0f; | ||
2213 | u2 = 1.0f; | ||
2214 | } | ||
2215 | else if (sides < 5) | ||
2216 | { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled | ||
2217 | // to reflect the entire texture width | ||
2218 | u1 *= sides; | ||
2219 | u2 *= sides; | ||
2220 | u2 -= (int)u1; | ||
2221 | u1 -= (int)u1; | ||
2222 | if (u2 < 0.1f) | ||
2223 | u2 = 1.0f; | ||
2224 | |||
2225 | //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; | ||
2226 | } | ||
2227 | |||
2228 | newViewerFace1.uv1.U = u1; | ||
2229 | newViewerFace1.uv2.U = u1; | ||
2230 | newViewerFace1.uv3.U = u2; | ||
2231 | |||
2232 | newViewerFace1.uv1.V = 1.0f - percentOfPath; | ||
2233 | newViewerFace1.uv2.V = lastV; | ||
2234 | newViewerFace1.uv3.V = lastV; | ||
2235 | |||
2236 | newViewerFace2.uv1.U = u1; | ||
2237 | newViewerFace2.uv2.U = u2; | ||
2238 | newViewerFace2.uv3.U = u2; | ||
2239 | |||
2240 | newViewerFace2.uv1.V = 1.0f - percentOfPath; | ||
2241 | newViewerFace2.uv2.V = lastV; | ||
2242 | newViewerFace2.uv3.V = 1.0f - percentOfPath; | ||
2243 | |||
2244 | newViewerFace1.v1 = this.coords[i]; | ||
2245 | newViewerFace1.v2 = this.coords[i - numVerts]; | ||
2246 | newViewerFace1.v3 = this.coords[iNext - numVerts]; | ||
2247 | |||
2248 | newViewerFace2.v1 = this.coords[i]; | ||
2249 | newViewerFace2.v2 = this.coords[iNext - numVerts]; | ||
2250 | newViewerFace2.v3 = this.coords[iNext]; | ||
2251 | |||
2252 | newViewerFace1.coordIndex1 = i; | ||
2253 | newViewerFace1.coordIndex2 = i - numVerts; | ||
2254 | newViewerFace1.coordIndex3 = iNext - numVerts; | ||
2255 | |||
2256 | newViewerFace2.coordIndex1 = i; | ||
2257 | newViewerFace2.coordIndex2 = iNext - numVerts; | ||
2258 | newViewerFace2.coordIndex3 = iNext; | ||
2259 | |||
2260 | // profile cut faces | ||
2261 | if (whichVert == cut1Vert) | ||
2262 | { | ||
2263 | newViewerFace1.n1 = newLayer.cutNormal1; | ||
2264 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; | ||
2265 | |||
2266 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; | ||
2267 | newViewerFace2.n2 = lastCutNormal1; | ||
2268 | } | ||
2269 | else if (whichVert == cut2Vert) | ||
2270 | { | ||
2271 | newViewerFace1.n1 = newLayer.cutNormal2; | ||
2272 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; | ||
2273 | |||
2274 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; | ||
2275 | newViewerFace2.n2 = lastCutNormal2; | ||
2276 | } | ||
2277 | |||
2278 | else // outer and hollow faces | ||
2279 | { | ||
2280 | if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) | ||
2281 | { | ||
2282 | newViewerFace1.CalcSurfaceNormal(); | ||
2283 | newViewerFace2.CalcSurfaceNormal(); | ||
2284 | } | ||
2285 | else | ||
2286 | { | ||
2287 | newViewerFace1.n1 = this.normals[i]; | ||
2288 | newViewerFace1.n2 = this.normals[i - numVerts]; | ||
2289 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | ||
2290 | |||
2291 | newViewerFace2.n1 = this.normals[i]; | ||
2292 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | ||
2293 | newViewerFace2.n3 = this.normals[iNext]; | ||
2294 | } | ||
2295 | } | ||
2296 | |||
2297 | //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = newLayer.faceNumbers[whichVert]; | ||
2298 | |||
2299 | this.viewerFaces.Add(newViewerFace1); | ||
2300 | this.viewerFaces.Add(newViewerFace2); | ||
2301 | |||
2302 | } | ||
2303 | } | ||
2304 | } | ||
2305 | |||
2306 | lastCutNormal1 = newLayer.cutNormal1; | ||
2307 | lastCutNormal2 = newLayer.cutNormal2; | ||
2308 | lastV = 1.0f - percentOfPath; | ||
2309 | |||
2310 | // calc the step for the next iteration of the loop | ||
2311 | |||
2312 | if (step < steps) | ||
2313 | { | ||
2314 | step += 1; | ||
2315 | percentOfPath += percentOfPathMultiplier; | ||
2316 | xOffset += xOffsetStepIncrement; | ||
2317 | yOffset += yOffsetStepIncrement; | ||
2318 | zOffset += stepSize; | ||
2319 | if (percentOfPath > this.pathCutEnd) | ||
2320 | done = true; | ||
2321 | } | ||
2322 | else done = true; | ||
2323 | |||
2324 | if (done && viewerMode) | ||
2325 | { | ||
2326 | // add the top faces to the viewerFaces list here | ||
2327 | Coord faceNormal = newLayer.faceNormal; | ||
2328 | ViewerFace newViewerFace = new ViewerFace(); | ||
2329 | newViewerFace.primFaceNumber = 0; | ||
2330 | int numFaces = newLayer.faces.Count; | ||
2331 | List<Face> faces = newLayer.faces; | ||
2332 | |||
2333 | for (int i = 0; i < numFaces; i++) | ||
2334 | { | ||
2335 | Face face = faces[i]; | ||
2336 | newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; | ||
2337 | newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; | ||
2338 | newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; | ||
2339 | |||
2340 | newViewerFace.coordIndex1 = face.v1 - coordsLen; | ||
2341 | newViewerFace.coordIndex2 = face.v2 - coordsLen; | ||
2342 | newViewerFace.coordIndex3 = face.v3 - coordsLen; | ||
2343 | |||
2344 | newViewerFace.n1 = faceNormal; | ||
2345 | newViewerFace.n2 = faceNormal; | ||
2346 | newViewerFace.n3 = faceNormal; | ||
2347 | |||
2348 | newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; | ||
2349 | newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; | ||
2350 | newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; | ||
2351 | |||
2352 | this.viewerFaces.Add(newViewerFace); | ||
2353 | } | ||
2354 | } | ||
2355 | } | ||
2356 | } | 1951 | } |
2357 | 1952 | ||
2358 | 1953 | ||
2359 | /// <summary> | 1954 | /// <summary> |
1955 | /// DEPRICATED - use Extrude(PathType.Circular) instead | ||
2360 | /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. | 1956 | /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. |
2361 | /// </summary> | 1957 | /// </summary> |
1958 | /// | ||
2362 | public void ExtrudeCircular() | 1959 | public void ExtrudeCircular() |
2363 | { | 1960 | { |
2364 | this.coords = new List<Coord>(); | 1961 | this.Extrude(PathType.Circular); |
2365 | this.faces = new List<Face>(); | ||
2366 | |||
2367 | if (this.viewerMode) | ||
2368 | { | ||
2369 | this.viewerFaces = new List<ViewerFace>(); | ||
2370 | this.calcVertexNormals = true; | ||
2371 | } | ||
2372 | |||
2373 | if (this.calcVertexNormals) | ||
2374 | this.normals = new List<Coord>(); | ||
2375 | |||
2376 | int step = 0; | ||
2377 | int steps = 24; | ||
2378 | |||
2379 | normalsProcessed = false; | ||
2380 | |||
2381 | float twistBegin = this.twistBegin / 360.0f * twoPi; | ||
2382 | float twistEnd = this.twistEnd / 360.0f * twoPi; | ||
2383 | float twistTotal = twistEnd - twistBegin; | ||
2384 | |||
2385 | // if the profile has a lot of twist, add more layers otherwise the layers may overlap | ||
2386 | // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't | ||
2387 | // accurately match the viewer | ||
2388 | float twistTotalAbs = Math.Abs(twistTotal); | ||
2389 | if (twistTotalAbs > 0.01f) | ||
2390 | { | ||
2391 | if (twistTotalAbs > Math.PI * 1.5f) | ||
2392 | steps *= 2; | ||
2393 | if (twistTotalAbs > Math.PI * 3.0f) | ||
2394 | steps *= 2; | ||
2395 | } | ||
2396 | |||
2397 | float yPathScale = this.holeSizeY * 0.5f; | ||
2398 | float pathLength = this.pathCutEnd - this.pathCutBegin; | ||
2399 | float totalSkew = this.skew * 2.0f * pathLength; | ||
2400 | float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; | ||
2401 | float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); | ||
2402 | float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; | ||
2403 | |||
2404 | // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end | ||
2405 | // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used | ||
2406 | // to calculate the sine for generating the path radius appears to approximate it's effects there | ||
2407 | // too, but there are some subtle differences in the radius which are noticeable as the prim size | ||
2408 | // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on | ||
2409 | // the meshes generated with this technique appear nearly identical in shape to the same prims when | ||
2410 | // displayed by the viewer. | ||
2411 | |||
2412 | float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; | ||
2413 | float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; | ||
2414 | float stepSize = twoPi / this.stepsPerRevolution; | ||
2415 | |||
2416 | step = (int)(startAngle / stepSize); | ||
2417 | int firstStep = step; | ||
2418 | float angle = startAngle; | ||
2419 | float hollow = this.hollow; | ||
2420 | |||
2421 | // sanity checks | ||
2422 | float initialProfileRot = 0.0f; | ||
2423 | if (this.sides == 3) | ||
2424 | { | ||
2425 | initialProfileRot = (float)Math.PI; | ||
2426 | if (this.hollowSides == 4) | ||
2427 | { | ||
2428 | if (hollow > 0.7f) | ||
2429 | hollow = 0.7f; | ||
2430 | hollow *= 0.707f; | ||
2431 | } | ||
2432 | else hollow *= 0.5f; | ||
2433 | } | ||
2434 | else if (this.sides == 4) | ||
2435 | { | ||
2436 | initialProfileRot = 0.25f * (float)Math.PI; | ||
2437 | if (this.hollowSides != 4) | ||
2438 | hollow *= 0.707f; | ||
2439 | } | ||
2440 | else if (this.sides > 4) | ||
2441 | { | ||
2442 | initialProfileRot = (float)Math.PI; | ||
2443 | if (this.hollowSides == 4) | ||
2444 | { | ||
2445 | if (hollow > 0.7f) | ||
2446 | hollow = 0.7f; | ||
2447 | hollow /= 0.7f; | ||
2448 | } | ||
2449 | } | ||
2450 | |||
2451 | bool needEndFaces = false; | ||
2452 | if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) | ||
2453 | needEndFaces = true; | ||
2454 | else if (this.taperX != 0.0f || this.taperY != 0.0f) | ||
2455 | needEndFaces = true; | ||
2456 | else if (this.skew != 0.0f) | ||
2457 | needEndFaces = true; | ||
2458 | else if (twistTotal != 0.0f) | ||
2459 | needEndFaces = true; | ||
2460 | else if (this.radius != 0.0f) | ||
2461 | needEndFaces = true; | ||
2462 | |||
2463 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces, calcVertexNormals); | ||
2464 | this.errorMessage = profile.errorMessage; | ||
2465 | |||
2466 | this.numPrimFaces = profile.numPrimFaces; | ||
2467 | |||
2468 | int cut1Vert = -1; | ||
2469 | int cut2Vert = -1; | ||
2470 | if (hasProfileCut) | ||
2471 | { | ||
2472 | cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; | ||
2473 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | ||
2474 | } | ||
2475 | |||
2476 | if (initialProfileRot != 0.0f) | ||
2477 | { | ||
2478 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | ||
2479 | if (viewerMode) | ||
2480 | profile.MakeFaceUVs(); | ||
2481 | } | ||
2482 | |||
2483 | Coord lastCutNormal1 = new Coord(); | ||
2484 | Coord lastCutNormal2 = new Coord(); | ||
2485 | float lastV = 1.0f; | ||
2486 | |||
2487 | bool done = false; | ||
2488 | while (!done) // loop through the length of the path and add the layers | ||
2489 | { | ||
2490 | bool isEndLayer = false; | ||
2491 | if (angle <= startAngle + .01f || angle >= endAngle - .01f) | ||
2492 | isEndLayer = true; | ||
2493 | |||
2494 | Profile newLayer = profile.Copy(); | ||
2495 | |||
2496 | float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; | ||
2497 | float yProfileScale = this.holeSizeY; | ||
2498 | |||
2499 | float percentOfPath = angle / (twoPi * this.revolutions); | ||
2500 | float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); | ||
2501 | |||
2502 | if (this.taperX > 0.01f) | ||
2503 | xProfileScale *= 1.0f - percentOfPath * this.taperX; | ||
2504 | else if (this.taperX < -0.01f) | ||
2505 | xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; | ||
2506 | |||
2507 | if (this.taperY > 0.01f) | ||
2508 | yProfileScale *= 1.0f - percentOfPath * this.taperY; | ||
2509 | else if (this.taperY < -0.01f) | ||
2510 | yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; | ||
2511 | |||
2512 | if (xProfileScale != 1.0f || yProfileScale != 1.0f) | ||
2513 | newLayer.Scale(xProfileScale, yProfileScale); | ||
2514 | |||
2515 | float radiusScale = 1.0f; | ||
2516 | if (this.radius > 0.001f) | ||
2517 | radiusScale = 1.0f - this.radius * percentOfPath; | ||
2518 | else if (this.radius < 0.001f) | ||
2519 | radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); | ||
2520 | |||
2521 | float twist = twistBegin + twistTotal * percentOfPath; | ||
2522 | |||
2523 | float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); | ||
2524 | xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; | ||
2525 | |||
2526 | float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; | ||
2527 | |||
2528 | float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; | ||
2529 | |||
2530 | // next apply twist rotation to the profile layer | ||
2531 | if (twistTotal != 0.0f || twistBegin != 0.0f) | ||
2532 | newLayer.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), twist)); | ||
2533 | |||
2534 | // now orient the rotation of the profile layer relative to it's position on the path | ||
2535 | // adding taperY to the angle used to generate the quat appears to approximate the viewer | ||
2536 | newLayer.AddRot(new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY)); | ||
2537 | newLayer.AddPos(xOffset, yOffset, zOffset); | ||
2538 | |||
2539 | if (isEndLayer && angle <= startAngle + .01f) | ||
2540 | { | ||
2541 | newLayer.FlipNormals(); | ||
2542 | |||
2543 | // add the top faces to the viewerFaces list here | ||
2544 | if (this.viewerMode && needEndFaces) | ||
2545 | { | ||
2546 | Coord faceNormal = newLayer.faceNormal; | ||
2547 | ViewerFace newViewerFace = new ViewerFace(); | ||
2548 | newViewerFace.primFaceNumber = 0; | ||
2549 | foreach (Face face in newLayer.faces) | ||
2550 | { | ||
2551 | newViewerFace.v1 = newLayer.coords[face.v1]; | ||
2552 | newViewerFace.v2 = newLayer.coords[face.v2]; | ||
2553 | newViewerFace.v3 = newLayer.coords[face.v3]; | ||
2554 | |||
2555 | newViewerFace.coordIndex1 = face.v1; | ||
2556 | newViewerFace.coordIndex2 = face.v2; | ||
2557 | newViewerFace.coordIndex3 = face.v3; | ||
2558 | |||
2559 | newViewerFace.n1 = faceNormal; | ||
2560 | newViewerFace.n2 = faceNormal; | ||
2561 | newViewerFace.n3 = faceNormal; | ||
2562 | |||
2563 | newViewerFace.uv1 = newLayer.faceUVs[face.v1]; | ||
2564 | newViewerFace.uv2 = newLayer.faceUVs[face.v2]; | ||
2565 | newViewerFace.uv3 = newLayer.faceUVs[face.v3]; | ||
2566 | |||
2567 | this.viewerFaces.Add(newViewerFace); | ||
2568 | } | ||
2569 | } | ||
2570 | } | ||
2571 | |||
2572 | // append the layer and fill in the sides | ||
2573 | |||
2574 | int coordsLen = this.coords.Count; | ||
2575 | newLayer.AddValue2FaceVertexIndices(coordsLen); | ||
2576 | |||
2577 | this.coords.AddRange(newLayer.coords); | ||
2578 | |||
2579 | if (this.calcVertexNormals) | ||
2580 | { | ||
2581 | newLayer.AddValue2FaceNormalIndices(this.normals.Count); | ||
2582 | this.normals.AddRange(newLayer.vertexNormals); | ||
2583 | } | ||
2584 | |||
2585 | if (isEndLayer) | ||
2586 | this.faces.AddRange(newLayer.faces); | ||
2587 | |||
2588 | // fill faces between layers | ||
2589 | |||
2590 | int numVerts = newLayer.coords.Count; | ||
2591 | Face newFace = new Face(); | ||
2592 | if (step > firstStep) | ||
2593 | { | ||
2594 | int startVert = coordsLen + 1; | ||
2595 | int endVert = this.coords.Count; | ||
2596 | |||
2597 | if (sides < 5 || this.hasProfileCut || hollow > 0.0f) | ||
2598 | startVert--; | ||
2599 | |||
2600 | for (int i = startVert; i < endVert; i++) | ||
2601 | { | ||
2602 | int iNext = i + 1; | ||
2603 | if (i == endVert - 1) | ||
2604 | iNext = startVert; | ||
2605 | |||
2606 | int whichVert = i - startVert; | ||
2607 | |||
2608 | newFace.v1 = i; | ||
2609 | newFace.v2 = i - numVerts; | ||
2610 | newFace.v3 = iNext - numVerts; | ||
2611 | this.faces.Add(newFace); | ||
2612 | |||
2613 | newFace.v2 = iNext - numVerts; | ||
2614 | newFace.v3 = iNext; | ||
2615 | this.faces.Add(newFace); | ||
2616 | |||
2617 | if (this.viewerMode) | ||
2618 | { | ||
2619 | int primFaceNumber = profile.faceNumbers[whichVert]; | ||
2620 | if (!needEndFaces) | ||
2621 | primFaceNumber -= 1; | ||
2622 | |||
2623 | // add the side faces to the list of viewerFaces here | ||
2624 | ViewerFace newViewerFace1 = new ViewerFace(primFaceNumber); | ||
2625 | ViewerFace newViewerFace2 = new ViewerFace(primFaceNumber); | ||
2626 | float u1 = newLayer.us[whichVert]; | ||
2627 | float u2 = 1.0f; | ||
2628 | if (whichVert < newLayer.us.Count - 1) | ||
2629 | u2 = newLayer.us[whichVert + 1]; | ||
2630 | |||
2631 | if (whichVert == cut1Vert || whichVert == cut2Vert) | ||
2632 | { | ||
2633 | u1 = 0.0f; | ||
2634 | u2 = 1.0f; | ||
2635 | } | ||
2636 | else if (sides < 5) | ||
2637 | { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled | ||
2638 | // to reflect the entire texture width | ||
2639 | u1 *= sides; | ||
2640 | u2 *= sides; | ||
2641 | u2 -= (int)u1; | ||
2642 | u1 -= (int)u1; | ||
2643 | if (u2 < 0.1f) | ||
2644 | u2 = 1.0f; | ||
2645 | |||
2646 | //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; | ||
2647 | } | ||
2648 | |||
2649 | newViewerFace1.uv1.U = u1; | ||
2650 | newViewerFace1.uv2.U = u1; | ||
2651 | newViewerFace1.uv3.U = u2; | ||
2652 | |||
2653 | newViewerFace1.uv1.V = 1.0f - percentOfPath; | ||
2654 | newViewerFace1.uv2.V = lastV; | ||
2655 | newViewerFace1.uv3.V = lastV; | ||
2656 | |||
2657 | newViewerFace2.uv1.U = u1; | ||
2658 | newViewerFace2.uv2.U = u2; | ||
2659 | newViewerFace2.uv3.U = u2; | ||
2660 | |||
2661 | newViewerFace2.uv1.V = 1.0f - percentOfPath; | ||
2662 | newViewerFace2.uv2.V = lastV; | ||
2663 | newViewerFace2.uv3.V = 1.0f - percentOfPath; | ||
2664 | |||
2665 | newViewerFace1.v1 = this.coords[i]; | ||
2666 | newViewerFace1.v2 = this.coords[i - numVerts]; | ||
2667 | newViewerFace1.v3 = this.coords[iNext - numVerts]; | ||
2668 | |||
2669 | newViewerFace2.v1 = this.coords[i]; | ||
2670 | newViewerFace2.v2 = this.coords[iNext - numVerts]; | ||
2671 | newViewerFace2.v3 = this.coords[iNext]; | ||
2672 | |||
2673 | newViewerFace1.coordIndex1 = i; | ||
2674 | newViewerFace1.coordIndex2 = i - numVerts; | ||
2675 | newViewerFace1.coordIndex3 = iNext - numVerts; | ||
2676 | |||
2677 | newViewerFace2.coordIndex1 = i; | ||
2678 | newViewerFace2.coordIndex2 = iNext - numVerts; | ||
2679 | newViewerFace2.coordIndex3 = iNext; | ||
2680 | |||
2681 | // profile cut faces | ||
2682 | if (whichVert == cut1Vert) | ||
2683 | { | ||
2684 | newViewerFace1.n1 = newLayer.cutNormal1; | ||
2685 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; | ||
2686 | |||
2687 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; | ||
2688 | newViewerFace2.n2 = lastCutNormal1; | ||
2689 | } | ||
2690 | else if (whichVert == cut2Vert) | ||
2691 | { | ||
2692 | newViewerFace1.n1 = newLayer.cutNormal2; | ||
2693 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; | ||
2694 | |||
2695 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; | ||
2696 | newViewerFace2.n2 = lastCutNormal2; | ||
2697 | } | ||
2698 | else // periphery faces | ||
2699 | { | ||
2700 | if (sides < 5 && whichVert < newLayer.numOuterVerts) | ||
2701 | { | ||
2702 | newViewerFace1.n1 = this.normals[i]; | ||
2703 | newViewerFace1.n2 = this.normals[i - numVerts]; | ||
2704 | newViewerFace1.n3 = this.normals[i - numVerts]; | ||
2705 | |||
2706 | newViewerFace2.n1 = this.normals[i]; | ||
2707 | newViewerFace2.n2 = this.normals[i - numVerts]; | ||
2708 | newViewerFace2.n3 = this.normals[i]; | ||
2709 | } | ||
2710 | else if (hollowSides < 5 && whichVert >= newLayer.numOuterVerts) | ||
2711 | { | ||
2712 | newViewerFace1.n1 = this.normals[iNext]; | ||
2713 | newViewerFace1.n2 = this.normals[iNext - numVerts]; | ||
2714 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | ||
2715 | |||
2716 | newViewerFace2.n1 = this.normals[iNext]; | ||
2717 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | ||
2718 | newViewerFace2.n3 = this.normals[iNext]; | ||
2719 | } | ||
2720 | else | ||
2721 | { | ||
2722 | newViewerFace1.n1 = this.normals[i]; | ||
2723 | newViewerFace1.n2 = this.normals[i - numVerts]; | ||
2724 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | ||
2725 | |||
2726 | newViewerFace2.n1 = this.normals[i]; | ||
2727 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | ||
2728 | newViewerFace2.n3 = this.normals[iNext]; | ||
2729 | } | ||
2730 | } | ||
2731 | |||
2732 | //newViewerFace1.primFaceNumber = newViewerFace2.primFaceNumber = newLayer.faceNumbers[whichVert]; | ||
2733 | this.viewerFaces.Add(newViewerFace1); | ||
2734 | this.viewerFaces.Add(newViewerFace2); | ||
2735 | |||
2736 | } | ||
2737 | } | ||
2738 | } | ||
2739 | |||
2740 | lastCutNormal1 = newLayer.cutNormal1; | ||
2741 | lastCutNormal2 = newLayer.cutNormal2; | ||
2742 | lastV = 1.0f - percentOfPath; | ||
2743 | |||
2744 | // calculate terms for next iteration | ||
2745 | // calculate the angle for the next iteration of the loop | ||
2746 | |||
2747 | if (angle >= endAngle - 0.01) | ||
2748 | done = true; | ||
2749 | else | ||
2750 | { | ||
2751 | step += 1; | ||
2752 | angle = stepSize * step; | ||
2753 | if (angle > endAngle) | ||
2754 | angle = endAngle; | ||
2755 | } | ||
2756 | |||
2757 | if (done && viewerMode && needEndFaces) | ||
2758 | { | ||
2759 | // add the bottom faces to the viewerFaces list here | ||
2760 | Coord faceNormal = newLayer.faceNormal; | ||
2761 | ViewerFace newViewerFace = new ViewerFace(); | ||
2762 | //newViewerFace.primFaceNumber = newLayer.bottomFaceNumber + 1; | ||
2763 | newViewerFace.primFaceNumber = newLayer.bottomFaceNumber; | ||
2764 | foreach (Face face in newLayer.faces) | ||
2765 | { | ||
2766 | newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; | ||
2767 | newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; | ||
2768 | newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; | ||
2769 | |||
2770 | newViewerFace.coordIndex1 = face.v1 - coordsLen; | ||
2771 | newViewerFace.coordIndex2 = face.v2 - coordsLen; | ||
2772 | newViewerFace.coordIndex3 = face.v3 - coordsLen; | ||
2773 | |||
2774 | newViewerFace.n1 = faceNormal; | ||
2775 | newViewerFace.n2 = faceNormal; | ||
2776 | newViewerFace.n3 = faceNormal; | ||
2777 | |||
2778 | newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; | ||
2779 | newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; | ||
2780 | newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; | ||
2781 | |||
2782 | this.viewerFaces.Add(newViewerFace); | ||
2783 | } | ||
2784 | } | ||
2785 | } | ||
2786 | } | 1962 | } |
2787 | 1963 | ||
1964 | |||
2788 | private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) | 1965 | private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) |
2789 | { | 1966 | { |
2790 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); | 1967 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); |