libgdx decal not drawing into stencil buffer - libgdx

I'm working on 3d app in libgdx engine.
I just figured out that decalBatch isn't drawing into stencil buffer.
I wanned to make stencil masks for 3d world, and it's not working at all.
This is the code which works for sprite batch, but it's not working with decal batch.
Pls help!
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_STENCIL_BUFFER_BIT);
// batch.setProjectionMatrix(camera.combined);
// setup drawing to stencil buffer
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);
Gdx.gl20.glColorMask(false, false, false, false);
// draw base pattern
shapeRenderer.begin(ShapeType.Filled);
shapeRenderer.identity();
shapeRenderer.setColor(1f, 0f, 0f, 0.5f);
shapeRenderer.rect(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 100, 100);
shapeRenderer.end();
spriteBatch.begin();
// fix stencil buffer, enable color buffer
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
// draw where pattern has NOT been drawn
Gdx.gl20.glStencilFunc(GL20.GL_NOTEQUAL, 0x1, 0xff);
// decalBatch.add(decal);
// decalBatch.flush();
spriteBatch.draw(Assets.instance.background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// draw where pattern HAS been drawn.
// Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0x1, 0xff);
// spriteBatch.draw(Assets.instance.actor1, -Gdx.graphics.getWidth() /
// 2, -Gdx.graphics.getHeight() / 2, Gdx.graphics.getWidth(),
// Gdx.graphics.getHeight());
spriteBatch.end();
EDIT:
I figured out that there should be clearing of Depth buffer, and enabling and disabling of DepthMask, but I cant manage it to work.

Oh I just figured it out.
Depth buffer must be enabled couse Decals are in 3d world.
this is the solution if somebody is interested:
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_STENCIL_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
// setup drawing to stencil buffer
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
Gdx.gl20.glStencilOp(GL20.GL_REPLACE, GL20.GL_REPLACE, GL20.GL_REPLACE);
Gdx.gl20.glColorMask(false, false, false, false);
Gdx.gl20.glDepthMask(false);
// draw base pattern
shapeRenderer.begin(ShapeType.Filled);
shapeRenderer.identity();
shapeRenderer.setColor(1f, 0f, 0f, 0.5f);
shapeRenderer.rect(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, 100, 100);
shapeRenderer.end();
// fix stencil buffer, enable color buffer
Gdx.gl20.glColorMask(true, true, true, true);
Gdx.gl20.glDepthMask(true);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);
// draw where pattern has NOT been drawn
Gdx.gl20.glStencilFunc(GL20.GL_NOTEQUAL, 0x1, 0xff);
decalBatch.add(decal);
decalBatch.flush();
Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);

Related

Pixmaps or Textures for dynamicalliy colored graphics in LibGdx?

I was trying to create a dynamic array containing sprites, that created from pixmap textures. I want to give randomly different colors to this array elements also.
None is working.
Then I tried to create a single pixmap. That also shows same behavior.
I created a pixmap in show() like this:
pixmap = new Pixmap(128, 128, Format.RGBA8888);
Pixmap.setBlending(Pixmap.Blending.None);
pixmap.setColor(128, 0, 0, 1f);
pixmap.fillCircle(64, 64, 64);
texture = new Texture(pixmap);
pixmap.dispose();
in render()
sprite = new Sprite(texture);
sprite.setPosition(b.getX()-sprite.getWidth()/2, b.getY()-sprite.getHeight()/2);
sprite.draw(batch);
Whenever I give an rgb color code, it gives either some different colors or black as output. Tried hex code also.
What wrong I did here?
Previousely I used pixmaps as overlay and single texture etc. But did not go deep in to it and tried.
Here, I planned to draw filled circles with pixmap, instead of using graphics. Because my game elements are very simple filled circles and more than 10 colors I should implement.
These circle objects will be generated dynamically throughout the game.
Now I am wondering what I planned to do will be effective with pixmaps. No exapmples I found on net.
Is it possible to create dynamic array with different colored objects?
Or using graphics is the better option compared to pixmaps?
It would be very helpful if I get suggestions from experienced persons.
r,g,b,a values should be in range from 0f to 1f. And it's bad to create new sprites in render(), since it's called every frame.
I'll try to answer your questions with this small code sample (left comments in the code):
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch spriteBatch;
Pixmap pixmap;
Texture texture;
Array<Sprite> sprites = new Array<Sprite>();
#Override
public void create() {
spriteBatch = new SpriteBatch();
// you should use only one Pixmap object and one Texture object
pixmap = new Pixmap(128, 128, Pixmap.Format.RGBA8888);
pixmap.setBlending(Pixmap.Blending.None);
pixmap.setColor(Color.WHITE);
pixmap.fillCircle(64, 64, 64);
texture = new Texture(pixmap);
pixmap.dispose();
// generate sprites with different colors
// r,g,b,a values should be in range from 0f to 1f
addCircleSprite(128f / 255f, 0f, 0f, 1f);
addCircleSprite(0.4f, 0.2f, 0.5f, 1f);
addCircleSprite(0.6f, 0f, 1f, 1f);
addCircleSprite(0.3f, 0.8f, 1f, 1f);
addCircleSprite(0.1f, 1f, 1f, 1f);
}
void addCircleSprite(float r, float g, float b, float a) {
// every sprite references on the same Texture object
Sprite sprite = new Sprite(texture);
sprite.setColor(r, g, b, a);
// I just set random positions, but you should handle them differently of course
sprite.setCenter(
MathUtils.random(Gdx.graphics.getWidth()),
MathUtils.random(Gdx.graphics.getHeight()));
sprites.add(sprite);
}
#Override
public void render() {
Gdx.gl.glClearColor(0f, 0f, 0f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
for (Sprite sprite : sprites) {
sprite.draw(spriteBatch);
}
spriteBatch.end();
}
#Override
public void dispose() {
texture.dispose();
}
}
also read this Q/A. I guess you could load your Texture object from .png file with white circle:
texture = new Texture("whiteCircle.png");
but creating Pixmap circle with only 64 pixels in radius (and then creating a Texture from it) is ok too, shouldn't make much difference.
setColor() takes r, g, b, a parameters to convert it to rgba8888 format -
public void setColor (float r, float g, float b, float a) {
color = Color.rgba8888(r, g, b, a);
}
So set r, g, b and alpha component as floats in the range [0,1].
use
pixmap.setColor(128f/255, 0, 0, 1f);
instead of
pixmap.setColor(128, 0, 0, 1f);
If you want to use hex then -
Color color = new Color(0x000000a6) //(Black with 65% alpha).

