Switching from perspective orthographic projection in OpenGL - c#

I'm really new to OpenGL and trying to learn from the 'modern' OpenGL tutorials.
I'm using C# and OpenTK.
I'm setting my projectionMatrix with this code:
_projectionMatrix = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver3, GetAspectRatio(), 0.1f, 100f);
After I set it, I upload it to the shaders, use for transformations, etc. Everything is working well this way, as the image below shows:
Now if I set my projection matrix this way, the result is very bad as the next image shows:
_projectionMatrix = Matrix4.CreateOrthographic(GLControl.ClientSize.Width, GLControl.ClientSize.Height, 0.1f, 100f);
Not only the new view is very strange, but if I move forward the scene, the objects starts to clipping, even having znear close to zero.
How can I set the orthographic projection correctly so I can have a view close to what I have in perspective?

It seems like you're having trouble understanding orthographic projections.
There are several reasons why your scene doesn't look right in an orthographic view:
The perspective projection gives the appropriate
depth to the floor so it can be seen; objects look bigger when they're closer to you. But the orthographic projection doesn't change their size according to their depth. Moreover, the reason the floor "disappears" in the orthographic projection is that the floor
is "infinitely thin" and oriented horizontally.
Your orthographic projection resizes the screen so that one pixel in window space
corresponds to 1 unit in object space. Since the rings are (it seems) about 12 units in size, they will look rather small on the screen. One solution may be to use a smaller size in CreateOrthographic. But this won't solve everything; for instance, the floor will still remain "invisible".
Note also:
If you use an orthographic projection, you can even use negative values for zNear,
but probably not 0. This isn't the case for a perspective projection.
The orthographic projection can form the basis for a 3D-like projection called the isometric projection.

Related

Drawing a specific region of a 3D scene to a larger canvas/viewport

I have a 3D scene of which I want to draw a specific region onto a larger canvas/viewport (think like a magnifying glass).
Something like the following image:
I want to maintain any perspective effects, simply moving my camera to the specified region wouldn't give that effect.
I gathered from http://www.mvps.org/DirectX/articles/tilerender/index.htm that it's possible to do some trickery with the Projection Matrix but I couldn't figure out the math behind getting a more specific subsection/region than what is described in that article.
If we assume the coordinates described in the article, x0y0 would be the exact center of the scene, x-1y1 would be the top-left and x1y-1 would be the bottom-right of the scene.
I would, for example, want to render the region ranging from x-0.75y0.75 to x-0.25y0.25.
I have a Projection matrix and a View matrix separately available. I am using the SharpDX library and my Projection matrix is Right-Handed(which seems the flip the y-coordinates described above).
How do I calculate the Scale/Translation matrices that I need to multiply my Projection matrix with? Or, alternatively, what other ways are there to tackle this issue?
Psuedo-code would be something like this:
public Matrix GetProjectionRegion(float topLeftX, float topLeftY, float bottomRightX, float bottomRightY)
{
var magicMatrix = Matrix.Identity;;
//some magic
return magicMatrix;
}
ProjectionMatrix *= GetProjectionRegion(-0.75f, 0.75f, -0.25f, 0.25f);
EDIT:
I am currently creating my Projection matrix using one of two methods:
ProjectionMatrix = Matrix.PerspectiveFovRH(FOV, Width / Height, NearPlane, FarPlane);
or
ProjectionMatrix = Matrix.OrthoOffCenterRH(_topLeft.X, _bottomRight.X, _topLeft.Y, _bottomRight.Y, NearPlane, FarPlane);
Nearplane is 75 farplane is 5000000; Width/Height/_topLeft/_topRight are all pixel formats as far as I remember.
The matrices are used Row-Major.
If you really want to do a very basic mechanism for zooming in, you could cheat with your camera matrix, that is the "World" in your world view projection matrix.
The zoom could be tackled through proximity to the location. Nothing more. BUT, if you are determined, you could also scale that World matrix also, which would then enlarge all objects, therefore effectively zoom.

Get the bounds of the plane visible at a specific z coordinate

