How do I get correct answers using my code with the barycentric formula? - c++

My function getHeightOfTerrain() is calling a barycentric formula function that is not returning the correct height for the one set test height in : heightMapFromArray[][].
I've tried watching OpenGL JAVA Game tutorials 14,21, 22, by "thin matrix" and I am confused on how to use my array: heightMapforBaryCentric in both of the supplied functions, and how to set the arguments that are passed to the baryCentic() function in some sort of manner so that I can solve the problem.
int creaateTerrain(int height, int width)
{
float holderY[6] = { 0.f ,0.f,0.f,0.f,0.f,0.f };
float scaleit = 1.5f;
float holder[6] = { 0.f,0.f,0.f,0.f,0.f,0.f };
for (int z = 0, z2 =0; z < iterationofHeightMap;z2++)
{
//each loop is two iterations and creates one quad (two triangles)
//however because each iteration is by two (i.e. : x=x+2) om bottom
//the amount of triangles is half the x value
//
//number of vertices : 80 x 80 x 6.
//column
for (int x = 0, x2 = 0; x < iterationofHeightMap;x2++)
{
//relevant - A : first triangle - on left triangle
//[row] [colum[]
holder[0] = heightMapFromArray[z][x];
//holder[0] = (float)imageData[(z / 2 * MAP_Z + (x / 2)) * 3];
//holder[0] = holder[0] / 255;// *scaleit;
vertices.push_back(glm::vec3(x, holder[0], z));
//match height map with online barycentric use
heightMapforBaryCentric[x2][z2] = holder[0];
holder[1] = heightMapFromArray[z+2][x];
//holder[1] = (float)imageData[(((z + 2) / 2 * MAP_Z + ((x) / 2))) * 3];
//holder[1] = holder[1] / 255;// 6 * scaleit;
vertices.push_back(glm::vec3(x, holder[1], z + 2));
//match height map with online barycentric use
heightMapforBaryCentric[x2][z2+1] = holder[1];
holder[2] = heightMapFromArray[z+2][x+2];
//holder[2] = (float)imageData[(((z + 2) / 2 * MAP_Z + ((x + 2) / 2))) * 3];
//holder[2] = holder[2] / 255;// *scaleit;
vertices.push_back(glm::vec3(x + 2, holder[2], z + 2));
////match height map with online barycentric use
heightMapforBaryCentric[x2+1][z2+1] = holder[2];
//relevant - B - second triangle (on right side)
holder[3] = heightMapFromArray[z][x];
//holder[3] = (float)imageData[((z / 2)*MAP_Z + (x / 2)) * 3];
//holder[3] = holder[3] / 255;// 256 * scaleit;
vertices.push_back(glm::vec3(x, holder[3], z));
holder[4] = heightMapFromArray[x+2][z+2];
//holder[4] = (float)imageData[(((z + 2) / 2 * MAP_Z + ((x + 2) / 2))) * 3];
//holder[4] = holder[4] / 255;// *scaleit;
vertices.push_back(glm::vec3(x + 2, holder[4], z + 2));
holder[5] = heightMapFromArray[x+2][z];
//holder[5] = (float)imageData[((z / 2)*MAP_Z + ((x + 2) / 2)) * 3];
//holder[5] = holder[5] / 255;// *scaleit;
vertices.push_back(glm::vec3(x + 2, holder[5], z));
x = x + 2;
}
z = z + 2;
}
return(1);
}
float getHeightOfTerrain(float worldX, float worldZ) {
float terrainX = worldX;
float terrainZ = worldZ;
int gridSquareSize = 2.0f;
gridX = (int)floor(terrainX / gridSquareSize);
gridZ = (int)floor(terrainZ / gridSquareSize);
xCoord = ((float)(fmod(terrainX, gridSquareSize)) / (float)gridSquareSize);
zCoord = ((float)(fmod(terrainZ, gridSquareSize)) / (float)gridSquareSize);
if (xCoord <= (1 - zCoord))
{
answer = baryCentric(
//left triangle
glm::vec3(0.0f, heightMapforBaryCentric[gridX][gridZ], 0.0f),
glm::vec3(0.0f, heightMapforBaryCentric[gridX][gridZ+1], 1.0f),
glm::vec3(1.0f, heightMapforBaryCentric[gridX+1][gridZ+1], 1.0f),
glm::vec2(xCoord, zCoord));
// if (answer != 1)
// {
// fprintf(stderr, "Z:gridx: %d gridz: %d answer: %f\n", gridX, gridZ,answer);
//
// }
}
else
{
//right triangle
answer = baryCentric(glm::vec3(0, heightMapforBaryCentric[gridX][gridZ], 0),
glm::vec3(1,heightMapforBaryCentric[gridX+1][gridZ+1], 1),
glm::vec3(1,heightMapforBaryCentric[gridX+1][gridZ], 0),
glm::vec2(xCoord, zCoord));
}
if (answer == 1)
{
answer = 0;
}
//answer = abs(answer - 1);
return(answer);
}
float baryCentric(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3 , glm::vec2 pos) {
float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
float l3 = 1.0f - l1 - l2;
return (l1 * p1.y + l2 * p2.y + l3 * p3.y);
}
My expected results were that the center of the test grid's height to be the set value .5 and gradually less as the heights declined. My results were the heights being all the same, varied, or increasing. Usually these heights were under the value of one.