LibGDX Polygon Mask

Is there a way in LibGDX to create a polygon shaped mask? I know how to do a mask with squares and circles but not a polygon. The below code works and renders a mask correctly using a rectangle.
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearDepthf(1f);
Gdx.gl.glClear(GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glDepthFunc(GL20.GL_LESS);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthMask(true);
Gdx.gl.glColorMask(false, false, false, false);
// Renders the rectangle
shapes.begin(ShapeRenderer.ShapeType.Filled);
shapes.setColor(1, 1, 1, 1);
shapes.rect(Gdx.graphics.getWidth() / 2, gdx.graphics.getHeight() / 2, 200f, 200);
shapes.end();
batch.begin();
Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthFunc(GL20.GL_EQUAL);
bg.draw(batch);
batch.end();
Gdx.gl.glDisable(GL20.GL_DEPTH_TEST);
This code below however does not work and simply renders a black screen.
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearDepthf(1f);
Gdx.gl.glClear(GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glDepthFunc(GL20.GL_LESS);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthMask(true);
Gdx.gl.glColorMask(false, false, false, false);
// This should be the polygon being rendered as a mask here
polyBatch.begin();
polygonSprite.draw(polyBatch);
polyBatch.end();
batch.begin();
Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthFunc(GL20.GL_EQUAL);
bg.draw(batch);
batch.end();
Gdx.gl.glDisable(GL20.GL_DEPTH_TEST);
This code below however renders the polygon just fine and uses the same coordinates as the last example.
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// This polygon uses the same coordinates as the last example
// however it now displays the polygon.
polyBatch.begin();
polygonSprite.draw(polyBatch);
polyBatch.end();
Try moving the batch.begin(); in the third paragraph downwards so that it doesn't enclose the Gdx.gl functions, like that:
//batch.begin();
//from here
Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthFunc(GL20.GL_EQUAL);
//to here
batch.begin();
bg.draw(batch);
batch.end();
Gdx.gl.glDisable(GL20.GL_DEPTH_TEST);

Libgdx - FrameBuffer rendering and FitViewport

I use ortho camera and FitViewport at my project.
In my render() method i create a fremeBuffer to store actual state of my game, then create a pixmap of that buffer and finally i set a new shader and do my postprocess stuff with that frame:
//--- render frame to buffer
screenBuffer.begin();
camera.update();
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(img, 0, 0);
batch.end();
stage.draw();
//--- create pixmap from that buffer
pixmap = ScreenUtils.getFrameBufferPixmap(0, 0,screenBuffer.getWidth(), screenBuffer.getHeight());
batch.flush();
screenBuffer.end();
//--- create texture from pixmap
renderedScreenTexture = new Texture(pixmap);
//--- finally render frame with postprocess shader
camera.update();
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setShader(monoShader);
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(renderedScreenTexture, 0,0);
batch.draw(renderedScreenTexture, 0, 0, 640, 320, 0, 0, 640, 320, false, true);
batch.end();
At my resize method I have:
viewport.update(width, height);
camera.position.set(camera.viewportWidth / 2,camera.viewportHeight / 2, 0);
The problem is that after resizing a window FitViewport doesen't work.
When i remove a creating frameBuffer from render method FitViewport works fine.
Can anybody tell me what is wrong with my code or whole concept?
Try this:
// the viewPort you are using
FitViewport v = viewport;
// end your buffer with your viewPort's position and size
screenBuffer.end(v.getScreenX(),v.getScreenY(),
v.getScreenWidth(),v.getScreenHeight());
You may have to call fitViewport.apply() before drawing your frameBuffer.

LibGDX: ShapeRenderer drawing... nothing

So drawing a shape should be really easy, right? Well, the following draws exactly nothing.
...why?
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.setColor(Color.WHITE);
shapeRenderer.rect(WIDTH / 2, HEIGHT / 2, 50, 50);
shapeRenderer.end();
Make sure your camera is properly initialized.
For Example:
camera = new OrthographicCamera(); //Put this in init
camera.setToOrtho(0,0,WIDTH,HEIGHT);

Render to texture not functioning

I'm trying to test Stage3D's setRenderToTexture function, but my test code is not providing any output. I was hoping someone could tell me why - I've tried practically everything to get this working. The code I've created is below:
import flash.events.Event;
import flash.display.*;
import flash.display3D.*;
import flash.display3D.textures.Texture;
import AGALMiniAssembler;
//using stage size in several locations for simplicity - needs to be square, 2^n
[SWF(width='512', height='512', backgroundColor='0x000000', frameRate='60')]
//vars
var context0:Context3D;
var vBuff:VertexBuffer3D;
var iBuff:IndexBuffer3D;
var tex0:Texture;
var tex1:Texture;
var vShader:AGALMiniAssembler = new AGALMiniAssembler();
var fShader:AGALMiniAssembler = new AGALMiniAssembler();
var program:Program3D;
//create a square
var square:Shape = new Shape();
square.graphics.beginFill(0xaa00ff,1);
square.graphics.drawRect(10, 10, stage.stageWidth - 20, stage.stageHeight - 20);
//draw square to bitmapdata and create one blank bitmapdata
var tex0data:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0);
tex0data.draw(square);
var tex1data:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0);
//initialize stage3d
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, initStage3D);
stage.stage3Ds[0].requestContext3D();
function initStage3D(e:Event):void {
context0 = stage.stage3Ds[0].context3D;
context0.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0);
//create buffers - simple quad
var vBuff_vec:Vector.<Number> = new <Number>[-1, -1, 0, 0, 1,
-1, 1, 0, 0, 0,
1, 1, 0, 1, 0,
1, -1, 0, 1, 1];
var iBuff_vec:Vector.<uint> = new <uint>[0, 1, 2, 0, 2, 3]
vBuff = context0.createVertexBuffer(4, 5);
vBuff.uploadFromVector(vBuff_vec, 0, 4);
iBuff = context0.createIndexBuffer(6);
iBuff.uploadFromVector(iBuff_vec, 0, 6);
//load bitmapdata into textures - square to tex0 and blank to tex1
tex0 = context0.createTexture(tex0data.width,tex0data.height,'bgra',false);
tex0.uploadFromBitmapData(tex0data);
tex1 = context0.createTexture(tex1data.width, tex1data.height,'bgra',true);
tex1.uploadFromBitmapData(tex1data);
//create and upload simple shader program
vShader.assemble('vertex', 'mov v0, va1 \n'+ //uv coords to v0
'mov op, va0'); //output xyz coords
fShader.assemble('fragment', 'tex oc, v0, fs0 <2d, linear, nomip>'); //output texture at fs0
program = context0.createProgram();
program.upload(vShader.agalcode, fShader.agalcode);
context0.setProgram(program);
//set buffers
context0.setVertexBufferAt(0, vBuff, 0, 'float3');
context0.setVertexBufferAt(1, vBuff, 3, 'float2');
//prep rendering
addEventListener(Event.ENTER_FRAME, render);
}
function render(e:Event):void {
context0.clear();
//render tex0 onto tex1
context0.setRenderToTexture(tex1);
context0.setTextureAt(0, tex0);
context0.drawTriangles(iBuff);
//render tex1 to back buffer and present
context0.setTextureAt(0, tex1);
context0.setRenderToBackBuffer();
context0.drawTriangles(iBuff);
context0.present();
}
EDIT: I have noticed that changing the color of the blank bitmap does change the color of the final output - it's being displayed, but the square isn't being rendered to it.
FINALLY figured this out! There is a subtle, but important, step that must be taken before a texture is viable as a render target - it must be cleared after the render target is switched. Revising the render function as follows causes the program to function as expected:
function render(e:Event):void {
//render tex0 onto tex1
context0.setRenderToTexture(tex1);
context0.clear();
context0.setTextureAt(0, tex0);
context0.drawTriangles(iBuff);
//render tex1 to back buffer and present
context0.setTextureAt(0, tex1);
context0.setRenderToBackBuffer();
context0.clear();
context0.drawTriangles(iBuff);
context0.present();
}