I have been trying to batch render two different pictures. I have 2 different QOpenGLTexture objects I want to draw in a single draw call with batch rendering but am struggling. Both texture objects have id's but only the last texture objects image is drawn. I believe my problem is with setting up the or frag shader.
//..............Setting up uniform...............//
const GLuint vals[] = {m_texture1->textureId(), m_texture2->textureId()};
m_program->setUniformValueArray("u_TextureID", vals, 2);
//..............frag Shader.....................//
#version 330 core
out vec4 color;
in vec2 v_textCoord; // Texture coordinate
in float v_index; // (0, 1) Vertex for which image to draw.
// 0 would draw the image of the first texture object
uniform sampler2D u_Texture[2];
void main()
{
int index = int(v_index);
color = texture(u_Texture[index], v_textCoord);
};
I've tried experimenting with the index value in the frag shader but it only draws the last texture image or blacks out. I tried implementing it how you would with openGL but have had no luck.
Related
I'm trying to use a QOpenGLWidget to show some images instead of using QLabel. But I'm a bit confused about how to do this.
To make the widget get the job done, I know I need to reimplement the initializeGL() method and paintGL() method.
To get the texture of an image, what I used is SOIL_load_image(). Why is unsigned char* img_data over unsigned char* img_data[3]? I think each pixel of an image has 3 values(RGB).
After getting the texture, I have no idea what I should do and where should I do them in initializeGL() or paintGL(). Can anyone tell the steps?
void MyOpenGLWidget::loadTexture(const char* file_path)
{
*image = cv::imread(file_path, cv::IMREAD_COLOR);
width = image->rows;
height = image->cols;
int channels = image->channels();
img_data = SOIL_load_image(file_path, &width, &height, &channels, SOIL_LOAD_RGB);
}
Why is unsigned char* img_data over unsigned char* img_data[3]
unsigned char* is a pointer to a buffer (of arbitrary length) of data. unsigned char* …[3] is an array of 3 pointers to buffers of data. You have only one buffer, not 3.
For some reason you're using both OpenCV and then SOIL to read the same image two times. Why?
Once you've loaded the image, to display it with OpenGL you have to
Create a texture object (glGenTextures, glBindTexture, glTexImage)
Create some geometry to draw it (usually a quad, or a viewport filling triangle), by filling a vertex buffer object (glGenBuffers, glBindBuffer, glBufferData) and associating the data in the buffer with vertex attributes of a vertex array object (glGenVertexArrays, glBindVertexArray, glEnableVertexArrayAttrib, glVertexAttribPointer)
Create a shader program, consisting of a vertex shader that places the geometry and paramtizes the fragment shader, which actually samples from the texture. (glCreateShader, glShaderSource, glCreateProgram, glLinkProgram)
Then to draw
select the shader program (glUseProgram)
set parameters (glUniform)
draw (glDrawArrays)
I have a little program that render a yellow triangle twice, once on the left half of a framebuffer and once on the right side.
Dump of the texture
Now, after that I render the content of this framebuffer on the screen.
It works if I use GL_TEXTURE_RECTANGLE in the framebuffer constructor:
https://github.com/elect86/Joglus/blob/master/Joglolus/src/joglus/example1/FrameBuffer.java
In binding the texture, function renderFullScreenQuad, line 372:
https://github.com/elect86/Joglus/blob/master/Joglolus/src/joglus/example1/GlViewer.java
And using sampler2DRect in the fragment shader:
#version 330
out vec4 outputColor;
uniform sampler2DRect texture0;
void main() {
outputColor = texture(texture0, gl_FragCoord.xy);
}
But if I change all the RECTANGLE to 2D and I use sample2D in the fs, I get a total black image at the end of the display(), although the dump of the texture shows always the correct image... I would like to know why.
Texture coordinates work differently between textures of types GL_TEXTURE_RECTANGLE and GL_TEXTURE_2D:
For GL_TEXTURE_RECTANGLE, the range of texture coordinates corresponding to the entire texture image is [0.0, width] x [0.0, height]. In other words, the unit of the texture coordinates is in pixels of the texture image.
For GL_TEXTURE_2D, the range of texture coordinates is [0.0, 1.0] x [0.0, 1.0].
With this statement in your fragment shader:
outputColor = texture(texture0, gl_FragCoord.xy);
you are using coordinates in pixel units as texture coordinates. Based on the above, this will work for the RECTANGLE texture, but not for 2D.
Since your original input coordinates in the vertex shader appear to be in the range [0.0, 1.0], the easiest approach to fix this is to pass the untransformed coordinates from vertex shader to fragment shader, and use them as texture coordinates. The vertex shader would then look like this:
#version 330
layout (location = 0) in vec2 position;
out vec2 texCoord;
uniform mat4 modelToClipMatrix;
void main() {
gl_Position = modelToClipMatrix * vec4(position, 0, 1);
texCoord = position;
}
And the fragment shader:
#version 330
in vec2 texCoord;
out vec4 outputColor;
uniform sampler2D texture0;
void main() {
outputColor = texture(texture0, texCoord);
}
I have a 2D BYTE (unsigned char) array. buf[50][100] which is having some data. I need to draw this buffer to an image in Qt using QGraphicsView. The byte in (x,y) represents the (x,y)th pixel of the array. How to pass this array to the QGraphicsView to draw very fast? Or is there any other method (without using QGraphicsView) to draw the image in 2D array Please help.
You can create a QImage object from a pre-existing memory area and then you can use a drawImage call to draw it on a normal QPainter.
Being your image 8 bit per pixel you will need to also set up a palette for the image.
The palette is simply a mapping from a byte index to a QRgb color value. You can set it up like so:
static void setGrayColorMap(QImage * img)
{
img->setColorCount(256);
for (int i = 0; i < 256; ++i) {
img->setColor(i, qRgb(i,i,i));
}
}
I'm following a tutorial on OpenGL ES 2.0 and combining it with a tutorial on GLSL lighting that I found, using a handy Utah teapot from developer.apple.com.
After a lot of fiddling and experimentation I have the teapot drawn moderately correctly on the screen, spinning around all three axes with the 'toon shading' from the lighting tutorial working. There's a few glitches in the geometry due to me simply drawing the whole vertex list as triangle strips (if you look in the teapot.h file there are '-1' embedded where I'm supposed to start new triangle strips, but this is only test data and not relevant to my problem).
The bit I am really confused about is how to position a light in the scene. In my Objective-C code I have a float3 vector that contains {0,1,0} and pass that into the shader to then calculate the intensity of the light.
Why does the light appear to move in the scene too? What I mean is the light acts as though it's attached to the teapot by an invisible stick, always pointing at the same side of it no matter what direction the teapot is facing.
This is the vertex shader
attribute vec4 Position;
attribute vec4 SourceColor;
attribute vec3 Normal;
uniform mat4 Projection;
uniform mat4 Modelview;
varying vec3 normal;
void main(void) {
normal = Normal;
gl_Position = Projection * Modelview * Position;
}
'Position' is set by the Obj-C code and is the vertices for the object, 'Normal' is the list of normals both from a vertex array (VBO), 'Projection' and 'Modelview' are calculated like this:
(A CC3GLMatrix is from the Cocos3D library, mentioned in the GLES tutorial linked above)
CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:1 andFar:100];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);
CC3GLMatrix *modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(0, 0, -7)];
[modelView scaleBy:CC3VectorMake(30, 30, 30)];
_currentRotation += displayLink.duration * 90;
[modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, _currentRotation)];
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
And I set the light in the scene by doing
float lightDir[] = {1,0,1};
glUniform3fv(_lightDirUniform, 1, lightDir);
The fragment shader looks like this
varying lowp vec4 DestinationColor; // 1
varying highp vec3 normal;
uniform highp vec3 LightDir;
void main(void) {
highp float intensity;
highp vec4 color;
intensity = dot(LightDir,normal);
if (intensity > 0.95)
color = vec4(1.0,0.5,0.5,1.0);
else if (intensity > 0.5)
color = vec4(0.6,0.3,0.3,1.0);
else if (intensity > 0.25)
color = vec4(0.4,0.2,0.2,1.0);
else
color = vec4(0.2,0.1,0.1,1.0);
gl_FragColor = color;
}
While trying to work this out I come across code that references the (non-existant in GLES) 'gl_LightSource' and 'gl_NormalMatrix' but don't know what to put into equivalents I have to pass into the shaders from my code. The references to 'eye space' 'camera space' 'world space' and so on are confusing, I know I should probably be converting things between them but don't understand why or how (and where - in code, or in the shader?)
Every frame do I need to modify the light source? The code I have for setting it looks too simplistic. I'm not really moving the teapot around, am I, instead I'm moving the entire scene - light and all around?
First of all some definitions:
world space: the space your whole world is defined in. By convention it is a static space that never moves.
view space/camera space/eye space: the space your camera is defined in. it is usually a position and rotation relative to world space
model space: the space your model is defined in. Like camera space, it is usually a position and rotation relative to world space
light space: same as model space
In simple examples (and i guess in your's) model space and world space are the same. In addition OpenGL by itself doesn't have a concept of world space, which doesn't mean you cannot use one. It comes in handy when you want to have more than one object moving around independently in your scene.
Now, what you are doing with your object before rendering is creating a matrix that transforms the vertices of a model into viewspace, hence 'modelViewMatrix'.
With light in this case it's a little different. Light calculation in your shader is done in modelspace, so you have to transform your lightposition every frame into modelspace.
This is done by calculating something like:
_lightDirUniform = inverseMatrix(model) * inverseMatrix(light) * lightPosition;
The lightposition is transformed from light into world and then into model space. If you don't have a world space, just leave out the model space transformation and you should be fine.
I am writing a rendering engine using Qt and am running into problems with texturing my models
I have a very simple shader to test texturing:
vertex shader:
Attribute vec4 Vertex;
Attribute vec2 texcoords;
uniform mat4 mvp;
varying vec2 outTexture;
void main() {
gl_Position = mvp * Vertex;
outTexture = texcoords;
}
and fragment shader:
uniform sampler2D tex;
varying vec2 outTexture;
void main() {
vec4 color = texture2D(tex, outTexture);
gl_FragColor = color;
}
I am passing my texture coordinates to the shaders correctly
My problem is with binding a QImage and sending it to its texture uniform.
I am using the following code to bind the texture:
const QString& filename;
GLuint m_texture;
QImage image(filename);
image = image.convertToFormat(QImage::Format_ARGB32);
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.width(), image.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glGenerateMipmap(GL_TEXTURE2D);
glEnable(GL_TEXTURE_2D);
The shader works and I can pass a uniform to the matrix and attributes to the vertex and texture coordinates, but when I try to send a uniform to the texture the same way as such:
effect->setUniformValue(effect->uniformLocation("tex", texture->m_texture));
the program crashes with an “access violation reading location” error with glGetError() returning “invalid enumerant”
Interestingly, when I try running the program without attempting to send the texture to the sampler, the texture is actually appearing on the model. Which makes me think the way I’m binding it has something to do with the legacy texture handling and the texture is being bound to a particular texture address which is being picked up by the shader. This is not the effect I want because I want the programmer to be able to explicitly state at draw time what texture should be passed to the uniform (just as any other uniform is set)
How can I pass the texture to it’s sampler, what do I need to change when binding a texture?
Change it to
effect->setUniformValue(effect->uniformLocation("tex"), texture->m_texture);
or
effect->setUniformValue("tex", texture->m_texture);
Try converting the QImage using:
image = QGLWidget::convertToGLFormat(image);
Another thought, if you are using ES2, then GL_RGBA8 is not valid. I think GL_BGRA may be an optional extension, or not ES 2. Hope this helps.