Related

Rotating line inside rectangle bounds

What I try to achieve is to rotate a line around rectangle center so it always stays in its bounds touching them (or having some padding).
Now I have the following routine for this, as you see I use tan calculations dividing my rectangle into 8 parts (red lines)
It works so far, but for some reason I have inconsistency using other calculation for radius drawing (green line), the lines won't always match as expected and I wonder why.
Basically the same could be achieved using just sin/cos calculations and finding cross points between lines and rect borders, but for some reason I could not get it to work.
std::pair<Point, Point>
MathUtils::calculateRotatingLine(Size size, double degrees)
{
auto width = size.width;
auto height = size.height;
double diagonalAngleTopRight = radiansToDegrees(atan((width / 2) / (height / 2)));
double diagonalAngleBottomRight = 90 + (90 - diagonalAngleTopRight);
double diagonalAngleBottomLeft = 180 + diagonalAngleTopRight;
double diagonalAngleTopLeft = 180 + diagonalAngleBottomRight;
double x, y;
/*
* *8*1*
* 7* *2
* 6* *3
* *5*4*
*/
// 1
if (degrees >= 0 && degrees <= diagonalAngleTopRight) {
x = width / 2 + height / 2 * tan(degreesToRadians(degrees));
y = 0;
}
// 2
else if (degrees > diagonalAngleTopRight && degrees <= 90) {
x = width;
y = width / 2 * tan(degreesToRadians(degrees - diagonalAngleTopRight));
}
// 3
else if (degrees > 90 && degrees <= diagonalAngleBottomRight) {
x = width;
y = height / 2 + width / 2 * tan(degreesToRadians(degrees - 90));
}
// 4
else if (degrees > diagonalAngleBottomRight && degrees <= 180) {
x = width - height / 2 * tan(degreesToRadians(degrees - diagonalAngleBottomRight));
y = height;
}
// 5
else if (degrees > 180 && degrees <= diagonalAngleBottomLeft) {
x = width / 2 - height / 2 * tan(degreesToRadians(degrees - 180));
y = height;
}
// 6
else if (degrees > diagonalAngleBottomLeft && degrees <= 270) {
x = 0;
y = height - width / 2 * tan(degreesToRadians(degrees - diagonalAngleBottomLeft));
}
// 7
else if (degrees > 270 && degrees <= diagonalAngleTopLeft) {
x = 0;
y = height / 2 - width / 2 * tan(degreesToRadians(degrees - 270));
}
// 8
else {
x = height / 2 * tan(degreesToRadians(degrees - diagonalAngleTopLeft));
y = 0;
}
return {Point{width / 2, height / 2}, Point{x, y}};
}
Green line calculation
Point
MathUtils::calculateCirclePoint(double radius, double degrees)
{
return {radius * cos(degreesToRadians(degrees)), radius * sin(degreesToRadians(degrees))};
}
EDIT
Awesome, it works thanks to #MBo
Point
MathUtils::calculateCrossPoint(Size size, double degrees)
{
auto x0 = size.width / 2;
auto y0 = size.height / 2;
auto vx = cos(degreesToRadians(degrees - 90));
auto vy = sin(degreesToRadians(degrees - 90));
//potential border positions
auto ex = vx > 0 ? size.width : 0;
auto ey = vy > 0 ? size.height : 0;
//check for horizontal/vertical directions
if (vx == 0) {
return {x0, ey};
}
if (vy == 0) {
return {ex, y0};
}
// in general case find times of intersections with horizontal and vertical edge line
auto tx = (ex - x0) / vx;
auto ty = (ey - y0) / vy;
// and get intersection for smaller parameter value
if (tx <= ty) {
return {ex, y0 + tx * vy};
}
return {x0 + ty * vx, ey};
}
Pseudocode to find intersection of ray emitted from rectangle center (with angle an in radians) with edges. (Works also for other (x0,y0) positions)
x0 = width / 2;
y0 = height / 2;
vx = cos(an);
vy = sin(an);
//potential border positions
ex = vx > 0? width: 0
ey = vy > 0? height: 0
//check for horizontal/vertical directions
if vx = 0 then
return cx = x0, cy = ey
if vy = 0 then
return cx = ex, cy = y0
//in general case find times of intersections with horizontal and vertical edge line
tx = (ex - x0) / vx
ty = (ey - y0) / vy
//and get intersection for smaller parameter value
if tx <= ty then
return cx = ex, cy = y0 + tx * vy
else
return cx = x0 + ty * vx, cy = ey

