Direction to Environment Map UV Coordinates - opengl

I'm trying to render an environment map as a sphere surrounding the scene. I would like to be able to sample the environment map, as a panoramic photo, using UV coordinates derived from a direction vector (where the origin is fixed at (0,0,0)).
How can I project the direction to calculate 2D UV coordinates, so I can sample the environment map?

Calculating texture coordinates for reflection map or environment map is here.
vec3 r = reflect( -vEyeVec, N );
float m = 2. * sqrt(pow( r.x, 2. ) + pow( r.y, 2. ) + pow( r.z + 1., 2.0));
vReflectionCoord = r.xy / m + .5;
vReflectionCoord.y = -vReflectionCoord.y;

Related

Adaptive Depth Bias for Shadow Maps Ray Casting

I have found this paper dealing with how to compute the perfect bias when dealing with shadow map.
The idea is to:
get the texel used when sampling the shadowMap
project the texel location back to eyeSpace (ray tracing)
get the difference between your frament.z and the intersection with
the fragment's face.
This way you have calculated the error which serve as the appropriate bias for z-fighting.
Now I am trying to implement it, but I experiment some troubles:
I am using a OrthoProjectionMatrix, so i think I don't need to divide by w back and forth.
I am good until I am computing the ray intersection with the face.
I have a lot of faces failing the test, and my bias is way to important.
This is my fragment shader code:
float getBias(float depthFromTexture)
{
vec3 n = lightFragNormal.xyz;
//no need to divide by w, we got an ortho projection
//we are in NDC [-1,1] we go to [0,1]
//vec4 smTexCoord = 0.5 * shadowCoord + vec4(0.5, 0.5, 0.5, 0.0);
vec4 smTexCoord = shadowCoord;
//we are in [0,1] we go to texture_space [0,1]->[0,shadowMap.dimension]:[0,1024]
//get the nearest index in the shadow map, the texel corresponding to our fragment we use floor (125.6,237.9) -> (125,237)
vec2 delta = vec2(xPixelOffset, yPixelOffset);
vec2 textureDim = vec2(1/xPixelOffset, 1/yPixelOffset);
vec2 index = floor(smTexCoord.xy * textureDim);
//we get the center of the current texel, we had 0.5 to put us in the middle (125,237) -> (125.5,237.5)
//we go back to [0,1024] -> [0,1], (125.5,237.5) -> (0.12, 0.23)
vec2 nlsGridCenter = delta*(index + vec2(0.5f, 0.5f));
// go back to NDC [0,1] -> [-1,1]
vec2 lsGridCenter = 2.0 * nlsGridCenter - vec2(1.0);
//compute lightSpace grid direction, multiply by the inverse projection matrice or
vec4 lsGridCenter4 = inverse(lightProjectionMatrix) * vec4(lsGridCenter, -frustrumNear, 0);
vec3 lsGridLineDir = vec3(normalize(lsGridCenter4));
/** Plane ray intersection **/
// Locate the potential occluder for the shading fragment
//compute the distance t we need to continue in the gridDir direction, the point is "t" far
float ls_t_hit = dot(n, lightFragmentCoord.xyz) / dot(n, lsGridLineDir);
if(ls_t_hit<=0){
return 0; // i got a lot of negativ values it shouldn t be the case
}
//compute the point p with the face
vec3 ls_hit_p = ls_t_hit * lsGridLineDir;
float intersectionDepth = lightProjectionMatrix * vec4(ls_hit_p, 1.0f).z / 2 + 0.5;
float fragmentDepth = lightProjectionMatrix * lightFragmentCoord.z / 2 + 0.5;
float result = abs(intersectionDepth - fragmentDepth);
return result;
}
I am struggling with this line:
vec4 lsGridCenter4 = inverse(lightProjectionMatrix) * vec4(lsGridCenter, -frustrumNear, 0);
i don't know if i am correct maybe:
vec4(lsGridCenter, -frustrumNear, 1);
and of course the plane intersection
from wikipedia:
where:
l = my vector normalized direction
Po = a point belonging to the the plane
l0 = offset of the vector, I think it's the origin so in eye space it should be (0,0,0) i might be wrong here
n = normal of the plane, the normal of my fragment in eyespace
in my code:
float ls_t_hit = dot(n, lightFragmentCoord.xyz) / dot(n, lsGridLineDir);

Discarding some voxels in ray casting

