I am learning PyOpenGL and my first animation test is trying to make a blinking rectangle, but I could not get it to animate, It only blinks when I move the cursor on a window. I guess I am missing a while loop but I could not figure out where to put it. Here is a short of my code.
In fragment shader:
#version 410 core
in Data
{
vec2 uv;
vec4 rgb;
} fs_in;
layout ( location = 0 ) out vec4 fragColor;
uniform float alpha;
void main(){
fragColor = vec4(1.0, 1.0, 1.0, alpha);
}
In main code:
I am only using QOpenGLWindow of PyQt5 to draw the scene.
class Rect(QOpenGLWindow):
def __init__(self):
super(Rect, self).__init__()
...
self.queued = 0.0
self.angle = 0.0
def initializeGL(self):
...
def blinking(self):
x = mapX(sin(self.angle), -1, 1, 0, 1 )
self.rect.shader.uniformf('alpha', x)
self.angle += 0.16
def paintGL(self):
glClearColor( 0.0, 0.0, 0.0, 1.0 )
glClear( GL_COLOR_BUFFER_BIT )
...
#Draw a rectangle
...
#Animate the rectangle
self.blinking()
....
And I try this in paintGL but still not working
start = time.time()
time.sleep(0.01)
done = time.time()
timeDifference = done - start
self.queued += timeDifference
while self.queued >= 0.01:
self.blinking()
self.queued -= 0.01
Any suggestions?
Related
I'm trying to draw a triangle using an OpenGL fragment shader.
I succeeded in drawing a circle but I have a problem with handling the equation/logic or the code to draw a triangle.
draw_triangle(vec2 v1 , vec2 v2, vec2 v3)
Here is the fragment shader:
#version 330 core
out vec4 frag_color;
void draw_circle(vec2 shift_val, int radius,int color)
{
vec2 res = vec2(1280,720);
vec2 norm_cord = gl_FragCoord.xy;
float dist = length(norm_cord - (res*shift_val));
if( dist < radius )
{
if( color ==1 )
frag_color = vec4(1.0, 1.0, 1.0, 1.0);
else
frag_color = vec4(0.0, 0.0, 0.0, 1.0);
}
}
void draw_triangle(vec2 v1 , vec2 v2, vec2 v3)
{
vec2 res = vec2(1280,720)*vec2(0.58,0.4);
vec2 v = vec2(gl_FragCoord.x,gl_FragCoord.y);
float slope1 = abs((v1.y-v2.y)/(v1.x-v2.x)); //y2-y1/x2-x1
float slope2 = abs((v2.y-v3.y)/(v2.x-v3.x)); //y2-y1/x2-x1
float slope3 = abs((v1.y-v3.y)/(v1.x-v3.x)); //y2-y1/x2-x1
float slope_ref1 = abs((v.y-v1.y)/(v.x-v1.x)); //y2-y1/x2-x1
float slope_ref2 = abs((v.y-v2.y)/(v.x-v2.x)); //y2-y1/x2-x1
float slope_ref3 = abs((v.y-v3.y)/(v.x-v3.x)); //y2-y1/x2-x1
float slope_RES1 = abs((res.y-v1.y)/(res.x-v1.x)); //y2-y1/x2-x1
float slope_RES2 = abs((res.y-v2.y)/(res.x-v2.x)); //y2-y1/x2-x1
float slope_RES3 = abs((res.y-v3.y)/(res.x-v3.x)); //y2-y1/x2-x1
if (slope_RES1 < slope1 )
{
if(slope_ref1 < slope1)// && slope_ref3 < slope2 )//slope_ref1 < slope1 &&
frag_color = vec4(1.0, 0.0, 1.0, 1.0);
}
if (slope_RES2 > slope2)
{
if(slope_ref2 > slope2)
frag_color = vec4(1.0, 0.5, 1.0, 1.0);
}
/*if (slope_RES3 < slope3)
{
if(slope_ref3 > slope3)
frag_color = vec4(1.0, 0.0, 1.0, 1.0);
}*/
}
// This is entry point of the fragment shader and it will be called for every fragment covered by the rasterized geometry
void main() {
// Here we just output a constant color which is red (R=1, G=0, B=0, A=1)
//frag_color = vec4(0.0, 0.0, 0.0, 1.0);
draw_circle(vec2(0.5,0.5),100,1); //draws face of circle
draw_circle(vec2(0.5,0.58),16,0); //draws eye (1 for white and anynumber for black)
draw_triangle(vec2(0.5f,0.5f),vec2(-0.5,0.0f),vec2(0.5f,-0.5f));
}
To compute if a point is in a triangle using the same side technique, you need to test the candidate point against three lines to see which side of each line it is on. If it meets the sidedness test for all three lines, then it is inside the triangle.
The condition test will be C(0) && C(1) && C(2).
Where C(n) means: "Is the point on the correct side of edge n"
The condition "which side of the line AB is the point X" is typically checked by checking the sign of the cross product of AB × AX. You could, by convention, assign a winding order to your triangle, and always check that the sign of this cross product is positive.
This, of course, depends on the winding order of the vertices of your triangle. (For example, clockwise vertices require a negative cross product, and counterclockwise vertices require a positive cross product. Choose whichever convention you like or is most convenient given the definition of your polygon.)
You can, alternatively, test using the barycentric technique.
See: this site for more details.
Hope you are rendering QUAD covering the view/screen...
The fragment shader friendly way of rendering triangle is to:
compute barycentric s,t coordinates of fragment
go for the matrix approach as you got mat3,vec3 in GLSL ...
decide if it is inside or outside
simply by testing s+t<=1.0
then set output color or discard;
however discard is not an option for you as you got more shapes...
So compute:
--------------------------------------------------------
| s | | (p1.a - p0.a) , (p2.a - p0.a) , p0.a | | p.a |
| t | = inverse | (p1.b - p0.b) , (p2.b - p0.b) , p0.b | * | p.b |
| 1 | | 0 , 0 , 1 | | 1 |
------------------------------------------------------------------
if (s+t<=1.0) set output color
You can also use the s,t for texturing (even procedural one).
I was wondering how can I draw curves using a triangle, so I ended up reading these 2 articles.
http://commaexcess.com/articles/6/vector-graphics-on-the-gpu
http://www.mdk.org.pl/2007/10/27/curvy-blues
As I understand it correctly, the hardware interpolates u and v across three vertices.
Here is my result
My coordinates for the triangle
vec![100.0, 100.0
100.0, 100.0,
200.0, 100.0];
UV coordinates
vec![0.0, 0.0
0.5, 0.0
1.0, 1.0]
My fragment shader looks like this
#version 430 core
out vec4 frag_color;
in vec2 uv;
in vec4 cords;
void main() {
float x = uv.x;
float y = uv.y;
float result = (x*x) - y;
if(result > 0.0) {
frag_color = vec4(1.0, 0.1, 0.5, 1.0);
} else {
frag_color = vec4(2.0, 0.2, 3.0, 1.0);
}
}
I would like to have a good stroke at the middle point. I tried the following.
if(result > 0.01) {
frag_color = vec4(1.0,0.1,0.5, 1.0);
} else if(result < -0.01) {
frag_color = vec4(2.0,0.2,1.0, 1.0);
} else {
frag_color = vec4(2.0, 0.2, 3.0, 0.0); // mid point
}
I got this
But when i try to resize the triangle i get this result
The stroke width is thicker, but I want to keep the width in the previous image.
I have no idea how to achieve this, is it even possible ?
I'm trying to implement tonemap correction in my own graphic engine and I'm using, as reference, the excellent demo from asylum2010 (https://github.com/asylum2010/Asylum_Tutorials)
Now look: this is an adaptation of the shader taken from the aforesaid demo:
#version 150
uniform sampler2D sampler0;
uniform vec2 texelSize;
uniform int prevLevel;
in vec2 tex;
out vec4 my_FragColor0;
void main()
{
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721);
vec4 sample = texture(sampler0, tex + vec2(-0.5, -0.5) * texelSize);
float dt = dot(sample.rgb, LUMINANCE_VECTOR);
if (sample.r > 0.99 && sample.g > 0.99 && sample.b > 0.99)
{
if (dt > 0.9998)
{
if (log(0.0001 + dt) < 1.0) // <== NOTICE THIS!
my_FragColor0 = vec4(0.1, 0.0, 0.0, 1.0);
else
my_FragColor0 = vec4(1.0, 0.0, 0.0, 1.0);
}
else
my_FragColor0 = vec4(0.0, 0.0, 0.0, 1.0);
}
else
my_FragColor0 = vec4(0.0, 0.0, 0.0, 1.0);
}
and this is the shader I wrote:
#version 150
uniform sampler2D ColorMap;
uniform vec2 TexelSize;
uniform int PreviousLevel;
in vec2 fragmentUV;
out vec4 fragment;
void main()
{
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721);
vec4 sample = texture(ColorMap, fragmentUV + vec2(-0.5, -0.5) * TexelSize);
float dt = dot(sample.rgb, LUMINANCE_VECTOR);
if (sample.r > 0.99 && sample.g > 0.99 && sample.b > 0.99)
{
if (dt > 0.9998)
{
if (log(0.0001 + dt) < 1.0) // <== NOTICE THIS!
fragment = vec4(0.1, 0.0, 0.0, 1.0);
else
fragment = vec4(1.0, 0.0, 0.0, 1.0);
}
else
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
else
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
You may notice that, except for the variable names, the code is exactly the same.
Now when I run the first shader on its own engine, it outputs a full red color for almost white pixels of the passed sampler is almost white (r, g and b > 0.99), meaning the result of the log calculation is greater than 1.0
When I run my own shader (of course passing the same sample and with the same texel size), it outputs a dark red, meaning the log result is lower than 1.0.
It looks to me that the result of the second shader is correct but this is not the point. The point is: how coult the result be different?
Ok for the ones interested I finally found the issue.
The error is actually the dot product. I was passing as ColorMap a texture with internal format GL_RGBA while it is supposed to be a floating point texture in order to store values higher than 1.
Also I would like to know the reason of the downvote I received. Knowing the reason will help me to avoid any mistake I possibly made posting the question.
This is the current shader I am using. It fades the object by slowly reducing the opacity. I want to fade to purple. How can this be done?
shader.frag:
uniform sampler2D texture;
uniform float opacity;
void main()
{
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
gl_FragColor = pixel * vec4(1.0, 1.0, 1.0, opacity);
}
shader.vert:
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
}
application of shader in main function:
sf::Shader shader;
if (!shader.loadFromFile("shader.vert", "shader.frag"))
return EXIT_FAILURE;
float opacity = 1.0; //transparency of shader
shader.setParameter("texture", sf::Shader::CurrentTexture); //shader.vert
shader.setParameter("opacity", opacity); //shader.frag
////////////////////////////
//Delete Text Display
counter1 = 0;
for (iter8 = textDisplayArray.begin(); iter8 != textDisplayArray.end(); iter8++)
{
if (textDisplayArray[counter1].destroy == true)
{
//shader
opacity -= 0.1;
if (opacity <= 0)
{
textDisplayArray.erase(iter8);
opacity = 1;
}
shader.setParameter("opacity", opacity);
}
The RGB value for purple is vec3( 1.0, 0.0, 1.0 ) (maximum red, minimal green and maximum blue). You have to interpolate between your frgment color and the color value of purpel, similar as you do it with opacity. Use mix for this. mix(x, y, a) performs a linear interpolation between x and y using a to weight between them. The return value is computed as x×(1−a)+y×ax×(1−a)+y×a.
uniform sampler2D texture;
uniform float opacity;
uniform float purpleFac;
void main()
{
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
vec3 mixedCol = mix( vec3( 1.0, 0.0, 1.0 ), pixel.rgb, purpleFac );
gl_FragColor = vec4( mixedCol , opacity );
}
Note you have to set uniform purpleFac similar as you do it with opacity. purpleFac shoud be in range [0.0, 1.0]. If purpleFac is 1.0 your fragment is colord purple and if it is 0.0 your fragment colol is the color of the texture only.
I'm trying to use geometry shaders to turn points into line segments (GL_POINTS to GL_LINE_STRIP), but no line segments appear. If I change the input to GL_LINES, and just repeat the vertex, then I get the behavior I'm expecting. What's going on?
Here's a complete program that demonstrates the behavior. As-is, I get nothing but a black window. Setting USE_POINTS to False gets me the rotating psychedelic flashing lines I'm expecting.
#!/usr/bin/python
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL.GL.ARB.geometry_shader4 import *
from OpenGL.GL.EXT.geometry_shader4 import *
import Image
import numpy
import numpy.linalg as linalg
import random
from math import sin, cos
shader = None
USE_POINTS = True
def update(*args):
glutTimerFunc(33, update, 0)
glutPostRedisplay()
def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
t = glutGet(GLUT_ELAPSED_TIME)
rot = t % (10 * 1000)
theta = 2 * 3.141592 * (rot / 10000.0)
glLoadIdentity()
gluLookAt(-10*sin(theta), -10*cos(theta), 0,
0, 0, 0,
0, 0, 1)
glUseProgram(shader)
glUniform1f(glGetUniformLocation(shader, "distance"), rot/10000.0)
# difference #1
glBegin(GL_POINTS if USE_POINTS else GL_LINES)
for x in [-2.5, 0, 2.5]:
for y in [-2.5, 0, 2.5]:
glVertexAttrib1f(7, random.uniform(0.0, 1.0))
glVertexAttrib3f(0, x, y, 0)
# difference #2
if not USE_POINTS:
glVertexAttrib1f(7, random.uniform(0.0, 1.0))
glVertexAttrib3f(0, x, y, 0)
glEnd()
glUseProgram(0)
glutSwapBuffers()
def key(*args):
if args[0] == '\x1b':
sys.exit(0);
def reshape(width, height):
aspect = float(width)/float(height) if (height>0) else 1.0
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0,
aspect,
1.0, 100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glutPostRedisplay()
glutInit([])
glutInitDisplayString("rgba>=8 depth>16 double")
glutInitWindowSize(1280, 720)
glutCreateWindow("Geometry Shader")
glutDisplayFunc(display)
glutReshapeFunc(reshape)
glutKeyboardFunc(key)
glutTimerFunc(33, update, 0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
shader = glCreateProgram()
vertex_shader = glCreateShader(GL_VERTEX_SHADER)
geometry_shader = glCreateShader(GL_GEOMETRY_SHADER)
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
# difference #3
glProgramParameteriEXT(shader, GL_GEOMETRY_INPUT_TYPE_ARB, GL_POINTS if USE_POINTS else GL_LINES)
glProgramParameteriEXT(shader, GL_GEOMETRY_OUTPUT_TYPE_ARB, GL_LINE_STRIP)
glProgramParameteriEXT(shader, GL_GEOMETRY_VERTICES_OUT_ARB, 200)
glAttachShader(shader, vertex_shader)
glAttachShader(shader, geometry_shader)
glAttachShader(shader, fragment_shader)
glShaderSource(vertex_shader, """
attribute float color;
varying float geom_color;
void main(void) {
gl_Position = gl_Vertex;
geom_color = color;
}
""")
glCompileShader(vertex_shader)
print glGetShaderInfoLog(vertex_shader)
glShaderSource(geometry_shader, """
#version 120
#extension GL_EXT_geometry_shader4 : enable
varying in float geom_color[1];
varying out float frag_color;
uniform float distance;
void main(void)
{
int x, y;
for(x=-1; x<=1; x+=1) {
for(y=-1; y<=1; y+=1) {
gl_Position = gl_PositionIn[0];
gl_Position.x += x * distance;
gl_Position.y += y * distance;
gl_Position.z -= 2.0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Position;
frag_color = geom_color[0];
EmitVertex();
gl_Position = gl_PositionIn[0];
gl_Position.x += x * distance;
gl_Position.y += y * distance;
gl_Position.z += 2.0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Position;
frag_color = geom_color[0];
EmitVertex();
EndPrimitive();
}
}
}
""")
glCompileShader(geometry_shader)
print glGetShaderInfoLog(geometry_shader)
glShaderSource(fragment_shader, """
varying float frag_color;
void main(void) {
gl_FragColor = vec4(frag_color,1.0-frag_color,frag_color,1);
}
""")
glCompileShader(fragment_shader)
print glGetShaderInfoLog(fragment_shader)
glLinkProgram(shader)
print glGetProgramInfoLog(shader)
glBindAttribLocation(shader, 7, "color")
glLinkProgram(shader)
print glGetProgramInfoLog(shader)
glutMainLoop()
I cross-checked the code with the GL_EXT_geometry_shader4 specification, and I don't see any obvious errors at least. According to the specification, all input primitives work with all types of output primitives. If OpenGL returns no errors via glGetError, and no shader linker/compilation errors, I'd say this is an ATI or pyOpenGL-related issue.
I'm fairly sure I've tested most combinations of input and output primitives for geometry shaders, and they all work on my Nvidia card. I use the native C OpenGL libraries though, not a binding.
I got the same problem just now with HD4850. It seems weird but the problem really has a cause and can be resolved. It looks like this is not the same situation as the original post. Just FYI when someone else happens to reach this post blocked by similar situations.
Here goes the cause. When GL_GEOMETRY_INPUT_TYPE_ARB is set to GL_POINTS, in the geometry shader code, there is code accessing the input array beyond 0.
Vertex Shader
in ivec4 vertex;
flat out ivec4 v;
Geometry Shader
flat in ivec4 v[gl_VerticesIn];
// somewhere in the code
v[1].x ...
Everything goes fine with compile/link, but glGetAttribLocationARB fails for the "vertex" attribute.