I try to implement some post-processing, so I need to use FrameBuffer to collect entire picture and then post-process it with shader. I've found some examples of how to work with FrameBuffer in LibGDX(Rendering a 3D model to texture in LibGDX), but it doesn't work. I get black screen. My code snippet:
#Override
public void show() {
modelBatch = new ModelBatch();
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 1f, 1f, 0f, 1f));
environment.add(new DirectionalLight().set(1f, 0.0f, 0.0f, 0f, -2f, 0f));
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(1f, 1f, 1f);
cam.lookAt(0,0,0);
cam.near = 0.1f;
cam.far = 300f;
cam.update();
com.badlogic.gdx.graphics.g3d.loader.ObjLoader loader =new ObjLoader();
model = loader.loadModel(Gdx.files.internal("cube/cube.obj"));
instance = new ModelInstance(model);
fbo = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
sb= new SpriteBatch();
camController = new CameraInputController(cam);
Gdx.input.setInputProcessor(camController);
}
#Override
public void render(float delta) {
fbo.begin();
camController.update();
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instance, environment);
modelBatch.end();
fbo.end();
//getting texture
tex = fbo.getColorBufferTexture();
//render texture
spriteBatch.begin();
spriteBatch.draw(tex,0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
spriteBatch.end();
}
What do I wrong?
UPDATE
I got another problem. Look at the pictures bellow:
I see this hidden fragment of landscape. I use
fb = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
But when I try to switch on the depth of FrameBuffer, it shows me black screen again:
fb = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
How to get rid of showing this fragment of landscape and why FrameBuffer doesn't work with depth parameter?
You can use ScreenUtils functions to get framebuffer/
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/ScreenUtils.html
ScreenUtils.getFrameBufferPixels(int x, int y, int w, int h, boolean flipY)
Related
I'm trying to add shadows to the bottom of my model but the shadow isn't showing at the bottom. Can anyone help? This is what I tried using the deprecated DirectionalShadowLight:
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, .4f, .4f, .4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
shadowLight = new DirectionalShadowLight(1024, 1024, 60, 60, 1f, 300);
shadowLight.set(0.8f, 0.8f, 0.8f, -1f, -.8f, -.2f);
environment.add(shadowLight);
environment.shadowMap = shadowLight;
shadowBatch = new ModelBatch(new DepthShaderProvider());
camera = new PerspectiveCamera(67, screenWidth, screenHeight);
camera.position.set(0, 6, 2);
camera.direction.set(0, 0, -4).sub(camera.position).nor();
camera.near = 1;
camera.far = 300;
camera.update();
private void renderSanta(GL20 gl) {
gl.glEnable(GL20.GL_DEPTH_TEST);
gl.glEnable(GL20.GL_CULL_FACE);
// /****************
shadowLight.begin(Vector3.Zero, camera.direction);
shadowBatch.begin(shadowLight.getCamera());
shadowBatch.render(santaModel);
shadowBatch.end();
shadowLight.end();
// ********************/
modelBatch.begin(camera);
modelBatch.render(santaModel, environment);
modelBatch.end();
gl.glDisable(GL20.GL_CULL_FACE);
gl.glDisable(GL20.GL_DEPTH_TEST);
}
private void renderBackground() {
viewMatrix.setToOrtho2D(0, 0, 480, 800);
spriteBatch.setProjectionMatrix(viewMatrix);
spriteBatch.begin();
spriteBatch.enableBlending();
spriteBatch.setColor(Color.WHITE);
spriteBatch.draw(background, 0, 0, 480, 800);
spriteBatch.draw(hammock, 0, 800 - 500 - 95, 182, 95);
spriteBatch.disableBlending();
spriteBatch.end();
}
#Override
public void draw(float delta) {
GL20 gl = Gdx.gl;
gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
renderBackground();
renderSanta(gl);
}
EDIT:
So like Xoppa commented, I added a "plane" under the santa model but still the shadow wasn't shown:
ModelBuilder modelBuilder = new ModelBuilder();
modelBuilder.begin();
MeshPartBuilder mpb = modelBuilder.part("parts", GL20.GL_TRIANGLES, VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal | VertexAttributes.Usage.ColorUnpacked,
new Material(ColorAttribute.createDiffuse(Color.WHITE)));
mpb.box(0, -1.5f, 0, 7, 1, 7);
mpb.setColor(1f, 0f, 1f, 1f);
model = modelBuilder.end();
instance = new ModelInstance(model);
instance.transform.setTranslation(0, -5, -3);
public void renderModel() {
shadowLight.begin(Vector3.Zero, camera.direction);
shadowBatch.begin(shadowLight.getCamera());
shadowBatch.render(instance);
shadowBatch.end();
shadowLight.end();
modelBatch.begin(camera);
modelBatch.render(instance, environment);
modelBatch.end();
}
#Override
public void draw(float delta) {
GL20 gl = Gdx.gl;
gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
renderBackground();
renderModel();
renderSanta(gl);
}
Updated output still now showing shadows
Edit 2: Thanks to Xoppa I was able to make the shadow appear:
My rigid body models are dropping through the floor. I am experimenting with Libgdx. When models fall on the ground created from a box they stop moving, but when I replace the ground with a model created from blender the objects fall through. I am trying to build a road track. Here is the code and other examples I tried I keep getting objects that fall through the modeled ground. I'm using blender for the modelling.
public BulletSample(ThrustCopter thrustCopter) {
super(thrustCopter);
// Create ModelBatch that will render all models using a camera
modelBatch = new ModelBatch(new DefaultShaderProvider());
// Create a camera and point it to our model
camera = new PerspectiveCamera(70, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(10f, 10f, 12f);
camera.lookAt(0, 0, 0);
camera.near = 0.1f;
camera.far = 300f;
camera.update();
// Create the generic camera input controller to make the app interactive
cameraController = new CameraInputController(camera);
Gdx.input.setInputProcessor(cameraController);
// Set up environment with simple lighting
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
// environment.set(new ColorAttribute(ColorAttribute.Fog, 0.13f, 0.13f, 0.13f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -0.8f, 0.3f, -1f));
shadowLight = new DirectionalShadowLight(1024, 1024, 60, 60, 1f, 300);
shadowLight.set(0.8f, 0.8f, 0.8f, -1f, -.8f, -.2f);
environment.add(shadowLight);
environment.shadowMap = shadowLight;
shadowBatch = new ModelBatch(new DepthShaderProvider());
Bullet.init();
collisionConfiguration = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfiguration);
broadphase = new btDbvtBroadphase();
solver = new btSequentialImpulseConstraintSolver();
world = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
world.setGravity(new Vector3(0, -9.81f, 1f));
ModelBuilder modelBuilder = new ModelBuilder();
/* Model ground = modelBuilder.createBox(40f, 2f, 40f,
new Material(ColorAttribute.createDiffuse(Color.GREEN)),
Usage.Position | Usage.Normal);
groundInstance=new ModelInstance(ground);
btCollisionShape groundshape = new btBoxShape(new Vector3(20, 1f, 20));
shapes.add(groundshape);
btRigidBody body = new btRigidBody(0,null,groundshape);
bodies.add(body);
world.addRigidBody(body); */
// testing rigid body ground with model from blender
game.manager.load("gameAssets/roadtest1.g3db", Model.class);
game.manager.finishLoading();
Model roadmodel = game.manager.get("gameAssets/roadtest1.g3db", Model.class);
roadInstance = new ModelInstance(roadmodel);
//instances.add(road);
btCollisionShape roadshape = createConvexHullShape(roadmodel, true);
shapes.add(roadshape);
btRigidBody body = new btRigidBody(0, null, roadshape);
world.addRigidBody(body);
Vector3 position=new Vector3();
for(int i=0;i<10;i++){
Model box = modelBuilder.createBox(1f, 1f, 1f,
new Material(ColorAttribute.createDiffuse(Color.BLUE)),
Usage.Position | Usage.Normal);
ModelInstance boxInstance=new ModelInstance(box);
instances.add(boxInstance);
models.add(box);
if(i<5){
position.set(-1, i+1, 0);
}else{
position.set(1, i-4, 0);
}
boxInstance.transform.setToTranslation(position);
btDefaultMotionState motionState = new btDefaultMotionState(boxInstance.transform);
motionState.setWorldTransform(boxInstance.transform.trn(0, 0, 0));
motionStates.add(motionState);
btCollisionShape boxshape = new btBoxShape(new Vector3(0.5f, 0.5f, 0.5f));
shapes.add(boxshape);
btRigidBody boxbody = new btRigidBody(1, motionState, boxshape);
bodies.add(boxbody);
world.addRigidBody(boxbody);
}
//Loading model
game.manager.load("planeanim1.g3db", Model.class);
game.manager.finishLoading();
Model model = game.manager.get("planeanim1.g3db", Model.class);
ModelInstance plane = new ModelInstance(model);
instances.add(plane);
plane.transform.setToRotation(Vector3.Y, 180);
plane.transform.trn(0, 7, 10);
btDefaultMotionState motionState = new btDefaultMotionState(plane.transform);
motionState.setWorldTransform(plane.transform.trn(0, 0, 0));
// motionState.setWorldTransform(plane.transform.rotate(0, 0, .5f,45));
motionStates.add(motionState);
btCollisionShape planeshape = createConvexHullShape(model,true);
shapes.add(planeshape);
btRigidBody planebody = new btRigidBody(5, motionState, planeshape);
bodies.add(planebody);
world.addRigidBody(planebody);
planebody.userData="plane";
planebody.applyCentralImpulse(new Vector3(0,0,-65));
// You use an AnimationController to control animations. Each control is tied to the model instance
controller = new AnimationController(plane);
// Pick the current animation by name
controller.setAnimation("Scene",-1);
contactListener = new MyContactListener();
}
public static btConvexHullShape createConvexHullShape (final Model model, boolean optimize) {
final Mesh mesh = model.meshes.get(0);
final btConvexHullShape shape = new btConvexHullShape(mesh.getVerticesBuffer(), mesh.getNumVertices(), mesh.getVertexSize());
if (!optimize) return shape;
// now optimize the shape
final btShapeHull hull = new btShapeHull(shape);
hull.buildHull(shape.getMargin());
final btConvexHullShape result = new btConvexHullShape(hull);
// delete the temporary shape
shape.dispose();
hull.dispose();
return result;
}
#Override
public void dispose() {
groundInstance.model.dispose();
instances.clear();
modelBatch.dispose();
for (Model model : models)
model.dispose();
for (btRigidBody body : bodies) {
body.dispose();
}
for (btMotionState motion : motionStates)
motion.dispose();
for (btCollisionShape shape : shapes)
shape.dispose();
world.dispose();
collisionConfiguration.dispose();
dispatcher.dispose();
broadphase.dispose();
solver.dispose();
contactListener.dispose();
shadowBatch.dispose();
shadowLight.dispose();
}
#Override
public void render(float delta) {
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glClearColor(0.13f, 0.13f, 0.13f, 1);
if(started){
world.stepSimulation(Gdx.graphics.getDeltaTime(), 5);
for (int i = 0; i < motionStates.size; i++) {
motionStates.get(i).getWorldTransform(instances.get(i).transform);
}
}else{
if(Gdx.input.isTouched()){
started=true;
System.out.println(instances.size);
if(Gdx.input.justTouched())instances.get(10).transform.rotate(0,0.2f,0,25);
}
}
// Respond to user events and update the camera
cameraController.update();
controller.update(delta);
shadowLight.begin(Vector3.Zero, camera.direction);
shadowBatch.begin(shadowLight.getCamera());
shadowBatch.render(instances);
shadowBatch.end();
shadowLight.end();
// Draw all model instances using the camera
modelBatch.begin(camera);
//modelBatch.render(groundInstance, environment);
modelBatch.render(roadInstance, environment);
modelBatch.render(instances, environment);
modelBatch.end();
super.render(delta);
}
I began to try to draw VBO using JOGL. Prior to that, I drew with the help of glBegin and glEnd, and everything worked. And then I see only a black screen. What could be the problem? I read somewhere that using VBO for drawing requires shaders. Is it so?
Code:
public class Main implements GLEventListener {
public static DisplayMode dm, dm_old;
private GLU glu = new GLU();
private float xrot,yrot,zrot;
private int texture;
Texture t;
#Override
public void display(GLAutoDrawable drawable) {
final GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity(); // Reset The View
gl.glTranslatef(0f, 0f, -5.0f);
gl.glBindTexture(GL2.GL_TEXTURE_2D, texture);
final float[] coordData = {
0, 0, //
1, 0, //
0, 1, //
};
final float[] vertices = {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
};
// Setup the vertices into the buffer
FloatBuffer verts = Buffers.newDirectFloatBuffer(vertices.length);
verts.put(vertices).position(0);
// Setup the texture coordinates
FloatBuffer coords = Buffers.newDirectFloatBuffer(coordData.length);
coords.put(coordData).position(0);
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, verts);
gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, coords);
gl.glDrawArrays(GL2.GL_TRIANGLES, 0, 3);
//change the speeds here
xrot += 5f;
}
#Override
public void init(GLAutoDrawable drawable) {
final GL2 gl = drawable.getGL().getGL2();
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glClearColor(0f, 0f, 0f, 0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL2.GL_DEPTH_TEST);
gl.glDepthFunc(GL2.GL_LEQUAL);
gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);
gl.glEnable(GL2.GL_TEXTURE_2D);
try {
File im = new File("/home/congard/pic/t.jpeg");
t = TextureIO.newTexture(im, true);
texture= t.getTextureObject(gl);
}catch(IOException e){
e.printStackTrace();
}
}
#Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
// some code
}
}
You didn't enable the client-side capabilities for vertex and texture coordinates. See Client-Side Vertex Arrays
and glEnableClientState.
Add the following to your code:
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, verts);
gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, coords);
I am playing with libgdx for making yet another physics game :) and I have found something weird. Namely I use SpriteBatch for rendering images at the same time with Box2DDebugRenderer for debuging.
But when the physics acts, they appear to be misplaced. I wrote:
public class Canon implements ApplicationListener {
private OrthographicCamera camera;
private Box2DDebugRenderer debugRenderer;
/...
public void create() {
camera = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
world = new World(new Vector2(0f, -9.8f), true);
camera.position.set(CAMERA_WIDTH/2, CAMERA_HEIGHT/2, 0f);
camera.update();
debugRenderer = new Box2DDebugRenderer();
spriteBatch = new SpriteBatch();
//Create a canon. A rectangle :)
bd = new BodyDef();
fd = new FixtureDef(); fd.density = 1;
PolygonShape ps = new PolygonShape();
// Cannon
bd.type = BodyDef.BodyType.StaticBody;
bd.position.set(new Vector2(8, 5));
ps.setAsBox(5f, 1f);
cannonBody = world.createBody(bd);
fd.shape = ps;
cannonBody.createFixture(fd);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
debugRenderer.render(world, camera.combined);
world.step(BOX_STEP, BOX_VELOCITY_ITERATIONS, BOX_POSITION_ITERATIONS);
spriteBatch.begin();
Sprite s = (Sprite)targetBody1.getUserData();
spriteBatch.draw(s.getTexture(),
(targetBody1.getPosition().x - bodyWidth/2)*ppuX, (targetBody1.getPosition().y - bodyheight/2)*ppuY,
0f, 0f, bodyWidth*ppuX, bodyheight*ppuY, 1f, 1f, radToGrad*targetBody1.getAngle(), 0, 0, s.getTexture().getWidth(), s.getTexture().getHeight(), false, false);
spriteBatch.end();
}
}
And here's how it looks thereafter
Any ideas?
Thanks!
I found it. This is due to the fact rotations in OpenGL are done around the bottom left corner, whereas rotations in Box2D are done around mass center's body.
Rotating the texture around mass center body gives right physics/texture behavior.
private Mesh mesh;
private Texture texture;
private SpriteBatch batch;
#Override
public void create() {
if (mesh == null) {
mesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3,
"a_position"));
mesh.setVertices(new float[] { -0.5f, -0.5f, 0,
0.5f, -0.5f, 0,
0, 0.5f, 0 });
mesh.setIndices(new short[] { 0, 1, 2 });
texture = new Texture(Gdx.files.internal("data/circle.png"));
batch = new SpriteBatch();
}
}
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.begin();
mesh.render(GL10.GL_TRIANGLES, 0, 3);
batch.draw(texture, 10, 10);
batch.end();
}
I'm trying to draw a triangle and a circle (From a png) on the screen, using libgdx.
When I run this, I can only see the Texture (circle) on the screen. What should I do in order to make both Mesh and the Texture visible ?
SpriteBatch uses orthographic projection matrix. When you call batch.begin() then it applies its matrices (see SpriteBatch.setupMatrices().
So either:
change vertices for mesh, so it is on screen:
mesh.setVertices(new float[] { 100f, 100f, 0,
400f, 100f, 0,
250, 400f, 0 });
move rendering of mesh out of batch rendering:
Gdx.gl10.glMatrixMode(GL10.GL_PROJECTION);
Gdx.gl10.glLoadIdentity();
Gdx.gl10.glMatrixMode(GL10.GL_MODELVIEW);
Gdx.gl10.glLoadIdentity();
mesh.render(GL10.GL_TRIANGLES, 0, 3);
batch.begin();
batch.draw(texture, 10, 10);
batch.end();
you have to reset the projection and transformation matrices set by batch in begin(); because SpriteBatch.end() doesn't set matrices back.