I am using XNA with SpriteBatch and custom drawn verticies in parallel. The goal is to have the same coordinate system for both techniques.
That means I need a projection matrix that maps to screen coordinates: (0, 0) is in the top left screen corner, while width and height are determined by the screen resolution.
Matrix.CreateOrthographicOffCenter(0, width, 0, height, -1, 1);
Works well but has the center in the bottom-left corner.
Matrix.CreateOrthographicOffCenter(0, width, height, 0, -1, 1);
Does not display anything at all.
Trying to combine the first projection matrix with a translation and scaling y by -1 does not display anything at all either. Scaling by positive values works well, translation too. But as soon as I scale by a negative value I do not get any output at all.
Any ideas?
PS: For testing purpose I am drawing vertices far beyond the screen coordinates, so I would at least see something if there is some error in translation.
I use this code to initialize my 2D camera for drawing lines, and use a basic custom effect to draw.
Vector2 center;
center.X = Game.GraphicsDevice.Viewport.Width * 0.5f;
center.Y = Game.GraphicsDevice.Viewport.Height * 0.5f;
Matrix View = Matrix.CreateLookAt( new Vector3( center, 0 ), new Vector3( center, 1 ), new Vector3( 0, -1, 0 ) );
Matrix Projection = Matrix.CreateOrthographic( center.X * 2, center.Y * 2, -0.5f, 1 );
Effect
uniform float4x4 xWorld;
uniform float4x4 xViewProjection;
void VS_Basico(in float4 inPos : POSITION, in float4 inColor: COLOR0, out float4 outPos: POSITION, out float4 outColor:COLOR0 )
{
float4 tmp = mul (inPos, xWorld);
outPos = mul (tmp, xViewProjection);
outColor = inColor;
}
technique Lines
{
pass Pass0
{
VertexShader = compile vs_2_0 VS_Basico();
FILLMODE = SOLID;
CULLMODE = NONE;
}
}
Related
I'm currently trying to scale a texture to the given size in pixels via SharpDX.Direct3D9.
I have the following code which draws a texture on the screen (2D)
public static bool DrawTexture(IntPtr device, IntPtr txt, RectangleF rect, float rotation, Color tint)
{
try {
Texture texture = (Texture)txt;
Matrix m = Matrix.Identity * Matrix.Translation(-0.5f, -0.5f, 0.0f) * Matrix.Scaling(rect.Width, rect.Height, 1.0f) * Matrix.RotationZ(rotation) * Matrix.Translation(rect.X, rect.Y, 0.0f);
using (Sprite s = new Sprite((Device)device)) {
s.Begin();
s.Transform = m;
s.Draw(texture, tint.ToRawColorBGRA());
s.End();
}
return true;
}
catch (Exception ex) {
Main.managerInstance.console.PrintError(string.Format("[Direct3D9] An error occured while trying to draw texture. Details: {0}", ex.ToString()));
}
return false;
}
Matrix.Scaling(rect.Width, rect.Height, 1.0f) is responsible for scaling my texture to the given size (128x128 pixel).
But as far as i understand, the Matrix.Scaling function takes in a float from 0 - 1 where 1 is the full texture size and 2 would be double the texture size. But i would like to enter the size in pixel and not in units(?).
So i tried the following:
Size res = CGame.Resolution;
float cW = rect.Width / res.Width;
float cH = rect.Height / res.Height;
Matrix m = Matrix.Identity * Matrix.Translation(-0.5f, -0.5f, 0.0f) * Matrix.Scaling(cW, cH, 1.0f) * Matrix.RotationZ(rotation) * Matrix.Translation(rect.X, rect.Y, 0.0f);
I divide the given texture Width and Height (which is 128x128 pixel) by the Width and Height of the current screen resolution (Which in my case is 1920x1080).
This leaves me with the following:
The result of the division by the screen resolution
As you can see there is a red rectangle in the texture, which is actually 128x128 pixel in size, and in the background, there is my texture, which is supposed to be scaled to 128x128 but as you can see, it clearly is larger then the red rectangle which is 128x128.
Here is how i load my texture
// D3DX.DefaultNonPowerOf2 = -2
Texture t = Texture.FromFile(device, filePath, D3DX.DefaultNonPowerOf2, D3DX.DefaultNonPowerOf2, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None, 0);
If someone could help me out with this problem i would be really grateful!
Got it working!
Needed to divide the target Size of the texture by the actual texture size like so:
SurfaceDescription sd = texture.GetLevelDescription(0);
float cW = rect.Width / sd.Width;
float cH = rect.Height / sd.Height;
This question already has an answer here:
OpenGL 4.2 LookAt matrix only works with -z value for eye position
(1 answer)
Closed 2 years ago.
I am currently trying to add shadows with Shadow Mapping to my 3D Engine.
First I render the scene from the light's point of view, and save the depth values in a texture. Then I use the defeault FBO to draw from the texture. Just like in this tutorial.
The problem is that my screen stays white, no matter where I move.
GL.GetError() outputs noError and the SSBO's which I use in vertex shader have the right values. GL.CheckFramebufferStatus() returns FramebufferCompleteExt.
This is how I create the FBO for depth values:
_depthMapFBO = GL.GenFramebuffer();
_depthMapFBOColorBuffer = BufferObjects.FBO_TextureAttachment(_depthMapFBO, PixelInternalFormat.DepthComponent, PixelFormat.DepthComponent, FramebufferAttachment.DepthAttachment, 1024, 1024);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _depthMapFBO);
GL.DrawBuffer(DrawBufferMode.None);
GL.ReadBuffer(ReadBufferMode.None);
====================================
public static int FBO_TextureAttachment(int FrameBuffer, PixelInternalFormat PixelInternalFormat, PixelFormat PixelFormat, FramebufferAttachment FramebufferAttachment, int Width, int Height)
{
// PixelInternalFormat = DepthComponent && PixelFormat = DepthComponent && FramebufferAttachment = DepthAttachment && Width, Height = 1024,
GL.BindFramebuffer(FramebufferTarget.Framebuffer, FrameBuffer);
int _texture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, _texture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat, Width, Height, 0, PixelFormat, PixelType.Float, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.Repeat);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment, TextureTarget.Texture2D, _texture, 0);
return _texture;
}
In my Render function it looks like this:
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _depthMapFBO);
GL.Clear(ClearBufferMask.DepthBufferBit);
GL.Viewport(0, 0, 1024, 1024);
_simpleDepthProgram.Use();
float _nearPlane = 1.0f, _farPlane = 100f;
_lightProjection = Matrix4.CreateOrthographicOffCenter(-100.0f, 100.0f, -100.0f, 100.0f, _nearPlane, _farPlane);
_ligthView = Matrix4.LookAt(_allLamps[0].Position, new Vector3(0f), new Vector3(0.0f, 1.0f, 0.0f));
_lightSpaceMatrix = _lightProjection * _ligthView;
GL.UniformMatrix4(21, false, ref _lightSpaceMatrix);
// Copy all SSBO's
GL.ActiveTexture(TextureUnit.Texture2);
GL.BindTexture(TextureTarget.Texture2D, _depthMapFBOColorBuffer);
Scene();
And the shader where I draw the depthMap:
#version 450 core
out vec4 FragColor;
uniform sampler2D scene;
uniform sampler2D bloomed;
uniform sampler2D depthMap;
uniform float zNear;
uniform float zFar;
float LinearizeDepth(float depth)
{
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * zNear * zFar) / (zFar + zNear - z * (zFar - zNear));
}
in vec2 TexCoord;
void main()
{
float depthValue = texture(depthMap, TexCoord).r;
//float depth = LinearizeDepth(gl_FragCoord.z) / far; // only for perspective
FragColor = vec4(vec3(depthValue), 1.0);
}
The computation of the _lightSpaceMatrix is wrong. The OpenTK matrix multiplication is reversed. See Problem with matrices #687:
Because of how matrices are treated in C# and OpenTK, multiplication order is inverted from what you might expect in C/C++ and GLSL. This is an old artefact in the library, and it's too late to change now, unfortunately.
Swap the _ligthView and _lightProjection when you multiply the matrices:
_lightSpaceMatrix = _lightProjection * _ligthView;
_lightSpaceMatrix = _ligthView * _lightProjection;
So, I'm just trying to draw a texture to two triangles that are the same size as the viewport, but it breaks up the image and distorts it, I have tried resizing the image file and everything, but nothing seems to work. Below is the code that maps the texture and draws the triangles.
public void Render()
{
Texture texture = _textureManager.Get("splash");
Gl.glEnable(Gl.GL_TEXTURE_2D);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture.Id);
double height = 720;
double width = 1280;
double x = 0;
double y = 0;
double z = 0;
float topUV = 0;
float bottomUV = 1;
float leftUV = 0;
float rightUV = 1;
Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
Gl.glBegin(Gl.GL_TRIANGLES);
{
Gl.glTexCoord2d(leftUV, topUV);
Gl.glVertex3d(x - width, y + height, z);
Gl.glTexCoord2d(rightUV, topUV);
Gl.glVertex3d(x + width, y + height, z);
Gl.glTexCoord2d(leftUV, bottomUV);
Gl.glVertex3d(x - width, y - height, z);
Gl.glTexCoord2d(rightUV, topUV);
Gl.glVertex3d(x + width, y + height, z);
Gl.glTexCoord2d(rightUV, bottomUV);
Gl.glVertex3d(x + width, y - height, z);
Gl.glTexCoord2d(leftUV, bottomUV);
Gl.glVertex3d(x - width, y - height, z);
}
Gl.glEnd();
}
Here is the original image:
And here's the result:
The image is 1920 x 1080, and the viewport is 1280 x 720, but I'm not too sure that matters because I have tried resizing the image and nothing seems to work.
Alright, so I ended up cutting the image in half down the center and just loading two images, and then I used four triangles. This may not be the most elegant solution, but it works just fine. I'm guessing it had to do with the dimensions of the image. (I also changed the parameters for the texture coordinates and all the vertices so that it is more straight forward in the context of Stack Overflow).
public void Render()
{
//Draw Left Half
Texture texture = _textureManager.Get("splash1");
Gl.glEnable(Gl.GL_TEXTURE_2D);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture.Id);
Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
Gl.glBegin(Gl.GL_TRIANGLES);
{
Gl.glTexCoord2d(0, 0);//top left
Gl.glVertex2f(-1280 , 720);
Gl.glTexCoord2d(1, 0);//middle top
Gl.glVertex2f(0, 720);
Gl.glTexCoord2d(0, 1);//bottom left
Gl.glVertex2f(-1280, -720);
Gl.glTexCoord2d(0, 1);//bottom left
Gl.glVertex2f(-1280, -720);
Gl.glTexCoord2d(1, 0);//middle right top
Gl.glVertex2f(0, 720);
Gl.glTexCoord2d(1, 1);//bottom middle
Gl.glVertex2f(0, -720);
}
Gl.glEnd();
//Draw Right Half
texture = _textureManager.Get("splash2");
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture.Id);
Gl.glBegin(Gl.GL_TRIANGLES);
{
Gl.glTexCoord2d(0, 0);//middle top
Gl.glVertex2f(0, 720);
Gl.glTexCoord2d(1, 0);//top right
Gl.glVertex2f(1280, 720);
Gl.glTexCoord2d(0, 1);//bottom middle
Gl.glVertex2f(0, -720);
Gl.glTexCoord2d(1, 0);//top right
Gl.glVertex2f(1280, 720);
Gl.glTexCoord2d(0, 1);//bottom middle
Gl.glVertex2f(0, -720);
Gl.glTexCoord2d(1, 1);//bottom right
Gl.glVertex2f(1280, -720);
}
Gl.glEnd();
}
I'm trying to implement something using OpenTK in C# where when you render a 3d plot, you can rotate it around the z axis (pointing up) as I move the mouse.
I already have it working but as shown below, I had to come up with an arbitrary constant 500;
The equation is:
arc_length = radius * theta
theta = arc_length / radius
where radius = eye_pos.Length
arc_length is the delta_x in model coordinate, but
(e.X - mouse_down_pos.X) is in screen coordinate.
so that 500 was used to map model coordinate to screen projected coordinate.
QUESTION: is there a way to eliminate this constant and properly obtain the conversion factor?
My educated guess is that I should use somehow multiply [delta_x, 0, 0] by inverse of the projection matrix...but do not have a clue how.
private static Vector3 eye_pos = new Vector3(30.0f, 0.0f, 0.0f);
GL.MatrixMode(MatrixMode.Modelview);
Matrix4 lookat = Matrix4.LookAt(eye_pos.X, eye_pos.Y, eye_pos.Z, 0, 0, 0, 0, 0, 1);
...
private void glControl1_MouseMove(object sender, MouseEventArgs e)
{
if (mouse_op == Mouse_Operation.Rotate)
{
decimal yaw = (decimal)MathHelper.DegreesToRadians((e.X - mouse_down_pos.X) * 500 / eye_pos.Length) + ref_yaw;
SetYawAndRedraw(yaw);
}
}
I want to scale an image so that the image is always the size of the screen no matter how it is rotated. Does anyone have any ideas on going about this? By the way I am programing this in C# with xna.
Perhaps something similiar to this, although I'm unsure how you expect to draw the texture. It would be easiest by using triangles and texture wrapping them.
This is how I got the new width and new height after rotating:
Matrix origin = Matrix.CreateTranslation(0, 0, 0);
Matrix scale = Matrix.CreateScale(1f);
Matrix rotation = Matrix.CreateRotationZ(MathHelper.ToRadians(rotate));
Matrix translation = Matrix.CreateTranslation(0, 0, 0);
Vector2 pos1 = Vector2.Transform(new Vector2(Texture.Width / 2, Texture.Height / 2), origin * scale * rotation * origin);
Vector2 pos2 = Vector2.Transform(new Vector2(Texture.Width, Texture.Height), origin * scale * rotation * translation);
int width = (int)Math.Abs(pos2.X - pos1.X) * 2;
int height = (int)Math.Abs(pos2.Y - pos1.Y) * 2;
float scaleX = (graphics.PreferredBackBufferWidth / width);
float scaleY = (graphics.PreferredBackBufferHeight / height);
You will probably figure out the best way to draw this, because an image flipped 45 degrees will look weird drawn on the screen so you probably have to scale it up so it fits the screen but still be rotated. That you left out, an image rotated 180 degrees or 90 degrees should work better.
You can apply a RotateTransform to transform the image, then enclose that in a LayoutTransform to fill the dimensions of the container (the screen in this case).