There is a camera represented by a quaternion [w, x, y, z] associated with a position [x, y, z].
The camera is looking at a mirror (plane) defined as a normal and a point residing on the mirror. This mirror may also be represented as the plane equation AX + BY + CZ + D = 0.
Using the information above, how would the reflected/virtual camera be found?
The quaternion roll should be preserved, ie if you are looking directly into a mirror, the quaternion looking back at you should have the same roll and not be upside down. Ray vs plane can be used to find the virtual camera position, the reflected vector origin and 3D direction, but I'm not sure that helps in finding the quaternion. Finding the virtual camera position was easy enough as shown below (I prefer this over the ray vs. plane tracing method due to parallel or looking away case):
//plane equation ax + by + cz + d = 0
float plane_equation[4];//a, b, c, d
plane_equation[0] = mirror_normal[0];
plane_equation[1] = mirror_normal[1];
plane_equation[2] = mirror_normal[2];
float mults[3];
mults[0] = plane_equation[0] * mirror_position[0];
mults[1] = plane_equation[1] * mirror_position[1];
mults[2] = plane_equation[2] * mirror_position[2];
plane_equation[3] = -1 * (mults[0] + mults[1] + mults[2]);
//find the virtual camera position for reflection using the plane equation
//a(p0 + aT) + b(p1 + bT) + c(p2 + cT) + d = 0
//ap0 + bp1 + cp2 + T(a^2 + b^2 + c^2) + d = 0
//U + TV + d = 0
//T = (-d - U) / V
float t_parts[2];
//U
t_parts[0] = plane_equation[0] * cam_pos[0] + plane_equation[1] * cam_pos[1] + plane_equation[2] * cam_pos[2];
//V
t_parts[1] = plane_equation[0] * plane_equation[0] + plane_equation[1] * plane_equation[1] + plane_equation[2] * plane_equation[2];
float t = (-plane_equation[3] - t_parts[0]) / t_parts[1];
//t gets us to the intersection point. 2t gets us to the virtual point
virtual_cam_pos[0] = 2 * t * plane_equation[0] + cam_pos[0];
virtual_cam_pos[1] = 2 * t * plane_equation[1] + cam_pos[1];
virtual_cam_pos[2] = 2 * t * plane_equation[2] + cam_pos[2];
One solution, it could probably be simplified but this works:
Do ray vs plane. There are 3 cases that need to be taken into account. First is looking towards the mirror so that there is an intersection. Second is looking parallel to the mirror. Third is looking away from the mirror (the mirror may still be visible by the camera, do flipped ray vs plane)
Find the reflected vector
Use the distance from the camera position to the mirror intersection point, intersection point, and reflected vector to find the virtual camera position
Use the vector from the virtual camera to the mirror intersection point to create a quaternion
Apply a local roll to the quaternion. An exact equation to find the appropriate amount of roll for all possible cases is a little unclear to me, but this gets most of the way there
Related
I'm trying to write an algorithm to determine if point is located inside a triangle or on it's edge in 3D coordinate space.
For example, I try to reach such results for different cases
I've figured out how to check if point P inside the triangle, I calculated normal vectors for triangles ABP, BCP, CAP and checked if they are similar.
Can someone explain how to check if a point is on the edge of a triangle (but not outside of a triangle)? You can provide formulas or code as you wish.
Make vectors:
r = p - A (r.x = p.x - A.x, r.y = p.y - A.y, r.z = p.z - A.z)
s = B - A
q = C - A
Calculate normal to ABC plane:
n = s x q (vector product)
Check if p lies in ABC plane using dot product:
dp = n.dot.r
If dp is zero (or has very small value like 1.0e-10 due to the floating point errors, then p is in the plane, and we can continue
Decompose vector p by base vectors s and q. At first check if z-component of normal (n.z) is non-zero. If so, use the next pair of equations (otherwise choose equations for x/z or y/z components):
px = a * sx + b * qx
py = a * sy + b * qy
Solve this system
a = (sy * qx - sx * qy) / (py * qx - px * qy)
b = (px - a * sx) / qx
If resulting coefficients a and b fulfill limits:
a >= 0
b >= 0
a + b <= 1.0
then point p lies in triangle plane inside it.
I am making my first raycasting engine, and would like to rotate a line over an angle θ
How does one do this? Would it be possible to show me some basic C++ code or some pseudocode?
This image describes my problem:
Optional question
I decided to make all of this in graphics.h, because it is the simplest graphics header for C/C++.
You want:
B = P + M * (A - P)
Where M is a 2D rotation matrix:
M = | cos(ϴ) -sin(ϴ) |
| sin(ϴ) cos(ϴ) |
In C++ it could be written as:
float c = cos(theta), s = sin(theta);
float dx = ax - px, dy = ay - py;
float bx = px + c * dx - s * dy;
float by = py + s * dx + c * dy;
One simple algorithm:
Move the circle -P, so that P is at (0, 0).
Rotate A by the angle by multiplying it by the rotation matrix.
Move the circle P to restore its original position.
All these three steps can be done using one 3x3 matrix multiplication.
The scalar product of two vectors have the following property:
vec(PA) . vec(PB) = rho cos theta
Taking the definition of our two vectors:
vec(PA) = (x_a-x_p, y_a-y_p)
vec(PB) = (x_b-x_p, y_b-y_p)
We can get:
(x_a-x_p)(x_b-x_p) + (y_a-y_p)(y_b-y_p) = rho cos theta (1)
Since PA=PB, we also have:
(x_a-x_p)^2 + (y_a-y_p)^2 = (x_b-x_p)^2 + (y_b-y_p)^2 (2)
From (1) and (2) you can derive x_band y_b with some arithmetic autopilot.
I am searching for an algorithm (using OpenCV C or C++) which does this:
Given the boundary image, I want to find the local curvature at all points and color map it, which is what is done in the image displayed above. I got this image from Wikipedia but haven't been able to find out a way to color the boundary in this way. Kindly let me know how it can be done.
If you observe the boundary, red denotes boundary has high slope, yellow shows that the boundary is almost linear.
How can this be done?
Edit
Just to give you an idea of how I was trying to do this since two days:
I used the openCV functions convexHull and convexityDefects but realized that I am going in the wrong direction. I have to work only on the contours/boundaries of the binary image.
You can solve the problem by fitting a path of cubic Bezier curves to the boundary, then taking the curvature analytically.
[elaborated]
The boundary consists of a list of points in x, y at pixel centres, each point 1px or root 2 px form the next in the list. You need to fit a smooth cubic Bezier path to this, using a technique by Schnider in Graphics Gems (Gems 1, pp 612, An algorithm for Fitting digitized curves).
The step along the curve taking tiny steps which are always sub-pixel, and
take the curvature using
double BezierCurve::Curvature(double t) const
{
// Nice mathematically perfect formula
//Vector2 d1 = Tangent(t);
//Vector2 d2 = Deriv2(t);
//return (d1.x * d2.y - d1.y * d2.x) / pow(d1.x * d1.x + d1.y * d1.y, 1.5);
// Get the cubic coefficients like this, I store them in the Bezier
// class
/*
a = p3 + 3.0 * p1 - 3.0 * p2 - p0;
b = 3.0 * p0 - 6.0 * p1 + 3.0 * p2;
c = 3.0 * p1 - 3.0 * p0;
d = p0;
*/
double dx, dy, ddx, ddy;
dx = 3 * this->ax * t*t + 2 * this->bx * t + this->cx;
ddx = 6 * this->ax * t + 2 * this->bx;
dy = 3 * this->ay * t*t + 2 * this->by * t + this->cy;
ddy = 6 * this->ay * t + 2 * this->by;
if (dx == 0 && dy == 0)
return 0;
return (dx*ddy - ddx*dy) / ((dx*dx + dy*dy)*sqrt(dx*dx + dy*dy));
}
OpenCV findContours used with mode= CV_RETR_EXTERNAL and method= CV_CHAIN_APPROX_NONE will give you all boundary pixels ordered such as two subsequent points are neighbors.
To get the radius of a circumference by three points, there are a lot of info in the Web. Because you only need the radius, not the center, this stackexchange answer is fast.
In pseudo code:
vector_of_points = OpenCV::findContours(...)
p1 = vector start
p2, p3 are next points in vector
//boundary is circular, so in the first loop pass we must adjust
p2 = next point
p3 = last point
//Use p1 as our iterator
while ( p1 <= vector.end )
{
//curvature
radius = calculateRadius(p1, p2, p3)
//set color for pixel p2
setColor(p, radius)
increment p1, p2, p3
adjust for start point = end point
}
I am making a little game and I am now working on a "radar". Now to do this I need to find two points based off how much a point has rotated around a center point.
A is going to rotate around C.
As A rotates around C, B & D will move along with A and stay in the same "positions" based off of where A is.
So for example, if A rotates around C 90 degrees B & D would then move and be in this position
But I am not very good at trig, so I don't really know the math I would need in order to find B & D based off how much A has rotated around C.
How do i find B & D based off of how much A has rotated around C?
I would image the final math would look somewhat similar to this:
float * returnB(float * APoint, float * CPoint)
{
float B_Out[2];
//calculate where B is based off A & C
B_Out[0] = B_X;
B_Out[1] = B_Y;
return B_Out;
}
float B[2];
B[0] = returnB(A,C)[0];
B[1] = returnB(A,C)[1];
float * returnD(float * APoint, float * CPoint)
{
float D_Out[2];
//calculate where D is based off A & C
D_Out[0] = D_X;
D_Out[1] = D_Y;
return D_Out;
}
float D[2];
D[0] = returnD(A,C)[0];
D[1] = returnD(A,C)[1];
You can rotate a point (x, y) around the origin by performing a simple matrix multiplication, which gives the following equations for the transformed point (x0, y0):
x0 = x * cos(theta) - y * sin(theta);
y0 = x * sin(theta) + y * cos(theta);
So you know A's relative 2d position respect to C. Lets say it is (ax, ay).
If you cross product(0,0,1) with (ax, ay, 0) you will find relative position of D that will be something like (dx, dy, 0)
d = (dx, dy) is relative position of D.
b is also -d
https://en.wikipedia.org/wiki/Cross_product
I am drawing hollow ellipse using opengl. I calculate vertices in c++ code using standard ellipse formula. In fragment shader i just assign color to each fragment. The ellipse that i see on the screen has thinner line width on the sharper curves as compared to that where curve is not that sharp. So question is, how to make line-width consistent across the entire parameter of ellipse? Please see the image below:
C++ code :
std::vector<float> BCCircleHelper::GetCircleLine(float centerX, float centerY, float radiusX, float radiusY, float lineWidth, int32_t segmentCount)
{
auto vertexCount = (segmentCount + 1) * 2;
auto floatCount = vertexCount * 3;
std::vector<float> array(floatCount);
const std::vector<float>& data = GetCircleData (segmentCount);
float halfWidth = lineWidth * 0.5f;
for (int32_t i = 0; i < segmentCount + 1; ++i)
{
float sin = data [i * 2];
float cos = data [i * 2 + 1];
array [i * 6 + 0] = centerX + sin * (radiusX - halfWidth);
array [i * 6 + 1] = centerY + cos * (radiusY - halfWidth);
array [i * 6 + 3] = centerX + sin * (radiusX + halfWidth);
array [i * 6 + 4] = centerY + cos * (radiusY + halfWidth);
array [i * 6 + 2] = 0;
array [i * 6 + 5] = 0;
}
return std::move(array);
}
const std::vector<float>& BCCircleHelper::GetCircleData(int32_t segmentCount)
{
int32_t floatCount = (segmentCount + 1) * 2;
float segmentAngle = static_cast<float>(M_PI * 2) / segmentCount;
std::vector<float> array(floatCount);
for (int32_t i = 0; i < segmentCount + 1; ++i)
{
array[i * 2 + 0] = sin(segmentAngle * i);
array[i * 2 + 1] = cos(segmentAngle * i);
}
return array;
}
Aiming this:
The problem is likely that your fragments are basically line segments radiating from the center of the ellipse.
If you draw a line, from the center of the ellipse through the ellipse you've drawn, at any point on the perimeter, you could probably convince yourself that the distance covered by that red line is in fact the width that you're after (roughly, since you're working at low spatial resolution; somewhat pixelated). But since this is an ellipse, that distance is not perpendicular to the path being traced. And that's the problem. This works great for circles, because a ray from the center is always perpendicular to the circle. But for these flattened ellipses, it's very oblique!
How to fix it? Can you draw circles at each point on the ellipse, instead of line segments?
If not, you might need to recalculate what it means to be that thick when measured at that oblique angle - it's no longer your line width, may require some calculus, and a bit more trigonometry.
Ok, so a vector tangent to the curve described by
c(i) = (a * cos(i), b * sin(i))
is
c'(i) = (- a * sin(i), b * cos(i))
(note that this is not a unit vector). The perpendicular to this is
c'perp = (b * cos(i), a * sin(i))
You should be able to convince yourself that this is true by computing their dot product.
Lets calculate the magnitude of c'perp, and call it k for now:
k = sqrt(b * b * cos(i) * cos(i) + a * a * sin(i) * sin(i))
So we go out to a point on the ellipse (c(i)) and we want to draw a segement that's perpendicular to the curve - that means we want to add on a scaled version of c'perp. The scaling is to divide by the magnitude (k), and then multiply by half your line width. So the two end points are:
P1 = c(i) + halfWidth * c'perp / k
P2 = c(i) - halfWidth * c'perp / k
I haven't tested this, but I'm pretty sure it's close. Here's the geometry you're working with:
--
Edit:
So the values for P1 and P2 that I give above are end-points of a line-segment that's perpendicular to the ellipse. If you really wanted to continue with just altering the radiusX and radiusY values the way you were doing, you could do this. You just need to figure out what the 'Not w' length is at each angle, and use half of this value in place of halfWidth in radiusX +/- halfWidth and radiusY +/- halfwidth. I leave that bit of geometry as an exercise for the reader.