What am I doing wrong when executing the sobel filter function in c++

Here is my sobel filter function performed on a grayscale image. Apparently I'm not doing my calculations correct because I keep getting an all black image. I have already turned in the project but it is bothering me that the results aren't right.
int sobelH[3][3] = { -1, 0, 1,
-2, 0, 2,
-1, 0, 1 },
sobelV[3][3] = { 1, 2, 1,
0, 0, 0,
-1, -2, -1 };
//variable declaration
int mag;
int pix_x, pix_y = 0;
int img_x, img_y;
for (img_x = 0; img_x < img->x; img_x++)
{
for (img_y = 0; img_y < img->y; img_y++)
{
pix_x = 0;
pix_y = 0;
//calculating the X and Y convolutions
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
pix_x += (img->data[img_y * img->x + img_x].red + img->data[img_y * img->x + img_x].green + img->data[img_y * img->x + img_x].blue) * sobelH[1 + i][1 + j];
pix_y += (img->data[img_y * img->x + img_x].red + img->data[img_y * img->x + img_x].green + img->data[img_y * img->x + img_x].blue) * sobelV[1 + i][1 + j];
}
}
//Gradient magnitude
mag = sqrt((pix_x * pix_x) + (pix_y * pix_y));
if (mag > RGB_COMPONENT_COLOR)
mag = 255;
if (mag < 0)
mag = 0;
//Setting the new pixel value
img->data[img_y * img->x + img_x].red = mag;
img->data[img_y * img->x + img_x].green = mag;
img->data[img_y * img->x + img_x].blue = mag;
}
}
Although your code could use some improvement, the main reason is that you compute the convolution at constant img_y and img_x. What you need to do is:
pix_x += (img->data[img_y * img->x + img_x + i].red + img->data[img_y * img->x + img_x + i].green + img->data[img_y * img->x + img_x + i].blue) * sobelH[1 + i][1 + j];
Indeed, the Sobel convolution is symmetric, so if you compute the convolution with a constant image, it will result in only black.
Note that in the above example I do not take into account the border of the image. You should make sure to not access pixels that are outside your pixel array.
Another mistake is that you're writing in the input image. You write at location (x,y), then compute the filter result for location (x+1,y) using the modified value at (x,y), which is the wrong value to use.
You need to write your result to a new image.

