Problem when trying to use simple Shaders + VBOs - graphics

Hello I'm trying to convert the following functions to a VBO based function for learning purposes, it displays a static texture on screen. I'm using OpenGL ES 2.0 with shaders on the iPhone (should be almost the same than regular OpenGL in this case), this is what I got working:
//Works!
- (void) drawAtPoint:(CGPoint)point depth:(CGFloat)depth
{
GLfloat coordinates[] = {
0, 1,
1, 1,
0, 0,
1, 0
};
GLfloat width = (GLfloat)_width * _maxS,
height = (GLfloat)_height * _maxT;
GLfloat vertices[] = {
-width / 2 + point.x, -height / 2 + point.y,
width / 2 + point.x, -height / 2 + point.y,
-width / 2 + point.x, height / 2 + point.y,
width / 2 + point.x, height / 2 + point.y,
};
glBindTexture(GL_TEXTURE_2D, _name);
//Attrib position and attrib_tex coord are handles for the shader attributes
glVertexAttribPointer(ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(ATTRIB_POSITION);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
I tried to do this to convert to a VBO however I don't see anything displaying on-screen with this version:
//Doesn't display anything
- (void) drawAtPoint:(CGPoint)point depth:(CGFloat)depth
{
GLfloat width = (GLfloat)_width * _maxS,
height = (GLfloat)_height * _maxT;
GLfloat position[] = {
-width / 2 + point.x, -height / 2 + point.y,
width / 2 + point.x, -height / 2 + point.y,
-width / 2 + point.x, height / 2 + point.y,
width / 2 + point.x, height / 2 + point.y,
}; //Texture on-screen position ( each vertex is x,y in on-screen coords )
GLfloat coordinates[] = {
0, 1,
1, 1,
0, 0,
1, 0
}; // Texture coords from 0 to 1
glBindVertexArrayOES(vao);
glGenVertexArraysOES(1, &vao);
glGenBuffers(2, vbo);
//Buffer 1
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), position, GL_STATIC_DRAW);
glEnableVertexAttribArray(ATTRIB_POSITION);
glVertexAttribPointer(ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, position);
//Buffer 2
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), coordinates, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
//Draw
glBindVertexArrayOES(vao);
glBindTexture(GL_TEXTURE_2D, _name);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
In both cases I'm using this simple Vertex Shader
//Vertex Shader
attribute vec2 position;//Bound to ATTRIB_POSITION
attribute vec4 color;
attribute vec2 texcoord;//Bound to ATTRIB_TEXCOORD
varying vec2 texcoordVarying;
uniform mat4 mvp;
void main()
{
//You CAN'T use transpose before in glUniformMatrix4fv so... here it goes.
gl_Position = mvp * vec4(position.x, position.y, 0.0, 1.0);
texcoordVarying = texcoord;
}
The gl_Position is equal to product of mvp * vec4 because I'm simulating glOrthof in 2D with that mvp
And this Fragment Shader
//Fragment Shader
uniform sampler2D sampler;
varying mediump vec2 texcoordVarying;
void main()
{
gl_FragColor = texture2D(sampler, texcoordVarying);
}
I really need help with this, maybe my shaders are wrong for the second case ?
thanks in advance.

Everything is right, except the glVertexAttribPointer call.
When you have a VBO bound, the last parameter o glVertexAttribPointer is used as an offset into the VBO, as a pointer (the pointer value is the offset). So, your data is at the start of the VBO, so the last parameter should be 0 (NULL) for both calls.

Related

Processing: how to make box() appear solid (non-transparent) in 3d mode

