I'm trying to make it so that I can move a camera around a world, however I'm having a tough time finding resources that will explain this clearly. Most resources I have found are explaining (At least I think they are) how to move the world around the camera, without the camera moving, to create the illusion of movement.
I have implemented this, however rotation of the world results in the world spinning around the origin of the world rather than the camera. Now I am of the mindset that I would get far better results if I could move the camera through the world and rotate it independently. I am asking which way is better for creating camera movement in JOGL.. Moving the world around the camera, or moving the camera through the world?
Use modern openGL with shaders so you can do the latter. Store the transform on the camera object and use that to compute the View Matrix which gets passed to your objects. Try having multiple cameras and multiple viewports.
//C++
//choose camera to use in the viewport
for (int i = 0; i < myWin.allObj.size(); ++i)
{
if (myWin.allObj[i]->name->val_s == "persp1") //set persp1 by default
selCam = myWin.allObj[i];
}
//rendering loop
ViewM_t = glm::translate(glm::mat4(), -selCam->t->val_3);
ViewM_rx = glm::rotate(glm::mat4(), selCam->r->val_3.x, myWin.axisX);
ViewM_ry = glm::rotate(glm::mat4(), selCam->r->val_3.y, myWin.axisY);
ViewM = ViewM_t * ViewM_rx * ViewM_ry;
//in object
compute MVP and upload to GPU
Related
I'm making a 2D platformer game. I have created a texture for the platform, that is meant to be repeated over and over to fill the entire platform, without going over. My first attempt was to draw all the pixels from the bitmap manually, but this caused the background to flicker through while moving the platform (the movement and drawing threads are seperate, so the movement can run at a specific speed, while the FPS doesn't need to suffer). I found this technique worked better:
// Init
bitmap = new BitmapDrawable(res, Texture.PLATFORM.getBitmap());
bitmap.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
// Drawing loop
int x = getX() + (isStill() ? 0 : (int)MainActivity.offsetX);
int y = getY() + (isStill() ? 0 : (int)MainActivity.offsetY);
bitmap.setBounds(x, y, x + getWidth(), y + getHeight());
bitmap.draw(canvas);
However, the bitmap appears to be staying static while the platform is acting as a "view hole" to see through to the bitmap. The only work around I can think of is to somehow "offset" the static bitmap:
bitmap.offset(x, y);
Obviously, that isn't a function. I couldn't find one that would do what I want when looking through the docs.
To summon things up, the BitmapDrawable is causing the background to not move with the platform, making it look super weird.
Thanks in advance!
Try these tips in your code:(I assumed the game moves forward in the horizontal direction)
The GUY should only move up and down(with the appropriate touch input) and not forward and backward as you want the focus(or camera alternatively) solely on the GUY.I noticed that the WALL was moving up in your video when the GUY moved from initial higher position of the wall to little bit lower position later, rectify this because the GUY should move down(try to implement Gravity effect).
The WALL should only move forward(mostly) and backward(less often I guess).The WALL shouldn't move up and down normally. Do not apply Gravity effect to it. You can create at least 2 BitmapDrawable instance of WALL for a screen. They are going to be reused sequencially(for eg: If the 1st one goes totally outside of the screen, reshow it in the desired position using setBounds() method) and continue same for others the whole game.
The currently BLUE BACKGROUND, if it is a part of a larger map, then it needs to be appropriately offsetted.
One of the obstacles that I can think of at the time of writing this is to move the WALL down until it goes out of the screen which results in the death of the GUY.
At those places, where I have used the word move, you need to use the setBounds(a, b, c, d) method to make necessary position based changes as I didn't find other way to update the position of a BitmapDrawable instance. I think, you need to use game framework like libGdx to get method of luxury like setOffset(x, y) or of similar sort.
Sorry that I could only present you the ideas without specific code as I do not have past experience working in a project like this. Hope, it helps you in anyway possible.
I am very new to this ARCore and I have been looking at the HelloAR Java Android Studio project provided in the SDK.
Everthing works OK and is pretty cool, however, I want to place/drop an object when I touch the screen even when no planes have been detected. Let me explain a little better...
As I understand ARCore, it will detect horizontal planes and ONLY on those horizontal planes I can place 3D objects to be motion tracked.
Is there any way (perhaps using PointCloud information) to be able to place an object in the scene even if there are no horizontal planes detected? Sort of like these examples?
https://experiments.withgoogle.com/ar/flight-paths
https://experiments.withgoogle.com/ar/arcore-drawing
I know they are using Unity and openFrameworks, but could that be done in Java?
Also, I have looked at
How to put an object in the air?
and
how to check ray intersection with object in ARCore
but I don't think I'm understanding the concept of Ancor (I managed to drop the object on the scene, but it either disappears immediately or it is just a regular OpenGL object with no knowledge about the real world.
What I want to understand is:
- How and is it possible to create a custom/user defined plane, that is, a plane that is NOT automatically detected by ARCore?
- How can I create an Ancor (the sample does it in the PlaneAttachment class, I think) that is NOT linked to any plane OR that is linked to some PointCloud point?
- How do I draw the object and place it at the Ancor previously created?
I think this is too much to ask but looking at the API documentation has not helped me at all
Thank you!
Edit:
Here is the code that I added to HelloArActivity.java (Everything is the same as the original file except for the lines after // ***** and before ...
#Override
public void onDrawFrame(GL10 gl) {
...
MotionEvent tap = mQueuedSingleTaps.poll();
// I added this to use screenPointToWorldRay function in the second link I posted... I am probably using this wrong
float[] worldXY = new float[6];
...
if (tap != null && frame.getTrackingState() == TrackingState.TRACKING) {
// ***** I added this to use screenPointToWorldRay function
worldXY = screenPointToWorldRay(tap.getX(), tap.getY(), frame);
...
}
...
// Visualize anchors created by touch.
float scaleFactor = 1.0f;
for (PlaneAttachment planeAttachment : mTouches) {
...
}
// ***** This places the object momentarily in the scene (it disappears immediately)
frame.getPose().compose(Pose.makeTranslation(worldXY[3], worldXY[4], worldXY[5])).toMatrix(mAnchorMatrix, 0);
// ***** This places the object in the middle of the scene but since it is not attached to anything, there is no tracking, it is always in the middle of the screen (pretty much expected behaviour)
// frame.getPose().compose(Pose.makeTranslation(0, 0, -1.0f)).toMatrix(mAnchorMatrix, 0);
// *****I duplicated this code which gets executed ONLY when touching a detected plane/surface.
mVirtualObject.updateModelMatrix(mAnchorMatrix, scaleFactor);
mVirtualObjectShadow.updateModelMatrix(mAnchorMatrix, scaleFactor);
mVirtualObject.draw(viewmtx, projmtx, lightIntensity);
mVirtualObjectShadow.draw(viewmtx, projmtx, lightIntensity);
...
}
You would first have to perform a hit test via Frame.hitTest and iterate over the HitResult objects until you hit a Point type Trackable. You could then retrieve a pose for that hit result via HitResult.getHitPose, or attach an anchor to that point and get the pose from that via ArAnchor.getPose (best approach).
However, if you want to do this yourself from an arbitraty point retrieved with ArPointCloud.getPoints, it will take a little more work. In this approach, the question effectively reduces down to "How can I derive a pose / coordinate basis from a point?".
When working from a plane it is relatively easy to derive a pose as you can use the plane normal as the up (y) vector for your model and can pick x and y vectors to configure where you want the model to "face" about that plane. (Where each vector is perpendicular to the other vectors)
When trying to derive a basis from a point, you have to pick all three vectors (x, y and z) relative to the origin point you have. You can derive the up vector by transforming the vector (0,1,0) through the camera view matrix (assuming you want the top of the model to face the top of your screen) using ArCamera.getViewMatrix. Then you can pick the x and z vectors as any two mutually perpendicular vectors that orient the model in your desired direction.
I'm new to opencv. I'm working with it in java, which is a pain, since most of the example and resources around the internet is in C++.
Currently my project involves recognizing a chessboard and then be able to draw on specific parts of the board.
I've gotten so far as to get the corners through the Calib3d part of the library. But this is where i get stuck. My question is how do i convert the corners info i got (Which is the corners placement on the 2D image) to something i can use in a 3D space to draw on with LibGdx?
Following is my code (in snippets):
public class chessboardDrawer implements ApplicationListner{
... //Fields are here
MatOfPoint2f corners = new MatOfPoint2f();
MatOfPoint3f objectPoints = new MatOfPoint3f();
public void create(){
webcam = new VideoCapture(0);
... //Program sleeps to make sure camera is ready
}
public void render(){
//Fetch webcam image
webcam.read(webcamImage);
//Grayscale the image
Imgproc.cvtColor(webcamImage, greyImage, Imgproc.COLOR_BGR2GRAY);
//Check if image contains a chessboard of with 9x6 corners
boolean foundCorners = Calib3d.findChessboardCorners(greyImage,
new Size(9,6),
corners, Calib3d.CALIB_CB_FAST_CHECK | Calib3d.CALIB_CB_ADAPTIVE_THRESH);
if(foundCorners){
for(int i = 0; i < corners.height; i++){
//This is where i have to convert the corners
//to something i can use in libGdx to draw boxes
//And insert them into the objectPoints variable
}
}
//Show the corners on the webcamIamge
Calib3d.drawChessboardCorners(webcamImage, new Size(9,6), corners, true);
//Helper library to show the webcamImage
UtilAR.imDrawBackground(webcamImage);
}
}
Any help?
You actually need to localize the (physical) camera using those coordinates.
Fortunately, it is really easy in case of a chessboard.
Camera pose estimation
Note:
The current implementation in OpenCV may not satisfy you in terms of accuracy (at least for a monocular camera). A good AR experience demands nice accuracy.
(Optional) Use some noise filtering method/estimation algorithm to stabilize the pose estimate across time/frames (Preferably Kalman Filter).
This would reduce jerks and wobbling.
Control pose (position + orientation) of a PerspectiveCamera using aforementioned pose estimated.
Draw 3D stuff using scales and initial orientation in accordance with the objPoints that you provided to the camera calibration method.
You can follow this nice blog post to do it.
All 3D models that you render now would be in the chessboard's frame of reference.
Hope this helps.
Good luck.
I'm developing right now an application for Android devices. The main functionality is to draw polylines on map to show what is the traffic in the city on each street. Unfortunately when I draw around 3K polylines - the number is reduced according to the screen size and zoom level - my map gets incredibly slow... I do not mention the time of drawing all of the lines.
Maybe you know more efficient way to mark streets or draw lines on a map?
I was also thinking about switching to OSM but I never used it and I don't know how efficient it is.
I debug app on Samsung Galaxy Note 10.1 and App uses Map API v2
My code to draw polylines:
Polyline line;
List<Float> coordinatesStart;
List<Float> coordinatesEnd;
LatLng start;
LatLng end;
List<List<Float>> coordinates;
int polylinesNumber = 0;
for(Features ftr : features){
coordinates = ftr.geometry.coordinates;
for(int i = 0; i<coordinates.size()-1; i++){
coordinatesStart = coordinates.get(i);
coordinatesEnd = coordinates.get(i+1);
start = new LatLng(coordinatesStart.get(1), coordinatesStart.get(0));
end = new LatLng(coordinatesEnd.get(1), coordinatesEnd.get(0));
line = map.addPolyline(new PolylineOptions()
.add(start, end)
.width(3)
.color(0x7F0000FF)); //semi-transparent blue
polylinesNumber++;
}
}
I would appreciate any help!
Great optimization here:
Your main error is that you use new PolyLineOptions instance for each and every line you draw to the maps. This is make the drawing terribly slow.
The solution would be:
Only use one instance of polyline options and use only the .add(LatLng) function inside the loops.
//MAGIC #1 here
//You make only ONE instance of polylineOptions.
//Setting width and color, points for the segments added later inside the loops.
PolylineOptions myPolylineOptionsInstance = new PolylineOptions()
.width(3)
.color(0x7F0000FF);
for (Features ftr : features) {
coordinates = ftr.geometry.coordinates;
for (int i = 0; i < coordinates.size(); i++) {
coordinatesStart = coordinates.get(i);
start = new LatLng(coordinatesStart.get(1), coordinatesStart.get(0));
//MAGIC #2 here
//Adding the actual point to the polyline instance.
myPolylineOptionsInstance.add(start);
polylinesNumber++;
}
}
//MAGIC #3 here
//Drawing, simply only once.
line = map.addPolyline(myPolylineOptionsInstance);
Attention:
If you would like to have different colors for different line segmnents/sections you would have to use multiple polyline options, because polyline option could have only 1 color. But the method would be the same: Use as few polylineOptions as you can.
Do you check if the polyline that you draw is even visible to the user on the screen? If not, that would be my first idea. This question could be of help for that.
This might be of help as well:
http://discgolfsoftware.wordpress.com/2012/12/06/hiding-and-showing-on-screen-markers-with-google-maps-android-api-v2/
I want to chime in on this because I didn't find this answer complete. If you zoom out you're going to still have a ton of individual polylines on screen and the UI thread will grind to a halt. I solved this problem using a custom TileProvider and a spherical mercator projection of my LatLng points to screen pixels. The idea came from the map-utils-library, which has most of the needed tools to write a canvas to a tile (and a lot of other niceities, too).
I've written an example ComplexTileOverlays from a project I was working on. This includes ways to change alpha and line thickness in the CustomTileProvider.
I first load my custom database of polylines into memory using a splashscreen (for this example, it's an open database of bike facilities on the island of Montréal). from there, I draw each line projection on a canvas 256x256 pixel canvas representing one tile. Overall this technique is faster by leaps and bounds if you have a lot of graphical overlays to tie to the map.
I'm in the process of developing a 2-D game for android which primarily i'm using as an experience to learn the in's and out's of programming for android apps, so naturally i run into a lot of puzzles to work through. Currently, my main activity instantiates a custom class which extends SurfaceView and implements SurfaceHolder.Callback. This view instantiates a thread which handles most of the logic and all the graphics processing (this includes instantiating a canvas and drawing to it., etc.
Well, being that I am a beginner I wasn't thinking when I started that designing the canvas to be much larger than the screen and to allow users to scroll around to see all parts of the canvas... but alas, that's what I need to happen.
If there is an easy way to do this, please let me know.
My best guess is putting the actual creation of the canvas in a separate class which extends ScrollView and somehow just calling all the Draw()'s to that canvas from my thread. is this possible? my click events are actually captured from the main activity (just fyi).
The best option would be to use a Camera to translate the canvas. Do something like this:
// Creates a new camera object
Camera mCam = new Camera();
float startX;
float startY;
#Override
public void onTouch(MotionEvent event)
{
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
startX = event.getX();
startY = event.getY();
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
float x = event.getX();
float y = event.getY();
// Lets you translate the camera by the difference
mCam.translate(x -startX, startY - y, 0.f);
startX = event.getX();
startY = event.getY();
}
}
#Override
public void onDraw(Canvas canvas)
{
// Draw here the objects you want static in the background
canvas.drawBitmap(mBackground, 0, 0, null);
canvas.save();
mCam.applyToCanvas();
// Draw here the objects you want to move
canvas.drawBitmap(mBall, 0, 0, null);
canvas.restore();
// Draw here the objects you want static on the forebround
canvas.drawBitmap(mScore, 0, 0, null);
}
Notice that you are drawing mBall at 0,0 but due to the camera translation it will move by the amount specified. I hope this helps. Have fun :)
I slept on the problem and came up with (if i don't say so myself) A brilliant, relatively simple and elegant solution. Sorry to toot my own horn but I was literally ecstatic that i was able to come up with this.
If anyone is thinking of using this method there are a couple of conditions that made this a good choice. First, all of my objects are drawables with predefined locations using the setBounds(int,int,int,int) method, all objects also store their own coordinates for the location to draw on the canvas and all objects are called in hashmaps which allows me to call and process all the objects in existence.
Now I was thinking about what kabuko said and how it's such a waste to draw a huge canvas and how id run into click event problems, that's when I came up with this.
when a screen touch event occurs near the edge of the screen, a custom method Scroll() is called which loops through every object and adjusts the stored coordinates of the object location depending on which direction the user is trying to scroll. after it increments the objects location, it (in parallel) increments a pair of variables for x and y offset. This offset is then factored into the coordinates of the touch events so that objects can still be selected by touch regardless of the position the screen is scrolled to.
then for performance's sake a simple if statement makes it so that draw is only called on an object if that objects coordinates fall in the range of the screen.
Sorry to gloat but I really surprised and impressed myself with this, haha. I've really only been coding about a month and I almost have a fully functional 2D strategy game!
Java for dummies paid off, lol.
You could give your approach a try, even though it's not really a strategy I'd ever use myself. I suspect you're going to run into some issues with that approach anyway though. If your game already uses touch for input, you're going to have conflicts. Also, if performance is at all a concern (especially if you have any animation), you don't want go with this approach.
If you're going as far as dealing with threading, performance probably matters. Drawing is expensive, and if you make a huge canvas, you'll have to be rendering the whole thing and it will cost you. You should only draw what's on the screen (more or less). Sorry, but you'll probably need a "major overhaul"...
That said, it's really not that bad to deal with scrolling. You probably have coordinates for everything you're drawing. All you need to do is keep track of your "current coordinates" and then translate your drawing x and y by your current x and y. Dealing with the performance stuff, there's a lot you can do, but that's starting to get a bit off-topic. Take a look at these videos if you want to know more:
http://www.youtube.com/watch?v=U4Bk5rmIpic
http://www.youtube.com/watch?v=7-62tRHLcHk
The simple trick with side-scrolling games is to divide your world into tiles, where each tile has a specified amount of area.
Displaying a Tile Based Map
Scrolling a Tile Based Map