how can i change the b-spline curves from 4 point to 6?

I have a code on C++ it's b-spline curve that has 4 points if I want to change it to 6 point what shall I change in the code?
You can check the code:
#include "graphics.h"
#include <math.h>
int main(void) {
int gd, gm, page = 0;
gd = VGA;
gm = VGAMED;
initgraph(&gd, &gm, "");
point2d pontok[4] = { 100, 100, 150, 200, 170, 130, 240, 270 }; //pontok means points
int ap;
for (;;) {
setactivepage(page);
cleardevice();
for (int i = 0; i < 4; i++)
circle(integer(pontok[i].x), integer(pontok[i].y), 3);
double t = 0;
moveto((1.0 / 6) * (pontok[0].x * pow(1 - t, 3) +
pontok[1].x * (3 * t * t * t - 6 * t * t + 4) +
pontok[2].x * (-3 * t * t * t + 3 * t * t + 3 * t + 1) +
pontok[3].x * t * t * t),
(1.0 / 6) * (pontok[0].y * pow(1 - t, 3) +
pontok[1].y * (3 * t * t * t - 6 * t * t + 4) +
pontok[2].y * (-3 * t * t * t + 3 * t * t + 3 * t + 1) +
pontok[3].y * t * t * t));
for (t = 0; t <= 1; t += 0.01)
lineto(
(1.0 / 6) * (pontok[0].x * pow(1 - t, 3) +
pontok[1].x * (3 * t * t * t - 6 * t * t + 4) +
pontok[2].x * (-3 * t * t * t + 3 * t * t + 3 * t + 1) +
pontok[3].x * t * t * t),
(1.0 / 6) * (pontok[0].y * pow(1 - t, 3) +
pontok[1].y * (3 * t * t * t - 6 * t * t + 4) +
pontok[2].y * (-3 * t * t * t + 3 * t * t + 3 * t + 1) +
pontok[3].y * t * t * t));
/* Egerkezeles */ //Egerkezeles means mouse event handling
if (!balgomb)
ap = getactivepoint((point2d *)pontok, 4, 5);
if (ap >= 0 && balgomb) { //balgomb means left mouse button
pontok[ap].x = egerx; //eger means mouse
pontok[ap].y = egery;
}
/* Egerkezeles vege */
setvisualpage(page);
page = 1 - page;
if (kbhit())
break;
}
getch();
closegraph();
return 0;
}
From your formula, it looks like you are trying to draw a cubic Bezier curve. But the formula does not seem entirely correct. You can google "cubic Bezier curve" to find the correct formula. The Wikipedia page contains the formula for any degree of Bezier curve. You can find the "6-points" formula from there by using degree = 5.

2d rotation opengl

Here is the code I am using.
#define ANGLETORADIANS 0.017453292519943295769236907684886f // PI / 180
#define RADIANSTOANGLE 57.295779513082320876798154814105f // 180 / PI
rotation = rotation *ANGLETORADIANS;
cosRotation = cos(rotation);
sinRotation = sin(rotation);
for(int i = 0; i < 3; i++)
{
px[i] = (vec[i].x + centerX) * (cosRotation - (vec[i].y + centerY)) * sinRotation;
py[i] = (vec[i].x + centerX) * (sinRotation + (vec[i].y + centerY)) * cosRotation;
printf("num: %i, px: %f, py: %f\n", i, px[i], py[i]);
}
so far it seams my Y value is being fliped.. say I enter the value of X = 1 and Y = 1 with a 45 rotation you should see about x = 0 and y = 1.25 ish but I get x = 0 y = -1.25.
Also my 90 degree rotation always return x = 0 and y = 0.
p.s I know I'm only centering my values and not putting them back where they came from. It's not needed to put them back as all I need to know is the value I'm getting now.
Your bracket placement doesn't look right to me. I would expect:
px[i] = (vec[i].x + centerX) * cosRotation - (vec[i].y + centerY) * sinRotation;
py[i] = (vec[i].x + centerX) * sinRotation + (vec[i].y + centerY) * cosRotation;
Your brackets are wrong. It should be
px[i] = ((vec[i].x + centerX) * cosRotation) - ((vec[i].y + centerY) * sinRotation);
py[i] = ((vec[i].x + centerX) * sinRotation) + ((vec[i].y + centerY) * cosRotation);
instead

