Related
I've been trying to add this post-processing (taken from sebastian lague video which I am trying to convert from unity to threejs) effect that when a ray hits the ocean on my mesh (the blue):
it is colored white (just like in his video):
and everywhere else the original color is returned. But for the life of me can't seem to figure out the problem, I assume my ray origin or direction might be wrong but nothing seems to work, Here's the code that I pass to the ray Sphere intersection function and the function itself.
vec2 raySphere(vec3 centre, float radius, vec3 rayOrigin, vec3 rayDir) {
vec3 offset = rayOrigin - centre;
float a = 1.0; // set to dot(rayDir, rayDir) instead of rayDir may not be normalized
float b = 2.0 * dot(offset, rayDir);
float c = dot(offset, offset) - radius * radius;
float discriminant = b*b-4.0*a*c;
// No intersection: discriminant < 0
// 1 intersection: discriminant == 0
// 2 intersection: discriminant > 0
if(discriminant > 0.0) {
float s = sqrt(discriminant);
float dstToSphereNear = max(0.0, (-b - s) / (2.0 * a));
float dstToSphereFar = (-b + s) / (2.0 * a);
if (dstToSphereFar >= 0.0) {
return vec2(dstToSphereNear, dstToSphereFar-dstToSphereNear);
}
}
return vec2(99999999, 0.0);
}
vec4 ro = inverse(modelMatrix) * vec4(cameraPosition, 1.0);
vec3 rd = normalize(position - ro.xyz);
vec3 oceanCentre = vec3(0.0, 0.0, 0.0);
float oceanRadius = 32.0;
vec2 hitInfo = raySphere(oceanCentre, oceanRadius, ro.xyz, rd);
float dstToOcean = hitInfo.x;
float dstThroughOcean = hitInfo.y;
vec3 rayOceanIntersectPos = ro.xyz + rd * dstToOcean - oceanCentre;
// dst that view ray travels through ocean (before hitting terrain / exiting ocean)
float oceanViewDepth = min(dstThroughOcean, depth - dstToOcean);
vec4 oceanCol;
float alpha;
if(oceanViewDepth > 0.0) {
gl_FragColor = vec4(vec3(1.0), .1);
}
gl_FragColor = texture2D(tDiffuse, vUv);
Can someone help point out where I might be messing up?
Oh wow, we're in the same place while we're stuck at making these shaders. I checked your ray intersectors have small problems. But here is the cases:
What we want if case 3 happens like on your example, so the intersection are in count the problem probably come from no depth correction by doing this:
Make sure your sphere intersection max depth same as the camera.
I do suspect if the last line is the problem, try do this:
vec3 col; // Declare the color
vec2 o = sphere(ro, rd, vec3(0), 1.0); // Ocean Depth.
float oceanViewDepth = min(o.y - o.x, t - o.x);
if(depth > 0.0 && tmax > depth) {
col = originalCol;
}
if(oceanViewDepth > 0.0) {
col = vec3(1);
}
gl_FragColor = vec4(col, 1.0);
If that doesn't work for you I have some finished example for you to checkout at shadertoy
I tried to render a triangle with a tessellation shader. Now, without the tessellation shaders, the triangle renders fine. As soon as I add the tessellation shaders, I get a blank screen. I have also written glPatchParameteri(GL_PATCH_VERTICES,3) before glDrawArrays(GL_PATCHES,0,3).
Here are the shaders:
VERTEX SHADER:
#version 440 core
layout (location = 0) in vec2 apos;
out vec2 pos;
void main()
{
//gl_Position = vec4(apos,1.0f,1.0f); without tessellation shaders
pos = apos;
}
TESSELLATION CONTROL SHADER
#version 440 core
layout (vertices = 3) out;
in vec2 pos[];
out vec2 EsPos[];
void main()
{
EsPos[gl_InvocationID] = pos[gl_InvocationID];
gl_TessLevelOuter[0] = 3.0f;
gl_TessLevelOuter[1] = 3.0f;
gl_TessLevelOuter[2] = 3.0f;
gl_TessLevelInner[0] = 3.0f;
}
TESSELLATION EVALUATE SHADER
#version 440 core
layout (triangles, equal_spacing, ccw) in;
in vec2 EsPos[];
vec2 finalpos;
vec2 interpolate2D(vec2 v0, vec2 v1);
void main()
{
finalpos = interpolate2D(EsPos[0],EsPos[1]);
gl_Position = vec4(finalpos,0.0f,1.0f);
}
vec2 interpolate2D(vec2 v0, vec2 v1)
{
return (vec2(gl_TessCoord.x)*v0 + vec2(gl_TessCoord.y)*v1);
}
FRAGMENT SHADER
#version 440 core
out vec4 Fragment;
void main()
{
Fragment = vec4(0.0f,1.0f,1.0f,1.0f);
}
EDIT:
I made changes in the interpolate2D function, but still I am getting a blank screen.
The output patch size of the Tessellation Evaluation shader is 3:
layout (vertices = 3) out;
Thus the length of the input array to the Tessellation Control Shader is 3, too. Furthermore, the abstract patch type is triangles,
layout (triangles, equal_spacing, ccw) in;
thus the tessellation coordinate (gl_TessCoord) is a Barycentric coordinate. Change the interpolation:
vec2 interpolate2D(vec2 v0, vec2 v1, vec2 v2)
{
return v0*gl_TessCoord.x + v1*gl_TessCoord.y + v2*gl_TessCoord.z;
}
void main()
{
finalpos = interpolate2D(EsPos[0], EsPos[1], EsPos[2]);
// [...]
}
I am trying to rotate a text in OpenGL, but however, the problem is that the text rotates like it should but in the wrong point i.e, it does not rotate at the center of the text(and by that I want to know how I could do that!).
The reason I am confused because I am using multiple texture for different letters of the text which makes me confused.
If you are wondering which library I'm using, it is CGLM
But when I compile this code the rotate function rotates the object with the wrong point of rotation.
According to Rabbid76. I did the following to get the size of the whole text:-
for (int i = 0; i < (signed)strlen(text); i++)
{
tw += iterator[(int)text[i]].Character_Array.Size[0];
th += iterator[(int)text[i]].Character_Array.Size[1];
}
Still I am not getting the proper result, the text is still misplaced.
Before any rotation(this is where IT SHOULD rotate):-
After 45 degrees rotation(it gets misplaced from its position):-
Edit: The whole code of the source file:-
// Std. Includes
#include <stdio.h>
#include <stdlib.h>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// GLM
#include <cglm/cglm.h>
// FreeType
#include <ft2build.h>
#include FT_FREETYPE_H
// Properties
const GLuint WIDTH = 800, HEIGHT = 600;
const GLchar * vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"uniform mat4 projection;\n"
"uniform mat4 model;\n"
"void main()\n"
"{\n"
"gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);\n"
"TexCoords = vertex.zw;\n"
"}\n\0";
const GLchar * fragmentShaderSource =
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec4 textColor;\n"
"void main()\n"
"{\n"
"vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
"color = textColor * sampled;\n"
"}\n\0";
/// Holds all state information relevant to a character as loaded using FreeType
typedef struct {
GLuint TextureID; // ID handle of the glyph texture
int Size[2]; // Size of glyph
int Bearing[2]; // Offset from baseline to left/top of glyph
GLuint Advance; // Horizontal offset to advance to next glyph
} Character;
typedef struct
{
GLchar char_Array;
Character Character_Array;
} Iterator;
Iterator * iterator;
GLuint VAO, VBO;
// RenderText function.. to render our text...
void RenderText(GLuint program, const char * text, GLfloat originx, GLfloat originy, GLfloat x, GLfloat y, GLfloat scalex, GLfloat scaley, float rotation, float r, float g, float b, float a);
// The MAIN function, from here we start our application and run the Game loop
int main()
{
iterator = NULL;
// Init GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", NULL, NULL); // Windowed
glfwMakeContextCurrent(window);
// Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE;
glewInit();
// Define the viewport dimensions
glViewport(0, 0, WIDTH, HEIGHT);
// Set OpenGL options
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Compile and setup the shader
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertexShaderSource, NULL);
glCompileShader(vertex_shader);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
mat4 projection;
glm_ortho(0.0f, (GLfloat)WIDTH, (GLfloat)HEIGHT, 0.0f, -1, 1, projection);
glUseProgram(program);
glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (GLfloat *)projection);
// FreeType
FT_Library ft;
// All functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&ft))
printf("ERROR::FREETYPE: Could not init FreeType Library\n");
// Load font as face
FT_Face face;
if (FT_New_Face(ft, "playfair.ttf", 0, &face))
printf("ERROR::FREETYPE: Failed to load font\n");
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, 72);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int i = 0;
// Load first 128 characters of ASCII set
for (GLubyte c = 0; c < 255; c++)
{
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
printf("ERROR::FREETYTPE: Failed to load Glyph\n");
continue;
}
// Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Now store character for later use
Character character = {
texture,
{(signed)face->glyph->bitmap.width, (signed)face->glyph->bitmap.rows},
{face->glyph->bitmap_left, face->glyph->bitmap_top},
(GLuint)face->glyph->advance.x
};
iterator = (Iterator*)realloc(iterator, sizeof(Iterator) * (i + 1));
iterator[i].Character_Array = character;
iterator[i].char_Array = c;
i++;
}
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
// Configure VAO/VBO for texture quads
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glfwVulkanSupported();
// Game loop
float k = 0;
while (!glfwWindowShouldClose(window))
{
// Check and call events
glfwPollEvents();
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (k > 360)
{
k = 0;
}
k += 0.1f;
RenderText(program, "Rotation", 0, 0, 10.0f, 10.0f, 1.0f, 1.0f, k, 0.5f, 0.8f, 0.2f, 1.0f);
// Swap the buffers
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
void RenderText(GLuint program, const char * text, GLfloat originx, GLfloat originy, GLfloat x, GLfloat y, GLfloat scalex, GLfloat scaley, float rotation, float r, float g, float b, float a)
{
// Activate corresponding render state
glUseProgram(program);
glUniform4f(glGetUniformLocation(program, "textColor"), r, g, b, a);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
GLfloat tw = iterator[(int)text[i]].Character_Array.Bearing[0],
th = 0.0f;
for (int i = 0; i < (signed)strlen(text); i++)
{
Character ch = iterator[(int)text[i]].Character_Array;
tw += (ch.Advance >> 6);
th += ch.Size[1];
}
GLfloat rx = tw / 2.0f;
GLfloat ry = th / 2.0f;
mat4 model;
glm_mat4_identity(model);
glm_translate(model, (vec3) { originx, originy, 0.0f });
glm_translate(model, (vec3) { scalex * rx, scaley * ry, 0.0f });
glm_rotate(model, glm_rad(rotation), (vec3) { 0.0f, 0.0f, 1.0f });
glm_translate(model, (vec3) { -scalex * rx, -scaley * ry, 0.0f });
glm_scale(model, (vec3) { scalex, scaley, 1.0f });
GLfloat xpos = 0.0;
GLfloat ypos = 0.0;
for (int i = 0; i < (signed)strlen(text); i++)
{
Character ch = iterator[(int)text[i]].Character_Array;
mat4 ch_model;
memcpy(ch_model, model, 16 * sizeof(float));
glm_translate(ch_model, (vec3) { x, 0.0f, 0.0f });
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6); // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, (GLfloat *)ch_model);
// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
GLfloat w = ch.Size[0] * scalex;
GLfloat h = ch.Size[1] * scaley;
GLfloat vertices[6][4] = {
{ 0.0f, h, 0.0, 1.0 },
{ w, 0.0f, 1.0, 0.0 },
{ 0.0f, 0.0f, 0.0, 0.0 },
{ 0.0f, h, 0.0, 1.0 },
{ w, h, 1.0, 01.0 },
{ w, 0.0f, 01.0, 0.0 },
};
// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
glm_rotate applies rotation at origin. So if your geometry's center is not at the origin then rotation will not made around center of object/geometry.
Solution: X = T(p)Rz(φ)T(−p) where X is final transform, p is pivot
Translate pivot (or object center, not object's position, it is not same) to origin
Apply Rotation or scaling
Translate pivot back to it's original position
If you want to rotate around center of object (if object's center is not at the origin) then you must compute center of that object/geometry. Before apply any rotation. You could compute bounding box then get center of that box.
cglm also provides functions for that: glm_vec_center(min, max, pivot); /* pivot = center of object */. Now we have center point. Let's rotate around that point:
/* ... */
glm_vec_center(min, max, pivot); /* center of object */
glm_vec_inv_to(pivot, pivotInv); /* -pivot */
/* ... */
glm_translate(model, pivot);
glm_rotate(model, angle, axis);
glm_translate(model, pivotInv);
The code above do same thing as X = T(p)Rz(φ)T(−p) (translate(-pivot), rotate, translate(pivot)). The order seems reverse in code because glm_translate = Transform * Translate. It would not be reverse order if glm_translate = Translate * Transform. cglm may provide this alternative translation multiplication too in the future
EDIT: By starting v0.4.2 version cglm provides functions for this purpose: check glm_rotate_at() and glm_quat_rotate_at(), glm_rotate_atm and glm_quat_rotate_atm creates NEW rotations for pivot point since glm_rotate_at and glm_quat_rotate_at rotates existing transforms. To use these functions make sure you have latest version.
I'm new to OpenGL, and I'm trying to move an object using the mouse. I'm using OpenGL 4.4 Core Profile, MinGW32, freeGLUT, GLU, and GLEW, programming in C.
The program draw an hexagon with GL_LINE_LOOP and the color (0.5, 0.5, 0.5, 1.0).
The problem is when I move it using the mouse, the object is softly blinking, the color changes to a darker grey. The blinking also occurs when drawing with the color (1.0, 1.0, 1.0, 1.0), but it is less visible.
I tried to change the swap interval using wglSwapIntervalEXT(), but it accepts only values 0 and 1. I also tried to enable Triple Buffering and "wait for Vsync" parameter of my graphic card. Changing these three parameters doesn't solve the problem.
The code is very simple, the vertex shader takes an Uniform vector t that corresponds to the translation to apply to the object.
Vertex shader program:
#version 440 core
in vec3 vertex_position;
uniform vec3 vertex_color;
uniform vec4 t;
uniform mat4 matrix;
out vec4 color;
vec4 vp;
void main() {
color = vec4(vertex_color,1.0);
vp = matrix * vec4(vertex_position,1.0);
gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);
}
Fragment shader program:
#version 440 core
in vec4 color;
void main()
{
gl_FragColor = color;
}
The draw function is very simple, and I have a timer function that call glutPostRedisplay() every 16 ms, in order to have arround 60 FPS. I tried without the timer function, it increases the FPS, but the blinking even occurs.
The draw function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
The complete source code that shows the problem is here:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
// coordinates of the hexagon:
GLfloat hexagon[18];
GLuint vao;
GLuint vbo;
// translations:
GLfloat tx = 0.0;
GLfloat ty = 0.0;
GLfloat tz = 0.0;
GLfloat tw = 0.0;
// window dimensions:
GLint width;
GLint height;
int window;
// coordinates of clicked point
int clicked_x;
int clicked_y;
// set to 1 if clicked down:
int clicked_down = 0;
/////////////////////////////////////////////////////////
//
// Shader programs for core profile:
//
const char * vsprog_core =
"#version 440 core\n"
"in vec3 vertex_position;\n"
"uniform vec3 vertex_color;\n"
"uniform vec4 t;\n"
"uniform mat4 matrix;\n"
" \n"
"out vec4 color;\n"
" \n"
"vec4 vp;\n"
" \n"
"void main() {\n"
" color = vec4(vertex_color,1.0);\n"
" vp = matrix * vec4(vertex_position,1.0);\n"
" gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);\n"
"}\n";
const char * fsprog_core =
"#version 440 core\n"
"in vec4 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
// uniforms locations:
GLint tloc;
GLint colorloc;
GLint matrixloc;
GLuint shader_program_core;
GLfloat PMVmatrix[16] = {
0.500000, 0.000000, 0.000000, 0.000000,
0.000000, 0.500000, 0.000000, 0.000000,
0.000000, 0.000000, 0.500000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000
};
void Draw()
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
//glutPostRedisplay();
}
void onMouseClick(int button, int state, int x, int y) {
if(state == GLUT_UP && button == GLUT_LEFT_BUTTON) clicked_down = 0;
if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
clicked_down = 1;
clicked_x = x;
clicked_y = y;
}
}
void onMouseMove(int x, int y) {
int i,j;
if(clicked_down == 1) {
// compute x coordinate of the clicked point from the clicked x pixel:
GLfloat x1 = (clicked_x)*2.0/width - 1.0;
// compute x coordinate of the actual point from the actual x pixel:
GLfloat x2 = (x)*2.0/width - 1.0;
// compute y coordinate of the clicked point from the clicked y pixel:
GLfloat y1 = (clicked_y)*2.0/height - 1.0;
// compute y coordinate of the actual point from the actual y pixel:
GLfloat y2 = (y)*2.0/height - 1.0;
tx += x2 - x1;
ty += y1 - y2;
// save actual coordinates as previous ones, for the next move:
clicked_x = x;
clicked_y = y;
}
}
void timer( int value )
{
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
int main( int argc, char *argv[ ], char *envp[ ] )
{
int i,j;
glutInitContextVersion(4, 4);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE/* | GLUT_DEBUG*/);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640,480);
window = glutCreateWindow("Program");
//glutFullScreen();
width = glutGet(GLUT_WINDOW_WIDTH);
height = glutGet(GLUT_WINDOW_HEIGHT);
// get version info
const GLubyte* renderer;
const GLubyte* version;
///////////////////////////////////////////////////////////////////////
//
// start GLEW extension handler
//
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return(-1);
}
fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
// get version info
renderer = glGetString(GL_RENDERER); // get renderer string
version = glGetString(GL_VERSION); // version as a string
printf("\nRenderer: %s", renderer);
printf("\nOpenGL version supported %s", version);
fflush(stdout);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
//////////////////////////////////////////////////////////
//
// Shaders:
//
GLint params;
GLint len;
GLuint vscore = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vscore, 1, &vsprog_core, NULL);
glCompileShader(vscore);
glGetShaderiv(vscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(vscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
GLuint fscore = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fscore, 1, &fsprog_core, NULL);
glCompileShader(fscore);
glGetShaderiv(fscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(fscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
shader_program_core = glCreateProgram();
glAttachShader(shader_program_core, fscore);
glAttachShader(shader_program_core, vscore);
glLinkProgram(shader_program_core);
glGetProgramiv(shader_program_core,GL_LINK_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetProgramInfoLog(shader_program_core,100000,&len,log);
printf("\n\n%s\n\n",log);
fflush(stdout);
return(-1);
}
//
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
//
// Compute coordinates of the hexagon:
//
hexagon[0] = cos(0.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[1] = sin(0.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[2] = 0.0;
hexagon[3] = cos(1.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[4] = sin(1.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[5] = 0.0;
hexagon[6] = cos(2.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[7] = sin(2.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[8] = 0.0;
hexagon[9] = cos(3.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[10] = sin(3.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[11] = 0.0;
hexagon[12] = cos(4.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[13] = sin(4.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[14] = 0.0;
hexagon[15] = cos(5.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[16] = sin(5.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[17] = 0.0;
// VAO:
glGenVertexArrays(1, &(vao));
glBindVertexArray(vao);
// VBO:
glGenBuffers(1,&(vbo));
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), hexagon, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0*sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
// End VAO:
glBindVertexArray(0);
glutMouseFunc(onMouseClick);
glutMotionFunc(onMouseMove);
glutDisplayFunc(Draw);
glutTimerFunc(0,timer,0);
glutMainLoop();
return 0;
}
The shaders are defined in two char* constants. Left-clicking and moving the mouse allow to move the object.
From your description, my (wild) guess is you have texturing enabled but you're not providing any texture information.
So, just call glDisable(GL_TEXTURE_2D); before drawing your cube.
I have some code that draws squares by passing points through a geometry shader. I construct an array which is sequences of 3 floats, bind that to the in vec3 vert attribute of my vertex shader, and everything is fine.
However, I want to add another float which the fragment shader will use to calculate color. This is in the vertex shader (to pass through) as in float val. Despite being able to find vert, glGetAttribLocation can't find val (get_program_attrib(): Atrrib val not found (-1)).
Code:
void load_model(GLuint* vao, GLuint* vbo) {
glGenVertexArrays(1, vao);
glBindVertexArray(*vao);
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
float data[SQUARES_PER_AXIS_SQ * 4] = {0};
squares_count = 0;
for (int i = 0; i < SQUARES_PER_AXIS_SQ; i++) {
int x_pos = i % SQUARES_PER_AXIS;
int y_pos = i / SQUARES_PER_AXIS;
if (fabs(squares[i]) > 0.0) {
data[squares_count * 4 + 0] = x_pos / ((float)SQUARES_PER_AXIS) * 2 - 1;
data[squares_count * 4 + 1] = (SQUARES_PER_AXIS - y_pos) / ((float)SQUARES_PER_AXIS) * 2 - 1;
data[squares_count * 4 + 2] = 0.5f;
data[squares_count * 4 + 3] = (float)squares[i];
squares_count++;
}
}
DPRINT("Loaded %d squares\n", squares_count);
glBufferData(GL_ARRAY_BUFFER, squares_count * 4 * sizeof(float), data, GL_STATIC_DRAW);
glEnableVertexAttribArray(get_program_attrib(main_shader, "vert"));
glEnableVertexAttribArray(get_program_attrib(main_shader, "val"));
glVertexAttribPointer(get_program_attrib(main_shader, "vert"), 3, GL_FLOAT, GL_FALSE, 4, NULL);
glVertexAttribPointer(get_program_attrib(main_shader, "val"), 1, GL_FLOAT, GL_FALSE, 4, (float*)(3 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
GLuint get_program_attrib(program_t* prog, GLchar* name) {
if (!name) {
DPRINT("ERROR: name == NULL\n");
return -1;
}
GLint attrib = glGetAttribLocation(prog->id, name);
if (attrib < 0)
DPRINT("Atrrib %s not found (%d)\n", name, attrib);
return attrib;
}
Vertex shader:
#version 150
in vec3 vert;
in float val;
out float value;
void main() {
gl_Position = vec4(vert, 1);
value = val;
}
Fragment shader:
#version 150
in float value;
out vec4 color;
void main() {
color = vec4(value, 0, 0, 1);
}
Geometry shader:
#version 150
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
uniform float square_size;
void main() {
vec4 position = gl_in[0].gl_Position;
gl_Position = vec4(position.x, position.y, position.zw);
EmitVertex();
gl_Position = vec4(position.x, position.y + square_size, position.zw);
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y, position.zw);
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y + square_size, position.zw);
EmitVertex();
EndPrimitive();
}
Vertex shader outputs are not passed directly to the fragment shader when you have a geometry shader.
It is this that is causing all of your problems. For a vertex attribute to be active, it has to contribute to the final output of your program. Basically that means something calculated in the fragment shader has to be based off of it.
Unfortunately, that is not happening right now. You have a variable called value that is output from your vertex shader and a variable called value that is input by your fragment shader. Because the geometry shader sits inbetween the two of them, the fragment shader only looks for an output named value in the geometry shader -- no such output exists.
Naturally you might think that the solution would be to create a variable called value in the geometry shader that serves as the input and the output. However, that will not work, you would have to declare it inout value and that is invalid.
Here are the necessary corrections:
Vertex shader:
#version 150
in vec3 vert;
in float val;
out float value_vtx; // Output is fed to the Geometry Shader
void main() {
gl_Position = vec4(vert, 1);
value_vtx = val;
}
Fragment shader:
#version 150
in float value_geo; // Takes its input from the Geometry Shader
out vec4 color;
void main() {
color = vec4(value_geo, 0, 0, 1);
}
Geometry shader:
#version 150
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
uniform float square_size;
in float value_vtx []; // This was output by the vertex shader
out float value_geo; // This will be the input to the fragment shader
void main() {
vec4 position = gl_in[0].gl_Position;
gl_Position = vec4(position.x, position.y, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x, position.y + square_size, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y + square_size, position.zw);
value_geo = value_vtx[0];
EmitVertex();
EndPrimitive();
}
You may be asking why I assigned value_geo 4 times when it is constant. That is because EmitVertex (...) causes all output variables to become undefined when it returns, so you have to set it every time.