107 lines
3.8 KiB
C#
107 lines
3.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Aiwaz.Contracts;
|
|
using SlimDX;
|
|
|
|
namespace Aiwaz.Resources
|
|
{
|
|
public class PickHull : IPickHull
|
|
{
|
|
private VertexElement positionElement;
|
|
private int strideToPosition;
|
|
|
|
private DataStream vertexData;
|
|
private int vertexCount;
|
|
private VertexElement[] vertexElements;
|
|
private int vertexElementSize;
|
|
|
|
private DataStream indexData;
|
|
private int indexCount;
|
|
|
|
private Vector3 boxMaxVector;
|
|
private Vector3 boxMinVector;
|
|
|
|
public PickHull(DataStream vertexData, int vertexCount, VertexElement[] vertexElements, DataStream indexData, int indexCount)
|
|
{
|
|
this.vertexData = vertexData;
|
|
this.vertexCount = vertexCount;
|
|
this.vertexElements = vertexElements;
|
|
this.indexData = indexData;
|
|
this.indexCount = indexCount;
|
|
|
|
this.vertexElementSize = (int)vertexData.Length / vertexCount;
|
|
|
|
this.positionElement = vertexElements.First(e => e.WellKnownFormat == VertexElement.Format.Position);
|
|
foreach (var element in vertexElements)
|
|
{
|
|
if (!element.Equals(positionElement))
|
|
strideToPosition += element.Size;
|
|
else
|
|
break;
|
|
}
|
|
|
|
this.Precalculate();
|
|
}
|
|
|
|
public bool TryPick(Ray pickRay, Matrix worldMatrix, out float distance)
|
|
{
|
|
distance = float.MaxValue;
|
|
|
|
var boundingSphere = CalcBoundingSphere(worldMatrix);
|
|
if (!Ray.Intersects(pickRay, boundingSphere, out distance))
|
|
return false;
|
|
|
|
distance = float.MaxValue;
|
|
indexData.Position = 0;
|
|
for (var i = 0; i < indexCount / 3; ++i)
|
|
{
|
|
var triangle = new Vector3[3];
|
|
triangle[0] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read<uint>()), worldMatrix);
|
|
triangle[1] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read<uint>()), worldMatrix);
|
|
triangle[2] = Vector3.TransformCoordinate(this.GetPositionFromData(indexData.Read<uint>()), worldMatrix);
|
|
|
|
float newDistance;
|
|
if (!Ray.Intersects(pickRay, triangle[0], triangle[1], triangle[2], out newDistance)
|
|
|| newDistance > distance)
|
|
continue;
|
|
distance = newDistance;
|
|
}
|
|
|
|
return distance != float.MaxValue;
|
|
}
|
|
|
|
private Vector3 GetPositionFromData(uint index)
|
|
{
|
|
vertexData.Position = index * vertexElementSize + strideToPosition;
|
|
return vertexData.Read<Vector3>();
|
|
}
|
|
|
|
protected void Precalculate()
|
|
{
|
|
boxMinVector = Vector3.Zero;
|
|
boxMaxVector = Vector3.Zero;
|
|
for (uint i = 0; i < vertexCount; ++i)
|
|
{
|
|
boxMinVector = i == 0 ? this.GetPositionFromData(i) : Vector3.Maximize(boxMinVector, this.GetPositionFromData(i));
|
|
boxMaxVector = i == 0 ? this.GetPositionFromData(i) : Vector3.Minimize(boxMaxVector, this.GetPositionFromData(i));
|
|
}
|
|
}
|
|
|
|
public BoundingSphere CalcBoundingSphere(Matrix worldMatrix)
|
|
{
|
|
var centerPosition = Vector3.TransformCoordinate(Vector3.Zero, worldMatrix);
|
|
var maxVec = Vector3.TransformCoordinate(boxMaxVector, worldMatrix);
|
|
return new BoundingSphere(centerPosition, maxVec.Length());
|
|
}
|
|
|
|
public BoundingBox CalcBoundingBox(Matrix worldMatrix)
|
|
{
|
|
var minVec = Vector3.TransformCoordinate(boxMinVector, worldMatrix);
|
|
var maxVec = Vector3.TransformCoordinate(boxMaxVector, worldMatrix);
|
|
return new BoundingBox(minVec, maxVec);
|
|
}
|
|
}
|
|
}
|