Using OpenTK, I've created a window (800x600) with a vertical FOV of 90°.
I want to make a 2D game with a background image that fits on the whole screen.
What I want is the plane at a variable z coordinate as a RectangleF.
Currently my code is:
var y = (float)(Math.Tan(Math.PI / 4) * z);
return new RectangleF(aspectRatio * -y, -y, 2 * aspectRatio * y, 2 * y);
The rectangle calculated by this is always a little to small, this effect seems to decrease with z increasing.
Hoping someone will find my mistake.
I want to make a 2D game with a background image that fits on the whole screen.
Then don't bother with perspective calculations. Just switch to an orthographic projection for drawing the background, disabling depth writes. Then switch to a perspective projection for the rest.
OpenGL is not a scene graph, it's a statefull drawing API. Make use of that fact.
To make a 2D game using OpenGL, you should use an orthographic projection, like this tutorial shows.
Then its simple to fill the screen with whatever image you want because you aren't dealing with perspective.
However, IF you were to insist on doing things the way you say, then you'd have to gluProject the 4 corners of your screen using the current modelview matrix and then draw a quad in 3D space with those corners. Even with this method, it is likely that the quad might not cover the entire screen sometimes due to floating point errors.

Scale a Plane to fit a Frustum or Grid Cell

I am attempting to create a function taking a plane in 3d space, and returning a plane which will fit in its entirety inside one section of a grid on the screen.
The grid on the screen is fixed and is defined by either divisions in X and Y, or by a set of lines across the screen.
The original plane can be any size or orientation on the screen, though it will never take the whole screen.
I am working in Unity3.5.2f2 with C#. I have posted this on SO as it is quite heavily math based as opposed to just Unity general knowledge. Ideally a solution will not use external libraries, though it is a possibility.
I have a few methods in mind and would appreciate any input;
Project the plane to screen space, get the min/max x and y values of the mesh, (bounding box), use this to calculate a scale xform (using difference in height/length of mesh to that of a screen division). Re-project into world space, after snapping two edges of the mesh to a selected division.
As the divisions are rectangular in nature, create several view frustums, and come up with some method of scaling/translating the plane in 3d space to fit the frustum.
Function prototype would be;
Plane adjustPlaneToFitScreens(Plane _plane)
Any thoughts?
I solved this issue using method 01. above. Unity provided several handy functions making the math easy, and calculating scaling and translation in pixel/screen space was far easier than in 3d space while having to take into account view angle / FOV.
There are issues with the re-projection into world after the scaling, but this particular application doesnt have the camera moving when viewing the scaled object, so the issues are not actually noticeable in black box

Making a lightsystem like Terraria?

I am trying to make my lighting similar to Terraria's, block-lighting. Now, I know how to make blocks darker, I can assign blocks to a certain lightlevel, but, how would I make an actual light entity, that emits light in a round shape (Can be diamond-shaped too)?
Help would be greatly appreciated, also, if I wasn't clear in my question, feel free to ask.
Basic 2D lighting is very simple. Just do a distance check from your block, to your light, and use that value to scale your light.
This is something you could do fairly simple, since Spritebatch.Draw has a nice Color tint parameter [link]
A pseudo function could be
distance = (block.position - light.position). Length();
lightPower = distance / light.MaxDistance;
finalTint = light.Color * lightPower;
Render Block, with finalTint
For more nice looking light, you could replace "distance / light.MaxDistance" with a more smooth effect.
If you also want lights to go through a few blocks like Terraria, you could count all blocks between your block and the light source. Scale your lightPower down by that amount, and you get the same effect like Terraria has.
Of course, this is a non optimized way of doing it, but should work.
The latest Terraria version however seems to have smooth per pixel lighting instead of per block [preview]. For that I assume they used a second render target and/or Pixel Shader to keep fast performance. This could be a little difficult if you are not familiar with rendering pipelines though.
Hope this helps!
I'm working on a game with a similar lighting model, and the way we do it is this:
Draw the scene, without lighting, to a render target (called the 'Scene Buffer')
Draw the scene's lights, represented as grayscale gradients of any required shape, to a second render target (called the 'Light Map')
Draw the Scene Buffer to the screen, passing in the Light Map as a parameter to the pixel shader
In the pixel shader, query the value of the Light Map at each pixel and adjust the color of the final pixel up or down as necessary.
This also gives you the ability to have colored lighting; all you have to do is tint the light gradients that you render to the Light Map. Just remember to use additive alpha blending.
The downside of this approach is that it's rather naive, and provides no easy way to occlude the lights (that is to say, they pass through walls). In our case, this isn't an issue; you might decide otherwise.

