Ambiguous results with Frame Buffers in libgdx - opengl

I am getting the following weird results with the FrameBuffer class in libgdx.
Here is the code that is producing this result:
// This is the rendering code
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
stage.act();
stage.draw();
fbo.begin();
batch.begin();
batch.draw(heart, 0, 0);
batch.end();
fbo.end();
test = new Image(fbo.getColorBufferTexture());
test.setPosition(256, 256);
stage.addActor(test);
}
//This is the initialization code
#Override
public void show() {
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
atlas = Assets.getAtlas();
batch = new SpriteBatch();
background = new Image(atlas.findRegion("background"));
background.setFillParent(true);
heart = atlas.findRegion("fluttering");
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, heart.getRegionWidth(), heart.getRegionHeight(), false);
stage.addActor(background);
Image temp = new Image(new TextureRegion(heart));
stage.addActor(temp);
}
Why is it that I am getting the heart that I drew on the frame buffer to get flipped and be smaller than the original one though the frame buffer width and height are the same as that of the image (71 x 72).

Your SpriteBatch is using the wrong projection matrix. Since you are rendering to a custom sized FrameBuffer you will have to manually set one.
projectionMatrix = new Matrix4();
projectionMatrix.setToOrtho2D(0, 0, heart.getRegionWidth(), heart.getRegionHeight());
batch.setProjectionMatrix(projectionMatrix);

To solve this, the frame buffer has to have a width and height equal to that of stage, like this:
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);

Related

OpenGL skybox texture wrapping artifacts

