public static RoadVertex operator*(RoadVertex v, float f) { RoadVertex ret = v; ret.pos *= f; ret.norm *= f; ret.uv *= f; Vector4 texSel = ret.texSelect.ToVector4(); texSel *= f; ret.texSelect = new Color(texSel); return(ret); }
public static RoadVertex operator+(RoadVertex v0, RoadVertex v1) { RoadVertex ret = v0; ret.pos += v1.pos; ret.norm += v1.norm; ret.uv += v1.uv; Vector4 v0TexSel = v0.texSelect.ToVector4(); Vector4 v1TexSel = v1.texSelect.ToVector4(); v0TexSel += v1TexSel; ret.texSelect = new Color(v0TexSel); return(ret); }
/// <summary> /// Generate (if necessary) an interpolated vertex, returning the index /// for the vertex based on this barycentric coordinate /// </summary> /// <param name="vtxData"></param> /// <param name="bary"></param> /// <param name="idx0"></param> /// <param name="idx1"></param> /// <param name="idx2"></param> /// <returns></returns> static protected Int16 AddVertex(List <RoadVertex> vtxData, Vector3 bary, Int16 idx0, Int16 idx1, Int16 idx2) { if ((bary.X == 1.0f) && (bary.Y == 0.0f) && (bary.Z == 0.0f)) { // original first vert return(idx0); } else if ((bary.X == 0.0f) && (bary.Y == 1.0f) && (bary.Z == 0.0f)) { // original second vert return(idx1); } else if ((bary.X == 0.0f) && (bary.Y == 0.0f) && (bary.Z == 1.0f)) { // original third vert return(idx2); } RoadVertex vtx0 = vtxData[idx0]; RoadVertex vtx1 = vtxData[idx1]; RoadVertex vtx2 = vtxData[idx2]; RoadVertex newVtx = vtx0 * bary.X + vtx1 * bary.Y + vtx2 * bary.Z; vtxData.Add(newVtx); return((Int16)(vtxData.Count - 1)); }
/// <summary> /// Generate a list of indices for the input geometry trimmed to the exterior /// of the planes in the list. /// This is a convex trim, for a concave trim, rather than trimming the output /// of one plane, you would trim the rejects of the previous trim. /// Convex trim: /// slice geometry at plane[0] boundary /// discard geometry on negative side of plane[0] /// slice positive side geometry at plane[1] boundary /// discard geometry on negative side of plane[1] /// [repeat for rest of planes] /// Concave trim: /// slice geometry at plane[0] boundary /// accept geometry on positive side of plane[0] /// slice negative side geometry at plane[1] boundary /// accept positive side geometry of plane[1] /// slice negative side geometry at plane[2] boundary /// accept positive side geometry of plane[2] /// [repeat for rest of planes] /// </summary> /// <param name="planes"></param> /// <param name="idxIn"></param> /// <param name="idxOut"></param> /// <param name="vtxData"></param> /// <returns></returns> static public bool TrimIndexedTriList(List <Vector4> planes, List <Int16> idxIn, List <Int16> idxOut, List <RoadVertex> vtxData) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; UInt32 numIndicesIn = (UInt32)idxIn.Count; UInt32 numTrisIn = numIndicesIn / 3; // Hardcoding for IndexElemetnSize.SixteenBits / Int16 Debug.Assert(numTrisIn * 3 == numIndicesIn); idxOut.Clear(); UInt32 numVertsIn = (UInt32)vtxData.Count; List <Vector3> baryIn = new List <Vector3>(3); List <Vector3> baryOut = new List <Vector3>(3); bool anyTrimmed = false; // for each plane foreach (Vector4 plane in planes) { // for each triangle for (int iTri = 0; iTri < numTrisIn; iTri++) { Int16 idx0 = idxIn[iTri * 3 + 0]; Int16 idx1 = idxIn[iTri * 3 + 1]; Int16 idx2 = idxIn[iTri * 3 + 2]; RoadVertex vtx0 = vtxData[idx0]; RoadVertex vtx1 = vtxData[idx1]; RoadVertex vtx2 = vtxData[idx2]; baryIn.Clear(); baryIn.Add(new Vector3(1.0f, 0.0f, 0.0f)); baryIn.Add(new Vector3(0.0f, 1.0f, 0.0f)); baryIn.Add(new Vector3(0.0f, 0.0f, 1.0f)); baryOut.Clear(); // Run the triangle through the trimmer bool trimmed = Trim(vtx0.pos, vtx1.pos, vtx2.pos, baryIn, baryOut, plane); // if the triangle wasn't trimmed anyTrimmed = anyTrimmed || trimmed; if (!trimmed) { // Copy the indices as is into the output list idxOut.Add(idx0); idxOut.Add(idx1); idxOut.Add(idx2); } else if (baryOut.Count > 2) { // We've been trimmed, but we still have non-zero count of // vertices, which means we contain new vertices. // We could get clever here and tell which vertices are new // and which have been generated, or we can be lazy and just // assume all are new. // In either case, we append any new vertices to the end of // the vertex list, and add the new indices to the output list Int16 idxPivot = AddVertex(vtxData, baryOut[0], idx0, idx1, idx2); Int16 idxLast = AddVertex(vtxData, baryOut[1], idx0, idx1, idx2); Int16 idxNext = AddVertex(vtxData, baryOut[2], idx0, idx1, idx2); idxOut.Add(idxPivot); idxOut.Add(idxLast); idxOut.Add(idxNext); for (int iBary = 3; iBary < baryOut.Count; ++iBary) { idxLast = idxNext; idxNext = AddVertex(vtxData, baryOut[iBary], idx0, idx1, idx2); idxOut.Add(idxPivot); idxOut.Add(idxLast); idxOut.Add(idxNext); } anyTrimmed = true; } // else the whole triangle was culled } } return(anyTrimmed); }
protected virtual bool NewFan( Road.Intersection isect, Vector2 startRadial, double rads, List <Road.RenderObj> fans) { Road road = isect.Road; int numRadials = (int)Math.Ceiling(rads / road.RadStep); double radStep = rads / numRadials; Vector2 center = isect.Node.Position2d; int vertsPerRadial = VertsPerStep / 2; int numVerts = (numRadials + 1) * vertsPerRadial + 1; RoadVertex[] verts = new RoadVertex[numVerts]; Vector3 terrNormal = Vector3.UnitZ; AABB box = AABB.EmptyBox(); int iVert = 0; for (int iRadial = 0; iRadial <= numRadials; ++iRadial) { double ang = radStep * iRadial; float cos = (float)Math.Cos(ang); float sin = (float)Math.Sin(ang); Vector2 radial = new Vector2(startRadial.X * cos - startRadial.Y * sin, startRadial.X * sin + startRadial.Y * cos); for (int iOut = 0; iOut < vertsPerRadial; ++iOut) { float width = widthTable[iOut]; float height = heightTable[iOut]; float arc = (float)(ang * width); RoadVertex vtx = new RoadVertex(); Vector2 pos = center + width * radial; //float baseHeight = isect.BaseHeight(pos); //height += baseHeight; vtx.pos.X = pos.X; vtx.pos.Y = pos.Y; vtx.pos.Z = height; box.Union(vtx.pos); vtx.norm = VtxNormal(terrNormal, radial, iOut); vtx.uv.X = arc; vtx.uv.Y = distTable[iOut]; vtx.texSelect = TexSelect(iOut); verts[iVert++] = vtx; } } float centerBaseHeight = 0.0f; // isect.BaseHeight(center); float heightAtCenter = centerHeight + centerBaseHeight; RoadVertex last = new RoadVertex(); last.pos.X = center.X; last.pos.Y = center.Y; last.pos.Z = heightAtCenter; box.Union(last.pos); last.norm = terrNormal; last.uv.X = 0.0f; last.uv.Y = 0.0f; last.texSelect = TexSelect(0); int centerIdx = iVert++; verts[centerIdx] = last; Debug.Assert(iVert == numVerts); // First step per radial is a single tri, // then the rest of the steps are quads int quadsPerRadial = vertsPerRadial - 1; int numTris = 0; if (!skipTable[0]) { numTris += numRadials; numTris += numRadials * (quadsPerRadial - numSkips) * 2; } else { numTris += numRadials * (quadsPerRadial - (numSkips - 1)) * 2; } Int16[] indices = new Int16[numTris * 3]; int nextRad = vertsPerRadial; int nextOut = 1; int baseVtx = 0; int idx = 0; for (int iRadial = 0; iRadial < numRadials; ++iRadial) { if (!skipTable[0]) { indices[idx++] = (Int16)(baseVtx); indices[idx++] = (Int16)(centerIdx); indices[idx++] = (Int16)(baseVtx + nextRad); } for (int iOut = 0; iOut < quadsPerRadial; iOut++) { if (!skipTable[iOut + 1]) { indices[idx++] = (Int16)(baseVtx + iOut + nextRad); indices[idx++] = (Int16)(baseVtx + iOut + nextRad + nextOut); indices[idx++] = (Int16)(baseVtx + iOut); indices[idx++] = (Int16)(baseVtx + iOut); indices[idx++] = (Int16)(baseVtx + iOut + nextRad + nextOut); indices[idx++] = (Int16)(baseVtx + iOut + nextOut); } } baseVtx += nextRad; } Debug.Assert(idx == numTris * 3); RoadStdRenderObj ro = null; if ((verts.Length > 0) && (indices.Length > 0)) { ro = new RoadStdRenderObj(); ro.Verts = verts; ro.Indices = indices; ro.DiffuseTex0 = diffTex0; ro.DiffuseTex1 = diffTex1; ro.NormalTex0 = normTex0; ro.NormalTex1 = normTex1; ro.UVXfm = uvXfm; ro.Shininess = Shininess; ro.Sphere = box.MakeSphere(); fans.Add(ro); return(true); } return(false); }
/// <summary> /// Generate the vertex data for a (straight) section of road. /// </summary> /// <param name="section"></param> /// <returns></returns> protected RoadVertex[] GenVerts(Road.Section section) { Vector2 p0 = section.Edge.Node0.Position2d; Vector2 p1 = section.Edge.Node1.Position2d; Vector2 axis = p1 - p0; float len = axis.Length(); axis /= len; Vector2 norm = new Vector2(-axis.Y, axis.X); float step = Road.Step; numSteps = Math.Max(1, (int)Math.Ceiling(len / step)); step = len / (float)numSteps; int vertsPerHalfStep = VertsPerStep / 2; int baseVertex = 0; RoadVertex[] verts = new RoadVertex[(numSteps + 1) * VertsPerStep]; for (int iStep = 0; iStep <= numSteps; ++iStep) { Vector2 posCen = p0 + axis * step * iStep; Vector3 terrNormal = Vector3.UnitZ; // line it up with direction of travel by subtracting out component // along norm. //vtxNormal.X -= vtxNormal.X * norm.X; //vtxNormal.Y -= vtxNormal.Y * norm.Y; //vtxNormal.Normalize(); // Negative side for (int iVert = vertsPerHalfStep - 1; iVert >= 0; --iVert) { float width = widthTable[iVert]; float height = heightTable[iVert]; Vector2 pos = new Vector2( posCen.X - norm.X * width, posCen.Y - norm.Y * width); //float baseHeight = section.BaseHeight(pos); //height += baseHeight; verts[baseVertex].pos.X = pos.X; verts[baseVertex].pos.Y = pos.Y; verts[baseVertex].pos.Z = height; verts[baseVertex].norm = VtxNormal(terrNormal, -norm, iVert); verts[baseVertex].uv.X = step * iStep; verts[baseVertex].uv.Y = distTable[iVert]; verts[baseVertex].texSelect = TexSelect(iVert); ++baseVertex; } // Center float centerBaseHeight = 0.0f; // section.BaseHeight(posCen); float heightAtCenter = centerHeight + centerBaseHeight; verts[baseVertex].pos.X = posCen.X; verts[baseVertex].pos.Y = posCen.Y; verts[baseVertex].pos.Z = heightAtCenter; verts[baseVertex].norm = terrNormal; verts[baseVertex].uv.X = step * iStep; verts[baseVertex].uv.Y = 0.0f; verts[baseVertex].texSelect = TexSelect(0); ++baseVertex; // Positive side for (int iVert = 0; iVert < vertsPerHalfStep; ++iVert) { float width = widthTable[iVert]; float height = heightTable[iVert]; Vector2 pos = new Vector2( posCen.X + norm.X * width, posCen.Y + norm.Y * width); //float baseHeight = section.BaseHeight(pos); //height += baseHeight; verts[baseVertex].pos.X = pos.X; verts[baseVertex].pos.Y = pos.Y; verts[baseVertex].pos.Z = height; verts[baseVertex].norm = VtxNormal(terrNormal, norm, iVert); verts[baseVertex].uv.X = step * iStep; verts[baseVertex].uv.Y = distTable[iVert]; verts[baseVertex].texSelect = TexSelect(iVert); ++baseVertex; } } return(verts); }