I'm trying to create layers of 3d boxes in Processing. I want them to appear solid, so that you can't see the boxes "behind" other boxes, but the way they're displaying makes them seem transparent; you can see the stroke of boxes behind other boxes. How do I make them appear solid?
// number of boxes
int numBox = 300;
// width of each box
int boxWidth = 30;
// number of boxes per row
float numPerRow;
void setup() {
size(800, 800, P3D);
pixelDensity(1);
colorMode(HSB, 360, 100, 100, 100);
background(40, 6, 85);
stroke(216, 0, 55);
smooth(4);
fill(0, 0, 90, 100);
numPerRow = width / boxWidth;
}
void draw() {
background(40, 6, 85);
translate((boxWidth / 2), 100);
rotateX(-PI/6);
rotateY(PI/8);
for (int i = 0; i < numBox; i++) {
drawBox(i);
if (i == numBox - 1) {
noLoop();
}
}
}
void drawBox(int i) {
if ((i % 2) == 0) {
pushMatrix();
translate(((boxWidth / 2) * i) % width, 20 * floor(i / (2 * numPerRow)));
translate(0, -((i % 30) / 2));
box(boxWidth, i % 30, boxWidth);
popMatrix();
};
}
Close-up of how the boxes are being displayed:
The issue is that the boxes are intersecting and the strokes of these intersecting boxes are what give the appearance of "see through".
I'm noticing you are using x and y translation, but not z.
If you don't plan to increase x, y spacing to avoid intersections, you can easily offset rows on the z axis so rows of boxes appear in front of each other.
Here's a slightly modified version of your code illustrating this idea:
// number of boxes
int numBox = 300;
// width of each box
int boxWidth = 30;
// number of boxes per row
float numPerRow;
void setup() {
size(800, 800, P3D);
pixelDensity(1);
colorMode(HSB, 360, 100, 100, 100);
background(40, 6, 85);
stroke(216, 0, 55);
smooth(4);
fill(0, 0, 90, 100);
numPerRow = width / boxWidth;
}
void draw() {
background(40, 6, 85);
translate((boxWidth / 2), 100);
if(mousePressed){
rotateX(map(mouseY, 0, height, -PI, PI));
rotateY(map(mouseX, 0, width, PI, -PI));
}else{
rotateX(-PI/6);
rotateY(PI/8);
}
for (int i = 0; i < numBox; i++) {
drawBox(i);
//if (i == numBox - 1) {
// noLoop();
//}
}
}
void drawBox(int i) {
if ((i % 2) == 0) {
pushMatrix();
float x = ((boxWidth / 2) * i) % width;
float y = 20 * floor(i / (2 * numPerRow));
float z = y * 1.5;
translate(x, y, z);
translate(0, -((i % 30) / 2));
box(boxWidth, i % 30, boxWidth);
popMatrix();
};
}
(Click and drag to rotate and observe the z offset.
Feel free to make z as interestersting as you need it it.
Nice composition and colours!
(framing (window size) could use some iteration/tweaking, but I'm guessing this is WIP))

How to draw sample code from the Cairo documentation?

I'm a complete beginner and would really like to draw some of the shapes from https://www.cairographics.org/samples/ and tinker a bit with the placement of these shapes. But first I need to set everything up - just copy-pasting the code doesn't work.
/* a custom shape that could be wrapped in a function */
double x = 25.6, /* parameters like cairo_rectangle */
y = 25.6,
width = 204.8,
height = 204.8,
aspect = 1.0, /* aspect ratio */
corner_radius = height / 10.0; /* and corner curvature radius */
double radius = corner_radius / aspect;
double degrees = M_PI / 180.0;
cairo_new_sub_path (cr);
cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
cairo_close_path (cr);
cairo_set_source_rgb (cr, 0.5, 0.5, 1);
cairo_fill_preserve (cr);
cairo_set_source_rgba (cr, 0.5, 0, 0, 0.5);
cairo_set_line_width (cr, 10.0);
cairo_stroke (cr);
This code should generate the following shape:
a rounded rectangle
But clearly more is needed. So I decided to run the following code, which creates a window:
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <stdio.h>
#include <stdlib.h>
/*! Simple Cairo/Xlib example.
* #author Bernhard R. Fischer, 2048R/5C5FFD47 <bf#abenteuerland.at>.
* #version 2014110801
* Compile with
* gcc -Wall $(pkg-config --libs --cflags cairo x11) -o cairo_xlib_simple cairo_xlib_simple.c
*/
/*! Check for Xlib Mouse/Keypress events. All other events are discarded.
* #param sfc Pointer to Xlib surface.
* #param block If block is set to 0, this function always returns immediately
* and does not block. if set to a non-zero value, the function will block
* until the next event is received.
* #return The function returns 0 if no event occured (and block is set). A
* positive value indicates that a key was pressed and the X11 key symbol as
* defined in <X11/keysymdef.h> is returned. A negative value indicates a mouse
* button event. -1 is button 1 (left button), -2 is the middle button, and -3
* the right button.
*/
int cairo_check_event(cairo_surface_t *sfc, int block)
{
char keybuf[8];
KeySym key;
XEvent e;
for (;;)
{
if (block || XPending(cairo_xlib_surface_get_display(sfc)))
XNextEvent(cairo_xlib_surface_get_display(sfc), &e);
else
return 0;
switch (e.type)
{
case ButtonPress:
return -e.xbutton.button;
case KeyPress:
XLookupString(&e.xkey, keybuf, sizeof(keybuf), &key, NULL);
return key;
default:
fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n", e.type);
}
}
}
/*! Open an X11 window and create a cairo surface base on that window.
* #param x Width of window.
* #param y Height of window.
* #return Returns a pointer to a valid Xlib cairo surface. The function does
* not return on error (exit(3)).
*/
cairo_surface_t *cairo_create_x11_surface0(int x, int y)
{
Display *dsp;
Drawable da;
int screen;
cairo_surface_t *sfc;
if ((dsp = XOpenDisplay(NULL)) == NULL)
exit(1);
screen = DefaultScreen(dsp);
da = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), 0, 0, x, y, 0, 0, 0);
XSelectInput(dsp, da, ButtonPressMask | KeyPressMask);
XMapWindow(dsp, da);
sfc = cairo_xlib_surface_create(dsp, da, DefaultVisual(dsp, screen), x, y);
cairo_xlib_surface_set_size(sfc, x, y);
return sfc;
}
/*! Destroy cairo Xlib surface and close X connection.
*/
void cairo_close_x11_surface(cairo_surface_t *sfc)
{
Display *dsp = cairo_xlib_surface_get_display(sfc);
cairo_surface_destroy(sfc);
XCloseDisplay(dsp);
}
int main(int argc, char **argv)
{
cairo_surface_t *sfc;
cairo_t *ctx;
sfc = cairo_create_x11_surface0(500, 500);
ctx = cairo_create(sfc);
cairo_set_source_rgb(ctx, 1, 1, 1);
cairo_paint(ctx);
cairo_move_to(ctx, 20, 20);
cairo_line_to(ctx, 200, 400);
cairo_line_to(ctx, 450, 100);
cairo_line_to(ctx, 20, 20);
cairo_set_source_rgb(ctx, 0, 0, 1);
cairo_fill_preserve(ctx);
cairo_set_line_width(ctx, 5);
cairo_set_source_rgb(ctx, 1, 1, 0);
cairo_stroke(ctx);
cairo_destroy(ctx);
cairo_check_event(sfc, 1);
cairo_close_x11_surface(sfc);
return 0;
}
The output can be accessed here: black window launches successfully
How do I now draw the shape and some text?
Kind regards,
'm a complete beginner and would really like to draw some of the shapes from https://www.cairographics.org/samples/ and tinker a bit with the placement of these shapes.
The simplest approach would not be to open an image, but instead to draw a PNG. Here is an example for the first example from that page.
#include <cairo.h>
#include <math.h> // For M_PI
int main() {
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 300, 300);
cairo_t *cr = cairo_create (surface);
// Start of example
double xc = 128.0;
double yc = 128.0;
double radius = 100.0;
double angle1 = 45.0 * (M_PI/180.0); /* angles are specified */
double angle2 = 180.0 * (M_PI/180.0); /* in radians */
cairo_set_line_width (cr, 10.0);
cairo_arc (cr, xc, yc, radius, angle1, angle2);
cairo_stroke (cr);
/* draw helping lines */
cairo_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
cairo_set_line_width (cr, 6.0);
cairo_arc (cr, xc, yc, 10.0, 0, 2*M_PI);
cairo_fill (cr);
cairo_arc (cr, xc, yc, radius, angle1, angle1);
cairo_line_to (cr, xc, yc);
cairo_arc (cr, xc, yc, radius, angle2, angle2);
cairo_line_to (cr, xc, yc);
cairo_stroke (cr);
// End of example
cairo_surface_write_to_png (surface, "example.png");
cairo_destroy (cr);
cairo_surface_destroy (surface);
return 0;
}

