Here is my code:
modify from qt example: Examples\Qt-5.14.2\quick\scenegraph\openglunderqml
void SquircleRenderer::init()
{
unsigned char* data = (unsigned char*)malloc(1200*4);
for(int i=0;i<600;i++)
{
data[i*4] = 0;
data[i*4+1] = 255;
data[i*4+2] = 0;
data[i*4+3] = 255;
}
for(int i=600;i<1200;i++)
{
data[i*4] = 0;
data[i*4+1] = 0;
data[i*4+2] = 255;
data[i*4+3] = 255;
}
if (!m_program) {
QSGRendererInterface *rif = m_window->rendererInterface();
Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL || rif->graphicsApi() == QSGRendererInterface::OpenGLRhi);
initializeOpenGLFunctions();
if (texs[0])
{
glDeleteTextures(1, texs);
}
glGenTextures(1, texs);
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 30, 40, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
m_program = new QOpenGLShaderProgram();
m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertices;"
"varying highp vec2 coords;"
"void main() {"
" gl_Position = vertices;"
" coords = vertices.xy;"
"}");
m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,
"varying highp vec2 coords;"
"uniform sampler2D inputImageTexture;"
"void main() {"
" gl_FragColor = texture2D(inputImageTexture, coords);"
"}");
m_program->bindAttributeLocation("vertices", 0);
m_program->link();
arrUni[0] = m_program->uniformLocation("inputImageTexture");
}
}
//! [4] //! [5]
void SquircleRenderer::paint()
{
// Play nice with the RHI. Not strictly needed when the scenegraph uses
// OpenGL directly.
m_window->beginExternalCommands();
m_program->bind();
m_program->enableAttributeArray(0);
float values[] = {
-1, 1,
1, 1,
-1, -1,
1, -1
};
// This example relies on (deprecated) client-side pointers for the vertex
// input. Therefore, we have to make sure no vertex buffer is bound.
glBindBuffer(GL_ARRAY_BUFFER, 0);
m_program->setAttributeArray(0, GL_FLOAT, values, 2);//values
//m_program->setUniformValue("t", (float) m_t);
qDebug()<<m_viewportSize.width()<<m_viewportSize.height()<<"\n";
glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texs[0]);
glUniform1i(arrUni[0], 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_program->disableAttributeArray(0);
m_program->release();
m_window->endExternalCommands();
}
As the picture you can see,it produces 4 same pictures,could you tell me how to produce 1 picture fill the whole window?:
I tried so many methods, but it didn't work, I guess the problem exists in the values array or the glTexImage2D function.
Textures are mapped accross the [0, 1] range, and values outside of that range are modulo-looped back into it, which creates a repeating pattern. Interpreting the texture over the [-1, 1] range leads to what you are seeing since you are mapping exactly twice the UV range in both axises.
There's a few ways to fix this. But my personal preference for a full-framebuffer pass like this is to have the attribute be normalized, and then have it converted to the expected [-1, 1] range for the clip-space coordinate in the vertex shader:
float values[] = {
0.f, 1.f,
1.f, 1.f,
0.f, 0.f,
1.f, 0.f
};
gl_Position = vertices * 2.0 - vec4(1.0, 1.0,0.0,1.0);
Another common technique is to do away with the attribute buffer altogether, and use gl_VertexID to directly generate both the UVs and coordinates.
Related
I am using the compute shader to get a column of colors to match the conditions and I want to get the results for further processing. I want to get the output data in image1D imgOutput, but get_img can't get anything, did I do something wrong?
the texture in the first block has been generated before.
Shader spriteRowProgram, spriteColumnProgram;
unsigned int resultTexture = 0;
const std::string path = found::utils::Environment::GetRunPath();
const std::string sprite_row_path = path + "shaders/glfw_sprite_row.comp";
spriteRowProgram = Shader(sprite_row_path);
std::vector<GLfloat> get_img(qMax(TEX_WIDTH, TEX_HEIGHT) * 4);
glGenTextures(1, &resultTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_1D, resultTexture);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, qMax(TEX_WIDTH, TEX_HEIGHT), 0, GL_RGBA, GL_FLOAT, get_img.data());
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture);
spriteRowProgram.use();
glUniform1i(1, 1);
glBindImageTexture(1, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
glUniform1i(0, 0);
glBindImageTexture(0, resultTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glClear(GL_COLOR_BUFFER_BIT);
spriteRowProgram.setInt("input_width", TEX_WIDTH);
spriteRowProgram.setInt("input_height", TEX_HEIGHT);
glDispatchCompute(TEX_WIDTH, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
#version 430 core
layout (local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, location = 0, binding = 0) uniform writeonly image1D imgOutput;
// texture samplers
layout(rgba32f, location = 1, binding = 1) uniform readonly image2D inputImage;
uniform int input_width;
uniform int input_height;
void main()
{
vec4 baseColor = imageLoad(inputImage, ivec2(0, 0));
bool alpha = baseColor.w == 1;
bool success = true;
for (int i = 0; i <= input_height; ++i)
{
vec4 current = imageLoad(inputImage, ivec2(gl_GlobalInvocationID.x, i));
if (alpha) {
if (current.w > 0.99) continue;
else {
success = false;
break;
}
} else {
vec4 difference = baseColor - current;
success = abs(difference.x) < 0.01 && abs(difference.y) < 0.01 && abs(difference.z) < 0.01;
if (success) continue;
else {
break;
}
}
}
if (success) baseColor = ivec4(0.1, 0.1, 0.1, 0.1);
else baseColor = ivec4(1.0, 1.0, 1.0, 1.0);
imageStore(imgOutput, int(gl_GlobalInvocationID.x), baseColor);
}
One issue might be that if you want to access images after the compute shader, the argument for glMemoryBarrier should be GL_SHADER_IMAGE_ACCESS_BARRIER_BIT and not GL_SHADER_STORAGE_BARRIER_BIT.
So
spriteRowProgram.setInt("input_width", TEX_WIDTH);
spriteRowProgram.setInt("input_height", TEX_HEIGHT);
glDispatchCompute(TEX_WIDTH, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
should really be
spriteRowProgram.setInt("input_width", TEX_WIDTH);
spriteRowProgram.setInt("input_height", TEX_HEIGHT);
glDispatchCompute(TEX_WIDTH, 1, 1);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
Following my latest question: My OpenGL QQuickItem won't have the size I want, I'm now trying,, instead of having an arbitrary size for my OpenGL video, to fit it inside my QQuickItem.
I've heard that QQuickItem::transform() will give me a list of transformation matrices. I'm assuming that this list contains all the transformations needed to arrive at a square the size and position of my QQuickItem. <<<< Is this true? If so, the transformations are from what coordinates and viewport dimensions?
Given that as true, I've made the following minimal verifiable and compilable example that tries to make the green screen fit into the size of my QQuickItem. But currently, it just takes the entire screen.
I used the function getModelMatrix() that you can find below, to get all the transformations and make a matrix out of it. Then I apply these transformations to my vertex shader by doing
gl_Position = u_transform * vertexIn;
As I said, the result is a green screen. However, it has the same dimensions of my window, instead of having the dimensions 640x480 and x,y=0, as specified in main.qml
You can find a minimal compilable and verifiable example here: https://github.com/lucaszanella/openglqtquickexample/tree/88fe0092d663dd92c551c72acccd0bf058fe7e5b
OpenGlVideoQtQuick.cpp:
#include "OpenGlVideoQtQuick.h"
#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4
//Simple shader. Outpus the same location as input, I guess
const char *vString2 = GET_STR(
attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
uniform mat4 u_transform;
void main(void)
{
gl_Position = u_transform * vertexIn;
textureOut = textureIn;
}
);
const char *tString2 = GET_STR(
varying vec2 textureOut;
uniform sampler2D tex_y;
uniform sampler2D tex_u;
uniform sampler2D tex_v;
void main(void)
{
vec3 yuv;
vec3 rgb;
yuv.x = texture2D(tex_y, textureOut).r;
yuv.y = texture2D(tex_u, textureOut).r - 0.5;
yuv.z = texture2D(tex_v, textureOut).r - 0.5;
rgb = mat3(1.0, 1.0, 1.0,
0.0, -0.39465, 2.03211,
1.13983, -0.58060, 0.0) * yuv;
gl_FragColor = vec4(rgb, 1.0);
}
);
OpenGlVideoQtQuick::OpenGlVideoQtQuick():
openGlVideoQtQuickRenderer(nullptr)
{
connect(this, &QQuickItem::windowChanged, this, &OpenGlVideoQtQuick::handleWindowChanged);
update();
}
void OpenGlVideoQtQuick::handleWindowChanged(QQuickWindow *win)
{
if (win) {
connect(win, &QQuickWindow::beforeSynchronizing, this, &OpenGlVideoQtQuick::sync, Qt::DirectConnection);
win->setClearBeforeRendering(false);
}
}
QMatrix4x4 OpenGlVideoQtQuick::getModelMatrix() {
QMatrix4x4 result;
// Compose model matrix from our transform properties in the QML
QQmlListProperty<QQuickTransform> transformations = transform();
const int count = transformations.count(&transformations);
for (int i=0; i<count; i++) {
QQuickTransform *transform = transformations.at(&transformations, i);
transform->applyTo(&result);
}
return result;
}
void OpenGlVideoQtQuick::update()
{
if (window())
window()->update();
}
OpenGlVideoQtQuickRenderer::~OpenGlVideoQtQuickRenderer()
{
delete program;
}
void OpenGlVideoQtQuick::sync()
{
if (!openGlVideoQtQuickRenderer) {
openGlVideoQtQuickRenderer = new OpenGlVideoQtQuickRenderer();
connect(window(), &QQuickWindow::beforeRendering, openGlVideoQtQuickRenderer, &OpenGlVideoQtQuickRenderer::render, Qt::DirectConnection);
connect(window(), &QQuickWindow::afterRendering, this, &OpenGlVideoQtQuick::update, Qt::DirectConnection);
}
this->openGlVideoQtQuickRenderer->qQuickVideoMatrix = getModelMatrix();
}
static const GLfloat ver[] = {
-1.0f,-1.0f,
1.0f,-1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
static const GLfloat tex[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
void OpenGlVideoQtQuickRenderer::render()
{
if (this->firstRun) {
std::cout << "Creating QOpenGLShaderProgram " << std::endl;
this->firstRun = false;
program = new QOpenGLShaderProgram();
initializeOpenGLFunctions();
std::cout << "Fragment Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Fragment, tString2) << std::endl;
std::cout << "Vertex Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Vertex, vString2) << std::endl;
program->bindAttributeLocation("vertexIn",A_VER);
program->bindAttributeLocation("textureIn",T_VER);
std::cout << "program->link() = " << program->link() << std::endl;
glGenTextures(3, texs);//TODO: ERASE THIS WITH glDeleteTextures
}
program->bind();
program->setUniformValue("u_transform", this->qQuickVideoMatrix);
//glViewport(50, 50, 50, 50);
glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
glEnableVertexAttribArray(A_VER);
glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
glEnableVertexAttribArray(T_VER);
unis[0] = program->uniformLocation("tex_y");
unis[1] = program->uniformLocation("tex_u");
unis[2] = program->uniformLocation("tex_v");
//Y
glBindTexture(GL_TEXTURE_2D, texs[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
//U
glBindTexture(GL_TEXTURE_2D, texs[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width/2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
//V
glBindTexture(GL_TEXTURE_2D, texs[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
program->disableAttributeArray(A_VER);
program->disableAttributeArray(T_VER);
program->release();
}
OpenGlVideoQtQuick.h:
#ifndef OpenGlVideoQtQuick_H
#define OpenGlVideoQtQuick_H
#include <QtQuick/QQuickItem>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFunctions>
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QString>
#include <iostream>
#include <QTimer>
class OpenGlVideoQtQuickRenderer : public QObject, protected QOpenGLFunctions
{
Q_OBJECT
public:
OpenGlVideoQtQuickRenderer() {
}
~OpenGlVideoQtQuickRenderer();
QMatrix4x4 qQuickVideoMatrix;
public slots:
void render();
private:
QOpenGLShaderProgram* program;
GLuint unis[3] = {0};
GLuint texs[3] = {0};
unsigned char *datas[3] = { 0 };
bool firstRun = true;
//TODO: make this variable according to video data
int width = 1920;
int height = 1080;
};
class OpenGlVideoQtQuick : public QQuickItem
{
Q_OBJECT
public:
OpenGlVideoQtQuick();
QMatrix4x4 getModelMatrix();
private slots:
void handleWindowChanged(QQuickWindow *win);
public slots:
void sync();
void update();//Updates the window
private:
OpenGlVideoQtQuickRenderer *openGlVideoQtQuickRenderer;
};
#endif // OpenGlVideoQtQuick_H
main.qml:
import QtQuick 2.0
import OpenGLComponents 1.0
Item {
width: 1280
height: 720
OpenGlVideoQtQuick {
width: 640
height: 480
}
}
From your question and your code it is a little unclear what you were "expecting" to see but I do see a few issues which might help you:
I don't think your render loop is actually called. You must do this in your constructor: setFlag(ItemHasContents);
Make sure you do pass some texture/video data into your glTexImage2D() calls otherwise you will get some garbage (random green garbage?)
You may want to have a look at QQuickItem::widthChanged and QQuickItem::heightChanged signals
Make sure you have that glViewport() as well as glClear() calls when debugging to avoid confusions - you can delete them later when you don't need them anymore
Given that you are outputting Normalized Device coordinates, you should just need to set glViewPort and scissor test to the item's x(), y(), width(), height() (no transform needed on vertices). As far as the green you are seeing, this is because none of your YUV textyres have actual data. As a result, in your pixel shader yuv contains (0, -0.5, -0.5) which when transformed by your YUV to RGB matrix yields rgb(0.0, 0.487625, -1.016055) which is a half intensity green.
I am newbie in Opengl. I used the following example from Qt as a start in Opengl as I know Qt.
http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-squircle-cpp.html
I replaced the paint function of the program with following code with an intent to draw chess board pattern. Following is not the paint or render function of my program
paint()
{
if (!m_program) {
initializeOpenGLFunctions();
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertices;"
"varying highp vec2 coords;"
"void main() {"
" gl_Position = vertices;"
" coords = vertices.xy;"
"}");
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
"uniform lowp float t;"
"varying highp vec2 coords;"
"void main() {"
" lowp float i = 1. - (pow(abs(coords.x), 4.) + pow(abs(coords.y), 4.));"
" i = smoothstep(t - 0.8, t + 0.8, i);"
" i = floor(i * 20.) / 20.;"
" gl_FragColor = vec4(coords * .5 + .5, i, i);"
"}");
m_program->bindAttributeLocation("vertices", 0);
m_program->link();
}
auto width = static_cast<float>(m_viewportSize.width());
auto height = static_cast<float>(m_viewportSize.height());
auto a = 2.f / width;
auto b = 2.f / height;
std::vector<float> matrix =
{
a , 0, 0, 0,
0, -b, 0, 0,
0, 0, 1, 0,
-1, 1, 0, 1
};
// Set the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(matrix.data());
// Initialize vertices:
std::vector<float> vertices =
{
0, 0,
0, height,
width, height,
width, 0
};
// Initialize colors
std::vector<float> colors =
{
1, 0, 0,
0, 1, 0,
0, 0, 1,
0, 1, 1
};
// Initialize texture virtice
std::vector<float> texCoord =
{
0, 0,
0, 1,
1, 1,
1, 0
};
// Create texture: simple chess board 8x8
auto numRows = 8u;
auto numCols = 8u;
auto character = 172u;
auto remain = 255u - character;
std::vector<unsigned char> texture(numCols * numRows);
for (auto i = 0u; i < texture.size(); ++i)
texture[i] = ((i + (i / numCols)) % 2) * remain + character;
// Upload to GPU texture
unsigned textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, numCols, numRows, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texture.data());
// Initialize clear colors
glClearColor(0.f, 0.f, 0.f, 1.f);
// Activate necessary states
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices.data());
glColorPointer(3, GL_FLOAT, 0, colors.data());
glTexCoordPointer(2, GL_FLOAT, 0, texCoord.data());
// render
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_QUADS, 0, 4);
m_program->disableAttributeArray(0);
m_program->release();
m_window->resetOpenGLState();
}
The chess board is drawn. But its drawn for a split second & then the screen turns fully white. I want to draw the chess board pattern continiously with each frame draw.
Can someone pls point out what might be going wrong ?
At the very top you have:
if (!m_program) {
then you initialize m_program, at the very bottom you have:
m_program->release();
which as Harish in comments points out is equivalent to calling glUseProgram(0);. So in the next iteration of paint your shader is not bound and not available.
According to docs, the reverse of release(); is bind(); so (I am not expert on this class) the solution might be to call QOpenGLShaderProgram::bind() on the next iteration of your paint.
For future reference, it's a good idea to run opengl programs through a graphics debugger like gDEbugger to give you an insight into what's actually happening inside the API.
So I've recently been learning some openGL. I've initially been using the SDL library to print images on screen but I figured it would be interested to try and achieve something similar with openGL and thus also being able to apply shaders to my images for neat effects such as lighting effects and night/day cycles and such. What I'm doing right now is simply loading a texture, then applying that texture to a quad with the same size of the texture. This works well.
Now I want to apply some shaders. This is an example of a vertex and fragment shader that I could apply to one of my textured quads:
in vec2 LVertexPos2D;
void main()
{
gl_Position = vec4( LVertexPos2D.x, LVertexPos2D.y, 0, 1);
}
which does nothing, then my fragment shader:
out vec4 LFragment;
void main()
{
LFragment = vec4(1.0, 1.0, 1.0, 1.0);
}
Which obviously just turns the texture I'm applying it on into a white block, which isn't exactly what I want. Somehow I need to retrieve the current texel data so I can modify that instead of simply changing it.
I've read that the function call to texture2D is supposed to return a vec4 of the current pixel data but I haven't gotten this to work. (Having a hard time finding a good explanation of the function inputs and how it works). Furthermore texture2D is supposedly deprecated but I can't get its replacement (texture()) to work either. Any nudges in the right direction would be greatly appreciated!
Edit: I'll throw in some more info on how I'm doing things, this is the function that loads my textures:
texture makeTexture(std::string fileLocation)
{
texture tempTexture;
SDL_Surface *mySurface = IMG_Load(fileLocation.c_str());
if (mySurface == NULL)
{
std::cout << "Error in loading image at: " << fileLocation << std::endl;
return tempTexture;
}
GLuint myTexture;
glGenTextures(1, &myTexture);
glBindTexture(GL_TEXTURE_2D, myTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mySurface->w, mySurface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mySurface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
SDL_FreeSurface(mySurface);
tempTexture.texture_id = myTexture;
tempTexture.h = mySurface->h;
tempTexture.w = mySurface->w;
return tempTexture;
}
Where this is my texture struct:
struct texture
{
int w;
int h;
GLuint texture_id;
};
and this function draws any texture to a given x and y coordinate:
void draw(int y, int x, texture &tempTexture)
{
glBindTexture(GL_TEXTURE_2D, tempTexture.texture_id);
glBegin(GL_QUADS);
glTexCoord2f(0, 1);
glVertex2f(-1 + ((float)(x) / SCREEN_WIDTH) * 2, 1 - ((float)(y + tempTexture.h) / SCREEN_HEIGHT) * 2); //Bottom left
glTexCoord2f(1, 1);
glVertex2f(-1 + ((float)(x + tempTexture.w)/SCREEN_WIDTH)*2, 1 - ((float)(y + tempTexture.h) / SCREEN_HEIGHT) * 2); //Bottom right?
glTexCoord2f(1, 0);
glVertex2f(-1 + ((float)(x + tempTexture.w) / SCREEN_WIDTH) * 2, 1.0 - ((float)y / SCREEN_HEIGHT) * 2); //top right
glTexCoord2f(0, 0);
glVertex2f(-1 + ((float)(x) / SCREEN_WIDTH) * 2, 1.0 - ((float)y / SCREEN_HEIGHT) * 2); //Top left (notification: Coordinates are (x,y), not (y,x).
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
}
then in my main render function I'm now doing:
draw(0, 0, myTexture);
glUseProgram(gProgramID);
glUniform1i(baseImageLoc, myTexture2.texture_id);
draw(100, 100, myTexture2);
glUseProgram(NULL);
where myTexture is just a meadow of grass and myTexture2 is a player character that I want to apply some shading shenanigans to. gPriogramID is a program that has my two aformentioned shaders loaded to it.
In order to access texture data in a shader you have to do the following:
First you need to glBind your texture to a specific texture unit (change active texture unit using glActiveTexture.
Pass the texture unit index as a uniform sampler to the shader.
Access the texture in the shader like the following.
// tex holds the value of the texture unit to be used (not the texture)
uniform sampler2D tex;
void main()
{
vec4 color = texture(tex,texCoord);
LFragment = color;
}
You also need to pass texCoords to the shader as in vertex attribute.
Image with two cubes is when its using BLIT Call - Test Code
Image with one Cube is when its not Using BLIT CALL - Test Code
Folks,
Please follow the attached pictures & Code as below..
Struggling with this from last 2 days..
Facing an issue while using FBO in below code, I am able to attach & render to FBo successfully, BUT some how not able to use that as a texture (color & depth buffers) in the same program, MY glReadpixel call after rendering to FBO Shows me all Zero's data...
When generated FBO(color,depth) is used in GLSL- shader code , which is called from Draw2() function displays a blend white cube without texture..
please suggest..., below is the complete code... , I am creating an FBO & using 2 shaders one for Normal rendering & other one uses the color & depth from FBO processed earlier..
Here is MY SHADER CODE
init_gl()
{
This Fragment Shader Code is for normal rendering used in Program under draw()
static const char *fragment_shader_source =
"precision mediump float; \n"
" \n"
"varying vec4 vVaryingColor; \n"
" \n"
"void main() \n"
"{ \n"
" gl_FragColor = vVaryingColor; \n"
"} \n";
This Fragment Shader Code is used in Program2 under draw2()
static const char *fragment_shader_source2 =
"precision mediump float; \n"
" \n"
"varying vec4 vVaryingColor; \n"
"uniform sampler2D color; \n"
"uniform sampler2D depth; \n"
" \n"
"void main() \n"
"{ \n"
"float r = pow(texture2D(color, gl_FragCoord.xy / vec2(256, 256)).a, 128.0); \n"
"float g = texture2D(depth, gl_FragCoord.xy / vec2(256, 256)).a;\n"
"float b = pow(texture2D(depth, gl_FragCoord.xy / vec2(256, 256)).a, 128.0); \n"
"gl_FragColor = vec4(r, g, b, 1.); \n"
"} \n";
MY FIRST DRAWING ON FBO
static void draw(uint32_t i)
{
EGL_CHECK(glEnable(GL_DEPTH_TEST));
glEnable(GL_TEXTURE_2D);
EGL_CHECK(glDepthFunc(GL_ALWAYS));
EGL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fboInfo.id));
EGL_CHECK(glUseProgram(program));
//CUBE DRAWING
Doing Read Pixel here, Its returning all zero's
GLubyte *pixels = malloc(4 * 256 * 256);
EGL_CHECK(glReadBuffer(GL_COLOR_ATTACHMENT0));
EGL_CHECK(glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
//**TO TEST my FBO , IF ITS HAVING SOME RENDER DATA**
EGL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboInfo.id);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
//TEST CODE ONLY
glBindTexture(GL_TEXTURE_2D, fboInfo.id);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
draw2(i);
}
2nd DRAWING WITHOUT FBO (BUT this uses FRAG SHADER WHICH CAN ACCESS FBO data color,depth)
static void draw2(uint32_t i)
{
glUseProgram(program2);
//Draw Same Kind of Cube , Which we draw in draw() function
}
These are the functions to create FBO (color,depth)
GLuint createTexture2D(const int w, const int h, GLint internalFormat, GLenum format, GLenum type)
{
GLuint textureIdX;
EGL_CHECK(glGenTextures(1, &textureIdX));
EGL_CHECK(glBindTexture(GL_TEXTURE_2D, textureIdX));
EGL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
EGL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
EGL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
EGL_CHECK(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
if (GL_DEPTH_COMPONENT == format) {
EGL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE));
EGL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY));
}
EGL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, type, 0));
EGL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
return textureIdX;
}
int createFBO(void)
{
int result = 0;
unsigned int fb = 0;
fboInfo.color = createTexture2D(WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
fboInfo.depth = createTexture2D(WINDOW_WIDTH, WINDOW_HEIGHT, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_FLOAT);
EGL_CHECK(glGenFramebuffers(1, &fboInfo.id));
EGL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, fboInfo.id));
EGL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboInfo.color, 0));
EGL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboInfo.depth, 0));
int data = EGL_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER));
if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
printf("FBO %d set up successfully\n", fboInfo.id);
result = 1;
}
else {
printf("FBO %d NOT set up properly!\n", fboInfo.id);
}
EGL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
return result;
}
This is how my FBO Struct Looks Like
typedef struct {
GLuint id;
GLuint color;
GLuint depth;
}FBOInfo;
My MAIN function looks a below where I create FBO & then call my draw function & swap the buffers..
unsigned long i = 0;
int ret = init_gl();
ret = createFBO();
draw(i);
EGL_CHECK(eglSwapBuffers(eglDisplay, eglSurface));
Since this is quite a lot of code, and you suggested that the problem is with the FBO setup, I focused on that section. I did spot a critical problem in that part of the code where you set up the attachments:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboInfo.depth, 0);
If you call glGetError() after this, you should see an error returned, because GL_RENDERBUFFER is not a valid value for the 3rd argument. The only valid arguments are GL_TEXTURE_2D and the GL_TEXTURE_CUBE_MAP_* values. You have to use GL_TEXTURE_2D in this case.
It might actually be better to use a renderbuffer for the depth buffer if you never use it as a texture. But to do that, you'll have to use all the corresponding calls:
Create the id with glGenRenderbuffers.
Bind it with glBindRenderbuffer.
Allocated it with glRenderbufferStorage.
Attach it to the FBO with glFramebufferRenderbuffer.