DirectX Sphere Texture Coordinates - geometry

I have a sphere with per-vertex normals and I'm trying to derive the texture coordinates for the object using the algorithm:
U = Asin(Norm.X) / PI + 0.5
V = Asin(Norm.Y) / PI + 0.5
With a polka dot texture, I get:
Here's the same object without the texture applied:
The issue I'm particuarly looking at (I know there's a few) is the misalignment of the textures.
I am inclined to believe the issue resides in my use of those algorithms, as the specular highlighting (which doesn't utilise any textures but does rely on the normals being correct) appears to have no artifacts.
Any ideas?

Can't you just set your UVs while you are building the sphere?
Then:
u = theta / (2 * PI);
v = phi / PI;
Edit: I might also point out that there probably is something wrong with your normals given the black dot on top ... There also appears to be highlighted lines along polygon edges. This again points to probable dodgy normals ...

Related

Homogeneous coordinates and perspective-correctness?

Does the technique that vulkan uses (and I assume other graphics libraries too) to interpolate vertex attributes in a perspective-correct manner require that the vertex shader must normalize the homogenous camera-space vertex position (ie: divide through by the w-coordinate such that the w-coordinate is 1.0) prior to multiplication by a typical projection matrix of the form...
g/s 0 0 0
0 g 0 n
0 0 f/(f-n) -nf/(f-n)
0 0 1 0
...in order for perspective-correctness to work properly?
Or, will perspective-correctness continue to work on any homogeneous vertex position in camera-space (with a w-coordinate other than 1.0)?
(I didn't completely follow the perspective-correctness math, so it is unclear which to me which is the case.)
Update:
In order to clarify terminology:
vec4 modelCoordinates = vec4(x_in, y_in, z_in, 1);
mat4 modelToWorld = ...;
vec4 worldCoordinates = modelToWorld * modelCoordinates;
mat4 worldToCamera = ...;
vec4 cameraCoordinates = worldToCamera * worldCoordinates;
mat4 cameraToProjection = ...;
vec4 clipCoordinates = cameraToProjection * cameraCoordinates;
output(clipCoordinates);
cameraToProjection is a matrix like the one shown in the question
The question is does cameraCoordinates.w have to be 1.0?
And consequently the last row of both the modelToWorld and worldToCamera matricies have to be 0 0 0 1?
You have this exactly backwards. Doing the perspective divide in the shader is what prevents perspective-correct interpolation. The rasterizer needs the perspective information provided by the W component to do its job. With a W of 1, the interpolation is done in window space, without any regard to perspective.
Provide a clip-space coordinate to the output of your vertex processing stage, and let the system do what it exists to do.
the vertex shader must normalize the homogenous camera-space vertex position (ie: divide through by the w-coordinate such that the w-coordinate is 1.0) prior to multiplication by a typical projection matrix of the form...
If your camera-space vertex position does not have a W of 1.0, then one of two things has happened:
You are deliberately operating in a post-projection world space or some similar construct. This is a perfectly valid thing to do, and the math for a camera space can be perfectly reasonable.
Your code is broken somewhere. That is, you intend for your world and camera space to be a normal, Euclidean, non-homogeneous space, but somehow the math didn't work out. Obviously, this is not a perfectly valid thing to do.
In both cases, dividing by W is the wrong thing to do. If your world space that you're placing a camera into is post-projection (such as in this example), dividing by W will break your perspective-correct interpolation, as outlined above. If your code is broken, dividing by W will merely mask the actual problem; better to fix your code than to hide the bug, as it may crop up elsewhere.
To see whether or not the camera coordinates need to be in normal form, let's represent the camera coordinates as multiples of w, so they are (wx,wy,wz,w).
Multiplying through by the given projection matrix, we get the clip coordinates (wxg/s, wyg, fwz/(f-n)-nfw/(f-n)), wz)
Calculating the x-y framebuffer coordinates as per the fixed Vulkan formula we get (P_x * xg/sz +O_x, P_y * Hgy/z + O_y). Notice this does not depend on w, so the position in the framebuffer of a polygons verticies doesn't require the camera coordinates be in normal form.
Likewise calculation of the barycentric coordinates of fragments within a polygon only depends on x,y in framebuffer coordinates, and so is also independant of w.
However perspective-correct perspective interpolation of fragment attributes does depend on W_clip of the verticies as this is used in the formula given in the Vulkan spec. As shown above W_clip is wz which does depend on w and scales with it, so we can conclude that camera coordinates must be in normal form (their w must be 1.0)

Number of points in UV sphere

I'm trying to generate a mesh from a sphere of radius r. My goal is to create a UV sphere such that every point on the polyhedron has distance from the sphere smaller than tol.
The following code creates a grid of points on the sphere. How can I compute parallels_count and meridians_count so that all the point of the mesh are within tolerance?
for j in parallels_count:
parallel = PI * (j+1) / parallels_count
for i in meridians_count:
meridian = 2.0 * PI * i / meridians_count
return spherical_to_cartesian(meridian, parallel)
The code comes from here, and this is a picture of the UV sphere:
The distance between each face of the mesh and the sphere will be maximum around the center of the face.
So, for the distance between a face and the sphere to be smaller than tol it is not sufficient that the distances between the edges of the face and the corresponding circumferences are smaller than tol.
This picture is out of context but helps me explaining what I mean.
the biggest distance between points is on equator so use circle circumference to obtain angular step if I am not mistaken it should be...
dangle = tol/r; //[rad]
where r is sphere radius in the same units as tol you can use smaller step to be sure like dangle*=0.75; use this for both parallel and meridian angles.
If you want your counts instead then try:
meridians_count = (2.0*PI*r/tol)+1; // ceil or +1 just to be sure
parallels_count = 0.5*meridians_count;
It is still early here so I hope I did not make any silly math mistake (the easiest stuff is the worst for silly bugs).
Also take a look at few related QA's of mine:
Applying map of the earth texture a Sphere
Make a sphere with equidistant vertices
Sphere triangulation
[Edit1] well your new definition of tol changes everything
I see it like this:
sin(da/2) = (r-tol)/r
da = 2.0*asin((r-tol)/r)
If you convert to sphericalsurface than max difference is in center of uv grid cell which represents sqrt(2)*dadiagonal so try to use:
da = sqrt(2.0)*asin((r-tol)/r)
so your angle step should be a bit smaller than that ...

Outline of a sphere after perspective projection?

I'm working on a 3D mapping application, and I've got to do some work with things like figuring out the visible region of a sphere (Earth) from a given point in space for things like clipping mapped regions and such.
Several things get easier if I can project the outline of Earth into screen space, clip polygons there, and then project back to the surface of the Earth (lat/lon), but I'm lost as to how to do that.
Is there a reasonable way to compute the outline of a sphere after perspective projection, and then a reasonable way to project things back onto the sphere?
You can clip the polygons in 3D. The silhouette of the sphere - back-projected into 3D - will always be a circle on a plane. Perspective projection does not change that. Thus, you can clip all polygons at the plane.
Calculating the plane is not too hard. If you consider the sphere's center the origin, then the plane could be represented in normal form as:
dot(n, x) = d
n is the normal. This one is easy. It is just the unit direction vector from the sphere center to the observer.
d is the distance from the sphere center. This is a bit harder but not too hard. If l is the distance of the observer to the sphere center and r is the sphere radius, then
d = r^2 / l
This is the plane which you can use to clip your polygons in 3D. If you need the radius of the circle on it, you can use the following formula:
r_c = r / sqrt(1 - r^2/(l-d)^2)
Let us take a point on a sphere in spherical coordinates (cos(u)sin(v),sin(u)sin(v),cos(v)) and an arbitrary projection center (x,y,z).
We express that a projecting line is tangent to the sphere by the perpendicularity condition of the direction of the line and the vector from the origin of the sphere:
(x-cos(u)sin(v))cos(u)sin(v) + (y-sin(u)sinv))sin(u)sin(v) + (z-cos(v)) cos(v) = 0
This simplifies to
x cos(u)sin(v) + y sin(u)sin(v) + z cos(v) = 1
which is a curve in the longitude/latitude coordinates. You can solve u as a function of v or conversely.

