public override bool FindIntersection(Ray ray, out Intersection intersect) { intersect = new Intersection(); Vector3D v = ray.Origin - this.center; float pdotuA = v * this.axisA; float pdotuB = v * this.axisB; float pdotuC = v * this.axisC; float udotuA = ray.Direction * this.axisA; float udotuB = ray.Direction * this.axisB; float udotuC = ray.Direction * this.axisC; float C = (pdotuA * pdotuA) + (pdotuB * pdotuB) + (pdotuC * pdotuC) - 1.0f; float B = (pdotuA * udotuA + pdotuB * udotuB + pdotuC * udotuC); if (C > 0.0f && B >= 0.0f) { return(false); // Pointing away from the ellipsoid } B += B; // Double B to get final factor of 2. float A = (udotuA * udotuA) + (udotuB * udotuB) + (udotuC * udotuC); float alpha1, alpha2; int numRoots = EquationSolver.SolveQuadric(A, B, C, out alpha1, out alpha2); if (numRoots == 0) { return(false); } if (alpha1 > 0.01f) { // Found an intersection from outside. intersect.TMin = alpha1; intersect.TMax = alpha2; intersect.HitFromInSide = false; } else if (numRoots == 2 && alpha2 > 0.01f) { // Found an intersection from inside. intersect.TMin = alpha2; intersect.TMax = alpha1; intersect.HitFromInSide = true; } else { return(false); // Both intersections behind us (should never get here) } // Calculate intersection position intersect.HitPoint = ray.Origin + intersect.TMin * ray.Direction; intersect.Normal = intersect.HitPoint - this.center; // Now v is the relative position float vdotuA = intersect.Normal * this.axisA; float vdotuB = intersect.Normal * this.axisB; float vdotuC = intersect.Normal * this.axisC; intersect.Normal = vdotuA * this.axisA + vdotuB * this.axisB + vdotuC * this.axisC; intersect.Normal.Normalize(); intersect.HitPrimitive = this; if (this.material != null && this.material.IsTexturized) { double uCoord = Math.Atan2(-vdotuB, vdotuA) * (1.0 / (Math.PI + Math.PI)); double vCoord = 1.0 - Math.Cos(-vdotuC) * (1.0 / Math.PI); if (uCoord < 0.0) { uCoord++; } //int widthTex = this.material.Texture.Width - 1; //int heightTex = this.material.Texture.Height - 1; //this.material.Color = this.material.Texture.GetPixel((int)(uCoord * widthTex), (int)(vCoord * heightTex)); intersect.CurrentTextureCoordinate.U = (float)uCoord; intersect.CurrentTextureCoordinate.V = (float)vCoord; } return(true); }
public override bool FindIntersection(Ray ray, out Intersection intersect) { intersect = new Intersection(); Vector3D rayDir = ray.Direction; Point3D rayPoint = ray.Origin; //this->boundingBox->intersect(line, point, normal, u, v); //if(!(*point)) //{ // *point = 0; // *normal = 0; // return; //} //@see: http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter4.htm float Aq_1 = this.a * (rayDir.X * rayDir.X); float Aq_2 = this.b * (rayDir.Y * rayDir.Y); float Aq_3 = this.c * (rayDir.Z * rayDir.Z); float Aq_4 = this.d * rayDir.X * rayDir.Y; float Aq_5 = this.e * rayDir.X * rayDir.Z; float Aq_6 = this.f * rayDir.Y * rayDir.Z; float Bq_1 = 2 * this.a * rayPoint.X * rayDir.X; float Bq_2 = 2 * this.b * rayPoint.Y * rayDir.Y; float Bq_3 = 2 * this.c * rayPoint.Z * rayDir.Z; float Bq_4 = this.d * ((rayPoint.X * rayDir.Y) + (rayPoint.Y * rayDir.X)); float Bq_5 = this.e * rayPoint.X * rayDir.Z; float Bq_6 = this.f * ((rayPoint.Y * rayDir.Z) + (rayDir.Y * rayPoint.Z)); float Bq_7 = this.g * rayDir.X; float Bq_8 = this.h * rayDir.Y; float Bq_9 = this.i * rayDir.Z; float Cq_1 = this.a * (rayPoint.X * rayPoint.X); float Cq_2 = this.b * (rayPoint.Y * rayPoint.Y); float Cq_3 = this.c * (rayPoint.Z * rayPoint.Z); float Cq_4 = this.d * rayPoint.X * rayPoint.Y; float Cq_5 = this.e * rayPoint.X * rayPoint.Z; float Cq_6 = this.f * rayPoint.Y * rayPoint.Z; float Cq_7 = this.g * rayPoint.X; float Cq_8 = this.h * rayPoint.Y; float Cq_9 = this.i * rayPoint.Z; float Aq = Aq_1 + Aq_2 + Aq_3 + Aq_4 + Aq_5 + Aq_6; float Bq = Bq_1 + Bq_2 + Bq_3 + Bq_4 + Bq_5 + Bq_6 + Bq_7 + Bq_8 + Bq_9; float Cq = Cq_1 + Cq_2 + Cq_3 + Cq_4 + Cq_5 + Cq_6 + Cq_7 + Cq_8 + Cq_9 + this.j; //quadratic equation: Aqt² + Bqt + Cq = 0 float t, t0, t1, tMin, tMax; if (EquationSolver.SolveQuadric(Aq, Bq, Cq, out t0, out t1) == 0) { return(false); } tMin = (float)Math.Min(t0, t1); tMax = (float)Math.Max(t0, t1); if (tMin > 0.01f) { t = tMin; } else if (tMax > 0.01f) { t = tMax; } else { return(false); } Point3D tempP = rayPoint + rayDir * t; //if (!this.boundBox.IsInside(tempP) && tMax > 0) //{ // tempP = rayPoint + rayDir * tMax; //} //bool isInsideBox = this->boundingBox->checkCollision(Box(tempP.getX(), tempP.getY(), tempP.getZ(), // tempP.getX(), tempP.getY(), tempP.getZ())); //if(!isInsideBox && t == tMin && tMax > 0) //{ // tempP = (*rayPoint) + ((*rayDir) * tMax); // isInsideBox = this->boundingBox->checkCollision(Box(tempP.getX(), tempP.getY(), tempP.getZ(), // tempP.getX(), tempP.getY(), tempP.getZ())); //} //if(isInsideBox) //{ //*point = new Point(tempP.getX(), tempP.getY(), tempP.getZ()); //calculating normal float nX1 = 2 * this.a * tempP.X; float nX2 = this.d * tempP.Y; float nX3 = this.e * tempP.Z; float nY1 = 2 * this.b * tempP.Y; float nY2 = this.d * tempP.X; float nY3 = this.f * tempP.Z; float nZ1 = 2 * this.c * tempP.Z; float nZ2 = this.e * tempP.X; float nZ3 = this.f * tempP.Y; float normalX = nX1 + nX2 + nX3 + this.g; float normalY = nY1 + nY2 + nY3 + this.h; float normalZ = nZ1 + nZ2 + nZ3 + this.i; intersect.Normal = new Vector3D(normalX, normalY, normalZ); intersect.Normal.Normalize(); intersect.HitPoint = tempP; intersect.HitPrimitive = this; intersect.TMin = t; return(true); //} }
public override bool FindIntersection(Ray ray, out Intersection intersect) { intersect = new Intersection(); float maxFrontDist = float.NegativeInfinity; float minBackDist = float.PositiveInfinity; HitSide frontType = HitSide.None, backType = HitSide.None; // 0, 1 = base, side float viewPosdotCtr = ray.Origin * this.centralAxis; float udotuCtr = ray.Direction * this.centralAxis; if (viewPosdotCtr > (this.apexDotCenterAxis) && udotuCtr >= 0.0f) { return(false); // Above the cone's apex } // Start with the bounding base plane float pdotnCap = this.baseNormal * ray.Origin; float udotnCap = this.baseNormal * ray.Direction; if (pdotnCap > this.coefBasePlane) { if (udotnCap >= 0.0f) { return(false); // Above (=outside) base plane, pointing away } maxFrontDist = (this.coefBasePlane - pdotnCap) / udotnCap; frontType = HitSide.BottomPlane; } else if (pdotnCap < this.coefBasePlane) { if (udotnCap > 0.0f) { // Below (=inside) base plane, pointing towards the plane minBackDist = (this.coefBasePlane - pdotnCap) / udotnCap; backType = HitSide.BottomPlane; } } // Now handle the cone's sides Vector3D v = ray.Origin - this.apex; float pdotuCtr = v * this.centralAxis; float pdotuA = v * this.axisA; float pdotuB = v * this.axisB; // udotuCtr already defined above float udotuA = ray.Direction * this.axisA; float udotuB = ray.Direction * this.axisB; float C = pdotuA * pdotuA + pdotuB * pdotuB - pdotuCtr * pdotuCtr; float B = (pdotuA * udotuA + pdotuB * udotuB - pdotuCtr * udotuCtr); B += B; float A = udotuA * udotuA + udotuB * udotuB - udotuCtr * udotuCtr; float alpha1, alpha2; // The roots, in order int numRoots = EquationSolver.SolveQuadric(A, B, C, out alpha1, out alpha2); if (numRoots == 0) { return(false); // No intersection } bool viewMoreVertical = (A < 0.0f); if (viewMoreVertical) { // View line leaves and then enters the cone if (alpha1 < minBackDist && pdotuCtr + alpha1 * udotuCtr <= 0.0f) { if (alpha1 < maxFrontDist) { return(false); } minBackDist = alpha1; backType = HitSide.Cone; } else if (numRoots == 2 && alpha2 > maxFrontDist && pdotuCtr + alpha2 * udotuCtr <= 0.0f) { if (alpha2 > minBackDist) { return(false); } maxFrontDist = alpha2; frontType = HitSide.Cone; } } else { // view line enters and then leaves if (alpha1 > maxFrontDist) { if (pdotuCtr + alpha1 * udotuCtr > 0.0f) { return(false); // Enters dual cone instead } if (alpha1 > minBackDist) { return(false); } maxFrontDist = alpha1; frontType = HitSide.Cone; } if (numRoots == 2 && alpha2 < minBackDist) { if (pdotuCtr + alpha2 * udotuCtr > 0.0f) { return(false); // Is leaving dual cone instead } if (alpha2 < maxFrontDist) { return(false); } minBackDist = alpha2; backType = HitSide.Cone; } } // Put it all together: float alpha; HitSide hitSurface = HitSide.None; if (maxFrontDist > 0.0f) { alpha = maxFrontDist; hitSurface = frontType; } else { alpha = minBackDist; hitSurface = backType; } if (alpha < 0.0) { return(false); } intersect.TMin = alpha; // Set v to the intersection point intersect.HitPoint = ray.Origin + intersect.TMin * ray.Direction; intersect.HitPrimitive = this; // Now set v equal to returned position relative to the apex v = intersect.HitPoint - this.apex; float vdotuA = v * this.axisA; float vdotuB = v * this.axisB; float vdotuCtr = v * this.centralAxis; switch (hitSurface) { case HitSide.BottomPlane: // Base face intersect.Normal = this.baseNormal; if (this.material != null && this.material.IsTexturized) { // Calculate U-V values for texture coordinates vdotuA /= vdotuCtr; // vdotuCtr is negative vdotuB /= vdotuCtr; vdotuA = 0.5f * (1.0f - vdotuA); vdotuB = 0.5f * (1.0f - vdotuB); //int widthTex = this.material.Texture.Width - 1; //int heightTex = this.material.Texture.Height - 1; //this.material.Color = // this.material.Texture.GetPixel((int)(vdotuB * widthTex), (int)(vdotuA * heightTex)); intersect.CurrentTextureCoordinate.U = vdotuB; intersect.CurrentTextureCoordinate.V = vdotuA; } break; case HitSide.Cone: // Cone's side intersect.Normal = vdotuA * this.axisA; intersect.Normal += vdotuB * this.axisB; intersect.Normal -= vdotuCtr * this.centralAxis; intersect.Normal.Normalize(); if (this.material != null && this.material.IsTexturized) { // Calculate u-v coordinates for texture mapping (in range[0,1]x[0,1]) float uCoord = (float)(Math.Atan2(vdotuB, vdotuA) / (Math.PI + Math.PI) + 0.5); float vCoord = (vdotuCtr + this.height) / this.height; //int widthTex = this.material.Texture.Width - 1; //int heightTex = this.material.Texture.Height - 1; //this.material.Color = // this.material.Texture.GetPixel((int)(uCoord * widthTex), (int)(vCoord * heightTex)); intersect.CurrentTextureCoordinate.U = uCoord; intersect.CurrentTextureCoordinate.V = vCoord; } break; } return(true); }
public override bool FindIntersection(Ray ray, out Intersection intersect) { intersect = new Intersection(); float maxFrontDist = float.MinValue; float minBackDist = float.MaxValue; HitPrimitive frontType = HitPrimitive.None, backType = HitPrimitive.None; // 0, 1, 2 = top, bottom, side // Start with the bounding planes float pdotn = (ray.Origin * this.centralAxis) - this.centerDotcentralAxis; float udotn = ray.Direction * this.centralAxis; if (pdotn > this.halfHeight) { if (udotn >= 0.0) { return(false); // Above top plane pointing up } // Hits top from above maxFrontDist = (this.halfHeight - pdotn) / udotn; frontType = HitPrimitive.TopPlane; minBackDist = -(this.halfHeight + pdotn) / udotn; backType = HitPrimitive.BottomPlane; } else if (pdotn < -this.halfHeight) { if (udotn <= 0.0) { return(false); // Below bottom, pointing down } // Hits bottom plane from below maxFrontDist = -(this.halfHeight + pdotn) / udotn; frontType = HitPrimitive.BottomPlane; minBackDist = (this.halfHeight - pdotn) / udotn; backType = HitPrimitive.TopPlane; } else if (udotn < 0.0) { // Inside, pointing down minBackDist = -(this.halfHeight + pdotn) / udotn; backType = HitPrimitive.BottomPlane; } else if (udotn > 0.0) { // Inside, pointing up minBackDist = (this.halfHeight - pdotn) / udotn; backType = HitPrimitive.TopPlane; } if (maxFrontDist < 0) { return(false); } // Now handle the cylinder sides Vector3D v = ray.Origin - this.center; float pdotuA = v * this.axisA; float pdotuB = v * this.axisB; float udotuA = ray.Direction * this.axisA; float udotuB = ray.Direction * this.axisB; float C = pdotuA * pdotuA + pdotuB * pdotuB - 1.0f; float B = (pdotuA * udotuA + pdotuB * udotuB); if (C >= 0.0 && B > 0.0) { return(false); // Pointing away from the cylinder } B += B; // Double B for final 2.0 factor float A = udotuA * udotuA + udotuB * udotuB; float alpha1, alpha2; // The roots, in order int numRoots = EquationSolver.SolveQuadric(A, B, C, out alpha1, out alpha2); if (numRoots == 0) { return(false); // No intersection } if (alpha1 > maxFrontDist) { if (alpha1 > minBackDist) { return(false); } maxFrontDist = alpha1; frontType = HitPrimitive.Cylinder; } if (numRoots == 2 && alpha2 < minBackDist) { if (alpha2 < maxFrontDist) { return(false); } minBackDist = alpha2; backType = HitPrimitive.Cylinder; } // Put it all together: float alpha; HitPrimitive hitSurface; if (maxFrontDist > 0.0) { intersect.HitFromInSide = true; // Hit from outside alpha = maxFrontDist; hitSurface = frontType; } else { intersect.HitFromInSide = false; // Hit from inside alpha = minBackDist; hitSurface = backType; } if (alpha < 0.01) { return(false); } intersect.TMin = alpha; intersect.TMax = alpha2; // Set v to the intersection point intersect.HitPoint = ray.Origin + ray.Direction * alpha; intersect.HitPrimitive = this; // Now set v equal to returned position relative to the center v = intersect.HitPoint - this.center; float vdotuA = v * this.axisA; float vdotuB = v * this.axisB; float uCoord = 0; float vCoord = 0; switch (hitSurface) { case HitPrimitive.TopPlane: // Top surface intersect.Normal = this.top.Normal; // Calculate U-V values for texture coordinates uCoord = 0.5f * (1.0f - vdotuA); vCoord = 0.5f * (1.0f + vdotuB); break; case HitPrimitive.BottomPlane: // Bottom face intersect.Normal = this.bottom.Normal; // Calculate U-V values for texture coordinates uCoord = 0.5f * (1.0f + vdotuA); vCoord = 0.5f * (1.0f + vdotuB); break; case HitPrimitive.Cylinder: // Cylinder's side intersect.Normal = ((vdotuA * this.axisA) + (vdotuB * this.axisB)); intersect.Normal.Normalize(); // Calculate u-v coordinates for texture mapping (in range[0,1]x[0,1]) uCoord = (float)(Math.Atan2(vdotuB, vdotuA) / (Math.PI + Math.PI) + 0.5); vCoord = ((v * this.centralAxis) + this.halfHeight) * 1.0f / this.height; break; } if (this.material != null && this.material.IsTexturized) { //int widthTex = this.material.Texture.Width - 1; //int heightTex = this.material.Texture.Height - 1; //this.material.Color = this.material.Texture.GetPixel((int)(uCoord * widthTex), (int)(vCoord * heightTex)); intersect.CurrentTextureCoordinate.U = uCoord; intersect.CurrentTextureCoordinate.V = vCoord; } return(true); }