How to find the normal of a complex shape(more than 4 vertices) and apply lighting on it?

im currently trying to apply lighting on a complex shape drawn with the GL_TRIANGLE_STRIP flag. since every plane in the XYZ can be defined by 3 points calculating the normal can be quite easy, but what happens when i use gl_triangle_strip?
just to make the following code more readable, the drawing process goes like this :
(x,y) -> (x+1 , y) -> (x , y+1) -> (x+1 , y+1)
for(int i = 0; i < m_GraphConfig.MAXY ; i +=2)
{
glBegin(GL_TRIANGLE_STRIP);
for (int j = 0; j < m_GraphConfig.MAXX ;j+=2)
{
if ( (i * m_GraphConfig.MAXX + j + 2) % (m_GraphConfig.MAXX) != 0 && (i+2) % (m_GraphConfig.MAXY) != 0 && (j + 2) % (m_GraphConfig.MAXX) != 0 )
{
index = i * (m_GraphConfig.MAXX) + j;
heightVal = host[index];
glColor3b(((heightVal % 32) * 7 %255), ((heightVal % 16) * 14) %255, ((heightVal % 128) * 2)%255);
glTexCoord2f(0.0f, 0.0f);
glVertex3d(xFactor * j , host[index] /m_GraphConfig.devider , zFactor * i);
index = i * (m_GraphConfig.MAXX) + j + 2;
heightVal = host[index];
glColor3b(((heightVal % 32) * 7)%255, ((heightVal % 16) * 14)%255, ((heightVal % 128) * 2)%255);
glTexCoord2f(1.0f, 0.0f);
glVertex3d(xFactor * (j + 2) , host[index] / m_GraphConfig.devider, zFactor * i);
index = i * (m_GraphConfig.MAXX) + j + (2 * m_GraphConfig.MAXX);
heightVal = host[index];
glColor3b(((heightVal % 32) * 7)%255, ((heightVal % 16) * 14)%255, ((heightVal % 128) * 2)%255);
glTexCoord2f(0.0f, 1.0f);
glVertex3d(xFactor * j , host[index] / m_GraphConfig.devider , zFactor * (i + 2));
index = i * (m_GraphConfig.MAXX) + j + (2 * m_GraphConfig.MAXX) + 2;
heightVal = host[index];
glColor3b(((heightVal % 32) * 7)%255, ((heightVal % 16) * 14)%255, ((heightVal % 128) * 2)%255);
glTexCoord2f(1.0f, 1.0f);
glVertex3d(xFactor * ( j + 2) , host[index] / m_GraphConfig.devider , zFactor * (i + 2));
}
}
glEnd();
glBindTexture( GL_TEXTURE_2D, 0 ); //clear the texture buffer
}
It much depends on your usage of it. Is it a flat surface (e.g. cylinder bottom) or a curvy shape (e.g. cylinder side)
For the first case you can calculate normal for every triangle in the strip and use average of all of them for the polygon.
For the second case you need to split the triangle strip into triangles and treat/render them separately one by one. If you want to keep the smoothshading and triangle strip then you will need to calculate and use per-vertice normals (which are averages of all triangles normals that use this vertice)