PyOpenGL texture rendering black

I have been following an online tutorial on OpenGL lately to test integration of PyOpenGL into a PyQt5 application with QOpenGLWidget. I was able to follow every episode with no issues until the textures episode; I cannot get the texture to render at all.
My code is as follows (wrappers removed to make the code simpler, but I have tested it to make sure it is the same):
def FirstFrame():
positions = [
-0.5, -0.5, 0.0, 0.0,
+0.5, -0.5, 1.0, 0.0,
+0.5, +0.5, 1.0, 1.0,
-0.5, +0.5, 0.0, 1.0
]
indices = [
0, 1, 2,
2, 3, 0,
]
global g_vao
vao = g_vao = glGenVertexArrays(1)
glBindVertexArray(vao)
global g_posBuffer
posBuffer = g_posBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, posBuffer)
glBufferData(GL_ARRAY_BUFFER, (GLfloat * len(positions))(*positions), GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), c_void_p(0))
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), c_void_p(8))
global g_idxBuffer
idxBuffer = g_idxBuffer = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxBuffer)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLuint * len(indices))(*indices), GL_STATIC_DRAW)
vertexShader = """
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texCoord;
out vec2 v_TexCoord;
void main()
{
gl_Position = position;
v_TexCoord = texCoord;
}
"""
fragmentShader = """
#version 330 core
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 colorTemp;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
void main()
{
vec4 texColor = texture(u_Texture, v_TexCoord);
color = texColor;
}
"""
global g_shader
shader = g_shader = compileProgram(compileShader(vertexShader, GL_VERTEX_SHADER),
compileShader(fragmentShader, GL_FRAGMENT_SHADER))
glUseProgram(shader)
global g_data
g_data, width, height = ParseRGBA8DDS("ChernoLogo.dds") # Parses input DDS file and returns bytearray of flipped texture
localBuffer = (GLubyte * len(g_data)).from_buffer(g_data) # Making a copy instead of using from_buffer does not work either
global g_tex
tex = g_tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, localBuffer) # Passing g_data directly does not work either
glBindTexture(GL_TEXTURE_2D, 0)
glActiveTexture(GL_TEXTURE0 + 0)
glBindTexture(GL_TEXTURE_2D, tex)
global g_tex_loc
tex_loc = g_tex_loc = glGetUniformLocation(shader, "u_Texture")
assert tex_loc != -1
glUniform1i(tex_loc, 0)
def MainLoopIteration():
glClear(GL_COLOR_BUFFER_BIT)
global g_shader, g_r, g_vao, g_idxBuffer
glUseProgram(g_shader)
glBindVertexArray(g_vao)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_idxBuffer)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, c_void_p(0))
I have tried color = vec4(v_TexCoord, 0.0, 1.0) and color = vec4(u_Texture, 0.0, 0.0, 1.0) (and binding to slot 1) in the fragment shader to make sure these variables are set correctly and indeed they are.
In fact, I have checked texColor and it looks to be (0.0, 0.0, 0.0, 1.0) for all pixels.
I have also verified the output of ParseRGBA8DDS() by hand and it looks to be correct.
I found the issue. This is something the tutorial does not mention, but I needed to rebind and reactivate the texture on each frame. Althought I'm not sure why it still works for the person giving the tutorial.

