public unsafe void PlaneFieldOffsetTest() { Plane *ptr = (Plane *)0; Assert.Equal(new IntPtr(0), new IntPtr(&ptr->Normal)); Assert.Equal(new IntPtr(12), new IntPtr(&ptr->D)); }
public unsafe bool IsBox(out Vector3 dimensions, out Vector3 center) { dimensions = new Vector3(); center = new Vector3(); if (_faceCount != 12) { return(false); } Plane *planes = stackalloc Plane[6]; var vbStream = _vb.Map(MapType.Read); var ibStream = _ib.Map(MapType.Read); CreateBoxPlanes(planes, 6, vbStream, ibStream); /* * A box must have 4 orthogonal an one paraller plane to every plane conforming the box */ for (int i = 0; i < 6; i++) { int ortoCount = 0; int parallerCount = 0; for (int j = 0; j < 6; j++) { if (i == j) { continue; } var dot = Vector3.Dot(planes[i].Normal, planes[j].Normal); if (dot == 0 || dot.IsZero()) { ortoCount++; } else if (dot == -1 || dot.IsEqual(-1)) { parallerCount++; } } if (parallerCount != 1 || ortoCount != 4) { _vb.Unmap(); _ib.Unmap(); return(false); } } FindDimensions(vbStream, out center, out dimensions); _vb.Unmap(); _ib.Unmap(); return(true); }
public void Init() { p = (Plane *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <Plane>() * 10000, UnsafeUtility.AlignOf <Plane>(), Allocator.Persistent); for (int i = 0; i < 10000; ++i) { p[i] = new Plane { NormalAndDistance = new float4(1.0f) }; } }
public unsafe bool IsPlane(out Plane plane) { plane = new Plane(); if (_faceCount != 2) { return(false); } var vbStream = _vb.Map(MapType.Read); var ibStream = _ib.Map(MapType.Read); Plane *planes = stackalloc Plane[2]; try { int posOffset = VertexDescriptor.OffsetOf(IASemantic.Position, 0); int size = VertexDescriptor.Size; byte *vbPter = (byte *)vbStream + posOffset; byte *ibPter = (byte *)ibStream; for (int iface = 0; iface < _faceCount; iface++) { Vector3 p0; Vector3 p1; Vector3 p2; if (_is16BitIndices) { p0 = *(Vector3 *)(vbPter + size * ((short *)ibPter)[iface * 3]); p1 = *(Vector3 *)(vbPter + size * ((short *)ibPter)[iface * 3 + 1]); p2 = *(Vector3 *)(vbPter + size * ((short *)ibPter)[iface * 3 + 2]); } else { p0 = *(Vector3 *)(vbPter + size * ((int *)ibPter)[iface * 3]); p1 = *(Vector3 *)(vbPter + size * ((int *)ibPter)[iface * 3 + 1]); p2 = *(Vector3 *)(vbPter + size * ((int *)ibPter)[iface * 3 + 2]); } planes[iface] = new Plane(p0, p1, p2); } } finally { _vb.Unmap(); _ib.Unmap(); } if (Plane.Equals(planes[0], planes[1])) { plane = planes[0]; return(true); } return(false); }
public void Init() { rng = new Random(1); p = (Plane *)UnsafeUtility.Malloc(UnsafeUtility.SizeOf <Plane>() * iterations, UnsafeUtility.AlignOf <Plane>(), Allocator.Persistent); for (int i = 0; i < iterations; ++i) { p[i] = new Plane { NormalAndDistance = new float4(1.0f) }; } }
private unsafe bool Contains(Plane *planes, int size, Plane p) { for (int i = 0; i < size; i++) { if (Plane.Equals(planes[i], p)) { return(true); } } return(false); }
public unsafe void PlaneFieldOffsetTest() { Plane plane = new Plane(); float *basePtr = &plane.Normal.X; // Take address of first element Plane *planePtr = &plane; // Take address of whole Plane Assert.Equal(new IntPtr(basePtr), new IntPtr(planePtr)); Assert.Equal(new IntPtr(basePtr + 0), new IntPtr(&plane.Normal)); Assert.Equal(new IntPtr(basePtr + 3), new IntPtr(&plane.D)); }
public ContainmentType Contains(Vector3 *point) { Plane *planes = (Plane *)Unsafe.AsPointer(ref _planes); // Is this safe? for (int i = 0; i < 6; i++) { if (Plane.DotCoordinate(planes[i], *point) < 0) { return(ContainmentType.Disjoint); } } return(ContainmentType.Contains); }
public ContainmentType Contains(ref BoundingBox box) { Plane *planes = (Plane *)Unsafe.AsPointer(ref _planes); ContainmentType result = ContainmentType.Contains; for (int i = 0; i < 6; i++) { Plane plane = planes[i]; // Approach: http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html Vector3 positive = new Vector3(box.Minimum.X, box.Minimum.Y, box.Minimum.Z); Vector3 negative = new Vector3(box.Maximum.X, box.Maximum.Y, box.Maximum.Z); if (plane.Normal.X >= 0) { positive.X = box.Maximum.X; negative.X = box.Minimum.X; } if (plane.Normal.Y >= 0) { positive.Y = box.Maximum.Y; negative.Y = box.Minimum.Y; } if (plane.Normal.Z >= 0) { positive.Z = box.Maximum.Z; negative.Z = box.Minimum.Z; } // If the positive vertex is outside (behind plane), the box is disjoint. float positiveDistance = Plane.DotCoordinate(plane, positive); if (positiveDistance < 0) { return(ContainmentType.Disjoint); } // If the negative vertex is outside (behind plane), the box is intersecting. // Because the above check failed, the positive vertex is in front of the plane, // and the negative vertex is behind. Thus, the box is intersecting this plane. float negativeDistance = Plane.DotCoordinate(plane, negative); if (negativeDistance < 0) { result = ContainmentType.Intersects; } } return(result); }
public ContainmentType Contains(BoundingSphere sphere) { Plane *planes = (Plane *)Unsafe.AsPointer(ref _planes); ContainmentType result = ContainmentType.Contains; for (int i = 0; i < 6; i++) { float distance = Plane.DotCoordinate(planes[i], sphere.Center); if (distance < -sphere.Radius) { return(ContainmentType.Disjoint); } else if (distance < sphere.Radius) { result = ContainmentType.Intersects; } } return(result); }
unsafe private void CreateBoxPlanes(Plane *planes, int planesCount, IntPtr vbStream, IntPtr ibStream) { int posOffset = VertexDescriptor.OffsetOf(IASemantic.Position, 0); int size = VertexDescriptor.Size; byte *vbPter = (byte *)vbStream + posOffset; byte *ibPter = (byte *)ibStream; int k = 0; for (int iface = 0; iface < _faceCount; iface++) { Vector3 p0; Vector3 p1; Vector3 p2; if (_is16BitIndices) { p0 = *(Vector3 *)(vbPter + size * ((short *)ibPter)[iface * 3]); p1 = *(Vector3 *)(vbPter + size * ((short *)ibPter)[iface * 3 + 1]); p2 = *(Vector3 *)(vbPter + size * ((short *)ibPter)[iface * 3 + 2]); } else { p0 = *(Vector3 *)(vbPter + size * ((int *)ibPter)[iface * 3]); p1 = *(Vector3 *)(vbPter + size * ((int *)ibPter)[iface * 3 + 1]); p2 = *(Vector3 *)(vbPter + size * ((int *)ibPter)[iface * 3 + 2]); } var facePlane = new Plane(p0, p1, p2); if (!Contains(planes, planesCount, facePlane)) { if (k >= planesCount) { throw new IndexOutOfRangeException(); } planes[k++] = facePlane; } } }
private static void GetCullingPlanes(ref Matrix4x4 invVp, Plane *frustumPlanes) { Vector3 nearLeftButtom = invVp.MultiplyPoint(new Vector3(-1, -1, 1)); Vector3 nearLeftTop = invVp.MultiplyPoint(new Vector3(-1, 1, 1)); Vector3 nearRightButtom = invVp.MultiplyPoint(new Vector3(1, -1, 1)); Vector3 nearRightTop = invVp.MultiplyPoint(new Vector3(1, 1, 1)); Vector3 farLeftButtom = invVp.MultiplyPoint(new Vector3(-1, -1, 0)); Vector3 farLeftTop = invVp.MultiplyPoint(new Vector3(-1, 1, 0)); Vector3 farRightButtom = invVp.MultiplyPoint(new Vector3(1, -1, 0)); Vector3 farRightTop = invVp.MultiplyPoint(new Vector3(1, 1, 0)); //Near frustumPlanes[0] = new Plane(nearRightTop, nearRightButtom, nearLeftButtom); //Up frustumPlanes[1] = new Plane(farLeftTop, farRightTop, nearRightTop); //Down frustumPlanes[2] = new Plane(nearRightButtom, farRightButtom, farLeftButtom); //Left frustumPlanes[3] = new Plane(farLeftButtom, farLeftTop, nearLeftTop); //Right frustumPlanes[4] = new Plane(farRightButtom, nearRightButtom, nearRightTop); //Far frustumPlanes[5] = new Plane(farLeftButtom, farRightButtom, farRightTop); }
public unsafe void Conjugate(Plane *input, Plane *output, int count) { Detail.sw012(false, &input->P0, P1, default, &output->P0, count);
private unsafe void UpdateIndexBufferCPU(CCommandList cmd, Graphics.CGfxCamera Camera) { if (mCpuDrawIndexBuffer == null) { return; } CBMeshBatch cbMesh = new CBMeshBatch(); { var pPlanes = stackalloc Plane[6]; Camera.CullingFrustum.GetPlanes(pPlanes); CBMeshBatch *pCBuffer = &cbMesh; Plane * planesTar = (Plane *)pCBuffer; for (uint i = 0; i < 6; i++) { planesTar[i] = pPlanes[i]; } cbMesh.GpuDrivenCameraPosition = Camera.CullingFrustum.TipPos; BoundingBox box = new BoundingBox(); Camera.CullingFrustum.GetBoundBox(ref box); cbMesh.GpuDrivenFrustumMinPoint = box.Minimum; cbMesh.GpuDrivenFrustumMaxPoint = box.Maximum; cbMesh.MeshBatchVertexStride = (uint)AllVertices.Count; cbMesh.ClusterNumber = (uint)GpuClusters.Count; UpdateCBMeshbatch(cmd, Camera); } UInt32_3 tri = new UInt32_3(); mDrawIndices.Clear(); for (int i = 0; i < GpuClusters.Count; i++) { var cluster = GpuClusters[i]; var GpuDrivenCameraDirection = GpuClusters[i].BoundCenter - cbMesh.GpuDrivenCameraPosition; var cameraDirInBoundSpace = Vector3.TransposeTransformNormal(GpuDrivenCameraDirection, GpuInstanceDatas[(int)cluster.InstanceId].InvMatrix); if (FrustumCull(ref cluster, ref cbMesh) == false) { UInt64 visBits = 0; if (cameraDirInBoundSpace.X >= 0) { visBits |= cluster.CubeFaces[(int)Cluster.GpuCluster.ECubeFace.CubeFace_NX]; } else { visBits |= cluster.CubeFaces[(int)Cluster.GpuCluster.ECubeFace.CubeFace_X]; } if (cameraDirInBoundSpace.Y >= 0) { visBits |= cluster.CubeFaces[(int)Cluster.GpuCluster.ECubeFace.CubeFace_NY]; } else { visBits |= cluster.CubeFaces[(int)Cluster.GpuCluster.ECubeFace.CubeFace_Y]; } if (cameraDirInBoundSpace.Z >= 0) { visBits |= cluster.CubeFaces[(int)Cluster.GpuCluster.ECubeFace.CubeFace_NZ]; } else { visBits |= cluster.CubeFaces[(int)Cluster.GpuCluster.ECubeFace.CubeFace_Z]; } uint InstanceStartIndex = cbMesh.MeshBatchVertexStride * cluster.InstanceId; for (int j = 0; j < cluster.FaceCount; j++) { if (TestBit(visBits, j) == false) { continue; } int srcIndex = (int)(cluster.StartFaceIndex + j) * 3; tri.x = InstanceStartIndex + AllIndices[srcIndex]; tri.y = InstanceStartIndex + AllIndices[srcIndex + 1]; tri.z = InstanceStartIndex + AllIndices[srcIndex + 2]; mDrawIndices.Add(tri); } } } mDrawArgs.InstanceCount = 1; mDrawArgs.IndexCountPerInstance = (uint)mDrawIndices.Count * 3; uint size = (uint)(mDrawIndices.Count * sizeof(UInt32_3)); if (mCpuDrawIndexBuffer.Desc.ByteWidth > size) { mCpuDrawIndexBuffer.UpdateBuffData(cmd, mDrawIndices.GetBufferPtr(), size); } }
public unsafe void GetPlanes(Plane *pPlanes) { SDK_v3dxFrustum_GetPlanes(CoreObject, pPlanes); }
public unsafe void Conjugate(Plane *input, Plane *output, int count) { Detail.sw012(true, &input->P0, P1, P2, &output->P0, count); }
public unsafe extern static Plane *D3DXPlaneScale(Plane *pOut, Plane *pP, float s);
public unsafe extern static Vector3 *D3DXPlaneIntersectLine(Vector3 *pOut, Plane *pP, Vector3 *pV1, Vector3 *pV2);
// If we resort the vertexes so all silverts come first, we can save some work here. public unsafe static LocalTrace R_LocalTrace(Vector3 start, Vector3 end, float radius, SrfTriangles tri) { int i, j; Plane * planes = stackalloc Plane[4]; LocalTrace hit = new(); int c_testEdges, c_testPlanes, c_intersect; Vector3 startDir; byte totalOr; float radiusSqr; var tri_verts = tri.verts.Value; var tri_indexes = tri.indexes.Value; var tri_facePlanes = tri.facePlanes.Value; #if TEST_TRACE Stopwatch trace_timer = new(); trace_timer.Start(); #endif hit.fraction = 1f; // create two planes orthogonal to each other that intersect along the trace startDir = end - start; startDir.Normalize(); startDir.NormalVectors(out planes[0].Normal, out planes[1].Normal); planes[0].d = -start * planes[0].Normal; planes[1].d = -start * planes[1].Normal; // create front and end planes so the trace is on the positive sides of both planes[2] = startDir; planes[2].d = -start * planes[2].Normal; planes[3] = -startDir; planes[3].d = -end * planes[3].Normal; // catagorize each point against the four planes var cullBits = stackalloc byte[tri.numVerts]; fixed(DrawVert *vertsD = tri_verts) Simd.TracePointCull(cullBits, out totalOr, radius, planes, vertsD, tri.numVerts); // if we don't have points on both sides of both the ray planes, no intersection if (((totalOr ^ (totalOr >> 4)) & 3) != 0) /*common.Printf("nothing crossed the trace planes\n");*/ return { (hit); } // if we don't have any points between front and end, no intersection if (((totalOr ^ (totalOr >> 1)) & 4) != 0) /*common.Printf("trace didn't reach any triangles\n");*/ return { (hit); } // scan for triangles that cross both planes c_testPlanes = c_testEdges = c_intersect = 0; radiusSqr = MathX.Square(radius); startDir = end - start; if (tri.facePlanes == null || !tri.facePlanesCalculated) { R_DeriveFacePlanes(tri); } for (i = 0, j = 0; i < tri.numIndexes; i += 3, j++) { float d1, d2, f, d, edgeLengthSqr; byte triOr; Vector3 cross, edge; Vector3[] dir = new Vector3[3]; // get sidedness info for the triangle triOr = cullBits[tri_indexes[i + 0]]; triOr |= cullBits[tri_indexes[i + 1]]; triOr |= cullBits[tri_indexes[i + 2]]; // if we don't have points on both sides of both the ray planes, no intersection if (((triOr ^ (triOr >> 4)) & 3) != 0) { continue; } // if we don't have any points between front and end, no intersection if (((triOr ^ (triOr >> 1)) & 4) != 0) { continue; } c_testPlanes++; ref Plane plane = ref tri_facePlanes[j]; d1 = plane.Distance(start); d2 = plane.Distance(end); if (d1 <= d2) { continue; // comning at it from behind or parallel } if (d1 < 0f) { continue; // starts past it } if (d2 > 0f) { continue; // finishes in front of it } f = d1 / (d1 - d2); if (f < 0f) { continue; // shouldn't happen } if (f >= hit.fraction) { continue; // have already hit something closer } c_testEdges++; // find the exact point of impact with the plane var point = start + f * startDir; // see if the point is within the three edges if radius > 0 the triangle is expanded with a circle in the triangle plane dir[0] = tri_verts[tri_indexes[i + 0]].xyz - point; dir[1] = tri_verts[tri_indexes[i + 1]].xyz - point; cross = dir[0].Cross(dir[1]); d = plane.Normal * cross; if (d > 0f) { if (radiusSqr <= 0f) { continue; } edge = tri_verts[tri_indexes[i + 0]].xyz - tri_verts[tri_indexes[i + 1]].xyz; edgeLengthSqr = edge.LengthSqr; if (cross.LengthSqr > edgeLengthSqr * radiusSqr) { continue; } d = edge * dir[0]; if (d < 0f) { edge = tri_verts[tri_indexes[i + 0]].xyz - tri_verts[tri_indexes[i + 2]].xyz; d = edge * dir[0]; if (d < 0f && dir[0].LengthSqr > radiusSqr) { continue; } } else if (d > edgeLengthSqr) { edge = tri_verts[tri_indexes[i + 1]].xyz - tri_verts[tri_indexes[i + 2]].xyz; d = edge * dir[1]; if (d < 0f && dir[1].LengthSqr > radiusSqr) { continue; } } } dir[2] = tri_verts[tri_indexes[i + 2]].xyz - point; cross = dir[1].Cross(dir[2]); d = plane.Normal * cross; if (d > 0f) { if (radiusSqr <= 0f) { continue; } edge = tri_verts[tri_indexes[i + 1]].xyz - tri_verts[tri_indexes[i + 2]].xyz; edgeLengthSqr = edge.LengthSqr; if (cross.LengthSqr > edgeLengthSqr * radiusSqr) { continue; } d = edge * dir[1]; if (d < 0f) { edge = tri_verts[tri_indexes[i + 1]].xyz - tri_verts[tri_indexes[i + 0]].xyz; d = edge * dir[1]; if (d < 0f && dir[1].LengthSqr > radiusSqr) { continue; } } else if (d > edgeLengthSqr) { edge = tri_verts[tri_indexes[i + 2]].xyz - tri_verts[tri_indexes[i + 0]].xyz; d = edge * dir[2]; if (d < 0f && dir[2].LengthSqr > radiusSqr) { continue; } } } cross = dir[2].Cross(dir[0]); d = plane.Normal * cross; if (d > 0f) { if (radiusSqr <= 0f) { continue; } edge = tri_verts[tri_indexes[i + 2]].xyz - tri_verts[tri_indexes[i + 0]].xyz; edgeLengthSqr = edge.LengthSqr; if (cross.LengthSqr > edgeLengthSqr * radiusSqr) { continue; } d = edge * dir[2]; if (d < 0f) { edge = tri_verts[tri_indexes[i + 2]].xyz - tri_verts[tri_indexes[i + 1]].xyz; d = edge * dir[2]; if (d < 0f && dir[2].LengthSqr > radiusSqr) { continue; } } else if (d > edgeLengthSqr) { edge = tri_verts[tri_indexes[i + 0]].xyz - tri_verts[tri_indexes[i + 1]].xyz; d = edge * dir[0]; if (d < 0f && dir[0].LengthSqr > radiusSqr) { continue; } } } // we hit it c_intersect++; hit.fraction = f; hit.normal = plane.Normal; hit.point = point; hit.indexes[0] = tri_indexes[i]; hit.indexes[1] = tri_indexes[i + 1]; hit.indexes[2] = tri_indexes[i + 2]; }