.NET high level graphics library

I am programming various simulation tools in C#/.NET
What I am looking for is a high level visualization library; create a scene, with a camera with some standard controls, and render a few hunderd thousand spheres to it, or some wireframes. That kind of thing. If it takes more than one line to initialize a context, it deviates from my ideal.
Ive looked at slimDX, but its way lower level than im looking for (at least the documented parts, but I dont really care for any other). WPF perspective looked cool, but it seems targeted at static XAML defined scenes, and that doesnt really suit me either.
Basically, im looking for the kind of features languages like blitzbasic used to provide. Does that exist at all?
I'm also interested in this (as I'm also developing simulation tools) and ended up hacking together some stuff in XNA. It's definitely a lot more work than you've described, however. Note that anything you can do in WPF via XAML can also be done via code, as XAML is merely a representation of an object hierarchy and its relationships. I think that may be your best bet, though I don't have any metrics on what kind of performance you could expect with a few hundred thousand spheres (you're absolutely going to need some culling in that case and the culling itself may be expensive if you don't use optimizations like grid partitioning.)
EDIT: If you really need to support 100K entities and they can all be rendered as spheres, I would recommend that you bypass the 3d engine entirely and only use XNA for math. I would imagine an approach like the following:
Use XNA to set up Camera (View) and Perspective matrices. It has some handy Matrix static functions that make this easy.
Compute the Projection matrix and project all of your 'sphere' origin points to the viewing frustrum. This will give you X,Y screen coordinates and Z depth in the frustrum. You can either express this as 100K individual matrix multiplications or multiplication of the Projection matrix by a single 3 x 100K element matrix. In the former case, this is a great candidate for parallelism using the new .NET 4 Parallel functionality.
If you find that the 100K matrix multplications are a problem, you can reduce this significantly by performing culling of points before transformation if you know that only a small subset of them will be visible at a given time. For instance, you can invert the Projection matrix to find the bounds of your frustrum in your original space and create an axis-aligned bounding box for the frustrum. You can then exclude all points outside this box (simple comparison tests in X, Y and Z.) You only need to recompute this bounding box when the Projection matrix changes, so if it changes infrequently, this can be a reasonable optimization.
Once you have your transformed points, clip any outside the frustum (Z < 0, Z > maxDist, X<0, Y<0, X>width, Y>height). You can now render each point by drawing a filled circle, with its radius proportional to Z (Z=0 would have largest radius and Z=maxDist would probably fade to a single point.) If you want to provide a sense of shading/depth, you can render with a shaded brush to very loosely emulate lighting on spheres. This works because everything in your scene is a sphere and you're presumably not worried about things like shadows. All of this would be fairly easy to do in WPF (including the Shaded Brush), but be sure to use DrawingVisual classes and not framework elements. Also, you'll need to make sure you draw in the correct Z order, so it helps if you store the transformed points in a data structure that sorts as you add.
If you're still having performance problems, there are further optimizations you can pursue. For instance, if you know that only a subset of your points are moving, you can cache the transformed locations for the immobile points. It really depends on the nature of your data set and how it evolves.
Since your data set is so large, you might consider changing the way you visualize it. Instead of rendering 100K points, partition your working space into a volumetric grid and record the number (density) of points inside each grid cube. You can Project only the center of the grid and render it as a 'sphere' with some additional feedback (like color, opacity or brush texture) to indicate the point density. You can combine this technique with the traditional rendering approach, by rendering near points as 'spheres' and far points as 'cluster' objects with some brush patterning to match the density. One simple algorithm is to consider a bounding sphere around the camera; all points inside the sphere will be transformed normally; beyond the sphere, you will only render using the density grid.
Maybe the XNA Game studio is what you are looking for.
Also take a look at DirectX.
WPF perspective looked cool, but it seems targeted at static XAML defined scenes
Look again, WPF can be as dynamic as you will ever need.
You can write any WPF program, including 3D, totally without XAML.
Do you have to use C#/.Net or would MonoDevelop be good enough? I can recomend http://unity3d.com/ if you want a powerful 3D-engine.

Categories

Resources