How can I convert world coordinates to screen coordinates using C++ and DirectX11? - directx-11

I am working on collisions for a simple 2d game and I am trying to make sure that the sprites cannot leave the edges of the screen, and I understand how this is done, but I can't seem to get the correct coordinates to perform the calculations.
In the image, the black rectangle is my sprite whos world position is around (2.2, 0.0, 0.0) however the screen width is around ~1200. I know that I will have to deal with some sort of matrix calculation but I'm not sure which matrix I will need to use.
I have tried the following from another post on SO, but it doesn't seem to give me correct results
How can I convert my world coordinate (2.2, 0.0, 0.0) to a screen-space coordinate in pixels, so I can compare that against the width of the screen? If anyone can point me in the right direction it would be much appreciated.
Edit
This implementation is slightly incorrect.
I am currently checking if the center position of the rectangle is outside the bounds of the screen.
Given the following image where the world position is (-2.2, 0.0, 0.0), when this is projected into screen space coordinates, I get an X value of -76 when it is clearly on the screen, so it should be above 0. It seems there is some slight offset the more I move the rectangle around, however, at the center of the screen, the X value is correct at ~630, which is half the screen width.
Here is the code I am using to get the screen space coordinates for the center of the rectangle.
float centerX = boundingBox.m_center.x;
XMVECTOR centerVector = XMVectorSet(centerX, 0.0f, 0.0f, 0.0f);
XMVECTOR centerProjection = XMVector3Project(centerVector, 0.0f, 0.0f, screenSize.Width, screenSize.Height, 0.0f, 1.0f, projection, view, worldMatrix);
float centerScreenSpace = XMVectorGetX(centerProjection);
Does anyone have any ideas why this might be?
There seems to be a 150-200 pixel offset

Related

Geometry Shader Quad Post Processing

Using directx 11, I'm working on a graphics effect system that uses a geometry shader to build quads in world space. These quads then use a fragment shader in which the main texture is the rendered scene texture. Effectively producing post process effects on qorld space quads. The simplest of which is a tint effect.
The vertex shader only passes the data through to the geometry shader.
The geometry shader calculates extra vertices based on a normal. Using cross product, I find the x and z axis and append the tri-stream with 4 new verts in each diagonal direction from the original position (generating a quad from the given position and size).
The pixel shader (tint effect) simply multiplies the scene texture colour with the colour variable set.
The quad generates and displays correctly on screen. However;
The problem that I am facing is the mapping of the uv coordinates fails to align with the image on the back buffer. That is, when using the tint shader with half alpha as the given colour you can see the image displayed on the quad does not overlay the image on the back buffer perfectly, unless the quad facing towards the camera. The closer the quad normal matches the cameras y axis, the more the image is skewed.
I am currently using the formula below to calculate the uv coordinates:
float2 uv = vert0.position.xy / vert0.position.w;
vert0.uv.x = uv.x * 0.5f + 0.5f;
vert0.uv.y = -uv.y * 0.5f + 0.5f;
I have also used the formula below, which resulted (IMO) in the uv's not taking perspective into concideration.
float2 uv = vert0.position.xy / SourceTextureResolution;
vert0.uv.x = uv.x * ASPECT_RATIO + 0.5f;
vert0.uv.y = -uv.y + 0.5f;
Question:
How can I obtain screen space uv coordinates based on a vertex position generated in the geometry shader?
If you would like me to elaborate on any points please ask and i will try my best :)
Thanks in advance.

Coloring a plane based on texture pixels