I am trying to make a path tracer using OpenTK and a compute shader, but I have been struggling with textures repeating on the edges of my skybox. I followed the tutorial from learnopengl and adapted it to work with my compute shader but I have not been able to get rid of these artifacts.
This is the snippet that loads the skybox texture:
private TextureHandle _skyboxTexture;
...
protected override void OnLoad() {
base.OnLoad();
GL.Enable(EnableCap.TextureCubeMapSeamless);
...
_skyboxTexture = GL.CreateTexture(TextureTarget.TextureCubeMap);
GL.BindTexture(TextureTarget.TextureCubeMap, _skyboxTexture);
foreach (var file in Directory.GetFiles(#"Images\Skybox")) {
using (var image = SixLabors.ImageSharp.Image.Load(file)) {
image.Mutate(img => img.Rotate(180)); // without this the textures dont line up
using (var ms = new MemoryStream()) {
image.Save(ms, new BmpEncoder());
GL.TexImage2D(Texture.CubeMapTextureTargetFromString(file), 0, (int)InternalFormat.Rgb, 2048, 2048, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, ms.ToArray());
}
}
}
GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexParameteri(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int)TextureWrapMode.ClampToEdge);
...
}
These are a couple screenshots from RenderDoc, you can clearly see the artifact in the skybox texture. In the other picture you can see that the clamping and seamless settings are loaded correctly.
This image is blurry on stackoverflow but when you click it it's better.
I don't think it is an issue with the sampling logic in my compute shader, because when using RenderDoc I can also see the artifact in the texture. I also tried saving the image from the MemoryStream to a .bmp to check if something is going wrong during the loading of the image, but the exported image looks fine. It's also not a problem with the skybox textures, it happens with all textures I try.
Thanks to derhass, I got it working. The problem was that the bitmap header caused a misalignment in the textures. I am using ImageSharp for image processing, so I created a new class that implements IImageEncoder and just puts the raw rgb values in the stream. I don't need the alpha channel so I omitted it but it can be added easily I think.
public class RawBytesEncoder : IImageEncoder {
public void Encode<TPixel>(Image<TPixel> image, Stream stream) where TPixel : unmanaged, IPixel<TPixel> {
for (var y = 0; y < image.Height; y++)
for (var x = 0; x < image.Width; x++) {
var target = new Rgba32();
image[x, y].ToRgba32(ref target);
stream.WriteByte(target.R);
stream.WriteByte(target.G);
stream.WriteByte(target.B);
}
}
public Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel<TPixel> {
throw new NotImplementedException();
}
}
I also had to change some stuff in the other part of my code. The image no longer needed to be rotated 180 degrees but needs to be flipped now, and the PixelFormat in glTexImage is Rgb again now.
foreach (var file in Directory.GetFiles(#"Images\Skybox"))
using (var image = Image.Load(file)) {
image.Mutate(img => img.Flip(FlipMode.Horizontal));
using (var ms = new MemoryStream()) {
image.Save(ms, new RawBytesEncoder());
GL.TexImage2D(Texture.CubeMapTextureTargetFromString(file), 0, (int)InternalFormat.Rgb, 2048, 2048, 0, PixelFormat.Rgb, PixelType.UnsignedByte, ms.ToArray());
}
}
}

Qt3D QAbstractTextureImage pixelated

I use Qt3D in my project, I need to change texture of the plane dynamicly. For this I use my implementation of QAbstractTextureImage.
I do:
auto planeMaterial = new Qt3DExtras::QTextureMaterial();
Qt3DRender::QTexture2D *planeTexture = new Qt3DRender::QTexture2D();
auto *planeTextureImage = new PaintedTextureImage();
planeTextureImage->update();
planeTexture->addTextureImage(planeTextureImage);
planeMaterial->setTexture(planeTexture);
Qt3DCore::QTransform *planeTransform = new Qt3DCore::QTransform();
planeTransform->setRotationX(90);
planeTransform->setTranslation(QVector3D(0.0f, 0.0f, 15.0f));
auto planeEntity = new Qt3DCore::QEntity(this->rootEntity);
planeEntity->addComponent(mPlane);
planeEntity->addComponent(planeMaterial);
planeEntity->addComponent(planeTransform);
planeEntity->setEnabled(true);
In my scenemodifier. So it adds plane to the scene with material using texture. mPlane has width and height: 4.0 and 3.0. The image for texture has resolution 640x480, so it's 4:3 too.
void PaintedTextureImage::paint(QPainter *painter)
{
...
current = QImage((uchar*)color.data, color.cols, color.rows, color.step, QImage::Format_RGB888);
painter->drawImage(0, 0, current);
}
This is how 'current' looks if I save it to file:
And this is how it looks painted as textue:
So image quality became VERY bad and I can't understand why.
Solution:
planeTextureImage->setWidth(640);
planeTextureImage->setHeight(480);
Default was 256x256.

What's wrong with this simple OpenGL/JOGL stencil test?

I'm learning how to use a stencil buffer, but so far have been unsuccessful at getting a even a simple example to work. In fact, despite trying various combinations of parameters for glStencilOp and glStencilFunc I have not been able to see any evidence that the stencil buffer is working at all. I'm starting to suspect my graphics driver (Mac Pro, Mac OS X 10.8.5) or JOGL (2.0.2) doesn't support it... or I'm missing something really basic.
Here's what I'm seeing:
I'm expecting to see the red diamond clipped by the green diamond. What am I doing wrong?
public class Test {
public static void main(String[] args) {
GLProfile glprofile = GLProfile.getDefault();
final GLCapabilities glcapabilities = new GLCapabilities(glprofile);
final GLCanvas glcanvas = new GLCanvas(glcapabilities);
final GLU glu = new GLU();
glcanvas.addGLEventListener(new GLEventListener() {
#Override
public void reshape(GLAutoDrawable glautodrawable, int x, int y, int width, int height) {}
#Override
public void init(GLAutoDrawable glautodrawable) {
GL2 gl = glautodrawable.getGL().getGL2();
glcapabilities.setStencilBits(8);
gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45, 1, 1, 10000);
glu.gluLookAt(0, 0, 100, 0, 0, 0, 0, 1, 0);
gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
gl.glLoadIdentity();
}
#Override
public void dispose(GLAutoDrawable glautodrawable) {}
#Override
public void display(GLAutoDrawable glautodrawable) {
GL2 gl = glautodrawable.getGL().getGL2();
gl.glEnable(GL.GL_STENCIL_TEST);
gl.glClearStencil(0x0);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT);
gl.glStencilFunc(GL.GL_ALWAYS, 1, 1);
gl.glStencilOp(GL.GL_REPLACE, GL.GL_REPLACE, GL.GL_REPLACE);
gl.glStencilMask(0xFF);
//gl.glColorMask(false, false, false, false);
//gl.glDepthMask(false);
gl.glColor3f(0, 1, 0);
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(-25.0f, 0.0f);
gl.glVertex2f(0.0f, 15.0f);
gl.glVertex2f(25.0f, 0.0f);
gl.glVertex2f(0.0f, -15.0f);
gl.glEnd();
gl.glStencilMask(0);
gl.glStencilFunc(GL2.GL_EQUAL, 1, 1);
gl.glStencilOp(GL2.GL_KEEP, GL2.GL_KEEP, GL2.GL_KEEP);
//gl.glColorMask(true, true, true, true);
//gl.glDepthMask(true);
gl.glColor3f(1, 0, 0);
gl.glBegin(GL2.GL_QUADS);
gl.glVertex2f(-20.0f, 0.0f);
gl.glVertex2f(0.0f, 20.0f);
gl.glVertex2f(20.0f, 0.0f);
gl.glVertex2f(0.0f, -20.0f);
gl.glEnd();
}
});
final JFrame jframe = new JFrame("One Triangle Swing GLCanvas");
jframe.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent windowevent) {
jframe.dispose();
System.exit(0);
}
});
jframe.getContentPane().add(glcanvas, BorderLayout.CENTER);
jframe.setSize(640, 480);
jframe.setVisible(true);
}
}
Zero298 has the right idea, though fails to explain why what you tried in your code does not work. This becomes more apparent when you understand how framebuffer pixel formats work in OpenGL; I will touch on this a little bit below, but first just to re-hash the proper solution:
public static void main(String[] args) {
GLProfile glprofile = GLProfile.getDefault ();
GLCapabilities glcapabilities = new GLCapabilities (glprofile);
// You must do this _BEFORE_ creating a render context
glcapabilities.setStencilBits (8);
final GLCanvas glcanvas = new GLCanvas (glcapabilities);
final GLU glu = new GLU ();
The important thing is that you do this before creating your render context ("canvas"). The stencil buffer is not something you can enable or disable whenever you need it -- you first have to select a pixel format that reserves storage for it. Since pixel formats are fixed from the time you create your render context onward, you need to do this before new GLCanvas (...).
You can actually use an FBO to do stencil operations in a render context that does not have a stencil buffer, but this is much more advanced than you should be considering at the moment. Something to consider if you ever want to do MSAA though, FBOs are a much nicer way of changing pixel formats at run-time than creating and destroying your render context ("canvas").
You need a call to glStencilMask() it's what controls what gets written or not. Set it to do or don't write, draw a stencil (in your case, the diamond), set the glStencilMask() again, and then draw what you want to get clipped.
This has a good sample: Stencil Buffer explanation
EDIT:
OK, I think I found the problem. You need to set your capabilities up at the top of the program.
final GLCapabilities glcapabilities = new GLCapabilities(glprofile);
glcapabilities.setStencilBits(8);
final GLCanvas glcanvas = new GLCanvas(glcapabilities);
The important part being:
glcapabilities.setStencilBits(8);
Thanks to: enabling stencil in jogl

Dynamic 2D Ogre3D Texutre

I'm trying to create a 2D background for my ogre scene that renders the camera frames for the QCAR SDK. This is on an iPad with iOS 6.
At the moment I'm retrieving the pixel data like so in renderFrameQCAR:
const QCAR::Image *image = camFrame.getImage(1);
if(image) {
pixels = (unsigned char *)image->getPixels();
}
This returns pixels in the RGB888 format, then passing it to my ogre scene in the renderOgre() functions:
if(isUpdated)
scene.setCameraFrame(pixels);
scene.m_pRoot->renderOneFrame();
The setCameraFrame(pixels) function consists of:
void CarScene::setCameraFrame(const unsigned char *pixels)
{
HardwarePixelBufferSharedPtr pBuffer = m_pBackgroundTexture->getBuffer();
pBuffer->lock(HardwareBuffer::HBL_DISCARD);
const PixelBox& pBox = pBuffer->getCurrentLock();
PixelBox *tmp = new PixelBox(screenWidth, screenHeight, 0, PF_R8G8B8, &pixels);
pBuffer->blit(pBuffer, *tmp, pBox);
pBuffer->unlock();
delete tmp;
}
In this function I'm attempting to create a new PixelBox, copy the pixels into it and the copy that over the the pixelBuffer.
When I first create my Ogre3D scene, I set up the m_pBackgroundTexture & background rect2d like so:
void CarScene::createBackground()
{
m_pBackgroundTexture = TextureManager::getSingleton().createManual("DynamicTexture", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, m_pViewport->getActualWidth(), m_pViewport->getActualHeight(), 0, PF_R8G8B8, TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
m_pBackgroundMaterial = MaterialManager::getSingleton().create("Background", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
m_pBackgroundMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("DynamicTexture");
m_pBackgroundMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
m_pBackgroundMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
m_pBackgroundMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
m_pBackgroundMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false);
m_pBackgroundRect = new Rectangle2D(true);
m_pBackgroundRect->setCorners(-1.0, 1.0, 1.0, -1.0);
m_pBackgroundRect->setMaterial("Background");
m_pBackgroundRect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND);
AxisAlignedBox aabInf;
aabInf.setInfinite();
m_pBackgroundRect->setBoundingBox(aabInf);
SceneNode* node = m_pSceneManager->getRootSceneNode()->createChildSceneNode();
node->attachObject(m_pBackgroundRect);
}
After this all I get is a white background with no texture, and I have no idea why this is not displaying the output! My goal for this is just to have the camera rendering in the background so I can project my 3d model onto it.
Thanks,
Harry.

OpenGL texture colors are wrong

I've made a simple program that cretes an Ortho perspective, and puts a texture containing a png on a quad
However, I can't figure out why some of the colors are displayed all jumbled.
The png looks like this (the white rectangle in the middle is transparent):
The quad in my OpenGL program looks like this:
Below is the code for initializing OpenGL as well as what goes on in the method called by the OpenGL thread.
I'm using JOGL.
public void init(GLAutoDrawable gLDrawable) {
gl.glGenTextures(1, textureId, 0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureId[0]);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_REPEAT);
gl.glTexParameterf(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_REPEAT);
BufferedImage image = null;
try {
image = ImageIO.read(new File("d:\\temp\\projects\\openglTest1\\texTest.png"));
} catch (IOException e1) {e1.printStackTrace();}
DataBufferByte dataBufferByte = (DataBufferByte) image.getRaster().getDataBuffer();
Buffer imageBuffer = ByteBuffer.wrap(dataBufferByte.getData());
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL2.GL_RGBA, GL.GL_UNSIGNED_BYTE, imageBuffer);
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL2.GL_BLEND_SRC);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
}
//this is called by the OpenGL Thread
public void display(GLAutoDrawable gLDrawable) {
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL2.GL_CCW);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, textureBuffer);
gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_BYTE, indexBuffer);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
}
This is puzzling to me because, while I'm not an OpenGL expert I tried to understand what all the above OpenGL commands do before using them. In fact, I've dont the same thing on Android, and everything is displayed ok, but when doing it in Java with JOGL I get this result described here. The only thing I'm doing different is the way I load the png image. On Adroid there's a helper method like this:
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapStatic, 0);
while with JOGL I'm doing my own loading via:
try {
image = ImageIO.read(new File("d:\\temp\\projects\\openglTest1\\texTest.png"));
} catch (IOException e1) {e1.printStackTrace();}
DataBufferByte dataBufferByte = (DataBufferByte) image.getRaster().getDataBuffer();
Buffer imageBuffer = ByteBuffer.wrap(dataBufferByte.getData());
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL2.GL_RGBA, GL.GL_UNSIGNED_BYTE, imageBuffer);
as detailed above.
==UPDATE==
As per jcadam's comment, I've tried setting the format of the pixel data to GL_BGRA like so:
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL2.GL_RGBA, image.getWidth(), image.getHeight(), 0, GL2.GL_BGRA, GL.GL_UNSIGNED_BYTE, imageBuffer);
The colors are still jumbled, but it's a different jumble this time:
How can I find out what particular format my png image is in?
== UPDATE 2 - solution implementation ==
Ok, first, I want to thank jcadam, rotoglup and Tim for pointing me in the right direction.
In short, the issue was that the way in which Java is ordering the pixels when decoding an image is not always the good order for passing to OpenGL. More precisely, if you do not have an Alpha Channel in your image, then it's ok but if you do have an alpha channel the order is bad and some colors will be jumbled.
Now, I started off by making my own manual implementation which works ok for 32bit PNGs and 24 bit JPEGs:
public void texImage2D(File imageLocation,GL gl) {
BufferedImage initialImage = null;
try {
initialImage = ImageIO.read(imageLocation);
} catch (IOException e1) {
throw new RuntimeException(e1.getMessage(), e1);
}
int imgHeight = initialImage.getHeight(null);
int imgWidth = initialImage.getWidth(null);
ColorModel cm = initialImage.getColorModel();
boolean hasAlpha = cm.hasAlpha();
Buffer buffer = null;
int openGlInternalFormat = -1;
int openGlImageFormat = -1;
if(!hasAlpha) {
DataBufferByte dataBufferByte = (DataBufferByte) initialImage.getRaster().getDataBuffer();
buffer = ByteBuffer.wrap(dataBufferByte.getData());
openGlInternalFormat = GL2.GL_RGB;
openGlImageFormat = GL2.GL_BGR;
} else {
openGlInternalFormat = GL2.GL_RGBA;
openGlImageFormat = GL2.GL_RGBA;
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, imgWidth, imgHeight, 4, null);
ComponentColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[] { 8, 8, 8, 8 },
true, false,
ComponentColorModel.TRANSLUCENT,
DataBuffer.TYPE_BYTE);
BufferedImage bufImg = new BufferedImage(colorModel,
raster, false,
null);
Graphics2D g = bufImg.createGraphics();
g.drawImage(initialImage, null, null);
DataBufferByte imgBuf = (DataBufferByte) raster.getDataBuffer();
byte[] bytes = imgBuf.getData();
buffer = ByteBuffer.wrap(bytes);
g.dispose();
}
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, openGlInternalFormat, imgWidth, imgHeight, 0, openGlImageFormat, GL.GL_UNSIGNED_BYTE, buffer);
}
however I later found out that JOGL has its own helper tools for this, and this is in fact what I ended up using:
//this code should be called in init(), to load the texture:
InputStream stream = new FileInputStream("d:\\temp\\projects\\openglTest1\\texTest.png");
TextureData data = TextureIO.newTextureData(gl.getGLProfile(),stream, false, "png");
Texture myTexture = TextureIO.newTexture(data);
//this code should be called in the draw/display method, before the vertices drawing call
myTexture.enable(gl);
myTexture.bind(gl);
It looks like ABGR to me. If you just look at the colors:
png red (A1,B0,G0,R1) looks like
opengl red (R1,G0,B0,A1)
png bluegreen (A1, B1, G1, R0) looks like
opengl white (R1, G1, B1, A0)
png blue (A1, B1, G0, R0) looks like
opengl yellow (R1, G1, B0, A0)
png clear (A0, B?, G?, R?) could be
ogl bluegreen (R0, B?, G?, A?)
If opengl transparency is disabled then the alpha channel wouldn't matter.
Hmm... It looks like a pixel format problem. You could get more specific and try GL_RGBA8, GL_RGBA16, etc. Is this an 8-bit PNG rather than 24 or 32? Is there not an alpha channel (in which case use GL_RGB rather than GL_RGBA)?
Just out of a quick search (I don't have any actual experience with Java ImageIO), it seems that Java has a native ARGB byte ordering, you may take a look at this source code for inspiration.