UV mapping a proceduraly generated sphere in OpenGL - opengl

I'm trying to UV a 2D texture on a globe. Here's a piece of code:
double
delta = 0.0, // angle of latitude
theta = 0.0, // angle of longitude
theta_interval = (2.0 * M_PI) / latitude, // angle of latitude
delta_interval = M_PI / longitude, // angle of longitude
u_lats = 0.0,
v_longs = 0.0,
u_lats_interval = 1.0 / latitude,
v_longs_interval = 1.0 / longitude;
for (int i = 0; i < longitude; ++i) {
for (int j = 0; j < latitude; ++j) {
double
x0 = calc_x0(radius, x, theta, delta),
y0 = calc_y0(radius, y, theta, delta),
z0 = calc_z0(radius, z, theta, delta),
u0 = u_lats,
v0 = v_longs + v_longs_interval,
x1 = calc_x1(radius, x, theta, delta, delta_interval),
y1 = calc_y1(radius, y, theta, delta, delta_interval),
z1 = calc_z1(radius, z, theta, delta, delta_interval),
u1 = u_lats + u_lats_interval,
v1 = v_longs + v_longs_interval,
x2 = calc_x2(radius, x, theta, theta_interval, delta, delta_interval),
y2 = calc_y2(radius, y, theta, delta, delta_interval),
z2 = calc_z2(radius, z, theta, theta_interval, delta, delta_interval),
u2 = u_lats + u_lats_interval,
v2 = v_longs,
x3 = calc_x3(radius, x, theta, theta_interval, delta),
y3 = calc_y3(radius, y, theta, theta_interval, delta),
z3 = calc_z3(radius, z, theta, theta_interval, delta),
u3 = u_lats,
v3 = v_longs;
theta += theta_interval;
u_lats += u_lats_interval;
}
v_longs += v_longs_interval;
theta = 0.0;
delta += delta_interval;
So the way I wanted to do it is to go through the first 'strap' on the texture and then move on to the next one but it doesn't look good. I'm starting to think that it might be something about the texture because if I render less sphere, for example only 3 iterations of latitude it looks different.
Here's some pictures:
Full globe:
Same globe with only three interations of latitude:
Does anyone have any idea what I'm doing wrong?

Related

How to rotate a cube around it's edges in OpenGL using c++?

I want to write a function that expects 2 points and a rotation value.
With that information I want to rotate the cube on the edge between the two given points by the given rotation.
That's what I have tried:
void rotateAroundEdge(float x1, float y1, float z1, float x2, float y2, float z2, float rot) {
// Calculate the axis of rotation
float axis_x = y2 - y1;
float axis_y = z2 - z1;
float axis_z = x2 - x1;
// Normalize the axis of rotation
float length = sqrtf(axis_x * axis_x + axis_y * axis_y + axis_z * axis_z);
axis_x /= length;
axis_y /= length;
axis_z /= length;
// Translate the cube so that the edge is at the origin
Model = glm::translate(Model, glm::vec3(x1, y1, z1));
// Rotate the cube around the edge
Model = glm::rotate(Model, rot, glm::vec3(axis_x, axis_y, axis_z));
// Translate the cube back to its original position
Model = glm::translate(Model, glm::vec3(-x1, -y1, -z1));
}
but somehow the rotation point is not on the edges.

Calculate spherical Terrain Normals from HeightMap

I try to calculate the Vertex Normal from HeightMap Values.
I create a HeightMap at the beginning. This works so far. LOD works too.
I know how to calculate Normals for flat Terrain but how can i do this for spherical Terrain?
As you can see the Lighting is not working and NormalMaps dont work too.
I was thinking about to first calculate the Normals and Tangents as it would be flat Terrain. And than use some Transformation so the Normals and Tangents
fit the spherical Terrrain.
Edit 1:
Thats what i got so far. Is this correct Michael Nastenko? Here i use PerlinNoise not the Heightmap
float x1 = pRadius * FMath::Cos(lat + yDelta) * FMath::Cos(lon);
float y1 = pRadius * FMath::Cos(lat + yDelta) * FMath::Sin(lon);
float z1 = pRadius * FMath::Sin(lat + yDelta);
float x2 = pRadius * FMath::Cos(lat - yDelta) * FMath::Cos(lon);
float y2 = pRadius * FMath::Cos(lat - yDelta) * FMath::Sin(lon);
float z2 = pRadius * FMath::Sin(lat - yDelta);
float x3 = pRadius * FMath::Cos(lat) * FMath::Cos(lon + xDelta);
float y3 = pRadius * FMath::Cos(lat) * FMath::Sin(lon + xDelta);
float z3 = pRadius * FMath::Sin(lat);
float x4 = pRadius * FMath::Cos(lat) * FMath::Cos(lon - xDelta);
float y4 = pRadius * FMath::Cos(lat) * FMath::Sin(lon - xDelta);
float z4 = pRadius * FMath::Sin(lat);
float xDifference = GetNoiseValue(FVector(x1, y1, z1).GetSafeNormal())
- GetNoiseValue(FVector(x2, y2, z2).GetSafeNormal());
float yDifference = GetNoiseValue(FVector(x3, y3, z3).GetSafeNormal())
- GetNoiseValue(FVector(x4, y4, z4).GetSafeNormal());
FVector planeTangent = FVector(1.f, 0.f, xDifference).GetSafeNormal();
FVector planeBiTangent = FVector(0.f, 1.f, yDifference).GetSafeNormal();
Edit 2:
x1,y1,z1... are the adjacent points of the Vertex, i want to calculate the Tangent/Normal. For each of those Points i get the NoiseValue. So i can use finite differences to get the slope of the surface.
Shouldn't this be the Way to get the Tangent of flat Terrain?
Edit 3:
Calculating Normals like this is somehow wrong.
TArray<FVector> normals;
normals.Init(FVector(0, 0, 0), geoData.GeoData.Num());
int32 triangleCount = geoData.Triangles.Num() / 3;
for (int32 i = 0; i < triangleCount; i++)
{
int32 normalTriangleIndex = i * 3;
int32 triangleIndexA = geoData.Triangles[normalTriangleIndex];
int32 triangleIndexB = geoData.Triangles[normalTriangleIndex + 1];
int32 triangleIndexC = geoData.Triangles[normalTriangleIndex + 2];
FVector pointA = geoData.GeoData[triangleIndexA];
FVector pointB = geoData.GeoData[triangleIndexB];
FVector pointC = geoData.GeoData[triangleIndexC];
FVector sideAB = pointB - pointA;
FVector sideAC = pointC - pointA;
FVector norm;
norm= FVector::CrossProduct(sideAB, sideAC);
normals[triangleIndexA] = -norm;
normals[triangleIndexB] = -norm;
normals[triangleIndexC] = -norm;
}
geoData.NormalsData = normals;
On the left is my calculation, on the right i used the build in function of UE4

Calculate position and rotation of camera with mouse events

My plan:
1. Calculate mouse direction [x, y] [success]
I my Mouse Move event:
int directionX = lastPosition.x - position.x;
int directionY = lastPosition.y - position.y;
2. Calculate angles [theta, phi] [success]
float theta = fmod(lastTheta + sensibility * directionY, M_PI);
float phi = fmod(lastPhi + sensibility * directionX * -1, M_PI * 2);
Edit {
bug fix:
float theta = lastTheta + sensibility * directionY * -1;
if (theta < M_PI / -2)theta = M_PI / -2;
else if (theta > M_PI / 2)theta = M_PI / 2;
float phi = fmod(lastPhi + sensibility * directionX * -1, M_PI * 2);
}
Now I have given theta, phi, the centerpoint and the radius and I want to calculate the position and the rotation [that the camera look at the centerpoint]
3. Calculate position coordinates [X,Y,Z] [failed]
float newX = radius * sin(phi) * cos(theta);
float newY = radius * sin(phi) * sin(theta);
float newZ = radius * cos(phi);
Solution [by meowgoesthedog]:
float newX = radius * cos(theta) * cos(phi);
float newY = radius * sin(theta);
float newZ = radius * cos(theta) * sin(phi);
4. Calculate rotation [failed]
float pitch = ?;
float yaw = ?;
Solution [by meowgoesthedog]:
float pitch = -theta;
float yaw = -phi;
Thanks for your solutions!
Your attempt was almost (kinda) correct:
As the diagram shows, in OpenGL the "vertical" direction is conventionally taken to be Y, whereas your formulas assume it is Z
phi and theta are in the wrong order
Very simple conversion: yaw = -phi, pitch = -theta (from the perspective of the camera)
Fixed formulas:
float position_X = radius * cos(theta) * cos(phi);
float position_Y = radius * sin(theta);
float position_Z = radius * cos(theta) * sin(phi);
(There may also be some sign issues with the mouse deltas but they should be easy to fix.)

C++ Finding parallel lines Coordinates inside a boundary

I am given a Line PQ and a boundary. I have to find two parallel lines to the given line but lines should intersect the boundary. Also i know the distance between the parallel lines to the given line. I need to find the P'Q' and P"Q".
Please any one give a simple solution.
float vx = x2 - x1;
float vy = y2 - y1;
float mag = sqrt(vx * vx + vy * vy);
float t = (mag / 2.0) / mag;
float px = (1 - t) * x1 + t * x2;
float py = (1 - t) * y1 + t * y2;
I just found the centre point of PQ by the above code. Further i planned to draw a perpendicular line thru (px, py) with the known distance, then drawing lines perpendicular to that new line(those lines will be parallel to PQ), thru the end points of that new line. But i could not achieve it. can anyone help me or suggest me a way who know maths
Finally i got the solution.
The steps are.
First i am getting the center point of PQ.
POINT find_a_point_in_distance(float x1, float y1, float x2, float y2, float len = 0) {
float vx = x2 - x1;
float vy = y2 - y1;
float mag = sqrt(vx * vx + vy * vy);
float t = len == 0 ? ((mag / 2.0) / mag) : (len / mag);
float px = (1 - t) * x1 + t * x2;
float py = (1 - t) * y1 + t * y2;
POINT res = { px, py };
return res;
}
here (px, py) is center point of PQ.
Then i am finding the perpendicular line through (px, py).
Already i have mentioned in the question that i know distance between PQ and P'Q' also PQ and P"Q". So i am getting two points in that perpendicular line using that distance. Finally i know the angle of the line PQ, so P'Q' and P"Q" should be in that same angle, using these details i can get the lines P'Q' and P"Q" what ever length i want. Here in below code i am getting the line P'Q' and P"Q" with the length of the diagonal of the rectangular box.
POINT res = find_a_point_in_distance(x1, y1, x2, y2);
POINT res2 = find_a_point_in_distance(res.x, res.y, x2, y2, halflen);
float cosA = acos((res2.x - res.x) / halflen) * 180 / PI;
float sinA = asin((res2.y - res.y) / halflen) * 180 / PI;
float cosAngle = cos((cosA + 90.0) * PI / 180.0);
float sinAngle = sin((sinA + 90.0) * PI / 180.0);
float cx1 = res.x + halflen * cosAngle;
float cy1 = res.y + halflen * sinAngle;
float cosAngle2 = cos((cosA - 90.0) * PI / 180.0);
float sinAngle2 = sin((sinA - 90.0) * PI / 180.0);
float cx2 = res.x + halflen * cosAngle2;
float cy2 = res.y + halflen * sinAngle2;
float diagonal = sqrt(width * width + height * height);
float halfdiagonal = diagonal / 2.0;
float cosAngleT = cos(cosA * PI / 180.0);
float sinAngleT = sin(sinA * PI / 180.0);
float cosAngleTD = cos((cosA + 180) * PI / 180.0);
float sinAngleTD = sin((sinA + 180) * PI / 180.0);
float cx10 = cx1 + halfdiagonal * cosAngleT;
float cy10 = cy1 + halfdiagonal * sinAngleT;
float cx11 = cx1 + halfdiagonal * cosAngleTD;
float cy11 = cy1 + halfdiagonal * sinAngleTD;
float cx20 = cx2 + halfdiagonal * cosAngleT;
float cy20 = cy2 + halfdiagonal * sinAngleT;
float cx21 = cx2 + halfdiagonal * cosAngleTD;
float cy21 = cy2 + halfdiagonal * sinAngleTD;
here (cx10, cy10) and (cx11, cy11) is line P'Q' and
(cx20, cy20) and (cx21, cy21) is line P"Q".
then finally im finding the intersect point of P'Q' and P"Q" with all sides of rectangle

Efficient way to draw Ellipse with OpenGL or D3D

There is a fast way to draw circle like this
void DrawCircle(float cx, float cy, float r, int num_segments)
{
float theta = 2 * 3.1415926 / float(num_segments);
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = r;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x + cx, y + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
I am wondering if there is a similar way to draw ellipse where its major/minor axes vector and size are both known.
If we take your example we can use an internal radius of 1 and apply horizontal/vertical radius separately in order to get an ellipse:
void DrawEllipse(float cx, float cy, float rx, float ry, int num_segments)
{
float theta = 2 * 3.1415926 / float(num_segments);
float c = cosf(theta);//precalculate the sine and cosine
float s = sinf(theta);
float t;
float x = 1;//we start at angle = 0
float y = 0;
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
//apply radius and offset
glVertex2f(x * rx + cx, y * ry + cy);//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
There is no way to draw a curve in openGL, just a lot of straight lines. But if you used vertex buffer objects then you won't have to send each vertex to the graphics card which will be much faster.
My Java Example
If the ellipse is ((x-cx)/a)^2 + ((y-cy)/b)^2 = 1 then change the glVertex2f call to
glVertext2d(a*x + cx, b*y + cy);
To simplify the sums, lets suppose for a while that the ellipse is centred at the origin.
If the ellipse is rotated so that the semi-major axis (of length a) makes an angle theta with the x axis, then the ellipse is the set of points p so that p' * inv(C) * p = 1, where C is the matrix R(theta) * D * R(theta)' where ' denotes transpose and D is the diagonal matrix with entries a*a,b*b (b the length of the semi-minor axis). If L is the cholesky factor (eg here) of C then the ellipse is the set of points p so that (inv(L) * p)'*(inv(L) *p ) = 1, so that L maps the unit circle to the ellipse. If we have computed L as ( u 0 ; v w) (just once, before the loop) then the glVertexf call becomes glVertex2f( u*x + cx, v*x + w*y + cy);
L can be calculated like this (where C is cos(theta) and S is sin(theta)):
u = sqrt( C*C*a*a + S*S*b*b); v = C*S*(a*a-b*b); w = a*b/u;