gif
Creating View, Porjection Matrix
void CameraSystem::CreateMatrix()
{
camera->aspect = viewport->Width / viewport->Height;
projection_matrix = XMMatrixPerspectiveFovLH(camera->fov, camera->aspect, camera->near_z, camera->far_z);
XMVECTOR s, o, q, t;
XMFLOAT3 position(camera->position.m128_f32[0], camera->position.m128_f32[1], camera->position.m128_f32[2]);
s = XMVectorReplicate(1.0f);
o = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
q = XMQuaternionRotationRollPitchYaw(camera->pitch, camera->yaw, camera->roll);
t = XMLoadFloat3(&position);
world_matrix = XMMatrixAffineTransformation(s, o, q, t);
view_matrix = XMMatrixInverse(0, world_matrix);
camera->look = XMVector3Normalize(XMMatrixTranspose(view_matrix).r[2]);
camera->right = XMVector3Normalize(XMMatrixTranspose(view_matrix).r[0]);
camera->up = XMVector3Normalize(XMMatrixTranspose(view_matrix).r[1]);
camera->position = world_matrix.r[3];
cb_viewproj.data.view_matrix = XMMatrixTranspose(view_matrix);
cb_viewproj.data.projection_matrix = XMMatrixTranspose(projection_matrix);
}
this code creating projection matrix with aspect, fov, near, far.
and create world, view with camera transform. and these work perfect for rendering but maybe not for create ray.
Creating Mouse Ray
MouseRay CameraSystem::CreateMouseRay()
{
MouseRay mouse_ray;
POINT cursor_pos;
GetCursorPos(&cursor_pos);
ScreenToClient(ENGINE->GetWindowHandle(), &cursor_pos);
// Convert the mouse position to a direction in world space
float mouse_x = static_cast<float>(cursor_pos.x);
float mouse_y = static_cast<float>(cursor_pos.y);
float ndc_x = 2.0f * mouse_x / (float)ENGINE->GetWindowSize().x - 1.0f;
float ndc_y = (2.0f * mouse_y / (float)ENGINE->GetWindowSize().y - 1.0f) * -1.0f;
float ndc_z = 1.0f;
ndc.x = ndc_x;
ndc.y = ndc_y;
XMMATRIX inv_view = XMMatrixInverse(nullptr, view_matrix);
XMMATRIX inv_world = XMMatrixInverse(nullptr, XMMatrixIdentity());
XMVECTOR ray_dir;
XMVECTOR ray_origin;
ndc_x /= projection_matrix.r[0].m128_f32[0];
ndc_y /= projection_matrix.r[1].m128_f32[1];
ray_dir.m128_f32[0] = (ndc_x * inv_view.r[0].m128_f32[0]) + (ndc_y * inv_view.r[1].m128_f32[0]) + (ndc_z * inv_view.r[2].m128_f32[0]) + inv_view.r[0].m128_f32[3];
ray_dir.m128_f32[1] = (ndc_x * inv_view.r[0].m128_f32[1]) + (ndc_y * inv_view.r[1].m128_f32[1]) + (ndc_z * inv_view.r[2].m128_f32[1]) + inv_view.r[1].m128_f32[3];
ray_dir.m128_f32[2] = (ndc_x * inv_view.r[0].m128_f32[2]) + (ndc_y * inv_view.r[1].m128_f32[2]) + (ndc_z * inv_view.r[2].m128_f32[2]) + inv_view.r[2].m128_f32[3];
ray_origin = XMVector3TransformCoord(camera->position, inv_world);
ray_dir = XMVector3TransformNormal(ray_dir, inv_world);
ray_dir = XMVector3Normalize(ray_dir);
XMtoRP(ray_origin, mouse_ray.start_point);
XMtoRP(ray_dir * 1000.f, mouse_ray.end_point);
return mouse_ray;
}
get cursor pos, and converto ndc, it's perpect, i guess 'ndc, porjection calulate' has some propelm, but i couldn't find any other code.
inversed view matrix to ray direction, and i guess this code also has problem.
As you can see, the mouse does not seem to generate a ray in the exact direction of the pointed mouse. The frustum feels narrower than it really is, and the further away from the map, the worse it gets.
It seems as if the camera position is fixed, but the camera position is being updated from the world matrix as shown in the properties window.
The fact that views and projection matrices are also honestly generated can be inferred from the fact that the rest except for raycasting are rendered correctly.
I assume that the ray direction vector is miscalculated.
I don't know what more calculations can be made in the next code.
raycast test by reactphysics3d library.
I'm creating a game in LibGDX and am using Tiled as my map system.
I'm trying to contain an OrthographicCamera within the bounds of my TiledMap. I use MathUtils.clamp to achieve this. When the camera is at a normal zoom of 1.0f, it works perfectly. However when the camera is zoomed in further, to lets say .75f, the camera is clamped to the wrong location because it has no information of the zoom value.
position.x = MathUtils.clamp(position.x * (gameScreen.gameCamera.camera.zoom), gameScreen.gameCamera.camera.viewportWidth / 2, gameScreen.mapHandler.mapPixelWidth - (gameScreen.gameCamera.camera.viewportWidth / 2));
position.y = MathUtils.clamp(position.y * (gameScreen.gameCamera.camera.zoom), (gameScreen.gameCamera.camera.viewportHeight / 2), gameScreen.mapHandler.mapPixelHeight - (gameScreen.gameCamera.camera.viewportHeight / 2));
My question: How do I include the zoom value in my clamp code so the camera is correctly clamped? Any ideas?
Thank you!
- Jake
You should multiply by zoom the world size, not the camera position:
float worldWidth = gameScreen.mapHandler.mapPixelWidth;
float worldHeight = gameScreen.mapHandler.mapPixelHeight;
float zoom = gameScreen.gameCamera.camera.zoom;
float zoomedHalfWorldWidth = zoom * gameScreen.gameCamera.camera.viewportWidth / 2;
float zoomedHalfWorldHeight = zoom * gameScreen.gameCamera.camera.viewportHeight / 2;
//min and max values for camera's x coordinate
float minX = zoomedHalfWorldWidth;
float maxX = worldWidth - zoomedHalfWorldWidth;
//min and max values for camera's y coordinate
float minY = zoomedHalfWorldHeight;
float maxY = worldHeight - zoomedHalfWorldHeight;
position.x = MathUtils.clamp(position.x, minX, maxX);
position.y = MathUtils.clamp(position.y, minY, maxY);
Note, that if a visible area can be smaller than the world size, then you must handle such situations differently:
if (maxX <= minX) {
//visible area width is bigger than the worldWidth -> set the camera at the world centerX
position.x = worldWidth / 2;
} else {
position.x = MathUtils.clamp(position.x, minX, maxX);
}
if (maxY <= minY) {
//visible area height is bigger than the worldHeight -> set the camera at the world centerY
position.y = worldHeight / 2;
} else {
position.y = MathUtils.clamp(position.y, minY, maxY);
}
Currently, I am working with a ray tracer that takes an iterative approach towards developing the scenes. My goal is to turn it into a recursive ray tracer.
At the moment, I have a ray tracer defined to do the following operation to create the bitmap it is stored in:
int WIDTH = 640;
int HEIGHT = 640;
BMP Image(WIDTH, HEIGHT); // create new bitmap
// Slightly shoot rays left of right camera direction
double xAMT, yAMT;
*/
Color blue(0.1, 0.61, 0.76, 0);
for (int x = 0; x < WIDTH; x++) {
for (int y = 0; y < HEIGHT; y++) {
if (WIDTH > HEIGHT) {
xAMT = ((x + 0.5) / WIDTH) * aspectRatio - (((WIDTH - HEIGHT) / (double)HEIGHT) / 2);
yAMT = ((HEIGHT - y) + 0.5) / HEIGHT;
}
else if (HEIGHT > WIDTH) {
xAMT = (x + 0.5) / WIDTH;
yAMT = (((HEIGHT - y) + 0.5) / HEIGHT) / aspectRatio - (((HEIGHT - WIDTH) / (double)WIDTH) / 2);
}
else {
xAMT = (x + 0.5) / WIDTH;
yAMT = ((HEIGHT - y) + 0.5) / HEIGHT;
}
..... // calculate intersections, shading, reflectiveness.... etc
Image.setPixel(x, y, blue); // this is here just as an example
}
}
Is there another approach to calculating the reflective and refractive child rays outside the double for-loop?
Are the for-loops necessary? // yes because of the bitmap?
What approaches can be taken to minimize/optimize an iterative ray tracer?
I have some problems figuring out where my error is. I got the following:
Have an image and corresponding GPS coordinates of its top-left and bottom-right vertices.
E.g:
topLeft.longitude = 8.235128;
topLeft.latitude = 49.632383;
bottomRight.longitude = 8.240547;
bottomRight.latitude = 49.629808;
Now a have an Point that lies in that map:
p.longitude = 8.238567;
p.latitude = 49.630664;
I draw my image in landscape fullscreen (1024*748).
Now I want to calculate the exact Pixel position (x,y) of my point.
For doing that I am trying to use the great circle distance approach from here: Link.
CGFloat DegreesToRadians(CGFloat degrees)
{
return degrees * M_PI / 180;
};
- (float) calculateDistanceP1:(CLLocationCoordinate2D)p1 andP2:(CLLocationCoordinate2D)p2 {
double circumference = 40000.0; // Erdumfang in km am Ă„quator
double distance = 0.0;
double latitude1Rad = DegreesToRadians(p1.latitude);
double longitude1Rad = DegreesToRadians(p1.longitude);
double latititude2Rad = DegreesToRadians(p2.latitude);
double longitude2Rad = DegreesToRadians(p2.longitude);
double logitudeDiff = fabs(longitude1Rad - longitude2Rad);
if (logitudeDiff > M_PI)
{
logitudeDiff = 2.0 * M_PI - logitudeDiff;
}
double angleCalculation =
acos(sin(latititude2Rad) * sin(latitude1Rad) + cos(latititude2Rad) * cos(latitude1Rad) * cos(logitudeDiff));
distance = circumference * angleCalculation / (2.0 * M_PI);
NSLog(#"%f",distance);
return distance;
}
Here is my code for getting the Pixel position:
- (CGPoint) calculatePoint:(CLLocationCoordinate2D)point {
float x_coord;
float y_coord;
CLLocationCoordinate2D x1;
CLLocationCoordinate2D x2;
x1.longitude = p.longitude;
x1.latitude = topLeft.latitude;
x2.longitude = p.longitude;
x2.latitude = bottomRight.latitude;
CLLocationCoordinate2D y1;
CLLocationCoordinate2D y2;
y1.longitude = topLeft.longitude;
y1.latitude = p.latitude;
y2.longitude = bottomRight.longitude;
y2.latitude = p.latitude;
float distanceX = [self calculateDistanceP1:x1 andP2:x2];
float distanceY = [self calculateDistanceP1:y1 andP2:y2];
float distancePX = [self calculateDistanceP1:x1 andP2:p];
float distancePY = [self calculateDistanceP1:y1 andP2:p];
x_coord = fabs(distancePX * (1024 / distanceX))-1;
y_coord = fabs(distancePY * (748 / distanceY))-1;
return CGPointMake(x_coord,y_coord);
}
x1 and x2 are the points on the longitude of p and with latitude of topLeft and bottomRight.
y1 and y2 are the points on the latitude of p and with longitude of topLeft and bottomRight.
So I got the distance between left and right on longitude of p and distance between top and bottom on latitude of p. (Needed for calculate the pixel position)
Now I calculate the distance between x1 and p (my distance between x_0 and x_p) after that I calculate the distance between y1 and p (distance between y_0 and y_p)
Last but not least the Pixel position is calculated and returned.
The Result is, that my point is on the red and NOT on the blue position:
Maybe you find any mistakes or have any suggestions for improving the accuracy.
Maybe I didn't understand your question, but shouldn't you be using the Converting Map Coordinates methods of MKMapView?
See this image
I used your co-ordinates, and simply did the following:
x_coord = 1024 * (p.longitude - topLeft.longitude)/(bottomRight.longitude - topLeft.longitude);
y_coord = 748 - (748 * (p.latitude - bottomRight.latitude)/(topLeft.latitude - bottomRight.latitude));
The red dot markes this point. For such small distances you don't really need to use great circles, and your rounding errors will be making things much more inaccurate
I have N squares.
I have a Rectangular box.
I want all the squares to fit in the box.
I want the squares to be as large as possible.
How do I calculate the largest size for the squares such that they all fit in the box?
This is for thumbnails in a thumbnail gallery.
int function thumbnailSize(
iItems, // The number of items to fit.
iWidth, // The width of the container.
iHeight, // The height of the container.
iMin // The smallest an item can be.
)
{
// if there are no items we don't care how big they are!
if (iItems = 0) return 0;
// Max size is whichever dimension is smaller, height or width.
iDimension = (iWidth min iHeight);
// Add .49 so that we always round up, even if the square root
// is something like 1.2. If the square root is whole (1, 4, etc..)
// then it won't round up.
iSquare = (round(sqrt(iItems) + 0.49));
// If we arrange our items in a square pattern we have the same
// number of rows and columns, so we can just divide by the number
// iSquare, because iSquare = iRows = iColumns.
iSize = (iDimension / iSquare);
// Don't use a size smaller than the minimum.
iSize = (iSize max iMin);
return iSize;
}
This code currently works OK. The idea behind it is to take the smallest dimension of the rectangular container, pretend the container is a square of that dimension, and then assume we have an equal number of rows and columns, just enough to fit iItems squares inside.
This function works great if the container is mostly squarish. If you have a long rectangle, though, the thumbnails come out smaller than they could be. For instance, if my rectangle is 100 x 300, and I have three thumbnails, it should return 100, but instead returns 33.
Probably not optimal (if it works which I haven't tried), but I think better than you current approach :
w: width of rectangle
h: height of rectangle
n: number of images
a = w*h : area of the rectangle.
ia = a/n max area of an image in the ideal case.
il = sqrt(ia) max length of an image in the ideal case.
nw = round_up(w/il): number of images you need to stack on top of each other.
nh = round_up(h/il): number of images you need to stack next to each other.
l = min(w/nw, w/nh) : length of the images to use.
The solution on https://math.stackexchange.com/a/466248 works perfectly.
An unoptimized javascript implementation:
var getMaxSizeOfSquaresInRect = function(n,w,h)
{
var sw, sh;
var pw = Math.ceil(Math.sqrt(n*w/h));
if (Math.floor(pw*h/w)*pw < n) sw = h/Math.ceil(pw*h/w);
else sw = w/pw;
var ph = Math.ceil(Math.sqrt(n*h/w));
if (Math.floor(ph*w/h)*ph < n) sh = w/Math.ceil(w*ph/h);
else sh = h/ph;
return Math.max(sw,sh);
}
I was looking for a similar solution, but instead of squares I had to fit rectangles in the container. Since a square is also a rectangle, my solution also answers this question.
I combined the answers from Neptilo and mckeed into the fitToContainer() function. Give it the number of rectangles to fit n, the containerWidth and containerHeight and the original itemWidth and itemHeight. In case items have no original width and height, use itemWidth and itemHeight to specify the desired ratio of the items.
For example fitToContainer(10, 1920, 1080, 16, 9) results in {nrows: 4, ncols: 3, itemWidth: 480, itemHeight: 270}, so four columns and 3 rows of 480 x 270 (pixels, or whatever the unit is).
And to fit 10 squares in the same example area of 1920x1080 you could call fitToContainer(10, 1920, 1080, 1, 1) resulting in {nrows: 2, ncols: 5, itemWidth: 384, itemHeight: 384}.
function fitToContainer(n, containerWidth, containerHeight, itemWidth, itemHeight) {
// We're not necessarily dealing with squares but rectangles (itemWidth x itemHeight),
// temporarily compensate the containerWidth to handle as rectangles
containerWidth = containerWidth * itemHeight / itemWidth;
// Compute number of rows and columns, and cell size
var ratio = containerWidth / containerHeight;
var ncols_float = Math.sqrt(n * ratio);
var nrows_float = n / ncols_float;
// Find best option filling the whole height
var nrows1 = Math.ceil(nrows_float);
var ncols1 = Math.ceil(n / nrows1);
while (nrows1 * ratio < ncols1) {
nrows1++;
ncols1 = Math.ceil(n / nrows1);
}
var cell_size1 = containerHeight / nrows1;
// Find best option filling the whole width
var ncols2 = Math.ceil(ncols_float);
var nrows2 = Math.ceil(n / ncols2);
while (ncols2 < nrows2 * ratio) {
ncols2++;
nrows2 = Math.ceil(n / ncols2);
}
var cell_size2 = containerWidth / ncols2;
// Find the best values
var nrows, ncols, cell_size;
if (cell_size1 < cell_size2) {
nrows = nrows2;
ncols = ncols2;
cell_size = cell_size2;
} else {
nrows = nrows1;
ncols = ncols1;
cell_size = cell_size1;
}
// Undo compensation on width, to make squares into desired ratio
itemWidth = cell_size * itemWidth / itemHeight;
itemHeight = cell_size;
return { nrows: nrows, ncols: ncols, itemWidth: itemWidth, itemHeight: itemHeight }
}
The JavaScript implementation form mckeed gave me better results then the other answers I found. The idea to first stretch the rectangle to a square came from Neptilo.
you want something more like
n = number of thumbnails
x = one side of a rect
y = the other side
l = length of a side of a thumbnail
l = sqrt( (x * y) / n )
Here is my final code based off of unknown (google)'s reply:
For the guy who wanted to know what language my first post is in, this is VisualDataflex:
Function ResizeThumbnails Integer iItems Integer iWidth Integer iHeight Returns Integer
Integer iArea iIdealArea iIdealSize iRows iCols iSize
// If there are no items we don't care how big the thumbnails are!
If (iItems = 0) Procedure_Return
// Area of the container.
Move (iWidth * iHeight) to iArea
// Max area of an image in the ideal case (1 image).
Move (iArea / iItems) to iIdealArea
// Max size of an image in the ideal case.
Move (sqrt(iIdealArea)) to iIdealSize
// Number of rows.
Move (round((iHeight / iIdealSize) + 0.50)) to iRows
// Number of cols.
Move (round((iWidth / iIdealSize) + 0.50)) to iCols
// Optimal size of an image.
Move ((iWidth / iCols) min (iHeight / iRows)) to iSize
// Check to make sure it is at least the minimum.
Move (iSize max iMinSize) to iSize
// Return the size
Function_Return iSize
End_Function
This should work. It is solved with an algorithm rather than an equation. The algorithm is as follows:
Span the entire short side of the rectangles with all of the squares
Decrease the number of squares in this span (as a result, increasing the size) until the depth of the squares exceeds the long side of the rectangle
Stop when the span reaches 1, because this is as good as we can get.
Here is the code, written in JavaScript:
function thumbnailSize(items, width, height, min) {
var minSide = Math.min(width, height),
maxSide = Math.max(width, height);
// lets start by spanning the short side of the rectange
// size: the size of the squares
// span: the number of squares spanning the short side of the rectangle
// stack: the number of rows of squares filling the rectangle
// depth: the total depth of stack of squares
var size = 0;
for (var span = items, span > 0, span--) {
var newSize = minSide / span;
var stack = Math.ceil(items / span);
var depth = stack * newSize;
if (depth < maxSide)
size = newSize;
else
break;
}
return Math.max(size, min);
}
In Objective C ... the length of a square side for the given count of items in a containing rectangle.
int count = 8; // number of items in containing rectangle
int width = 90; // width of containing rectangle
int height = 50; // width of container
float sideLength = 0; //side length to use.
float containerArea = width * height;
float maxArea = containerArea/count;
float maxSideLength = sqrtf(maxArea);
float rows = ceilf(height/maxSideLength); //round up
float columns = ceilf(width/maxSideLength); //round up
float minSideLength = MIN((width/columns), (height/rows));
float maxSideLength = MAX((width/columns), (height/rows));
// Use max side length unless this causes overlap
if (((rows * maxSideLength) > height) && (((rows-1) * columns) < count) ||
(((columns * maxSideLength) > width) && (((columns-1) * rows) < count))) {
sideLength = minSideLength;
}
else {
sideLength = maxSideLength;
}
My JavaScript implementation:
var a = Math.floor(Math.sqrt(w * h / n));
return Math.floor(Math.min(w / Math.ceil(w / a), h / Math.ceil(h / a)));
Where w is width of the rectangle, h is height, and n is number of squares you want to squeeze in.
double _getMaxSizeOfSquaresInRect(double numberOfItems, double parentWidth, double parentHeight) {
double sw, sh;
var pw = (numberOfItems * parentWidth / parentHeight).ceil();
if ((pw * parentHeight / parentWidth).floor() * pw < numberOfItems) {
sw = parentHeight / (pw * parentHeight / parentWidth).ceil();
} else {
sw = parentWidth / pw;
}
var ph = (sqrt(numberOfItems * parentHeight / parentWidth)).ceil();
if ((ph * parentWidth / parentHeight).floor() * ph < numberOfItems) {
sh = parentWidth / (parentWidth * ph / parentHeight).ceil();
} else {
sh = parentHeight / ph;
}
return max(sw, sh);
}