public RaycastResult?Raycast(Vector3 start, Vector3 dir) { float tFirst = (float)double.PositiveInfinity; Vector3?currPoint = null; Vector3?currNorm = null; foreach (OctreeNode octbox in OctreeNode.m_List) { //The condition glitches at times and since a stage model has less than //about 2500 polygons, it's not worth fixing right now. if (true /*octbox.IntersectsRay(ref start, ref dir)*/) { for (int i = 0; i < octbox.m_PlaneList.Count; ++i) { if (octbox.m_PlaneList[i] >= m_Planes.Count) { continue; } ColFace tri = m_Planes[octbox.m_PlaneList[i]]; //Find point of intersection float dot = Vector3.Dot(tri.normal, dir); if (dot >= 0) { continue; //Either they don't intersect or they graze. No grazes allowed here! } float t = Vector3.Dot(tri.normal, tri.point1 - start) / dot; if (t < 0 || t > 1 || t >= tFirst) { continue; //Nope! Gotta hit the plane! (or too far back) } //Find out if the intersection point is inside the triangle. Vector3 intersection = dir * t + start; Vector3 basisX = tri.point2 - tri.point1, basisY = tri.point3 - tri.point1, intFromPoint1 = intersection - tri.point1; //OpenTK got rid of a function that multiplies a matrix3 by a vector3 Matrix3 planeBasis = new Matrix3(basisX.X, basisY.X, tri.normal.X, basisX.Y, basisY.Y, tri.normal.Y, basisX.Z, basisY.Z, tri.normal.Z).Inverted(); Vector3 resultant = planeBasis.Column0 * intFromPoint1.X + planeBasis.Column1 * intFromPoint1.Y + planeBasis.Column2 * intFromPoint1.Z; if (resultant.X >= 0 && resultant.Y >= 0 && (resultant.X + resultant.Y) <= 1) { currPoint = intersection; currNorm = tri.normal; tFirst = t; } } } } return(currPoint != null ? (RaycastResult?)new RaycastResult((Vector3)currPoint, (Vector3)currNorm, tFirst) : null); }
public KCL(NitroFile file) { m_File = file; m_Planes = new List <ColFace>(); m_PointsSectionOffset = m_File.Read32(0x00); m_NormalsSectionOffset = m_File.Read32(0x04); m_PlanesSectionOffset = m_File.Read32(0x08); m_OctreeSectionOffset = m_File.Read32(0x0C); int planeid = 0; for (uint offset = m_PlanesSectionOffset + 0x10; offset < m_OctreeSectionOffset; offset += 0x10) { uint length = m_File.Read32(offset); ushort pt_id = m_File.Read16(offset + 0x04); int pt_x = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id * 12))); int pt_y = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id * 12) + 4)); int pt_z = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id * 12) + 8)); ushort nr_id = m_File.Read16(offset + 0x06); short nr_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id * 6))); short nr_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id * 6) + 2)); short nr_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id * 6) + 4)); ushort d1_id = m_File.Read16(offset + 0x08); short d1_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id * 6))); short d1_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id * 6) + 2)); short d1_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id * 6) + 4)); ushort d2_id = m_File.Read16(offset + 0x0A); short d2_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id * 6))); short d2_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id * 6) + 2)); short d2_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id * 6) + 4)); ushort d3_id = m_File.Read16(offset + 0x0C); short d3_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id * 6))); short d3_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id * 6) + 2)); short d3_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id * 6) + 4)); ColFace plane = new ColFace((float)(length / 65536000f), new Vector3((float)pt_x / 64000f, (float)pt_y / 64000f, (float)pt_z / 64000f), new Vector3((float)nr_x / 1024f, (float)nr_y / 1024f, (float)nr_z / 1024f), new Vector3((float)d1_x / 1024f, (float)d1_y / 1024f, (float)d1_z / 1024f), new Vector3((float)d2_x / 1024f, (float)d2_y / 1024f, (float)d2_z / 1024f), new Vector3((float)d3_x / 1024f, (float)d3_y / 1024f, (float)d3_z / 1024f), m_File.Read16(offset + 0x0E)); /* if (planeid == 31) * MessageBox.Show(string.Format("PLANE 32:\n{0}\n{1}\n{2}\n\n{3}\n{4}\n{5}\n\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}", * d1_x, d1_y, d1_z, * d2_x, d2_y, d2_z, * plane.m_Position, plane.m_Normal, plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Length));*/ planeid++; /* if (Math.Abs(plane.m_Dir1.Length - 1f) > 0.0001f || Math.Abs(plane.m_Dir2.Length - 1f) > 0.0001f || * Math.Abs(plane.m_Dir3.Length - 1f) > 0.0001f || Math.Abs(plane.m_Normal.Length - 1f) > 0.0001f || * plane.m_Length < 0f) * MessageBox.Show(string.Format("WRONG PLANE | {0} | {1} | {2} | {3} | {4}", * plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); * * if (plane.m_Dir1.Length < 0.001f || plane.m_Dir2.Length < 0.001f || * plane.m_Dir3.Length < 0.001f || plane.m_Normal.Length < 0.001f || * Math.Abs(plane.m_Length) < 0.001f) * MessageBox.Show(string.Format("ZERO PLANE | {0} | {1} | {2} | {3} | {4}", * plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); * * Vector3 lol1 = Vector3.Cross(plane.m_Dir1, plane.m_Normal); * float lol1len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol1, plane.m_Dir3)))); * Vector3 lol2 = Vector3.Cross(plane.m_Normal, plane.m_Dir2); * float lol2len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol2, plane.m_Dir3)))); * if (Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol1, lol1len)) || * Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol2, lol2len))) * MessageBox.Show(string.Format("WEIRD PLANE {5:X8} | {0} | {1} | {2} | {3} | {4}\n{6} | {7} / cos(acos({8})) = cos({9}) = {10}", * plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Normal, plane.m_Length, * offset, lol2, plane.m_Length, Vector3.Dot(lol2, plane.m_Dir3), Math.Acos(Vector3.Dot(lol2, plane.m_Dir3)), Math.Cos(Math.Acos(Vector3.Dot(lol2, plane.m_Dir3))))); */ m_Planes.Add(plane); } OctreeNode.maxkids = 0; int shift = (int)m_File.Read32(0x2C); Vector3 octreestart = new Vector3((float)(int)m_File.Read32(0x14) / 64000f, (float)(int)m_File.Read32(0x18) / 64000f, (float)(int)m_File.Read32(0x1C) / 64000f); float _cubesize = (float)(1 << shift) / 1024f; Vector3 cubesize = new Vector3(_cubesize, _cubesize, _cubesize); Vector3 octreesize = new Vector3((~m_File.Read32(0x20) >> shift) + 1, (~m_File.Read32(0x24) >> shift) + 1, (~m_File.Read32(0x28) >> shift) + 1); OctreeNode.m_List = new List <OctreeNode>(); uint loloffset = m_OctreeSectionOffset; for (int z = 0; z < octreesize.Z; z++) { for (int y = 0; y < octreesize.Y; y++) { for (int x = 0; x < octreesize.X; x++) { new OctreeNode(m_File, m_OctreeSectionOffset, loloffset, octreestart + new Vector3(cubesize.X * x, cubesize.Y * y, cubesize.Z * z), cubesize); loloffset += 4; } } } //MessageBox.Show(OctreeNode.m_List.Count.ToString()); }
public KCL(NitroFile file) { m_File = file; m_Planes = new List<ColFace>(); m_PointsSectionOffset = m_File.Read32(0x00); m_NormalsSectionOffset = m_File.Read32(0x04); m_PlanesSectionOffset = m_File.Read32(0x08); m_OctreeSectionOffset = m_File.Read32(0x0C); int planeid = 0; for (uint offset = m_PlanesSectionOffset + 0x10; offset < m_OctreeSectionOffset; offset += 0x10) { uint length = m_File.Read32(offset); ushort pt_id = m_File.Read16(offset + 0x04); int pt_x = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id*12) )); int pt_y = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id*12) + 4)); int pt_z = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id*12) + 8)); ushort nr_id = m_File.Read16(offset + 0x06); short nr_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id*6) )); short nr_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id*6) + 2)); short nr_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id*6) + 4)); ushort d1_id = m_File.Read16(offset + 0x08); short d1_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id*6) )); short d1_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id*6) + 2)); short d1_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id*6) + 4)); ushort d2_id = m_File.Read16(offset + 0x0A); short d2_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id*6) )); short d2_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id*6) + 2)); short d2_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id*6) + 4)); ushort d3_id = m_File.Read16(offset + 0x0C); short d3_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id*6) )); short d3_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id*6) + 2)); short d3_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id*6) + 4)); ColFace plane = new ColFace((float)(length / 65536000f), new Vector3((float)pt_x / 64000f, (float)pt_y / 64000f, (float)pt_z / 64000f), new Vector3((float)nr_x / 1024f, (float)nr_y / 1024f, (float)nr_z / 1024f), new Vector3((float)d1_x / 1024f, (float)d1_y / 1024f, (float)d1_z / 1024f), new Vector3((float)d2_x / 1024f, (float)d2_y / 1024f, (float)d2_z / 1024f), new Vector3((float)d3_x / 1024f, (float)d3_y / 1024f, (float)d3_z / 1024f), m_File.Read16(offset + 0x0E)); /* if (planeid == 31) MessageBox.Show(string.Format("PLANE 32:\n{0}\n{1}\n{2}\n\n{3}\n{4}\n{5}\n\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}", d1_x, d1_y, d1_z, d2_x, d2_y, d2_z, plane.m_Position, plane.m_Normal, plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Length));*/ planeid++; /* if (Math.Abs(plane.m_Dir1.Length - 1f) > 0.0001f || Math.Abs(plane.m_Dir2.Length - 1f) > 0.0001f || Math.Abs(plane.m_Dir3.Length - 1f) > 0.0001f || Math.Abs(plane.m_Normal.Length - 1f) > 0.0001f || plane.m_Length < 0f) MessageBox.Show(string.Format("WRONG PLANE | {0} | {1} | {2} | {3} | {4}", plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); if (plane.m_Dir1.Length < 0.001f || plane.m_Dir2.Length < 0.001f || plane.m_Dir3.Length < 0.001f || plane.m_Normal.Length < 0.001f || Math.Abs(plane.m_Length) < 0.001f) MessageBox.Show(string.Format("ZERO PLANE | {0} | {1} | {2} | {3} | {4}", plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); Vector3 lol1 = Vector3.Cross(plane.m_Dir1, plane.m_Normal); float lol1len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol1, plane.m_Dir3)))); Vector3 lol2 = Vector3.Cross(plane.m_Normal, plane.m_Dir2); float lol2len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol2, plane.m_Dir3)))); if (Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol1, lol1len)) || Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol2, lol2len))) MessageBox.Show(string.Format("WEIRD PLANE {5:X8} | {0} | {1} | {2} | {3} | {4}\n{6} | {7} / cos(acos({8})) = cos({9}) = {10}", plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Normal, plane.m_Length, offset, lol2, plane.m_Length, Vector3.Dot(lol2, plane.m_Dir3), Math.Acos(Vector3.Dot(lol2, plane.m_Dir3)), Math.Cos(Math.Acos(Vector3.Dot(lol2, plane.m_Dir3))))); */ m_Planes.Add(plane); } OctreeNode.maxkids = 0; int shift = (int)m_File.Read32(0x2C); Vector3 octreestart = new Vector3((float)(int)m_File.Read32(0x14) / 64000f, (float)(int)m_File.Read32(0x18) / 64000f, (float)(int)m_File.Read32(0x1C) / 64000f); float _cubesize = (float)(1 << shift) / 1024f; Vector3 cubesize = new Vector3(_cubesize, _cubesize, _cubesize); Vector3 octreesize = new Vector3((~m_File.Read32(0x20) >> shift) + 1, (~m_File.Read32(0x24) >> shift) + 1, (~m_File.Read32(0x28) >> shift) + 1); OctreeNode.m_List = new List<OctreeNode>(); uint loloffset = m_OctreeSectionOffset; for (int z = 0; z < octreesize.Z; z++) for (int y = 0; y < octreesize.Y; y++) for (int x = 0; x < octreesize.X; x++) { new OctreeNode(m_File, m_OctreeSectionOffset, loloffset, octreestart + new Vector3(cubesize.X * x, cubesize.Y * y, cubesize.Z * z), cubesize); loloffset += 4; } //MessageBox.Show(OctreeNode.m_List.Count.ToString()); }