Texturing a sphere in a Cg shader

So I need to map a texture to a sphere from within a pixel/fragment shader in Cg.
What I have as "input" in every pass are the Cartesian coordinates x, y, z for the point on the sphere where I want the texture to be sampled. I then transform those coordinates into Spherical coordinates and use the angles Phi and Theta as U and V coordinates, respectively, like this:
u = atan2(y, z)
v = acos(x/sqrt(x*x + y*y + z*z))
I know that this simple mapping will produce seams at the poles of the sphere but at the moment, my problem is that the texture repeats several times across the sphere. What I want and need is that the whole texture gets wrapped around the sphere exactly once.
I've fiddled with the shader and searched around for hours but I can't find a solution. I think I need to apply some sort of scaling somewhere but where? Or maybe I'm totally on the wrong track, I'm very new to Cg and shader programming in general... Thanks for any help!
Since the results of inverse trigonometric functions are angles, they will be in [-Pi, Pi] for u and [0, Pi] for v (though you can't have searched for hours with at least basic knowledge of trigonometrics, as acquired from school). So you just have to scale them appropriately. u /= 2*Pi and v /= Pi should do, assuming you have GL_REPEAT (or the D3D equivalent) as texture coordinate wrapping mode (which your description sounds like).

how to draw circular arc with give two points and radius and clockwise direction

The problem is draw arc with two pints on bitmap with radius and clockwise direction.
From your one-sentence question, I'm gonna assume you're ok with drawing Bezier curves. If not, there is plenty of information about them out there.
Anyway, you cannot create a perfect circular arc with Bezier curves (or splines). What you can do is approximating a circle to a level where the eye won't be able to see the difference. This is usually done with 8 quadratic Bezier curve segments, each covering 1/8th of the circle. This is i.e. how Adobe Flash creates circles.
If you're after a plain parametrization using sin and cos, it's way easier:
for (float t = 0; t < 2 * Math.PI; t+=0.05) {
float x = radius * sin(t);
float y = radius * cos(t);
}

Resources