Ray tracing: Ellipsoid Hit function - c++

We are working with shape generation using ray tracing. We believe that the hit function is not working appropriately. Currently, the "front" side of the ellipsoid is lit correctly. As the shape rotates, it has problems reflecting light. Example of rotating the ellipsoid.
Below is the current version of the Hit function.
bool Ellipsoid::Hit(const Ray& ray,
const double minHitDistance,
const double maxHitDistance,
HitRecord& hitRecord,
const Vector3d& light) const {
if (hitRecord.shapeHit == this) {
return false;
}
// M is a 3x3 matrix
const Vector3d& direction = (M.inverse()*ray.Direction());
const Vector3d oc = M.inverse()*(ray.Origin() -this->center);
const double a = direction.dot(direction);
const double b = oc.dot(direction);
const double c = oc.dot(oc) - 1;
const double discriminant = b*b - a*c;
if (discriminant > 0) {
const double sqrtDiscriminant = sqrt(discriminant);
const double aReciprocal = 1.0 / a;
double temp = (-b - sqrtDiscriminant) * aReciprocal;
if (temp < maxHitDistance && temp > minHitDistance) {
hitRecord.distance = temp;
hitRecord.closestIntersection = ray.PointAtParameter(hitRecord.distance);
hitRecord.normal = M.inverse()*((hitRecord.closestIntersection - center) / 1);
hitRecord.shapeHit = this;
return true;
}
temp = (-b + sqrtDiscriminant) * aReciprocal;
if (temp < maxHitDistance && temp > minHitDistance) {
hitRecord.distance = temp;
hitRecord.closestIntersection = ray.PointAtParameter(hitRecord.distance);
hitRecord.normal = M.inverse()*((hitRecord.closestIntersection - center) / 1);
hitRecord.shapeHit = this;
return true;
}
}
return false;
}
The first thing we tried was changing M.transpose() to M.inverse() on the lines where we set hitRecord.normal. This made the light look significantly better but did not completely help the light accuracy after rotating the object. We are unsure if the Hit function is completely correct. We just need some guidance to see if we need to look for other faults in the program. Any advice helps.
Edit: We have tried modifying the discriminant as well. This causes the function to break because the "4" is accounted for throughout the function (as seen in comment section).

After completely rewriting the function, we have determined the issue does not lie within the hit function.

Related

I have a issue with collision equation

int Electra2D::Collision()
{
for (std::list<Entity>::iterator affecting = entities.begin(); affecting != entities.end(); ++affecting) {
for (std::list<Entity>::iterator affected = entities.begin(); affected != entities.end(); ++affected) {
if (affecting->type == DrawTypes::Circle && affected->type == DrawTypes::Circle && affecting->object->id != affected->object->id) {
float distance = affected->pos.getDistance(affecting->pos);
float limit = ((ObjectCircle*)affected->object)->radius + ((ObjectCircle*)affecting->object)->radius;
if (distance <= limit) {
Vector2 SP = affected->velocity * affected->mass + affecting->velocity * affecting->mass;
Vector2 V2 = (SP - (affected->velocity-affecting->velocity) * affecting->mass) / (affected->mass + affecting->mass);
affecting->velocity = V2 + (affected->velocity-affecting->velocity);
affected->velocity = V2;
//Equation https://imgur.com/cQqBn9S
}
}
}
}
return 0;
}
I wrote base for 2d simulation in c ++ with d2d1 but when I wrote an equation for collision algorithm I made mistake but I don't know where I mistaken so i need help guys :)
affecting pointer is V1,m1 and affected pointer is V2,m2.
V2' is in code V2, and Sum of momentum in code SP
Source
Edit:
I found my mistake, still thanks. My mistake is I created one dimension equation for two-dimension simulation. When I create an equation I will share my equation and code in this post.

Separating Axis thereom: Calculating the MTV for Polygon & Line Segment

