光线跟踪C#三角形交点
所以基本上我想在三角形上反射光线。这是我的雷课光线跟踪C#三角形交点,c#,.net,geometry,linear-algebra,raytracing,C#,.net,Geometry,Linear Algebra,Raytracing,所以基本上我想在三角形上反射光线。这是我的雷课 public sealed class Ray { public readonly Point3D Source; public readonly Point3D Direction; public readonly Color Light; public Ray(Point3D source, Point3D direction, Color light) { if (source ==
public sealed class Ray
{
public readonly Point3D Source;
public readonly Point3D Direction;
public readonly Color Light;
public Ray(Point3D source, Point3D direction, Color light)
{
if (source == direction)
{
throw new ArgumentException("Source and Direction cannot be equal");
}
this.Source = source;
this.Direction = direction;
this.Light = light;
}
}
这是我的Point3D课程
public struct Point3D : IEquatable<Point3D>
{
public static readonly Point3D Zero = new Point3D();
public float X;
public float Y;
public float Z;
public Point3D(float x, float y, float z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public override bool Equals(object obj)
{
if (!(obj is Point3D))
{
return false;
}
return this.Equals((Point3D)obj);
}
public static bool operator ==(Point3D one, Point3D two)
{
return one.Equals(two);
}
public static bool operator !=(Point3D one, Point3D two)
{
return !one.Equals(two);
}
public static Point3D operator *(float n, Point3D v)
{
return new Point3D(v.X * n, v.Y * n, v.Z * n);
}
public static Point3D operator +(Point3D v1, Point3D v2)
{
return new Point3D(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
}
public static Point3D operator -(Point3D v1, Point3D v2)
{
return new Point3D(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
}
public static float operator *(Point3D v1, Point3D v2)
{
return (v1.X * v2.X) + (v1.Y * v2.Y) + (v1.Z * v2.Z);
}
public static float Magnitude(Point3D v)
{
return (float)Math.Sqrt(v * v);
}
public static Point3D Normalize(Point3D v)
{
float mag = Magnitude(v);
float div = (mag == 0) ? float.PositiveInfinity : (1 / mag);
return div * v;
}
public static Point3D Cross(Point3D v1, Point3D v2)
{
return new Point3D(((v1.Y * v2.Z) - (v1.Z * v2.Y)),
((v1.Z * v2.X) - (v1.X * v2.Z)),
((v1.X * v2.Y) - (v1.Y * v2.X)));
}
/// <summary>
/// doesnt take square root
/// </summary>
public static float FastDistance(Point3D v1, Point3D v2)
{
float x = v1.X - v2.X;
x *= x;
float y = v1.Y - v2.Y;
y *= y;
float z = v1.Z - v2.Z;
z *= z;
return x + y + z;
}
/// <summary>
/// Takes square root:
/// </summary>
public static float Distance(Point3D v1, Point3D v2)
{
return (float)Math.Sqrt(Point3D.FastDistance(v1, v2));
}
public override int GetHashCode()
{
return this.X.GetHashCode()
^ this.Y.GetHashCode()
^ this.Y.GetHashCode();
}
public override string ToString()
{
return this.X + ", " + this.Y + ", " + this.Z;
}
public bool Equals(Point3D other)
{
return this.X == other.X
&& this.Y == other.Y
&& this.Z == other.Z;
}
}
public struct Point3D:IEquatable
{
public static readonly Point3D Zero=new Point3D();
公共浮动X;
公众浮躁;
公共浮动Z;
公共点3D(浮点x、浮点y、浮点z)
{
这个.X=X;
这个。Y=Y;
这个。Z=Z;
}
公共覆盖布尔等于(对象对象对象)
{
如果(!(对象是Point3D))
{
返回false;
}
返回此.Equals((Point3D)obj);
}
公共静态布尔运算符==(点3D 1,点3D 2)
{
返回1。等于(2);
}
公共静态布尔运算符!=(点3D 1,点3D 2)
{
返回!1。等于(2);
}
公共静态Point3D操作符*(浮点n,Point3D v)
{
返回新的点3d(v.X*n,v.Y*n,v.Z*n);
}
公共静态Point3D操作符+(Point3D v1,Point3D v2)
{
返回新的Point3D(v1.X+v2.X,v1.Y+v2.Y,v1.Z+v2.Z);
}
公共静态Point3D操作符-(Point3D v1,Point3D v2)
{
返回新的Point3D(v1.X-v2.X,v1.Y-v2.Y,v1.Z-v2.Z);
}
公共静态浮点运算符*(Point3D v1,Point3D v2)
{
返回(v1.X*v2.X)+(v1.Y*v2.Y)+(v1.Z*v2.Z);
}
公共静态浮动幅度(点3D v)
{
返回(浮点)数学Sqrt(v*v);
}
公共静态Point3D规范化(Point3D v)
{
浮动磁极=幅值(v);
float div=(mag==0)?float.PositiveInfinity:(1/mag);
返回div*v;
}
公共静态Point3D交叉(Point3D v1、Point3D v2)
{
返回新的Point3D(((v1.Y*v2.Z)-(v1.Z*v2.Y)),
((v1.Z*v2.X)-(v1.X*v2.Z)),
((v1.X*v2.Y)-(v1.Y*v2.X));
}
///
///不取平方根
///
公共静态浮点快速距离(Point3D v1、Point3D v2)
{
浮动x=v1.x-v2.x;
x*=x;
浮动y=v1.y-v2.y;
y*=y;
float z=v1.z-v2.z;
z*=z;
返回x+y+z;
}
///
///取平方根:
///
公共静态浮动距离(Point3D v1、Point3D v2)
{
返回(浮点)Math.Sqrt(Point3D.FastDistance(v1,v2));
}
公共覆盖int GetHashCode()
{
返回此.X.GetHashCode()
^this.Y.GetHashCode()
^这个.Y.GetHashCode();
}
公共重写字符串ToString()
{
返回此.X+”、“+this.Y+”、“+this.Z”;
}
公共布尔等于(点3D其他)
{
返回这个.X==other.X
&&this.Y==其他.Y
&&this.Z==other.Z;
}
}
最后,我需要在这里实现我的方法
public interface ITriangleAccess
{
Triangle3D Find(Ray ray, out Point3D crossPoint);
}
public sealed class TriangleAccess : ITriangleAccess
{
private readonly List<KeyValuePair<float, Triangle3D>> trianglesByX;
private readonly List<Triangle3D> allTriangles;
public TriangleAccess(Body[] bodies)
{
if (null == bodies)
{
throw new ArgumentNullException("bodies");
}
this.allTriangles = bodies.SelectMany((x) => x.Parts).ToList();
this.trianglesByX = bodies.SelectMany((x) => x.Parts).SelectMany((y) => new KeyValuePair<float, Triangle3D>[]
{
new KeyValuePair<float,Triangle3D>(y.Point1.X,y),
new KeyValuePair<float,Triangle3D>(y.Point2.X,y),
new KeyValuePair<float,Triangle3D>(y.Point3.X,y)
}).ToList();
}
public Triangle3D Find(Ray ray, out Point3D crossPoint)
{
crossPoint = Point3D.Zero;
List<Triangle3D> relevant = this.GetRelevantTriangles(ray);
Triangle3D absoluteTriangle = null;
float min = float.MaxValue;
foreach (Triangle3D item in relevant)
{
Point3D currentCrossPoint;
if (this.RayIntersectTriangle(ray, item, out currentCrossPoint))
{
float distance = Point3D.Distance(ray.Source, currentCrossPoint);
if (distance < min)
{
absoluteTriangle = item;
crossPoint = currentCrossPoint;
min = distance;
}
}
}
return absoluteTriangle;
}
public Ray Reflect(Ray ray, Point3D crossPoint, Triangle3D intersect)
{
//need this to be realized
//please help
}
/// <summary>
/// TODO: Finish this Up:
/// </summary>
/// <param name="ray"></param>
/// <returns></returns>
private List<Triangle3D> GetRelevantTriangles(Ray ray)
{
return this.allTriangles;
}
private bool RayIntersectTriangle(Ray ray, Triangle3D triangle, out Point3D crossPoint)
{
// Find vectors for two edges sharing vert0
Point3D edge1 = triangle.Point2 - triangle.Point1;
Point3D edge2 = triangle.Point3 - triangle.Point1;
// Begin calculating determinant - also used to calculate barycentricU parameter
Point3D pvec = Point3D.Cross(ray.Direction, edge2);
// If determinant is near zero, ray lies in plane of triangle
float det = edge1 * pvec;
if (det < 0.0001f)
{
crossPoint = Point3D.Zero;
return false;
}
// Calculate distance from vert0 to ray origin
Point3D tvec = ray.Source - triangle.Point1;
// Calculate barycentricU parameter and test bounds
float barycentricU = tvec * pvec;
if (barycentricU < 0.0f || barycentricU > det)
{
crossPoint = Point3D.Zero;
return false;
}
// Prepare to test barycentricV parameter
Point3D qvec = Point3D.Cross(tvec, edge1);
// Calculate barycentricV parameter and test bounds
float barycentricV = ray.Direction * qvec;
if (barycentricV < 0.0f || barycentricU + barycentricV > det)
{
crossPoint = Point3D.Zero;
return false;
}
// Calculate pickDistance, scale parameters, ray intersects triangle
float pickDistance = edge2 * qvec;
float fInvDet = 1.0f / det;
pickDistance *= fInvDet;
barycentricU *= fInvDet;
barycentricV *= fInvDet;
crossPoint = MathHelper.BaryCentric(triangle, barycentricU, barycentricV);
return true;
}
}
公共接口ITriangleAccess
{
三角形3D查找(光线、点外3D交叉点);
}
公共密封类三角形访问:ITriangleAccess
{
私有只读列表三角形Byx;
私有只读列表所有三角形;
公共访问(正文[]正文)
{
if(null==实体)
{
抛出新的异常(“实体”);
}
this.allTriangles=body.SelectMany((x)=>x.Parts.ToList();
this.trianglesByX=body.SelectMany((x)=>x.Parts.SelectMany((y)=>newkeyvaluepair[]
{
新的KeyValuePair(y.Point1.X,y),
新的KeyValuePair(y.Point2.X,y),
新的KeyValuePair(y.Point3.X,y)
}).ToList();
}
公共三角形3D查找(光线、出点3D交叉点)
{
交叉点=点3d.Zero;
List relevant=this.GetRelevantTriangles(光线);
三角形3D绝对三角形=空;
float min=float.MaxValue;
foreach(相关文件中的三角形3D项目)
{
点3D电流交叉点;
if(此.RayIntersect三角形(光线、项目、out currentCrossPoint))
{
浮动距离=点3D.距离(射线源、当前交叉点);
如果(距离<分钟)
{
绝对三角形=项目;
交叉点=当前交叉点;
最小值=距离;
}
}
}
返回绝对三角形;
}
公共光线反射(光线、点3D交叉点、三角形3D相交)
{
//需要实现这一点吗
//请帮忙
}
///
///TODO:完成此操作:
///
///
///
私有列表获取相关三角形(光线)
{
返回这个.allTriangles;
}
私有布尔光线相交三角形(光线、三角形3D三角形、点外3D交叉点)
{
//查找共享顶点0的两条边的向量
Point3D edge1=triangle.Point2-triangle.Point1;
Point3D edge2=triangle.Point3-triangle.Point1;
//开始计算行列式-也用于计算重心参数
Point3D pvec=Point3D.Cross(光线方向,边2);
//若行列式接近零,则光线位于三角形平面内
浮点数=边缘1*pvec;
如果(det<0.0001f)
{
交叉点=点3d.Zero;
返回false;
}
//计算从顶点0到光线原点的距离
Point3D tvec=射线源-三角形点1;
//计算重心参数和测试边界
浮球重心=tvec*pvec;
如果(重心<0.0f | |重心>det)
{
交叉点=点3d.Zero;
返回false;
}
//准备测试重心参数
Point3D qvec=Point3D.Cross(tvec,edge1);
//计算重心参数和测试边界
浮动重心=射线方向*qvec;
如果(重心<0.0f | |重心+重心>det)
{
交叉点=点3d.Zero;
返回false;
}
//算计
public Ray Reflect(Ray ray, Point3D crossPoint, Triangle3D intersect)
{
Point3D V = -ray.Direction.Normalize();
return new Ray(crossPoint,
V - 2 * intersect.Normal * (V * intersect.Normal),
Color.white);
}
public Ray Reflect(Ray ray, Point3D crossPoint, Triangle3D intersect)
{
// find normal of intersect triangle
Point3D normal = Point3D.Cross( intersect.Point2 - intersect.Point1,
intersect.Point3 - intersect.Point1 );
normal = Point3D.Normalize( normal );
// find ray part before intersection
Point3D inbound = crossPoint - ray.Source;
// find projection of inbound ray to normal
Point3D projection = (normal * inbound) * normal;
// find lateral component of inbound ray
Point3D lateral = inbound - projection;
// find outbound direction
Point3D direction = (ray.Source + 2 * lateral) - crossPoint;
direction = Point3D.Normalize( direction );
// I assume your direction is unit vector (magnitude = 1)
// if not multiply it with magnitude you want to be
// direction = ... * direction;
return new Ray( crossPoint, direction, ray.Color );
}