Using a shader I'm trying to color a plane so it replicates the pixels on a texture. The texture is 32x32 pixels and the plane is also sized 32x32 in space coordinates.
Does anyone know how I would inspect the first pixel on the texture, then use it to color the first square (1x1) on the plane?
Generated texture example: (First pixel is red on purpose)
This code using a vec2 with coordinates (0,0) doesn't work as I expected. I assumed the color at (0,0) would be red but it's not, it's green:
vec4 color = texture2D(texture, vec2(0, 0));
I guess there's something that I'm missing, or not understanding about texture2D as (0,0) doesn't appear to be the ending pixel either.
If anyone could help me out, it would be greatly appriciated. Thanks.
EDIT:
Thanks for the comments and answers! Using this code, it's working now:
// Flip the texture vertically
vec3 verpos2 = verpos.xyz * vec3(1.0, 1.0, -1.0);
// Calculate the pixel coordinates the fragment belongs to
float pixX = floor(verpos2.x - floor(verpos2.x / 32.0) * 32.0);
float pixZ = floor(verpos2.z - floor(verpos2.z / 32.0) * 32.0);
float texX = (pixX + 0.5) / 32.0;
float texZ = (pixZ + 0.5) / 32.0;
gl_FragColor = texture2D(texture, vec2(texX, texZ));
That said, I'm having an issue with jagged lines on the edges of each "block". Looks to me like my math is off and it's confused about what color the sides should be, because I didn't have this problem when using only vertex colors. Can anyone see where I've gone wrong or how it could be done better?
Thanks again!
Yes... as Ben Pious mentioned in a comment, remember that WebGL displays 0,0 in lower left.
Also, for indexing into your textures, try to sample from the "middle" of each pixel. On a 32x32 source texture, to get pixel (0,0) you'd want:
texture2D(theSampler, vec2(0.5/32.0, 0.5/32.0));
Or more generally,
texture2D(theSampler, vec2((xPixelIndex + 0.5) / width, (yPixelIndex + 0.5) / height);
This is only if you're explicitly accessing texture pixels; if you're getting values interpolated and passed through from the vertex shader (say a (-1,-1) to (1,1) square, and pass varying vec2((x+1)/2,(y+1)/2) to the fragment shader), this "middle of each pixel" is reflected in your varying value.
But it's probably just the Y-up like Ben says. :)

Three.js plane facing away from camera aligned with viewport

I'm trying to have a plane face away from the camera with same orientation so it's aligned in the viewport.
I have a plane in front of the camera, perfectly aligned to the cameras viewport, and I want to flip it in front of the camera, along the objects Y axis, regardless of camera orientation.
The following will orient my plane to face at the camera and works for any orientation:
target.rotation.copy(camera.rotation);
The following will then flip the plane along the plane's Y axis:
target.rotation.y += Math.PI;
All good so far? Except when the camera rotation has a funky tilt to it, let's say it's looking up and to the left, tilted slightly to the right, the plane's flip is tilted, but not the same way as the camera, leaving me with a plane tilted either to the left or right...
I've tried several things such as:
target.rotation.z -= camera.rotation.z;
Nothing... Thanks for your help.
So the problem I was running into was when the camera was in negative z coordinates. This causes the flip on the Y axis to get messed up.
So basically you would do something like this:
var target = new THREE.Object3D();
//position
target.position.copy(s.camera.position);
target.position.add(THREE.Utils.cameraLookDir(s.camera).multiplyScalar(300));
//rotation
target.rotation.copy(s.camera.rotation);
target.rotation.y += PI;
target.rotation.z = -s.camera.rotation.z;
if (s.camera.position.z < 0) {
target.rotation.z = s.camera.rotation.z;
}
EDIT:
Add the following to appropriate spots in your program.
camera.rotation.eulerOrder = 'XZY';
target.rotation.eulerOrder = 'XZY';
Seems to solve previously encountered tilt issues! (see below)
RESOLVED:
Flipped planes tilted the wrong way in some instances, for example when in negative z coords and also the y rotation is not equal to 0, example: point in space hovering and looking at 0, 0, 0.
This is the solution I was looking for when I found this page (taken from this answer):
mesh.lookAt( camera.position );
The local z-axis of the mesh should then point toward the camera.

Direct3D9 Calculating view space point light position

I am working on my own deffered rendering engine. I am rendering the scene to the g-buffer containing diffuse color, view space normals and depth (for now). I have implemented directional light for the second rendering stage and it works great. Now I want to render a point light, which is a bit harder.
I need the point light position for the shader in view space because I have only depth in the g-buffer and I can't afford a matrix multiplication in every pixel. I took the light position and transformed it by the same matrix, by which I transform every vertex in shader, so it should align with verices in the scene (using D3DXVec3Transform). But that isn't the case: transformed position doesn't represent viewspace position nearly at all. It's x,y coordinates are off the charts, they are often way out of the (-1,1) range. The transformed position respects the camera orientation somewhat, but the light moves too quick and the y-axis is inverted. Only if the camera is at (0,0,0), the light stands at (0,0) in the center of the screen. Here is my relevant rendering code executed every frame:
D3DXMATRIX matView; // the view transform matrix
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (x,y,z), // the camera position
&D3DXVECTOR3 (xt,yt,zt), // the look-at position
&D3DXVECTOR3 (0.0f, 0.0f, 1.0f)); // the up direction
D3DXMatrixPerspectiveFovLH(&matProjection,
fov, // the horizontal field of view
asp, // aspect ratio
znear, // the near view-plane
zfar); // the far view-plane
D3DXMATRIX vysl=matView*matProjection;
eff->SetMatrix("worldViewProj",&vysl); //vertices are transformed ok ín shader
//render g-buffer
D3DXVECTOR4 lpos; D3DXVECTOR3 lpos2(0,0,0);
D3DXVec3Transform(&lpos,&lpos2,&vysl); //transforming lpos into lpos2 using vysl, still the same matrix
eff->SetVector("poslight",&lpos); //but there is already a mess in lpos at this time
//render the fullscreen quad with wrong lighting
Not that relevant shader code, but still, I see the light position this way (passing IN.texture is just me being lazy):
float dist=length(float2(IN.texture0*2-1)-float2(poslight.xy));
OUT.col=tex2D(Sdiff,IN.texture0)/dist;
I have tried to transform a light only by matView without projection, but the problem is still the same. If I transform the light in a shader, it's the same result, so the problem is the matrix itself. But it is the same matrix as is transforming the vertices! How differently are vertices treated?
Can you please take a look at the code and tell me where the mistake is? It seems to me it should work ok, but it doesn't. Thanks in advance.
You don't need a matrix multiplication to reconstruct view position, here is a code snippet (from andrew lauritzen deffered light example)
tP is the projection transform, position screen is -1/1 pixel coordinate and viewspaceZ is linear depth that you sample from your texture.
float3 ViewPosFromDepth(float2 positionScreen,
float viewSpaceZ)
{
float2 screenSpaceRay = float2(positionScreen.x / tP._11,
positionScreen.y / tP._22);
float3 positionView;
positionView.z = viewSpaceZ;
positionView.xy = screenSpaceRay.xy * positionView.z;
return positionView;
}
Result of this transform D3DXVec3Transform(&lpos,&lpos2,&vysl); is a vector in homogeneous space(i.e. projected vector but not divided by w). But in you shader you use it's xy components without respecting this(w). This is (quite probably) the problem. You could divide vector by its w yourself or use D3DXVec3Project instead of D3DXVec3Transform.
It's working fine for vertices as (I suppose) you mul them by the same viewproj matrix in the vertex shader and pass transformed values to interpolator where hardware eventually divides it's xyz by interpolated 'w'.