Clamp segment inside rectangle

I have a rectangle, and there lines that outgoing from center of it into arbitrary position outside of rectangle. I need to clamp them to rectangle edges, so endpoint will lie on rectangle. I tried using intersection algorithms and it works, but it pretty slow because it handles any kind of collisions, while I have specific conditions: start of segment is always in center of rectangle, and end of line is always outside of rectangle, maybe there some fast algorithm for this?
I assume that rectangle dimensions are width, height and rectangle center is at (0,0)
(otherwise subtract center coordinates from endx, endy variables and add them to final results)
if abs(endx) * height <= abs(endy) * width //top or bottom side
return height/2 * endx / abs(endy), sign(endy) * height/2
else //left or right side
return sign(endx) * width/2, width/2 * endy / abs(endx)
Python quick check:
from math import copysign
def rectclamp(rectcenterx, rectcentery, width, height, lineendx, lineendy):
endx = lineendx - rectcenterx
endy = lineendy - rectcentery
if abs(endx) * height <= abs(endy) * width: #at top or bottom
return (rectcenterx + height / 2 * endx / abs(endy),
rectcentery + copysign(1, endy) * height / 2)
else:
return (rectcenterx + copysign(1, endx) * width/2,
rectcentery+ width/2 * endy / abs(endx))
print(rectclamp(6, 4, 12, 8, 9, 9))
print(rectclamp(6, 4, 12, 8, 27, 10))
print(rectclamp(6, 4, 12, 8, -12, -8))
>>>
(8.4, 8.0) #top edge
(12.0, 5.714285714285714) # right edge
(0.0, 0.0) #corner

How to draw this circle instead of Bresenham's Circle Algorithm

int main()
{
const auto console = ::GetConsoleWindow();
const auto context = ::GetDC(console);
constexpr auto red = RGB(255, 0, 0);
constexpr auto yellow = RGB(255, 255, 0);
RECT rectClient, rectWindow;
GetClientRect(console, &rectClient);
GetWindowRect(console, &rectWindow);
int posx, posy;
posx = GetSystemMetrics(SM_CXSCREEN) / 2 - (rectWindow.right - rectWindow.left) / 2;
posy = GetSystemMetrics(SM_CYSCREEN) / 2 - (rectWindow.bottom - rectWindow.top) / 2;
const int radius = 150;
for (int y = -radius; y <= radius; y++)
for (int x = -radius; x <= radius; x++)
if (x * x + y * y <= radius * radius)
SetPixel(context, posx + x, posy + y, red);
}
It gives me this result img
it looks good but i saw this weird pixels at sides (up, down, right, left)
img
and this is what I want (I added some pixels at the top so it looks better)
enter image description here
Your "what I want" looks anti-aliased. So draw anti-aliased.
If the original condition is not met, but x*x + y*y <= (radius+1)*(radius+1) is met then you need a partially-shaded pixel.
Another way to do anti-aliasing is to test not the center of each pixel but the four corners (x \plusminus 0.5, y \plusminus 0.5). If more than zero but fewer than four corners are inside the circle, you need a partially-shaded pixel.

Resources