I'm making a 360 media player with Cardboard SDK in android (actually I'm using the new GoogleVR SDK, but it works pretty much alike). To do this I'm following this code:
Everything works great with a monocular vision and with a stereo one when not distorted (cardboardView.setDistortionCorrectionEnabled(false)). But when I try to use the distortion correction it draws this:
I've found this in the GVR API:
If distortion correction is enabled the GL context will be set to draw
into a framebuffer backed by a texture at the time of this call, so if
an implementor need to change the framebuffer for some rendering stage
then the implementor must reset the framebuffer to the one obtained
via glGetIntegerv(GL_FRAMEBUFFER_BINDING, ...) afterwards.
But I'm not sure if this is related.
This is my onDrawEye code:
/**
* Draws a frame for an eye.
*
* #param eye The eye to render. Includes all required transformations.
*/
#Override
public void onDrawEye(Eye eye) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
Matrix.multiplyMM(mView, 0, eye.getEyeView(), 0, mCamera, 0);
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mView, 0);
mSphere.draw(mViewProjectionMatrix);
checkGLError("onDrawEye");
}
Any ideas how to solve this? Thanks so much
(By the way, if I draw a cube instead of a sphere everything works well)
Alright, almost 2 months later I finally solved my problem. If someone wants to know how, it was not a problem of gvr but how I was initializing my scene. Basically i moved every work in the Sphere constructor to the draw method but the shaders initiallization.
Related
I write a game for android using libgdx. If the user opens the pause menu I take a screenshot of the current game, blur it and use it as background for the options menu. This works fine but the code for getting the screenshot is very slow. It takes about 0.8 seconds on average using the code below...
Is there another way to take a screenshot in libgdx which is much faster?
If not, when the user opens the options menu I could try to just keep rendering the game, pause the game logic and blur the screen and draw the options on top.. If this is the only fast way, how could one blur the screen? I found this link but I didn't get it to work.
If it is possible I prefer the solution with the screenshot because it is much easier...
Code to get the screenshot (from official wiki):
public static Pixmap getScreenshot(){
long start = TimeUtils.millis();
byte[] pixels = ScreenUtils.getFrameBufferPixels(0, 0, Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), true);
Pixmap pixmap = new Pixmap(Gdx.graphics.getBackBufferWidth(), Gdx.graphics.getBackBufferHeight(), Pixmap.Format.RGBA8888);
BufferUtils.copy(pixels, 0, pixmap.getPixels(), pixels.length);
long time = TimeUtils.millis()-start;
Gdx.app.log("INFO", "Time for screenshot in sec.: " + time); // about 0.8 seconds
return pixmap;
}
I use the resulting Pixmap to draw my texture.
EDIT:
My code now with the answer of Deniz Yılmaz for getting the screenshot fast:
public Texture getScreenshot(){
Texture texture = new Texture(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Pixmap.Format.RGB888);
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
texture.bind();
Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGB, 0, 0,Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0);
Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);
return texture;
}
Actually taking screenshot is not slow.
Slow part is data transfer between GPU and CPU so any other way to get pixels wont be faster so much.
But also there are openGl codes helping us right here.
You can use opengl codes via Gdx.gl class.
void glCopyTexImage2D(
GLenum target, //Target Opengl Texture
GLint level, //Mipmap level
GLenum internalformat, //Color format
GLint x,
GLint y,
GLsizei width,
GLsizei height,
GLint border);
This function copy pixels into a 2D texture image but not bringing them to CPU.
You just belong a FBO at GPU.
In libgdx first you must bind texture to openGl's texture with a method.
This texture can be empty screen sized texture or you can use old texture you wont use again.
Texture.bind();
or
Gdx.gl.glBindTexture(Opengltexture, texture.getTextureObjectHandle());
For bounding and taking screen
Enable GPUtexture type.
Activate for exact GPUtexture
Call texture bind method
Call opengl function for active GPUtexture
Disable GPUtexture type.
Here is what code look like :
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
texture.bind();
Gdx.gl.glCopyTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA,0, 0,width , height, 0);
Gdx.gl.glDisable(GL20.GL_TEXTURE_2D);
Be aware binding is only active in 1 and 5. My fault was here because i tried to bind texture in create method and had got black screen.
BE AWARE!!!
On android, it needs opengl es 2.0 . You can edit manifest to make sure unsupported devices cant download your game.
< uses-feature android:glEsVersion="0x00020000"
android:required="true" >
RGBA format color space doesnt supported. So make sure you are
using Format.RGB for both opengl function and texture creation.
Result texture will be flipped vertically because of openGl matrix
system. So you have to fix it manually.
I also suggest you to look at fragments and shaders.
It seems like hard but actually enjoyable.
I'm making an Android game using LibGDX. I want to do something hard to explain but I'll try nonetheless.
Look at this camera view (it's from 3ds max):
I can get same exact view in LibGDX without any problems:
perspCam = new PerspectiveCamera(40, screenHeight, screenWidth * h / w);
perspCam.position.set(1, 6, 18f);
perspCam.lookAt(1, 3, -1f);
perspCam.update();
Now the tricky part. What I actually want to see in-game is part inside the red rectangle but filling the whole screen.
I have managed (using GlScissors) to make it look like this:
But I have no idea how to make it fit the whole screen.
Gdx.gl20.glEnable(Gdx.gl20.GL_SCISSOR_TEST);
Gdx.gl20.glScissor(0, 0, 450, 550);
modelBatch.render(instance);
modelBatch.flush();
Gdx.gl20.glDisable(Gdx.gl20.GL_SCISSOR_TEST);
modelBatch.end();
In stead of using glScissor, you should change camera position.
Make it nearer and shift it sideways too. The exact coordinates can be calculated properly.
Hope this helps.
This is a continuation of my previous problem and post, seen here. Thanks to the answer I received there I feel I was able to get a little closer to my goal, as well as further my learning of OpenGL, but shortly after figuring out the basics of working with stencil buffers, I've run into a problem.
It seems that when I draw a sprite to the stencil buffer, it draws the entire square area, rather than just the pixels that aren't fully transparent as I had ignorantly hoped. I vaguely understand why it happens that way, but I am not sure where the solution lies. I have experimented with the stencil itself quite a bit, and I have modified the shaders that the spritebatch uses to discard low-alpha fragments, but I seem to be failing to see the bigger picture.
As a visual example of the problem, I will continue with the examples I used in the previous question. Right now, trying to draw two circles over each other (So they blend perfectly, no overlapping), I am getting this :
So, basically, is there a way for me to utilize stencil buffers using the Sprite and SpriteBatch functionality of LibGDX on complex shapes (Circles are only being used as an example), or do I need to look for an alternative route?
EDIT ::
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthMask(true);
batch.begin();
sprite.draw(batch);
sprite2.draw(batch);
batch.end();
Gdx.gl.glDisable(GL20.GL_DEPTH_TEST);
Stencil writing/testing happens at the fragment level. When you draw a circle, you are actually drawing a quad of fragments where each fragment may or may not be textured. The issue of the matter is that the GPU doesn't care what color you write into the fragment when it does the stencil test for the fragment. Therefore, you need to discard fragments to stop the stencil writes for the parts of the quad where you don't want to write stencil values.
TL;DR Use "if(gl_FragColor.a < 0.01) discard;" in the fragment shader to make sure a circle of fragments (and stencil values) are generated.
Mby this helps.
I solve same problem with blending and depth test.
First you need clear depth and color bit.
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
Then you need enable some gl features:
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
Gdx.gl.glDepthMask(true);
After that you can draw your objects. In my project smtng like this:
shapeRenderer.setColor(c.getR(), c.getG(), c.getB(), FIELD_ALPHA);
shapeRenderer.filledCircle(p.getPos().x + s.getOffset().x, ApplicationEnv.SCREEN_HEIGHT - p.getPos().y + s.getOffset().x, b.getRadius());
Important! After drawing you call end() for your spriteBatch (or something else) and disable depth_test feature:
Gdx.gl.glDisable(GL10.GL_DEPTH_TEST);
Result:
Before
After
I'm having issues with the Camera class in libGDX, I just can't visually move it even though its position changes.
This is how I setup the camera:
camera = new OrthographicCamera(frustumWidth, frustumHeight);
This is how I change its position:
world.onUpdate(deltaTime, camera);
renderer.render(world);
camera.position.set(MathUtils.random(0, 800), MathUtils.random(0, 480), 0);
//camera.position.set(
// world.dynamicObjects.get(GameWorld.MainPgID).pos.x * GameWorld.frustumToWorldRatio,
//world.dynamicObjects.get(GameWorld.MainPgID).pos.y * GameWorld.frustumToWorldRatio, 0);
I submit the changes at the beginning of the .render function:
camera.update();
batcher.setProjectionMatrix(camera.combined);
batcher.begin();
polygonBatcher.begin();
As I've said the position does change, and yet of the many combinations I've tried none works.
Perhaps I misunderstood how the Camera works and I need to move the objects and not the camera? Seems to be stupid to me, after all it's called camera for a reason.
You have to apply the combined projection matrix on every batch/renderer you want it to affect.
But besides of that it seems to be fine. Try to debug it step by step.
Setup a simple project with only new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); and some lines (ShapeRenderer) or sprites (SpriteBatch), set the projection matrix to camera.combined, change camera.position and update() the camera. That should do it.
Then when you change camera.position all the renderer with the camera's frustum should offset accordingly without changing the offsets of the sprites/geometry.
btw. the viewport is not 0 - 800, but rather -400 - 400 for x and respectively for y;
In the two attached pictures, the desktop screenshot of libgdx functions as expected. The screenshot from my Galaxy Nexus is unfortunately not as expected. I am attempting to create a simple motion blur or trail effect.
Rendering as I expected on my desktop.
Not rendering as I expected on my Galaxy nexus.
The circle textures are drawn in a for loop during rendering and the effect is achieved with a pixmap using the RGBA of 0, 0, 0, 0.1f that is drawn before the circles.
screenClearSprite creation
Pixmap screenClearPixmap = new Pixmap(256, 256, Format.RGBA8888);
screenClearPixmap.setColor(Color.rgba8888(0, 0, 0, 0.1f));
screenClearPixmap.fillRectangle(0, 0, 256, 256);
screenClearTexture = new Texture(screenClearPixmap);
screenClearSprite = new Sprite(screenClearTexture);
screenClearSprite.setSize(screenWidth, screenHeight);
screenClearPixmap.dispose();
Render
batch.begin();
font.draw(batch, "fps:" + Gdx.graphics.getFramesPerSecond(), 0, 20);
screenClearSprite.draw(batch);
for (int i = 0; i < circleBodies.size(); i++) {
tempPos = circleBodies.get(i).getPosition();
batch.draw(circleTexture, (tempPos.x * SCALE) + screenWidthHalf
- circleSizeHalf, (tempPos.y * SCALE) + screenHeightHalf
- circleSizeHalf);
}
batch.end();
So, what did I do wrong? Perhaps there is a better way to get the 'motion blur' effect of movement?
Here is a different approach, where you clear your screen each time with solid color and no alpha.
This means that you will have to modify your code some. The good thing about this, is that the way you are doing it has some flaws: It will blur everything in motion, not just the balls. And can quickly produce ugly results/artefacts unless you are careful.
Do the same as you are doing now, but instead of drawing the balls to the batch, draw them onto a texture/bitmap/whatever. Then each frame add an alpha-blended image over the balls-image, and then draw the balls in their current position on top of that. Then add that image to your screen. Very much like you are doing now, except you draw to something else and keep it. This way you don't have to rely on the viewport you are drawing onto, and can keep everything separated.
This method is similar to drawing to an accumulation buffer.
Instead of doing it the way you are doing, you can keep track of the n latest positions of each ball. And then draw all of them each frame, with different alpha. This is very easy to implement. Can result in many drawing calls if you have many balls or a large n, but if it's not too much it shouldn't limit your fps and gives nice control.
Perhaps there is a better way to get the 'motion blur' effect of
movement?
in order to make motion blur in my game i use another approch "The particle effect" it works realy fine with me and i didn't have Android/Desktop problems or with different android devices
all you have to do is to use "Particle Effect Editor" of Libgdx and make your effect then load it in your project finally draw it at the same position you draw your object (and alos draw your object)
Tips to make the right effect file with Paticle Editor :
set (use) the same image of the object that you want to blur it motion in the particle effect
try to limit the count : the max number of particle allowed
Disable the "velocity" and "Angle"
parameter
Particle effect help to do motion effect
Hope this will help someone !