I've been attempting, for months now, to write a function to return the minimum translation needed to be applied to a line segment in order to separate it from an polygon in which intersects. I'm using the separating axis theorem and it seems I'm able to calculate the magnitude correctly however, the direction returned is sometimes wrong. Yet, when the returned translation is incorrect, the inverse is always correct.
In the pictures below, the yellow line is the one used in calculations, the purple line is the yellow line + translation and the red line is the yellow line minus the translation. As you can see either the purple or the red line is correct in different positions but I'm not sure under what conditions to return which line.
So my question is: On what condition does the translation actually need to be flipped so that my function always returns a translation with the correct direction?
const Projection Polygon::Project(const Axis &a) const
{
float min = a.Dot(GetPoint(0));
float max = min;
for (unsigned i = 1; i < GetPointCount(); i++)
{
float prj = a.Dot(GetPoint(i));
if (prj < min)
min = prj;
else if (prj > max)
max = prj;
}
return Projection(min, max);
}
const Projection Segment::Project(const Axis &a) const
{
const float dot0 = a.Dot(GetPoint(0));
const float dot1 = a.Dot(GetPoint(1));
return Projection(std::min(dot0, dot1), std::max(dot0, dot1));
}
const float Projection::GetOverlap(const Projection &p) const
{
// x = min & y = max
return std::min(y - p.x, p.y - x);
}
const Vector2 Segment::GetTranslation(const Polygon &p) const
{
float Overlap = std::numeric_limits<float>::infinity();
Axis smallest;
Vector2 translation;
AxesVec axes(p.GetAxes());
axes.push_back(GetAxis());
for (auto && axis : axes)
{
const Projection pA = p.Project(axis);
const Projection pB = Project(axis);
if (pA.IsOverlap(pB))
{
const float o = pA.GetOverlap(pB);
if (o < Overlap)
{
Overlap = o;
smallest = axis;
}
}
}
translation = smallest * (Overlap + 1);
return translation;
}
The trouble is that your GetOverlap function returns the magnitude of the overlap, but not the sense (left or right).
You could change it to this:
if(y - p.x < p.y - x)
return y - p.x;
else
return x - p.y;
Then in GetTranslation:
const float o = pA.GetOverlap(pB);
if (abs(o) < abs(Overlap))
{
...
}
if (Overlap > 0)
++Overlap;
else
--Overlap;
translation = smallest * Overlap;

Rotating one object to face another C++