I have a volume rendering implementation in shaders which uses the gpu raycasting technique. Basically I have a unit cube at the center of my scene.
I render the vertices of the unit cube in my vertex shader and pass texture coordinates to the fragment shader like this:
in vec3 aPosition;
uniform mat4 uMVPMatrix;
smooth out vec3 vUV;
void main() {
gl_Position = uMVPMatrix * vec4(aPosition.xyz,1);
vUV = aPosition + vec3(0.5);
}
Since the unit cube coordinates goes from -0.5 to 0.5 I clamp the texture coordinates from 0.0 to 1.0 by adding 0.5 to them..
In the fragment shader I got the texture coordinate which is interpolated by the rasterizer:
...
smooth in vec3 vUV; // Position of the data interpolated by the rasterizer
...
void main() {
...
vec3 dataPos = vUV;
...
for (int i = 0; i < MAX_SAMPLES; i++) {
dataPos = dataPos + dirStep;
...
float sample = texture(volume, dataPos).r;
...//Some more operations on the sampled color
float prev_alpha = transferedColor.a * (1.0 - fragColor.a);
fragColor.rgb += prev_alpha * transferedColor.rgb;
fragColor.a += prev_alpha; //final color
if(fragColor.a>0.99)
break;
}
}
My rendering works well.
Now I have implemented a selection algorithm, which is working fine with particles (real vertices in the world coordinates).
My question is how can I make it work with the volumetric dataset? Because only vertices I have is the vertices of the unit cube. Since the data points are interpolated by the rasterizer I don't know the real(world) coordinates of the voxels.
It's fair enough for me to get the center coordinates of the voxels and treat them like particles so I can omit or include the necesseary voxels (I guess vUV coordinates?) in the fragment shader.
First you have to work out your sampled voxel coordinate. (I'm assuming that volume is your 3D texture). To find it you have to de-linearization it from dataPos into the 3 axis components in your 3D texture (w x h x d). So if a sample in MAX_SAMPLES has an index computed like ((z * d) + y) * h + x, then the coordinate can be found by..
z = floor(sample / (w * h))
y = floor((sample - (z * w * h)) / w)
x = sample - (z * w * h) - (y * w)
The floor operation is important to retrieve the integer index.
This is the coordinate of your sample. Now you can multiply it with the inverse of the mvp you used for the 4 vertices, this gives you the position (or the center, maybe you have to add vec3(0.5)) of your sample in world space.
This raises a new question however: see if you can rewrite your selection algorithm so that you don't have to jump through all the computations, and do the selection in screen-space rather than world space.

Texture Warping Shader: Polar to Rectangular Coordinates

I am writing a 2D game using OpenGL and I have planned a shadow casting algorithm which needs a transformation of a texture from Polar Coordinates to Rectangular Coordinates. The desired effect is the following:
From this:
To this:
I know the formulas for converting coordinates between both Polar and Rectangular systems but I am having problems on writing the shader to achieve the desired effect.
My shader receives a texture as an input and should draw the warped texture to the screen. I planned the following (knowing that the fragment shader acts upon one fragment at a time):
Find the coordinates of the current fragment using gl_FragCoord.xy
Determine r and theta that correspond to the point (x, y).
Transform r and theta into texture_x and texture_y (which will be used to sample the texture)
Transfer the sampled pixel to the current fragment
My final result is the same input texture rotated 90 degrees clock-wise. I think that I'm missing something on step 3. I might be just getting the same x and y of the current fragment, because I'm simply using both the transform and inverse transform formulas.
How should I proceed to get the expected result?
Here is my shader:
#version 120
uniform sampler2D tex;
void main() {
vec2 fragCoords = gl_FragCoord.xy - vec2(128, 128); //shift the coordinates so that 0, 0 is in the center of the screen (the final texture is 256 * 256)
fragCoords /= vec2(256, 256);
float r = sqrt(pow(fragCoords.x, 2) + pow(fragCoords.y, 2));
float theta = atan(fragCoords.y, fragCoords.x);
if (fragCoords.y/fragCoords.x <= 0.5 && fragCoords.y/fragCoords.x >= -0.5) {
r *= 1/(256*sin(theta));
} else {
r *= 1/(0.5*256*cos(theta));
}
vec2 texCoords = vec2(r, theta);
vec4 texFrag = texture2D(tex, texCoords);
gl_FragColor = texFrag * vec4(1.0, 0.0, 0.0, 1.0);
}
In your shader you're first translating into polar coordinates
float r = sqrt(pow(fragCoords.x, 2) + pow(fragCoords.y, 2));
float theta = atan(fragCoords.y, fragCoords.x);
and then you't translating them back into cartesian
float tX = r * sin(theta);
float tY = r * cos(theta);
You want to stay in polar coordinates, so just plug r and theta into the texture coordinates
vec2 texCoords = vec2(r , theta);
vec4 texFrag = texture2D(tex, texCoords);
However by the looks of the images you pasted there's some renormalization step involved, so that (r, theta) will cover a rectangular area. If I'm not entirely mistaken, then r is scaled by the distance it takes a ray from the center-bottom to intersect with the rectangular area. If we assume theta=0 to be straight up, then for the range [-atan(0.5)…atan(0.5)] it's scaled by 1/(height*sin(theta)) and outside that range by 1/(0.5*width*cos(theta))

How to recover view space position given view space depth value and ndc xy

I am writing a deferred shader, and am trying to pack my gbuffer more tightly. However, I cant seem to compute the view position given the view space depth correctly
// depth -> (gl_ModelViewMatrix * vec4(pos.xyz, 1)).z; where pos is the model space position
// fov -> field of view in radians (0.62831855, 0.47123888)
// p -> ndc position, x, y [-1, 1]
vec3 getPosition(float depth, vec2 fov, vec2 p)
{
vec3 pos;
pos.x = -depth * tan( HALF_PI - fov.x/2.0 ) * (p.x);
pos.y = -depth * tan( HALF_PI - fov.y/2.0 ) * (p.y);
pos.z = depth;
return pos;
}
The computed position is wrong. I know this because I am still storing the correct position in the gbuffer and testing using that.
3 Solutions to recover view space position in perspective projection
The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. It transforms from view (eye) space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1).
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
Perspective Projection Matrix:
r = right, l = left, b = bottom, t = top, n = near, f = far
2*n/(r-l) 0 0 0
0 2*n/(t-b) 0 0
(r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -1
0 0 -2*f*n/(f-n) 0
it follows:
aspect = w / h
tanFov = tan( fov_y * 0.5 );
prjMat[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect)
prjMat[1][1] = 2*n/(t-b) = 1.0 / tanFov
At Perspective Projection, the Z component is calculated by the rational function:
z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye
The depth (gl_FragCoord.z and gl_FragDepth) is calculated as follows:
z_ndc = clip_space_pos.z / clip_space_pos.w;
depth = (((farZ-nearZ) * z_ndc) + nearZ + farZ) / 2.0;
1. Field of view and aspect ratio
Since the projection matrix is defined by the field of view and the aspect ratio it is possible to recover the viewport position with the field of view and the aspect ratio. Provided that it is a symmetrical perspective projection and the normalized device coordinates, the depth and the near and far plane are known.
Recover the Z distance in view space:
z_ndc = 2.0 * depth - 1.0;
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
Recover the view space position by the XY normalized device coordinates:
ndc_x, ndc_y = xy normalized device coordinates in range from (-1, -1) to (1, 1):
viewPos.x = z_eye * ndc_x * aspect * tanFov;
viewPos.y = z_eye * ndc_y * tanFov;
viewPos.z = -z_eye;
2. Projection matrix
The projection parameters, defined by the field of view and the aspect ratio, are stored in the projection matrix. Therefore the viewport position can be recovered by the values from the projection matrix, from a symmetrical perspective projection.
Note the relation between projection matrix, field of view and aspect ratio:
prjMat[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect);
prjMat[1][1] = 2*n/(t-b) = 1.0 / tanFov;
prjMat[2][2] = -(f+n)/(f-n)
prjMat[3][2] = -2*f*n/(f-n)
Recover the Z distance in view space:
A = prj_mat[2][2];
B = prj_mat[3][2];
z_ndc = 2.0 * depth - 1.0;
z_eye = B / (A + z_ndc);
Recover the view space position by the XY normalized device coordinates:
viewPos.x = z_eye * ndc_x / prjMat[0][0];
viewPos.y = z_eye * ndc_y / prjMat[1][1];
viewPos.z = -z_eye;
3. Inverse projection matrix
Of course the viewport position can be recovered by the inverse projection matrix.
mat4 inversePrjMat = inverse( prjMat );
vec4 viewPosH = inversePrjMat * vec3( ndc_x, ndc_y, 2.0 * depth - 1.0, 1.0 )
vec3 viewPos = viewPos.xyz / viewPos.w;
See also the answers to the following question:
How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
I managed to make it work in the end, As its a different method from above I will detail it so anyone who sees this will have a solution.
Pass 1: Store the depth value in view space to the gbuffer
To re-create the (x, y, z) position in the second pass:
Pass the horizontal and vertical field of view in radians into the shader.
Pass the near plane distance (near) to the shader. (distance from camera position to near plane)
Imagine a ray from the camera to the fragment position. This ray intersects the near plane at a certain position P. We have this position in the ndc space and want to compute this position in view space.
Now, we have all the values we need in view space. We can use the law of similar triangles to find the actual fragment position P'
P = P_ndc * near * tan(fov/2.0f) // computation is the same for x, y
// Note that by law of similar triangles, P'.x / depth = P/near
P'.xy = P/near * -depth; // -depth because in opengl the camera is staring down the -z axis
P'.z = depth;
I wrote a deferred shader, and used this code to recalculate screen space positioning:
vec3 getFragmentPosition()
{
vec4 sPos = vec4(gl_TexCoord[0].x, gl_TexCoord[0].y, texture2D(depthTex, gl_TexCoord[0].xy).x, 1.0);
sPos.z = 2.0 * sPos.z - 1.0;
sPos = invPersp * sPos;
return sPos.xyz / sPos.w;
}
where depthTex is the texture holding depth info, and invPersp is a pre-calculated inverse perspective matrix. You take the screen's fragment position, and multiply it by the inverse perspective matrix to get model-view coordinates. Then you divide by w to get homogenous coordinates. The multiplication by two and subtraction by one is to scale the depth from [0, 1] (as it is stored in the texture) to [-1, 1].
Also, depending on what kind of MRTs you are using, the recalculated result won't be exactly equal to the stored info, since you lose the float precision.

Drawing circles on a sphere

I'm trying to draw lots of circles on a sphere using shaders. The basic alogrith is like this:
calculate the distance from the fragment (using it's texture coordinates) to the location of the circle's center (the circle's center is also specified in texture coordinates)
calculate the angle from the fragent to the center of the circle.
based on the angle, access a texture (which has 360 pixels in it and the red channel specifies a radius distance) and retrieve the radius for the given angle
if the distance from the fragment to the circle's center is less than the retrieved radius then the fragment's color is red, otherwise blue.
I would like to draw ... say 60 red circles on a blue sphere. I got y shader to work for one circle, but how to do 60? Here's what I've tried so far....
I passed in a data texture that specifies the radius for a given angle, but I notice artifacts creep in. I believe this is due to linear interpolation when I try to retrieve information from the data texture using:
float returnV = texture2D(angles, vec2(x, y)).r;
where angles is the data texture (Sampler2D) that contains the radius for a given angle, and x = angle / 360.0 (angle is 0 to 360) and y = 0 to 60 (y is the circle number)
I tried passing in a Uniform float radii[360], but I cannot access radii with dynamic indexing. I even tried this mess ...
getArrayValue(int index) {
if (index == 0) {
return radii[0];
}
else if (index == 1) {
return radii[1];
}
and so on ...
If I create a texture and place all of the circles on that texture and then multi-texture the blue sphere with the one containing the circles it works, but as you would expect, I have really bad aliasing. I like the idea of proceduraly generating the circles based on the position of the fragment and that of the circle because of virtually no aliasing. However, I do I do ore than one?
Thx!!!
~Bolt
i have a shader that makes circle on the terrain. It moves by the mouse moves.
maybe you get an inspiration?
this is a fragment program. it is not the main program but you can add it to your program.
try this...
for now you can give some uniform parameters in hardcode.
uniform float showCircle;
uniform float radius;
uniform vec4 mousePosition;
varying vec3 vertexCoord;
void calculateTerrainCircle(inout vec4 pixelColor)
{
if(showCircle == 1)
{
float xDist = vertexCoord.x - mousePosition.x;
float yDist = vertexCoord.y - mousePosition.y;
float dist = xDist * xDist + yDist * yDist;
float radius2 = radius * radius;
if (dist < radius2 * 1.44f && dist > radius2 * 0.64f)
{
vec4 temp = pixelColor;
float diff;
if (dist < radius2)
diff = (radius2 - dist) / (0.36f * radius2);
else
diff = (dist - radius2) / (0.44f * radius2);
pixelColor = vec4(1, 0, 0, 1.0) * (1 - diff) + pixelColor * diff;
pixelColor = mix(pixelColor, temp, diff);
}
}
}
and in vertex shader you add:
varying vec3 vertexCoord;
void main()
{
gl_Position = ftransform();
vec4 v = vec4(gl_ModelViewMatrix * gl_Vertex);
vertexCoord = vec3(gl_ModelViewMatrixInverse * v);
}
ufukgun, if you multuiply a matrix by its inverse you get the identity.
Your;
vec4 v = vec4(gl_ModelViewMatrix * gl_Vertex);
vertexCoord = vec3(gl_ModelViewMatrixInverse * v);
is therefore equivalent to
vertexCoord = vec3(gl_Vertex);