I have a problem with my ray tracer program. The image looks wrong. Here is the output image:
Barycentric coordinates and collision calculation codes are as follows:
bool CTriangle::Intersect(Calculus::CRay& ray, CIntersection* isect) const {
// Möller–Trumbore intersection algorithm
const Calculus::CPoint3<float>& p1 = v_points[0];
const Calculus::CPoint3<float>& p2 = v_points[1];
const Calculus::CPoint3<float>& p3 = v_points[2];
Calculus::CVector3<float> e1 = p2 - p1;
Calculus::CVector3<float> e2 = p3 - p1;
Calculus::CVector3<float> s1 = Calculus::Math::Cross(ray.direction, e2);
float determinant = Calculus::Math::Dot(s1, e1);
if (determinant == 0.0f)
return false;
float inv_determinant = 1.0f / determinant;
Calculus::CVector3<float> s = ray.origin - p1;
float b1 = Calculus::Math::Dot(s, s1) * inv_determinant;
if (b1 < 0.0f || b1 > 1.0f)
return false;
Calculus::CVector3<float> s2 = Calculus::Math::Cross(s, e1);
float b2 = Calculus::Math::Dot(ray.direction, s2) * inv_determinant;
if (b2 < 0.0f || b1 + b2 > 1.0f)
return false;
float b0 = 1 - b1 - b2;
float thit = Calculus::Math::Dot(e2, s2) * inv_determinant;
if (thit < ray.mint || thit > ray.maxt)
return false;
isect->p = ray(thit);
isect->n = Calculus::Math::Normalize(Calculus::CVector3<float>
(v_normals[0].x, v_normals[0].y, v_normals[0].z) * b0 +
Calculus::CVector3<float>(v_normals[1].x, v_normals[1].y,
v_normals[1].z) * b1 +
Calculus::CVector3<float>(v_normals[2].x, v_normals[2].y,
v_normals[2].z) * b2);
isect->uv = v_uvs[0] * b0 + v_uvs[1] * b1 + v_uvs[2] * b2;
isect->tHit = thit;
isect->ray_epsilon = 1e-5f * thit;
return true;
}
Texture i used int the ray trace program:(file type: bmp)
my obj file is as follows. The background shape consists of two triangles. Texture projection is applied only to the background shape:
v -24.1456 -11.1684 -26.2413
v 24.1455 -11.1684 -26.2413
v -24.1456 37.1227 -26.2413
v 24.1455 37.1227 -26.2413
# 4 vertices
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 0.0000 1.0000
# 6 vertex normals
vt 0.9995 0.0005 0.0000
vt 0.0005 0.0005 0.0000
vt 0.9995 0.9995 0.0000
vt 0.0005 0.9995 0.0000
# 4 texture coords
o back
g back
usemtl default
s 1
f 1/1/1 2/2/2 4/4/3
f 4/4/4 3/3/5 1/1/6
# 2 faces
Here is the interpolated uv draw call.
Here is indexing algorithm, i'm starting from zero:
...
Calculus::CPoint3<unsigned short> p, t, n;
sscanf_s(token, "%hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu",
&p.x, &t.x, &n.x, &p.y, &t.y, &n.y, &p.z, &t.z, &n.z);
pi.push_back(p);
ti.push_back(t);
ni.push_back(n);
…
index = ti[i].x - 1;
temp_t[0] = vt[index]; // first uv
index = ti[i].y - 1;
temp_t[1] = vt[index]; // second uv
index = ti[i].z - 1;
temp_t[2] = vt[index]; // third uv
I wonder where I'm making a mistake. Thank you.
isect->uv = v_uvs[0] * b1 + v_uvs[1] * b2;
This is not the correct parametric interpolation of vertex attributes:
The parameters b1, b2 are being applied to the wrong vertices
You are not taking the third vertex v_uvs[2] into account
Correct version:
isect->uv = v_uvs[0] * b0 + v_uvs[1] * b1 + v_uvs[2] * b2;
Related
Not sure if this is the best place to ask this.
So I'm trying to study the orthogonality of the wave function solutions by calculating the Integral of the product of two solutions of different orders m and n. Now I get to the part where I have to do the product of 2 Hermite matrices of different dimensions, which I can't mathematically perform, one being 3x20 and the other one 4x20. Is there a way around this?
arma::mat Orthonormality::gaussHermiteG(int n, int m, arma::mat Z)
{
Miscellaneous misc;
Calcul *caln = new Calcul(n,Z);
Calcul *calm = new Calcul(m,Z);
double f1;
arma::mat Hnm;
arma::mat res;
f1 = (1 / std::sqrt(std::exp(n * std::log(2)) * misc.factorial(n))) * (1 / std::sqrt(std::exp(m * std::log(2)) * misc.factorial(m))) * std::sqrt(1 / M_PI);
Hnm = caln->calculPolynomeHermite() % calm->calculPolynomeHermite();
res = f1 * Hnm;
return res;
}
Here's my function for getting the quadrature. It this the way to prove the orthogonality, or am I doing it wrong?
long double Orthonormality::quadrature(int n, int m)
{
arma::mat gx;
arma::mat gauss_point = {{
-2.453407083009012499038365306336166239661e-1,
2.453407083009012499038365306336166239661e-1,
-7.374737285453943587056051442521042290772e-1,
7.374737285453943587056051442521042290772e-1,
1.234076215395323007885818346959410229585,
-1.234076215395323007885818346959410229584,
-1.738537712116586206780865662136406442958,
1.738537712116586206780865662136406442953,
2.254974002089275523082333344734565128082,
-2.254974002089275523082333344734565128065,
-2.788806058428130480525033756403185410695,
2.788806058428130480525033756403185410655,
3.347854567383216326914924522996463698566,
-3.347854567383216326914924522996463698495,
-3.94476404011562521037562880052441180715,
3.944764040115625210375628800524411807067,
4.603682449550744273077675248978347585171,
-4.603682449550744273077675248978347585109,
5.387480890011232862016900410681120753981,
-5.387480890011232862016900410681120754003,
}
};
arma::mat gauss_point_weight = {{
4.622436696006100896503286398612081142142e-1,
4.622436696006100896503286398612081142142e-1,
2.866755053628341297196597062280879168236e-1,
2.866755053628341297196597062280879168236e-1,
1.090172060200233200137550335354255770852e-1,
1.090172060200233200137550335354255770846e-1,
2.481052088746361088216495255894039439922e-2,
2.481052088746361088216495255894039440028e-2,
3.24377334223786183218324713235370544232e-3,
3.243773342237861832183247132353705443042e-3,
2.283386360163539672571459179634955394906e-4,
2.283386360163539672571459179634955393512e-4,
7.802556478532063694145991999647569104495e-6,
7.802556478532063694145991999647569095955e-6,
1.086069370769281693999524563447163430255e-7,
1.086069370769281693999524563447163432688e-7,
4.399340992273180553628851455467928211995e-10,
4.399340992273180553628851455467928212879e-10,
2.229393645534151292522500616029095785758e-13,
2.22939364553415129252250061602909578525e-13,
}
};
gx = Orthonormality::gaussHermiteG(n, m, gauss_point);
arma::mat res;
res = gx * gauss_point_weight.t();
long double resDouble = res(0, 0);
return resDouble;
}
Here's the Hermite Polynomial function and its output for the 3 an 4 modes:
mat Calcul::calculPolynomeHermite(int n_max, mat z)
{
mat H(n_max, z.n_elem);
if (n_max == 0)
{
H = z.ones(size(z));
}
else
{
if (n_max == 1)
{
return z.for_each([](arma::mat::elem_type& val)
{
val = 2 * val;
});
}
else {
for(int i = 0; i < z.n_elem; ++i)
{
H(0, i) = 1;
}
rowvec h2 = rowvec(z.n_elem);
h2 = 2 * z;
H.row(1) = h2;
for(int i = 2; i < n_max; i++)
{
rowvec hn = rowvec(z.n_elem);
hn = h2 % H.row(i - 1) - (2 * i) * H.row(i - 2);
H.row(i) = hn;
}
}
}
return H;
}
output :
H(3,z):
1.0000 1.0000 1.0000 1.0000 1.0000
-4.0000 -2.0000 0 2.0000 4.0000
12.0000 0 -4.0000 0 12.0000
H(4,z):
1.0000 1.0000 1.0000 1.0000 1.0000
-4.0000 -2.0000 0 2.0000 4.0000
12.0000 0 -4.0000 0 12.0000
-24.0000 12.0000 0 -12.0000 24.0000
The psuedocode for the Halton sequnce can be found here. I wrote a function that does this but for some reason checking the Matlab results for the 4th dimensional Halton sequence my numbers do not match up and I am not sure why. Here is my code:
double Halton_Seq(int index, double base){
double f = 1, r;
while(index > 0){
f = f/base;
r = r + f*(fmod(index,base));
index = index/base;
}
return r;
}
Here are the first 10 results I get:
1
0.25
0.5
0.75
0.0625
0.3125
0.5625
0.8125
0.125
0.375
Here is the first 10 results MATLAB gets:
Columns 1 through 2
0 0.5000
Columns 3 through 4
0.2500 0.7500
Columns 5 through 6
0.1250 0.6250
Columns 7 through 8
0.3750 0.8750
Columns 9 through 10
0.0625 0.5625
You forgot to initialize r in line 2.
r = 0;
double Halton_Seq(int index, int base){
double f = 1, r = 0;
while(index > 0){
f = f/base;
r = r + f* (index% base);
index = index/base;
}
return r;
}
// Output for 10 (base 2)
0.000000
0.500000
0.250000
0.750000
0.125000
0.625000
0.375000
0.875000
0.062500
0.562500
I copied a code for conversion of 3D roation matrix to quaternions and back. The same code is used in jMonkey (I just rewrote it into my C++ class). However, it does not work properly (at least not as I would expect.)
e.g. I made this test:
matrix (a,b,c):
a : 0.707107 0.000000 0.707107
b : 0.000000 -1.000000 0.000000
c : -0.707107 0.000000 0.707107
>>> ortonormality:
a.a b.b c.c 1.000000 1.000000 1.000000
a.b a.c b.c 0.000000 0.000000 0.000000
>>> matrix -> quat
quat: 0.000000 0.594604 0.000000 0.594604 norm(quat) 0.707107
>>> quat -> matrix
matrix (a,b,c):
a: 0.000000 0.000000 1.000000
b: 0.000000 1.000000 0.000000
c: -1.000000 0.000000 0.000000
I think the problem is in matrix -> quat because I have used quat -> matrix procedure before, and it was working fine. Also it is strange that quaternion made from orthonormal matrix is not unitary.
the matrix -> quat procedure
inline void fromMatrix( TYPE m00, TYPE m01, TYPE m02, TYPE m10, TYPE m11, TYPE m12, TYPE m20, TYPE m21, TYPE m22) {
// Use the Graphics Gems code, from
// ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z
TYPE t = m00 + m11 + m22;
// we protect the division by s by ensuring that s>=1
if (t >= 0) { // by w
TYPE s = sqrt(t + 1);
w = 0.5 * s;
s = 0.5 / s;
x = (m21 - m12) * s;
y = (m02 - m20) * s;
z = (m10 - m01) * s;
} else if ((m00 > m11) && (m00 > m22)) { // by x
TYPE s = sqrt(1 + m00 - m11 - m22);
x = s * 0.5;
s = 0.5 / s;
y = (m10 + m01) * s;
z = (m02 + m20) * s;
w = (m21 - m12) * s;
} else if (m11 > m22) { // by y
TYPE s = sqrt(1 + m11 - m00 - m22);
y = s * 0.5;
s = 0.5 / s;
x = (m10 + m01) * s;
z = (m21 + m12) * s;
w = (m02 - m20) * s;
} else { // by z
TYPE s = sqrt(1 + m22 - m00 - m11);
z = s * 0.5;
s = 0.5 / s;
x = (m02 + m20) * s;
y = (m21 + m12) * s;
w = (m10 - m01) * s;
}
}
the quat -> matrix procedure
inline void toMatrix( MAT& result) const {
TYPE r2 = w*w + x*x + y*y + z*z;
//TYPE s = (r2 > 0) ? 2d / r2 : 0;
TYPE s = 2 / r2;
// compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
// will be used 2-4 times each.
TYPE xs = x * s; TYPE ys = y * s; TYPE zs = z * s;
TYPE xx = x * xs; TYPE xy = x * ys; TYPE xz = x * zs;
TYPE xw = w * xs; TYPE yy = y * ys; TYPE yz = y * zs;
TYPE yw = w * ys; TYPE zz = z * zs; TYPE zw = w * zs;
// using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
result.xx = 1 - (yy + zz);
result.xy = (xy - zw);
result.xz = (xz + yw);
result.yx = (xy + zw);
result.yy = 1 - (xx + zz);
result.yz = (yz - xw);
result.zx = (xz - yw);
result.zy = (yz + xw);
result.zz = 1 - (xx + yy);
};
sorry for TYPE, VEC, MAT, QUAT it is part of class tepmpltes... should be replaced by double, Vec3d, Mat3d, Quat3d or float, Vec3f, Mat3f, Quat3f.
EDIT:
I also checked if I get the same behaviour with jMonkey directly (in case I made a bug in Java to C++ conversion ). And I do - using this code:
Matrix3f Min = new Matrix3f( 0.707107f, 0.000000f, 0.707107f, 0.000000f, -1.000000f, 0.000000f, -0.707107f, 0.000000f, 0.707107f );
Matrix3f Mout = new Matrix3f( );
Quaternion q = new Quaternion();
q.fromRotationMatrix(Min);
System.out.println( q.getX()+" "+q.getY()+" "+q.getZ()+" "+q.getW() );
q.toRotationMatrix(Mout);
System.out.println( Mout.get(0,0) +" "+Mout.get(0,1)+" "+Mout.get(0,2) );
System.out.println( Mout.get(1,0) +" "+Mout.get(1,1)+" "+Mout.get(1,2) );
System.out.println( Mout.get(2,0) +" "+Mout.get(2,1)+" "+Mout.get(2,2) );
Your matrix:
matrix (a,b,c):
a : 0.707107 0.000000 0.707107
b : 0.000000 -1.000000 0.000000
c : -0.707107 0.000000 0.707107
is orthogonal but it is not a rotation matrix. A rotation matrix has determinant 1; your matrix has determinant -1 and is thus an improper rotation.
I think your code is likely correct and the issue is in your data. Try it with a real rotation matrix.
Side note: hey everyone, if you found my question/answer helpful, please don't forget to up vote. I kind of need it...
So there seems to be something different with my implementation of both matrix [projection and model] (other than the stuff I've commented out for debugging purposes). Below is a screenshot of the bug I see when drawing a cube. Keep in mind I do keep the viewport and matrix up to date with the window size and calculate screen ratio with float and not int, so don't bother asking, I've checked the usual suspects.....
Screen Shot
Files (linux build, see readme in ./build)
side note: while debugging, I've changed the cube's distance. To reproduce the screen shot, on line 76 of workspace.cpp set mDistance to about 90 and stretch the window frame to dimensions noted at lower right corner of the window.
Please keep in mind the screen shot and the debug text output are seperate events as I'm constantly debugging this problem and getting new numbers.
The code:
#define _AP_MAA 0
#define _AP_MAB 1
#define _AP_MAC 2
#define _AP_MAD 3
#define _AP_MBA 4
#define _AP_MBB 5
#define _AP_MBC 6
#define _AP_MBD 7
#define _AP_MCA 8
#define _AP_MCB 9
#define _AP_MCC 10
#define _AP_MCD 11
#define _AP_MDA 12
#define _AP_MDB 13
#define _AP_MDC 14
#define _AP_MDD 15
Setting up the camera perspective:
void APCamera::setPerspective(GMFloat_t fov, GMFloat_t aspect, GMFloat_t near, GMFloat_t far)
{
GMFloat_t difZ = near - far;
GMFloat_t *data;
mProjection->clear(); //set to identity matrix
data = mProjection->getData();
GMFloat_t v = 1.0f / tan(fov / 2.0f);
data[_AP_MAA] = v / aspect;
data[_AP_MBB] = v;
data[_AP_MCC] = (far + near) / (difZ);
data[_AP_MCD] = -1.0f;
data[_AP_MDD] = 0.0f;
data[_AP_MDC] = (2.0f * far * near)/ (difZ);
mRatio = aspect;
mInvProjOutdated = true;
mIsPerspective = true;
}
Setting up the camera direction:
bool APCamera::lookTo(Coordinate &to, Coordinate &from, Coordinate &up)
{
Coordinate f, unitUp, right;
GMFloat_t *data;
CoordinateOp::diff(&to, &from, &f);
VectorOp::toUnit(&f, &f);
VectorOp::toUnit(&up, &unitUp);
VectorOp::cross(&f, &unitUp, &right);
if((fabs(right.x) < FLOAT_THRESHOLD) && (fabs(right.y) < FLOAT_THRESHOLD) && (fabs(right.z) < FLOAT_THRESHOLD))
{
return false;
}
mCamPt = from;
VectorOp::toUnit(&right, &mRight);
mForward = f;
VectorOp::cross(&mRight, &mForward, &mUp);
mModelView->clear();
data = mModelView->getData();
data[_AP_MAA] = mRight.x;
data[_AP_MBA] = mRight.y;
data[_AP_MCA] = mRight.z;
data[_AP_MAB] = mUp.x;
data[_AP_MBB] = mUp.y;
data[_AP_MCB] = mUp.z;
data[_AP_MAC] = -mForward.x;
data[_AP_MBC] = -mForward.y;
data[_AP_MCC] = -mForward.z;
//translation part is commented out to narrow bugs down, "camera" is kept at the center (0,0,0)
//data[_AP_MDA] = (data[_AP_MAA] * -mCamPt.x) + (data[_AP_MBA] * -mCamPt.y) + (data[_AP_MCA] * -mCamPt.z);
//data[_AP_MDB] = (data[_AP_MAB] * -mCamPt.x) + (data[_AP_MBB] * -mCamPt.y) + (data[_AP_MCB] * -mCamPt.z);
//data[_AP_MDC] = (data[_AP_MAC] * -mCamPt.x) + (data[_AP_MBC] * -mCamPt.y) + (data[_AP_MCC] * -mCamPt.z);
mInvViewOutdated = true;
return true;
}
The debug output:
LookTo() From:<0,0,0> To:<-1,0,0>:
0.000000 0.000000 -1.000000 0.000000
0.000000 1.000000 0.000000 0.000000
1.000000 -0.000000 -0.000000 0.000000
0.000000 0.000000 0.000000 1.000000
setPerspective() fov:0.785398 ratio:1.185185 near:0.500000 far:100.000000:
2.036993 0.000000 0.000000 0.000000
0.000000 2.414213 0.000000 0.000000
0.000000 0.000000 -1.010050 -1.005025
0.000000 0.000000 -1.000000 0.000000
In the end, it looks like the trouble maker was just the FOV. So the quick answer is NO I didn't do anything different from the documented perspective and look at function. For anyone having a similar problem 2.0f * atan(tan(DEFAULT_FOV_RAD/mRatio) * mRatio) did the job for me.
i have a kind of problem. i've seen some more similar question but i can't find a solution.
my problem is that i have a CV_32FC3 cv::Mat, where values are stored in range between 0 and 255, let's call it S.
I have to create a matrix, called P, where store BGR values of all pixel.
So P should have as rows number the total element of S pixel, and as cols number the number of channels (3).
this is what i've tried to do:
int n_pixels = S.cols * S.rows;
p = Mat::zeros(n_pixels, 3, CV_32FC1);
for(int i=0; i<n_pixels; i++) {
Scalar pixel = S.at<Scalar>(i); // i've tried also Vec3f, Point3_, etc..
p.at<float>(i,0) = pixel[0];
p.at<float>(i,1) = pixel[1];
p.at<float>(i,2) = pixel[2];
}
i've also tried low level c-api data access like this:
for(int i=0; i<selection.rows; i++) {
p.at<float>(i,0) = S.ptr<float>(i)[0];
p.at<float>(i,1) = S.ptr<float>(i)[1];
p.at<float>(i,2) = S.ptr<float>(i)[2];
}
and also splitting channels (but splitted channels have type CV_8U so i think it is wrong):
vector<Mat> bgr;
cv::split(S, bgr);
for(int i=0; i<n_pixels; i++) {
p.at<float>(i,0) = bgr[0].data[i];
p.at<float>(i,1) = bgr[1].data[i];
p.at<float>(i,2) = bgr[2].data[i];
}
but every time i get really weird result if coutting the pixels, like:
172.2042 0.0000 0.0000
2771.1414 0.0000 0.0000
2939505920.0000 3.3468 0.0000
3079446986752.0000 0.0129 0.0000
192669347217408.0000 0.8367 0.0000
51956177323392237568.0000 16301891256320.0000 0.0509
58314208864123224064.0000 3.3945 0.0029
180449.1406 0.0000 0.0000
0.6531 0.0000 0.0000
0.0100 0.0000 0.0000
2.7373 0.0000 0.0000
10957.3184 0.0000 0.0000
739729604608.0000 3.3778 0.0000
0.0000 0.0000 0.0000
0.0000 0.0000 0.0000
0.0000 0.0000 0.0000
0.0000 0.0000 0.0000
and, in some cases also segfault..
any delucidations? how to resolve it? why my trials are wrong?
EDIT: i think the problems are data types conversion
for(int row = 0; row < resiz.rows; ++row) {
float* p = resiz.ptr<float>(row);
for(int col = 0; col < resiz.cols; ++col,p+=3) {
p[0]=; p[1]=; p[2]=;
}
}
I think you are accessing your matrix elements the wrong way.
S.at<Scalar>(i);
which is the same as
S.at<Scalar>(Point(i,0));
But you need to supply the x and y coordinates.
For me this code gives the expected results:
for(int i=0; i<n_pixels; i++)
{
Vec3f pixel = S.at<Vec3f>(i/S.cols, i%S.cols);
p.at<float>(i,0) = pixel[0];
p.at<float>(i,1) = pixel[1];
p.at<float>(i,2) = pixel[2];
}