The transform property in CGPathAddEllipseInRect

I am using CGPathAddEllipseInRect to draw a circle and then using that in CAKeyframeAnimation. My issue is that the animation always starts in the same spot. I thought that I could do the following with a CGAffineTransform to make it start in a different point:
CGAffineTransform temp = CGAffineTransformMakeRotation(M_PI / 2);
CGPathAddEllipseInRect(animationPath , &temp, rect);
I do not know what this is doing. When it runs, I don't even see this portion of the animation. It is doing something offscreen. Any help understanding this would be great.
The rotation happens around the origin (0,0) by default, but you want to rotate around the center of the circle, so you have to do additional transformations:
float midX = CGRectGetMidX(rect);
float midY = CGRectGetMidY(rect);
CGAffineTransform t =
CGAffineTransformConcat(
CGAffineTransformConcat(
CGAffineTransformMakeTranslation(-midX, -midY),
CGAffineTransformMakeRotation(angle)),
CGAffineTransformMakeTranslation(midX, midY));
CGPathAddEllipseInRect(animationPath, &t, rect);
Essentially, this chains three transformations: First, the circle is moved to the origin (0,0), then the rotation is applied and afterwards it is moved back to its original position. I've made a little visualization to illustrate the effect:
I chose a square instead of a circle and 45° instead of 90° to make the rotation easier to see, but the principle is the same.

Resources