I am trying to see if my camera is facing a building.
I use xDelta and zDelta when moving the camera along the place
xDelta=sine/4 and zDelta=cosine/4 (to limit speed of movement).
Basically, my idea is to take the distance of the building, and apply the deltas scaled to the distance of the building to the camera's coordinates to get a set of projected coordinates. I then try to take the distance between the building coordinates and the projected coordinates to see if the camera is facing it.
I can confirm that the distances to the building are correct, however, I think there is a problem with the projection coordinates. This is my code so far:
building1Distance = Math.pow((double)(CAMERA_X - BUILDING1_X), 2) + Math.pow((double)(CAMERA_Z - BUILDING1_Z), 2);
building1Distance = Math.sqrt(building1Distance);
building2Distance = Math.pow((double)(CAMERA_X - BUILDING2_X), 2) + Math.pow((double)(CAMERA_Z - BUILDING2_Z), 2);
building2Distance = Math.sqrt(building2Distance);
building3Distance = Math.pow((double)(CAMERA_X - BUILDING3_X), 2) + Math.pow((double)(CAMERA_Z - BUILDING3_Z), 2);
building3Distance = Math.sqrt(building3Distance);
building4Distance = Math.pow((double)(CAMERA_X - BUILDING4_X), 2) + Math.pow((double)(CAMERA_Z - BUILDING4_Z), 2);
building4Distance = Math.sqrt(building4Distance);
//sort them
distances = new double[4];
distances[0] = building1Distance;
distances[1] = building2Distance;
distances[2] = building3Distance;
distances[3] = building4Distance;
Arrays.sort(distances);
//search to see if pointing at building
for(int i = 0; i < distances.length; i++){
//projected coordinates of where camera is facing at that distance
pX = CAMERA_X + (xDelta * 4.0 * distances[i]);
pZ = CAMERA_Z + (zDelta * 4.0 * distances[i]);
//check to see which building is at that distance
if(building1Distance == distances[i]){
//check to see if its within diameter of the building.
if(Math.sqrt(Math.pow((double)(CAMERA_X - pX), 2) + Math.pow((double)(CAMERA_Z - pZ), 2)) < 50){
buildingIndex = 1;
return;
}
}else if(building2Distance == distances[i]){
if(Math.sqrt(Math.pow((double)(CAMERA_X - pX), 2) + Math.pow((double)(CAMERA_Z - pZ), 2)) < 30){
buildingIndex = 2;
return;
}
}else if(building3Distance == distances[i]){
if(Math.sqrt(Math.pow((double)(CAMERA_X - pX), 2) + Math.pow((double)(CAMERA_Z - pZ), 2)) < 50){
buildingIndex = 3;
return;
}
}else{
if(Math.sqrt(Math.pow((double)(CAMERA_X - pX), 2) + Math.pow((double)(CAMERA_Z - pZ), 2)) < 10){
buildingIndex = 4;
return;
}
}
}
buildingIndex = -1;
It seems to be always setting buildingIndex to -1.
It's not easy to debug because I am making a Google Cardboard application, and to move in my world I must unplug the USB and plug in a keyboard (I don't have a bluetooth one).
Can anyone see a problem in my logic/code?
Thanks
It looks like your threshold logic is not accurate.
The problem was that I was using CAMERA_X and CAMERA_Z instead of the building's coordinates when testing how far the projected point was.
Related
I have a "physics ball" that can bounce around the screen off the edges which works fine. But I wanted to be able to add boxes and have my ball be able to bounce of those, too. I have tried to create something and it feels like it is quite close, but there is flaw that I understand why it exists, but am unsure on how I can get around it.
if (colliding(ball, block))
{
if (ball.velocity.x > 0)
{
ball.velocity.x *= -ball.restitution;
ball.vector.x = block.vector.x - ball.radius;
}
else
{
ball.velocity.x *= -ball.restitution;
ball.vector.x = block.vector.x + block.width + ball.radius;
}
if (ball.velocity.y > 0)
{
ball.velocity.y *= -ball.restitution;
ball.vector.y = block.vector.y - ball.radius;
}
else
{
ball.velocity.y *= -ball.restitution;
ball.vector.y = block.vector.y + block.height + ball.radius;
}
}
colliding():
boolean colliding(MassEntity ball, Block block)
{
return PVector.dist(ball.vector, block.vector) < ball.radius
|| PVector.dist(ball.vector, new PVector(block.vector.x + block.width, block.vector.y)) < ball.radius
|| PVector.dist(ball.vector, new PVector(block.vector.x + block.width, block.vector.y + block.height)) < ball.radius
|| PVector.dist(ball.vector, new PVector(block.vector.x, block.vector.y + block.height)) < ball.radius
|| (ball.vector.x - ball.radius < block.vector.x + block.width && ball.vector.x + ball.radius > block.vector.x
&& ball.vector.y - ball.radius < block.vector.y + block.height && ball.vector.y + ball.radius > block.vector.y);
}
(I know the if statement is a little monstrous, but I don't know what happened to the formatting honestly)
The issue is that when the ball collides with the rectangle, since the ball is "teleported" to outside of the rectangle (so it doesn't stay inside the rectangle due to the velocity being flipped), it teleports on both axes so pretty much the ball will weirdly teleport to the end of one of the edges.
I just need to somehow make if statements for the respective axes to only be considered in the appropriate situation.
First, compute P, the nearest point to the ball that is in the box :
PVector P = new PVector(
max(min(ball.vector.x, box.vector.x + box.width / 2), box.vector.x - box.width / 2),
max(min(ball.vector.y, box.vector.y + box.height / 2), box.vector.y - box.height / 2)
);
To check if there is a collision, you can check if the distance between P and the center of the ball is smaller than the radius of the ball.
To update the speed of the ball, you can do this :
PVector n = normalize(ball.vector.copy().sub(P));
ball.velocity.sub(n.mult(2 * n.dot(ball.velocity)));
n is the normal vector a the collision's position and to reflect the speed on the surface you have to delete the component of the velocity that is parallel to it. Then you have to add this same component multiplied by -1. As those two operations are the same, you can just do it one time with a factor 2.
A last precision I have to make is that you may need to check if the ball is going away from the box to avoid reversing the speed in that case :
PVector n = normalize(ball.vector.copy().sub(P));
float f = n.dot(ball.velocity);
if (f < 0)
ball.velocity.sub(n.mult(2 * f));
I haven't tested my code so tell me if there is a problem.
So I made a game and I want the enemies to bounce off the wall when they hit in a random x and y speed. However, somehow these little buggers are still getting out of the window. Most the time it works but every like 10ish times it will sneak out the border and I can't figure out how.
#Override
public void tick()
{
x += speedX;
y += speedY;
Random r = new Random();
//BUGS
if(y <= 0 || y >= Game.HEIGHT - 48) //This is correct size of the window edges
{
if(speedY <= 0)
speedY = (r.nextInt(8) + 1);
else
speedY = -(r.nextInt(8) + 1);
}
if(x <= 0 || x >= Game.WIDTH - 32) //This is correct size of the window edges
{
if(speedX <= 0)
speedX = (r.nextInt(8) + 1);
else
speedX = -(r.nextInt(8) + 1);
}
Issues:
Don't re-create Random as it's wasteful and sometimes dangerous. Better to create one Random object and assign it to an instance field of the class, and use it throughout.
Avoid "magic numbers". So instead of y >= Game.HEIGHT - 48, do y >= Game.HEIGHT - WINDOW_EDGES (or something similar)
Don't swap speed as you're doing but instead check for y <= 0 or y >= Game.HEIGHT -SOME_CONSTANT separately, and gear the results based on this finding to avoid getting caught in a speed "trap". This is your main problem in fact.
e.g.,
if (y <= 0) {
speedY = r.nextInt(8) + 1; // change 8 to a constant
} else if (y >= Game.HEIGHT - SOME_CONSTANT) {
speedY = -(r.nextInt(8) + 1);
}
Same for x and speedX
Regarding:
2) I would like to do that but since I have multiple object sizes, I have to change the edges.
Then each object should have a method that returns its edge size (or whatever property is needed), and you should use this, again, not magic numbers
3) I tried swapping and they just shot off the screen.
I don't know what you mean by this or what specific code changes you may have made.
If still stuck, consider creating and posting a valid Minimal Reproducible Example
(Just a note, my app takes a video feed at 1920x1080#60fps, and the processing and calculations are done post-recording. The videos recorded are all less than ~6 seconds.)
I am currently developing an image processing algorithm to run on an android device and need to calculate the standard deviation (and mean) of a single pixel's value across time. In other words, I want to be able to determine what the standard deviation for an arbitrary pixel at coordinate (x, y) is across z seconds/frames.
I use VideoCapture to read the video feed frame by frame.
OpenCV does not seem to provide functions for processing across the time axis, so I have had to implement my own processing functions. Currently, my algorithm makes use of an incremental computation method (more on it here: https://math.stackexchange.com/questions/102978/incremental-computation-of-standard-deviation) to calculate stdev, but it runs very slowly on a mobile device. I use this iterative method because I originally tried to organize each pixel's data into separate vectors/lists to then perform mean and stdev calculations on, but I ran out of memory given the video resolution, frame rate, and video duration.
// Define window boundaries
int startFrame = i * frameRate + temporalSizeRBF;
int endFrame = (i + 1) * frameRate + temporalSizeRBF - 1;
// Calculating Mean and STD for current window
// First frame (frame 0)
vc.read(frame);
// Extract only red channel
Core.extractChannel(frame, redMat, 2);
redMat.convertTo(mean, CvType.CV_64FC1, 1/255.0);
stdev = Mat.zeros(frameHeight, frameWidth, CvType.CV_64FC1);
// Rest of the frames [1:frameRate)
for (int j = startFrame + 1; j <= endFrame; j++) {
double n = j - startFrame + 1;
Log.d(TAG, "Current Frame: " + n);
vc.read(frame);
Core.extractChannel(frame, redMat, 2);
redMat.convertTo(convRedMat, CvType.CV_64FC1, 1/255.0);
// Per row
for (int x = 0; x < frame.rows(); x++) {
// Per col
for (int y = 0; y < frame.cols(); y++) {
double newStd = (stdev.get(x, y)[0] * ((n - 2) / (n - 1))) + ((1 / n) * Math.pow(convRedMat.get(x, y)[0] - mean.get(x, y)[0], 2));
double newMean = (convRedMat.get(x, y)[0] + (n - 1) * mean.get(x, y)[0]) / n;
stdev.put(x, y, newStd);
mean.put(x, y, newMean);
}
}
}
Given the lack of proper 3+ dimensional Matrices on OpenCV Java (at least for OCV 3.4), I decided to proceed and refine the iterative method of calculating Stdev. Instead of doing pixel by pixel traversals, I used the array operations that OpenCV provides in its Core library (https://docs.opencv.org/3.4/d2/de8/group__core__array.html).
Here is my solution.
int startFrame = i * fps + offset;
int endFrame = (i + 1) * fps + offset - 1;
// Calculating STD for current window
// First frame (frame 0)
frame = frames.get(startFrame);
Imgproc.cvtColor(frame, bgr, Imgproc.COLOR_YUV2BGR_I420);
// Extract only red channel
Core.extractChannel(bgr, redMat, 2);
redMat.convertTo(mean, CvType.CV_32FC1, 1/255.0);
var = Mat.zeros((int) frameSize.height, (int) frameSize.width, CvType.CV_32FC1);
// Rest of the frames [1:frameRate)
for (int j = startFrame + 1; j <= endFrame; j++) {
double n = j - startFrame + 1;
Log.d(TAG, "Current Frame: " + n);
frame = frames.get(j);
Imgproc.cvtColor(frame, bgr, Imgproc.COLOR_YUV2BGR_I420);
Core.extractChannel(bgr, redMat, 2);
redMat.convertTo(convRedMat, CvType.CV_32FC1, 1/255.0);
// Calculate the iterative variance and mean for this frame
// Var(n) = (n-2)/(n-1)*var(n-1) + 1/n*(X(n) - Mean(n-1))^2
Core.multiply(var, new Scalar((n-2)/(n-1)), var); // (n-2)/(n-1)*var(n-1)
Core.subtract(convRedMat, mean, temp1); // (X(n) - Mean(n-1))
Core.multiply(temp1, temp1, temp2); // (X(n) - Mean(n-1))^2
Core.multiply(temp2, new Scalar(1/n), temp2); // 1/n*(X(n) - Mean(n-1))^2
Core.add(var, temp2, var); // (n-2)/(n-1)*var(n-1) + 1/n*(X(n) - Mean(n-1))^2
// Mean(n) = 1/n*(X(n) + (n-1)*Mean(n-1))
Core.multiply(mean, new Scalar(n-1), temp1); // (n-1)*Mean(n-1)
Core.add(convRedMat, temp1, temp2); // X(n) - (n-1)*Mean(n-1)
Core.multiply(temp2, new Scalar(1/n), mean);
}
At the end of this we then square root the values of the var matrix to find the standard deviation of each pixel.
Using the OpenCV matrix operations significantly decreased runtime for the algorithm.
Note - these are the CvTypes of the matrices used:
bgr - 8UC3
redMat - 8UC1
mean, stdev, convRedMat, temp1, temp2 - 32FC1
I'm shooting an idea here and have come across a few problems. Firstly I have a class with a method for creating new worlds.
The 2D tiled world gets created like this:
for(int y = 0; y < WORLDSIZE; y++){
for(int x = 0; x < WORLDSIZE; x++){
tiles.add(new Tile(Sprite.blanktile, x*32, y*32));
}
}
This creates and predefines the entire worlds tile positions and gives them all a blank tile sprite. It's only run once at start. The class where this gets processed is where the problem starts.
Here the tiles are iterated through and skips all tiles that are not on the screen. The xoff and yoff are up, down, left, right offsets for moving the screen around. I'm a bit worried about editing the actual grid locations. I'm sure I will be able to account for that when needed.
This is the general idea.
while(true){
for(int i = 0; i < world.tiles.size(); i++){
world.tiles.get(i).x += xoff;
world.tiles.get(i).y += yoff;
if(world.tiles.get(i).y + yoff > GameWindow.HEIGHT || world.tiles.get(i).y + yoff < -64 || world.tiles.get(i).x + xoff > GameWindow.WIDTH || world.tiles.get(i).x + xoff < -64){
continue;
}else
render.setTilePixel(world.tiles.get(i).sprite, world.tiles.get(i).x, world.tiles.get(i).y);
}
window.draw(render.visualization());
}
It sets each tiles pixels every time it updates. Which is making it quite slow for something that should be less. The way it sets the pixels is like this:
public void setTilePixel(Sprite sprite, int x, int y){
int xa, ya;
for(int hrzt = 0; hrzt < sprite.SIZE; hrzt++){
for(int vtc = 0; vtc < sprite.SIZE; vtc++){
xa = (hrzt + x);
ya = (vtc + y);
if(xa < width && xa > -1){
if (xa + ya * width < width*height && xa + ya * width > 0){
if(sprite.pixels[hrzt + vtc * sprite.SIZE] != 0xff000000 && sprite.pixels[hrzt + vtc * sprite.SIZE] != 0){
visualizer.pixels[xa + ya * width] = sprite.pixels[hrzt + vtc * sprite.SIZE];
}
}
}
}
}
}
The last operations send the new image data to the window to be drawn to the screen.
window.draw(render.visualization());
The issue here is that it is taking a long time each cycle. I've tried a few other ways but its taking a long time, like a whole week. So, I've come here. The more tiles I'm processing causes it to get a lot slower. I'm looking for a new way. Possibly where it does everything in the same section of for loops cutting the reiteration down?
Hope I've got enough up. Let me know what else I should add. Thanks.
A couple of small suggestions:
Firstly, you are ultimately rendering these to a screen, I assume. Can you work out where the tiles are in relation to what will be displayed, and skip the ones that are not going to be rendered? This should cut down your calculation volume significantly.
Secondly, in your setTilePixel method, you loop through the full range of hrzt and vtc values, and then have some checks to see whether to do action or not. You could do something like this, change:
for(int hrzt = 0; hrzt < sprite.SIZE; hrzt++){
for(int vtc = 0; vtc < sprite.SIZE; vtc++){
xa = (hrzt + x);
ya = (vtc + y);
if(xa < width && xa > -1){
if (xa + ya * width < width*height && xa + ya * width > 0){
// ***
}
}
}
}
to:
int maxValidHrzt = width-x;
int minValidHrzt = -1;
int maxValidVtc = etc...
int minValidVtc = etc...
for(int hrzt = minValidHrzt; hrzt < maxValidHrzt; hrzt++){
for(int vtc = minValidVtc; vtc < maxValidVtc; vtc++){
// ***
}
}
Alright, so I'm working on collision detection for a 3d game, this is what I got so far:
public void mapCol(Spatial map, Node model2){
Mesh m = (Mesh) ((Node) map).getChild("obj_mesh0");
int c = 0;
m.updateWorldBound(true);
boolean col = false;
c = m.getMeshData().getPrimitiveCount(0);
// System.out.println(c);
Vector3[][] v3 = new Vector3[c][3];
for(int s = 0; s < c; s++){
v3[s] = null;
v3[s] = m.getMeshData().getPrimitive(s, 0, v3[s]);
Vector3 min = new Vector3((float)Math.min((float) Math.min(v3[s][0].getXf(), v3[s][1].getXf()), v3[s][2].getXf()),
(float)Math.min((float)Math.min(v3[s][0].getYf(), v3[s][1].getYf()), v3[s][2].getYf()),
(float)Math.min((float)Math.min(v3[s][0].getZf(), v3[s][1].getZf()), v3[s][2].getZf()));
Vector3 max = new Vector3((float) Math.max((float)Math.max(v3[s][0].getXf(), v3[s][1].getXf()), v3[s][2].getXf()),
(float)Math.max((float)Math.max(v3[s][0].getYf(), v3[s][1].getYf()), v3[s][2].getYf()),
(float)Math.max((float)Math.max(v3[s][0].getZf(), v3[s][1].getZf()), v3[s][2].getZf()));
Vector3 v2 = new Vector3();
v2 = max.add(min, v2);
v2.divideLocal(2);
if(max.getXf() > model2.getTranslation().getXf() - sp1.getRadius()&&
min.getXf() < model2.getTranslation().getXf() + sp1.getRadius() &&
max.getZf() > model2.getTranslation().getZf() - sp1.getRadius() &&
min.getZf() < model2.getTranslation().getZf() + sp1.getRadius() &&
max.getYf() > model2.getTranslation().getYf() + sp1.getRadius()&&
!col){
float cosine = (float) v2.dot(v2);
float angle = (float) Math.toDegrees(Math.acos( cosine ));
float pangle = (float) Math.toDegrees(Math.atan2((min.getX() + ((max.getX() - min.getX())/2)) - model2.getTranslation().getX(), (min.getZ() + ((max.getZ() - min.getZ())/2) - model2.getTranslation().getZ())));
if(min.getY() < max.getY()){
System.out.println("pangle:" + pangle + " angle:" + angle);
model2.setTranslation(
(min.getX() + ((max.getX() - min.getX())/2)) - (Math.sin(Math.toRadians(pangle)) * (sp1.getRadius())),
model2.getTranslation().getYf(),
(min.getZ() + ((max.getZ() - min.getZ())/2)) - (-Math.cos(Math.toRadians(pangle)) * (sp1.getRadius()))
);
col = true;
}
}
}
}
Now the part to really look at is right here:
model2.setTranslation(
(min.getX() + ((max.getX() - min.getX())/2)) - (Math.sin(Math.toRadians(pangle)) * (sp1.getRadius())),
model2.getTranslation().getYf(),
(min.getZ() + ((max.getZ() - min.getZ())/2)) - (-Math.cos(Math.toRadians(pangle)) * (sp1.getRadius()))
);
Any idea why it wouldn't set model2 modle2's radius away from the wall? (making it stop at the way and able to go no further)
float cosine = v2.dot(v2)
is intentional ?
Because it just gives you length of v2, squared.
Probably that should be
float cosine = velocity.dot(normalVector)/(velocity.length()*normalVector.length())
, if you wanted cosine of angle between them, but I don't fully understand your code, so I don't know.