I am trying to rotate a an object (a car) to face an object however I am having quite a bit of difficulty with it.
I've had varying success with this code, it knows when the angle is correct and will stop rotating when if it manages to face the right way but most of the time it gets stuck rapidly twitching due to the sign value flicking from 1 > -1 or from -1 > 1 every single frame, thus causing all rotation to stop and for the car to just twitch uncontrollably and never really correct itself.
Honestly, I'm not sure if my Sign calculation is using the correct values as the car moves on the X/Z axis but rotate on the Y-axis to turn left/right
I'm using C++ and DirectX11 by the way
Any advice/help would be appreciated, thanks in advance!
bool ParticleModel::FaceTarget(XMFLOAT3 target)
{
XMFLOAT3 toNormalize;
toNormalize.x = transform->GetPosition().x - target.x;
toNormalize.y = transform->GetPosition().y - target.y;
toNormalize.z = transform->GetPosition().z - target.z;
XMFLOAT3 toTarget = NormalizeVector(toNormalize);
//Determine the angle between the heading vector and the target.
XMFLOAT3 carHeading;
carHeading.x = sin(transform->GetRotation().y);
carHeading.y = sin(transform->GetRotation().x);
carHeading.z = cos(transform->GetRotation().y);
carHeading = NormalizeVector(carHeading);
double angle = acos(DotProduct(carHeading, toTarget));
//Return true if the player is facing the target.
if (angle < 0.01000)
{
return true;
}
/*if (signTimer < signCooldown)
{
signTimer++;
}
else if (signTimer >= signCooldown)
{
signTimer = 0;
sign = GetSign(carHeading, toTarget);
}*/
sign = GetSign(carHeading, toTarget);
transform->SetYRot(transform->GetRotation().y + (0.030f*sign));
//bool thing = false;
//RotateHeadingByRadian(angle, mHeading.Sign(toTarget));
return true;
}
float ParticleModel::DotProduct(XMFLOAT3 a, XMFLOAT3 b)
{
float dot;
dot = (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
return dot;
}
int ParticleModel::GetSign(XMFLOAT3 v1, XMFLOAT3 v2)
{
if (v1.y*v2.z > v1.z*v2.y)
{
return -1;
}
else
{
return 1;
}
}
It's ok I found out how to do it, essentially this is now the code
XMFLOAT3 distance;
distance.x = transform->GetPosition().x - target.x;
distance.y = transform->GetPosition().y - target.y;
distance.z = transform->GetPosition().z - target.z;
XMFLOAT3 carHeading;
carHeading.x = sin(transform->GetRotation().y);
carHeading.y = sin(transform->GetRotation().x);
carHeading.z = cos(transform->GetRotation().y);
if (VectorLength(distance) < 0.5)
{
return true;
}
//Don't actually need to call normalize for directionA - just doing it to indicate
//that this vector must be normalized.
XMFLOAT3 directionA = carHeading;
XMFLOAT3 directionB = NormalizeVector(distance);
float rotationAngle = (float)acos(DotProduct(directionA, directionB));
if (abs(rotationAngle) < 0.5)
{
return true;
}
XMFLOAT3 rotationAxis = CrossProduct(directionA, directionB);
rotationAxis = NormalizeVector(rotationAxis);
transform->SetYRot(transform->GetRotation().y + (rotationAngle*rotationAxis.y));

Ray tracing - refraction bug

I am writing a ray tracer. So far I have diffuse, Blinn lighting and reflections. Something has gone wrong with my refractions and I have no idea what. I'm hoping someone can help me out.
I have a big red diffuse + Blinn sphere and a small refractive one with refraction index n = 1.5.
The small one is just really screwed up.
Relevant code:
ReflectiveSurface::ReflectiveSurface(const Color& _n, const Color& _k) :
F0(Color(((_n - 1)*(_n - 1) + _k * _k) / ((_n + 1)*(_n + 1) + _k * _k))) {}
Color ReflectiveSurface::F(const Point& N, const Point& V) const {
float cosa = fabs(N * V);
return F0 + (F0 * (-1) + 1) * pow(1 - cosa, 5);
}
Color ReflectiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const {
Point reflectedDir = reflect(incidence.normal, incidence.direction);
Ray ray = Ray(incidence.point + reflectedDir * epsilon, reflectedDir);
return F(incidence.normal, incidence.direction) * scene.rayTrace(ray, traceDepth + 1);
}
Point ReflectiveSurface::reflect(const Point& N, const Point& V) const {
return V - N * (2 * (N * V));
}
bool RefractiveSurface::refractionDir(Point& T, Point& N, const Point& V) const {
float cosa = -(N * V), cn = n;
if (cosa < 0) { cosa = -cosa; N = N * (-1); cn = 1 / n; }
float disc = 1 - (1 - cosa * cosa) / cn / cn;
if (disc < 0) return false;
T = V / cn + N * (cosa / cn - sqrt(disc));
return true;
}
RefractiveSurface::RefractiveSurface(float _n, const Color& _k) : ReflectiveSurface(Color(1, 1, 1) * _n, _k) {}
Surface* RefractiveSurface::copy() { return new RefractiveSurface(*this); }
Color RefractiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const {
Incidence I = Incidence(incidence);
Color reflectedColor, refractedColor;
Point direction = reflect(I.normal, I.direction);
Ray reflectedRay = Ray(I.point + direction * epsilon, direction);
if (refractionDir(direction, I.normal, I.direction)) {
Ray refractedRay = Ray(I.point + direction * epsilon, direction);
Color colorF = F(I.normal, I.direction);
reflectedColor = colorF * scene.rayTrace(reflectedRay, traceDepth + 1);
refractedColor = (Color(1, 1, 1) - colorF) * scene.rayTrace(refractedRay, traceDepth + 1);
}
else {
reflectedColor = scene.rayTrace(reflectedRay, traceDepth + 1);
}
return reflectedColor + refractedColor;
}
The code is all over the place, since this is a homework and I'm not allowed to include additional headers and I have to send it in in one cpp file, so i had to separate every class into forward declaration, declaration and implementation in that one file. It makes me vomit but I tried to keep it as clean as possible. There is tons of code so I only included what I thought was most related. ReflectiveSurface is RefractiveSurface's parent class. N is the surface normal, V is the ray direction vector this normal, n is the refraction index. The incidence structure holds a point, a normal and a direction vector.
Formulas for the Fersnel approximation and the refraction vector respectively:
You can see in the code that I use an epsilon * ray direction value to avoid shadow acne caused by float imprecision. Something similar seems to be happening to the small sphere, though.
Another screenshot:
As you can see, the sphere doesn't appear transparent, but it does inherit the diffuse sphere's color. It also usually has some white pixels.
Without refraction:
RefractiveSurface::refractionDir takes the normal N by (non-const) reference, and it may invert it. This seems dangerous. It's not clear the caller wants I.normal to be flipped, as it's used in color calculations further down.
Also, refracted_color is not always initialized (unless the Color constructor makes it black).
Try (temporarily) simplifying and just see if the refracted rays hit where you expect. Remove the Fresnel computation and the reflection component and just set refracted_color to the result of the trace of the refracted ray. That will help determine if the bug is in the Fresnel calculation or in the geometry of bending the ray.
A debugging tip: Color the pixels that don't hit anything with something other than black. That makes it easy to distinguish the misses from the shadows (surface acne).
The answer turned out to be pretty simple, but it took me like 3 days of staring at the code to catch the bug. I have a Surface class, I derive from it two classes: RoughSurface (diffuse+blinn) and RelfectiveSurface. Then, RefractiveSurace is derived from RefleciveSurface. ReflectiveSurface's constructor takes the refractive index(n) and the extinction value (k) as parameters, but doesn't store them. (F0) is computed from them during construction, and then they are lost. RefractiveSurface, on the other hand, uses (n) in the refraction angle calculation.
Old constructor:
RefractiveSurface::RefractiveSurface(float _n, const Color& _k) :
ReflectiveSurface(Color(1, 1, 1) * _n, _k) {}
New Constructor:
RefractiveSurface::RefractiveSurface(float _n, const Color& _k) :
ReflectiveSurface(Color(1, 1, 1) * _n, _k), n(_n) {}
As you can see, I forgot to save the (n) value for RefractiveSurface in the constructor.
Small red sphere behind big glass sphere lit from the two sides of the camera:
It looks awesome in motion!D
Thank you for your time, guys. Gotta finish this homework, then I'll rewrite the whole thing and optimize the hell out of it.

Sort points by angle from given axis?

How can I sort an array of points/vectors by counter-clockwise increasing angle from a given axis vector?
For example:
If 0 is the axis vector I would expect the sorted array to be in the order 2, 3, 1.
I'm reasonably sure it's possible to do this with cross products, a custom comparator, and std::sort().
Yes, you can do it with a custom comparator based on the cross-product. The only problem is that a naive comparator won't have the transitivity property. So an extra step is needed, to prevent angles either side of the reference from being considered close.
This will be MUCH faster than anything involving trig. There's not even any need to normalize first.
Here's the comparator:
class angle_sort
{
point m_origin;
point m_dreference;
// z-coordinate of cross-product, aka determinant
static double xp(point a, point b) { return a.x * b.y - a.y * b.x; }
public:
angle_sort(const point origin, const point reference) : m_origin(origin), m_dreference(reference - origin) {}
bool operator()(const point a, const point b) const
{
const point da = a - m_origin, db = b - m_origin;
const double detb = xp(m_dreference, db);
// nothing is less than zero degrees
if (detb == 0 && db.x * m_dreference.x + db.y * m_dreference.y >= 0) return false;
const double deta = xp(m_dreference, da);
// zero degrees is less than anything else
if (deta == 0 && da.x * m_dreference.x + da.y * m_dreference.y >= 0) return true;
if (deta * detb >= 0) {
// both on same side of reference, compare to each other
return xp(da, db) > 0;
}
// vectors "less than" zero degrees are actually large, near 2 pi
return deta > 0;
}
};
Demo: http://ideone.com/YjmaN
Most straightforward, but possibly not the optimal way is to shift the cartesian coordinates to be relative to center point and then convert them to polar coordinates. Then just subtract the angle of the "starting vector" modulo 360, and finally sort by angle.
Or, you could make a custom comparator for just handling all the possible slopes and configurations, but I think the polar coordinates are little more transparent.
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
struct Point {
static double base_angle;
static void set_base_angle(double angle){
base_angle = angle;
}
double x;
double y;
Point(double x, double y):x(x),y(y){}
double Angle(Point o = Point(0.0, 0.0)){
double dx = x - o.x;
double dy = y - o.y;
double r = sqrt(dx * dx + dy * dy);
double angle = atan2(dy , dx);
angle -= base_angle;
if(angle < 0) angle += M_PI * 2;
return angle;
}
};
double Point::base_angle = 0;
ostream& operator<<(ostream& os, Point& p){
return os << "Point(" << p.x << "," << p.y << ")";
}
bool comp(Point a, Point b){
return a.Angle() < b.Angle();
}
int main(){
Point p[] = { Point(-4., -4.), Point(-6., 3.), Point(2., -4.), Point(1., 5.) };
Point::set_base_angle(p[0].Angle());
sort(p, p + 4, comp);
Point::set_base_angle(0.0);
for(int i = 0;i< 4;++i){
cout << p[i] << " angle:" << p[i].Angle() << endl;
}
}
DEMO
Point(-4,-4) angle:3.92699
Point(2,-4) angle:5.17604
Point(1,5) angle:1.3734
Point(-6,3) angle:2.67795
Assuming they are all the same length and have the same origin, you can sort on
struct sorter {
operator()(point a, point b) const {
if (a.y > 0) { //a between 0 and 180
if (b.y < 0) //b between 180 and 360
return false;
return a.x < b.x;
} else { // a between 180 and 360
if (b.y > 0) //b between 0 and 180
return true;
return a.x > b.x;
}
}
//for comparison you don't need exact angles, simply relative.
}
This will quickly sort them from 0->360 degress. Then you find your vector 0 (at position N), and std::rotate the results left N elements. (Thanks TomSirgedas!)
This is an example of how I went about solving this. It converts to polar to get the angle and then is used to compare them. You should be able to use this in a sort function like so:
std::sort(vectors.begin(), vectors.end(), VectorComp(centerPoint));
Below is the code for comparing
struct VectorComp : std::binary_function<sf::Vector2f, sf::Vector2f, bool>
{
sf::Vector2f M;
IntersectComp(sf::Vector2f v) : M(v) {}
bool operator() ( sf::Vector2f o1, sf::Vector2f o2)
{
float ang1 = atan( ((o1.y - M.y)/(o1.x - M.x) ) * M_PI / 180);
float ang2 = atan( (o2.y - M.y)/(o2.x - M.x) * M_PI / 180);
if(ang1 < ang2) return true;
else if (ang1 > ang2) return false;
return true;
}
};
It uses sfml library but you can switch any vector/point class instead of sf::Vector2f. M would be the center point. It works great if your looking to draw a triangle fan of some sort.
You should first normalize each vector, so each point is in (cos(t_n), sin(t_n)) format.
Then calculating the cos and sin of the angles between each points and you reference point. Of course:
cos(t_n-t_0)=cos(t_n)cos(t_0)+sin(t_n)sin(t_0) (this is equivalent to dot product)
sin(t_n-t_0)=sin(t_n)cos(t_0)-cos(t_n)sin(t_0)
Only based on both values, you can determine the exact angles (-pi to pi) between points and reference point. If just using dot product, clockwise and counter-clockwise of same angle have same values. One you determine the angle, sort them.
I know this question is quite old, and the accepted answer helped me get to this, still I think I have a more elegant solution which also covers equality (so returns -1 for lowerThan, 0 for equals, and 1 for greaterThan).
It is based on the division of the plane to 2 halves, one from the positive ref axis (inclusive) to the negative ref axis (exclusive), and the other is its complement.
Inside each half, comparison can be done by right hand rule (cross product sign), or in other words - sign of sine of angle between the 2 vectors.
If the 2 points come from different halves, then the comparison is trivial and is done between the halves themselves.
For an adequately uniform distribution, this test should perform on average 4 comparisons, 1 subtraction, and 1 multiplication, besides the 4 subtractions done with ref, that in my opinion should be precalculated.
int compareAngles(Point const & A, Point const & B, Point const & ref = Point(0,0)) {
typedef decltype(Point::x) T; // for generality. this would not appear in real code.
const T sinA = A.y - ref.y; // |A-ref|.sin(angle between A and positive ref-axis)
const T sinB = B.y - ref.y; // |B-ref|.sin(angle between B and positive ref-axis)
const T cosA = A.x - ref.x; // |A-ref|.cos(angle between A and positive ref-axis)
const T cosB = B.x - ref.x; // |B-ref|.cos(angle between B and positive ref-axis)
bool hA = ( (sinA < 0) || ((sinA == 0) && (cosA < 0)) ); // 0 for [0,180). 1 for [180,360).
bool hB = ( (sinB < 0) || ((sinB == 0) && (cosB < 0)) ); // 0 for [0,180). 1 for [180,360).
if (hA == hB) {
// |A-ref|.|B-ref|.sin(angle going from (B-ref) to (A-ref))
T sinBA = sinA * cosB - sinB * cosA;
// if T is int, or return value is changed to T, it can be just "return sinBA;"
return ((sinBA > 0) ? 1 : ((sinBA < 0) ? (-1) : 0));
}
return (hA - hB);
}
If S is an array of PointF, and mid is the PointF in the centre:
S = S.OrderBy(s => -Math.Atan2((s.Y - mid.Y), (s.X - mid.X))).ToArray();
will sort the list in order of rotation around mid, starting at the point closest to (-inf,0) and go ccw (clockwise if you leave out the negative sign before Math).