I trying to get the Red Book (8th edition) chapter 10 Fur example to work on my Ubuntu 14.04 laptop with Nvidia GTX675MX
I've changed the code to use SDL2 and glm but everything else is as it is in the Red Book.
The code compiles and runs but the 3d object is not fur shaded.
Can anyone spot any errors or is my GPU simply not up to the task?
(Full source is here: http://openme.gl/redbook_chapter_10_fur.zip)
#define GLM_FORCE_RADIANS
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <SDL2/SDL.h>
#include "vermilion.h"
#include "vutils.h"
#include "vbm.h"
#define BUFFER_OFFSET(x) ((const void*) (x))
#define PROGRAM_NAME "Red Book - Chapter 10 - Fur"
void Initialize();
void Display();
void Finalize(void);
void Reshape(int width, int height);
float aspect;
GLuint base_prog;
GLuint fur_prog;
GLuint fur_texture;
VBObject object;
GLint fur_model_matrix_pos;
GLint fur_projection_matrix_pos;
GLint base_model_matrix_pos;
GLint base_projection_matrix_pos;
void Initialize()
{
base_prog = glCreateProgram();
static const char base_vs_source[] =
"#version 410\n"
"\n"
"layout (location = 0) in vec4 position_in;\n"
"layout (location = 1) in vec3 normal_in;\n"
"layout (location = 2) in vec2 texcoord_in;\n"
"\n"
"uniform mat4 model_matrix;\n"
"uniform mat4 projection_matrix;\n"
"\n"
"out VS_FS_VERTEX\n"
"{\n"
" vec3 normal;\n"
"} vertex_out;\n"
"\n"
"void main(void)\n"
"{\n"
" vertex_out.normal = normal_in;\n"
" gl_Position = projection_matrix * (model_matrix * position_in);\n"
"}\n";
static const char base_fs_source[] =
"#version 410\n"
"\n"
"layout (location = 0) out vec4 color;\n"
"\n"
"in VS_FS_VERTEX\n"
"{\n"
" vec3 normal;\n"
"} vertex_in;\n"
"\n"
"void main(void)\n"
"{\n"
" vec3 normal = vertex_in.normal;\n"
" color = vec4(0.2, 0.1, 0.5, 1.0) * (0.2 + pow(abs(normal.z), 4.0)) + vec4(0.8, 0.8, 0.8, 0.0) * pow(abs(normal.z), 137.0);\n"
"}\n";
vglAttachShaderSource(base_prog, GL_VERTEX_SHADER, base_vs_source);
vglAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, base_fs_source);
glLinkProgram(base_prog);
glUseProgram(base_prog);
base_model_matrix_pos = glGetUniformLocation(base_prog, "model_matrix");
base_projection_matrix_pos = glGetUniformLocation(base_prog, "projection_matrix");
fur_prog = glCreateProgram();
static const char fur_vs_source[] =
"#version 410\n"
"\n"
"layout (location = 0) in vec4 position_in;\n"
"layout (location = 1) in vec3 normal_in;\n"
"layout (location = 2) in vec2 texcoord_in;\n"
"\n"
"out VS_GS_VERTEX\n"
"{\n"
" vec3 normal;\n"
" vec2 tex_coord;\n"
"} vertex_out;\n"
"\n"
"void main(void)\n"
"{\n"
" vertex_out.normal = normal_in;\n"
" vertex_out.tex_coord = texcoord_in;\n"
" gl_Position = position_in;\n"
"}\n";
static const char fur_gs_source[] =
"#version 410\n"
"\n"
"layout (triangles) in;\n"
"layout (triangle_strip, max_vertices = 240) out;\n"
"\n"
"uniform mat4 model_matrix;\n"
"uniform mat4 projection_matrix;\n"
"\n"
"uniform int fur_layers = 30;\n"
"uniform float fur_depth = 5.0;\n"
"\n"
"in VS_GS_VERTEX\n"
"{\n"
" vec3 normal;\n"
" vec2 tex_coord;\n"
"} vertex_in[];\n"
"\n"
"out GS_FS_VERTEX\n"
"{\n"
" vec3 normal;\n"
" vec2 tex_coord;\n"
" flat float fur_strength;\n"
"} vertex_out;\n"
"\n"
"void main(void)\n"
"{\n"
" int i, layer;\n"
" float disp_delta = 1.0 / float(fur_layers);\n"
" float d = 0.0;\n"
" vec4 position;\n"
"\n"
" for (layer = 0; layer < fur_layers; layer++)\n"
" {\n"
" for (i = 0; i < gl_in.length(); i++) {\n"
" vec3 n = vertex_in[i].normal;\n"
" vertex_out.normal = n;\n"
" vertex_out.tex_coord = vertex_in[i].tex_coord;\n"
" vertex_out.fur_strength = 1.0 - d;\n"
" position = gl_in[i].gl_Position + vec4(n * d * fur_depth, 0.0);\n"
" gl_Position = projection_matrix * (model_matrix * position);\n"
" EmitVertex();\n"
" }\n"
" d += disp_delta;\n"
" EndPrimitive();\n"
" }\n"
"}\n";
static const char fur_fs_source[] =
"#version 410\n"
"\n"
"layout (location = 0) out vec4 color;\n"
"\n"
"uniform sampler2D fur_texture;\n"
"uniform vec4 fur_color = vec4(0.8, 0.8, 0.9, 1.0);\n"
"\n"
"in GS_FS_VERTEX\n"
"{\n"
" vec3 normal;\n"
" vec2 tex_coord;\n"
" flat float fur_strength;\n"
"} fragment_in;\n"
"\n"
"void main(void)\n"
"{\n"
" vec4 rgba = texture(fur_texture, fragment_in.tex_coord);\n"
" float t = rgba.a;\n"
" t *= fragment_in.fur_strength;\n"
" color = fur_color * vec4(1.0, 1.0, 1.0, t);\n"
"}\n";
vglAttachShaderSource(fur_prog, GL_VERTEX_SHADER, fur_vs_source);
vglAttachShaderSource(fur_prog, GL_GEOMETRY_SHADER, fur_gs_source);
vglAttachShaderSource(fur_prog, GL_FRAGMENT_SHADER, fur_fs_source);
glLinkProgram(fur_prog);
glUseProgram(fur_prog);
fur_model_matrix_pos = glGetUniformLocation(fur_prog, "model_matrix");
fur_projection_matrix_pos = glGetUniformLocation(fur_prog, "projection_matrix");
glGenTextures(1, &fur_texture);
unsigned char * tex = (unsigned char *)malloc(1024 * 1024 * 4);
memset(tex, 0, 1024 * 1024 * 4);
int n, m;
for (n = 0; n < 256; n++)
{
for (m = 0; m < 1270; m++)
{
int x = rand() & 0x3FF;
int y = rand() & 0x3FF;
tex[(y * 1024 + x) * 4 + 0] = (rand() & 0x3F) + 0xC0;
tex[(y * 1024 + x) * 4 + 1] = (rand() & 0x3F) + 0xC0;
tex[(y * 1024 + x) * 4 + 2] = (rand() & 0x3F) + 0xC0;
tex[(y * 1024 + x) * 4 + 3] = n;
}
}
glBindTexture(GL_TEXTURE_2D, fur_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
free(tex);
object.LoadFromVBM("ninja.vbm", 0, 1, 2);
}
void Display()
{
float t = float(SDL_GetTicks() & 0x3FFF) / float(0x3FFF);
static const glm::vec3 X(1.0f, 0.0f, 0.0f);
static const glm::vec3 Y(0.0f, 1.0f, 0.0f);
static const glm::vec3 Z(0.0f, 0.0f, 1.0f);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 p(glm::frustum(-1.0f, 1.0f, aspect, -aspect, 1.0f, 5000.0f));
glm::mat4 m;
m = glm::mat4(glm::translate(glm::mat4(1.0),glm::vec3(0.0f,
0.0f,
/* 100.0f * sinf(6.28318531f * t)*/ - 130.0f)) *
//glm::rotation(360.0f * t, X) *
glm::rotate(glm::mat4(1.0),36.0f * t * 1.0f, Y) *
glm::rotate(glm::mat4(1.0),18.0f, Z) *
glm::translate(glm::mat4(1.0),glm::vec3(0.0f, -80.0f, 0.0f)));
glUseProgram(base_prog);
glUniformMatrix4fv(base_model_matrix_pos, 1, GL_FALSE, glm::value_ptr(m));
glUniformMatrix4fv(base_projection_matrix_pos, 1, GL_FALSE, glm::value_ptr(p));
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
object.Render();
glUseProgram(fur_prog);
glUniformMatrix4fv(fur_model_matrix_pos, 1, GL_FALSE, glm::value_ptr(m));
glUniformMatrix4fv(fur_projection_matrix_pos, 1, GL_FALSE, glm::value_ptr(p));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE);
object.Render();
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
void Finalize(void)
{
glUseProgram(0);
glDeleteProgram(fur_prog);
}
void Reshape(int width, int height)
{
glViewport(0, 0 , width, height);
aspect = float(height) / float(width);
}
int main(int argc, char *argv[]){
SDL_Window *mainwindow; /* Our window handle */
SDL_GLContext maincontext; /* Our opengl context handle */
if (SDL_Init(SDL_INIT_VIDEO) < 0) { /* Initialize SDL's Video subsystem */
std::cout << "Unable to initialize SDL";
return 1;
}
/* Request opengl 4.4 context. */
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
/* Turn on double buffering with a 24bit Z buffer.
* You may need to change this to 16 or 32 for your system */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
/* Create our window centered at 512x512 resolution */
mainwindow = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (!mainwindow){ /* Die if creation failed */
std::cout << "SDL Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
/* Create our opengl context and attach it to our window */
maincontext = SDL_GL_CreateContext(mainwindow);
GLenum rev;
glewExperimental = GL_TRUE;
rev = glewInit();
if (GLEW_OK != rev){
std::cout << "Error: " << glewGetErrorString(rev) << std::endl;
exit(1);
} else {
std::cout << "GLEW Init: Success!" << std::endl;
}
/* This makes our buffer swap syncronized with the monitor's vertical refresh */
SDL_GL_SetSwapInterval(1);
bool quit=false;
Initialize();
Reshape(512,512);
SDL_Event event;
while(!quit){
Display();
SDL_GL_SwapWindow(mainwindow);
while( SDL_PollEvent( &event ) ){
if( event.type == SDL_QUIT ){
quit = true;
}
if(event.type ==SDL_WINDOWEVENT){
if(event.window.event = SDL_WINDOWEVENT_SIZE_CHANGED){
int w,h;
SDL_GetWindowSize(mainwindow,&w,&h);
Reshape(w,h);
}
}
}
}
Finalize();
/* Delete our opengl context, destroy our window, and shutdown SDL */
SDL_GL_DeleteContext(maincontext);
SDL_DestroyWindow(mainwindow);
SDL_Quit();
return 0;
}
I added
glGetProgramInfoLog(fur_prog, sizeof(buffer), &length, buffer);
std::cout << length << std::endl;
std::cout << buffer << std::endl;
And got
Geometry info
-------------
(0) : error C6033: Hardware limitation reached, can only emit 146 vertices of this size
Changed max_vertices to 146 and now the shader compiles and links.
Related
so I got an exception thrown when I used the function glGenBuffer. can anyone help me to fix it?
P.S. I am using glad instead of glew.
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;
unsigned int createShader(unsigned int shadertype, const char* shaderSource) {
unsigned int shader;
shader = glCreateShader(shadertype);
glShaderSource(shader, 1, &shaderSource, NULL);
glCompileShader(shader);
int status;
char info[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status) {
glGetShaderInfoLog(shader, 512, NULL, info);
cout << "FAILED TO COMPILE!\n" << info << '\n';
glDeleteShader(shader);
}
return shader;
}
unsigned int createShaderProgram(const char* VshaderSrc, const char* FshaderSrc) {
unsigned int vertexShader = createShader(GL_VERTEX_SHADER, FshaderSrc);
unsigned int fragmentShader = createShader(GL_FRAGMENT_SHADER, FshaderSrc);
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
int status;
char info[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
if (!status) {
glGetProgramInfoLog(shaderProgram, 512, NULL, info);
cout << "FAILED TO LINK PROGRAM\n" << info << '\n';
}
return shaderProgram;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void closeWindow(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}
void cobwebDiagmramForLogistics(float x0, float miu, float* ptr) {
*(ptr) = x0;
*(ptr + 1) = 0.0f;
*(ptr + 2) = 0.0f;
*(ptr + 3) = x0;
*(ptr + 4) = miu * x0 * (1.0f - x0);
*(ptr + 5) = 0.0f;
float x = x0;
for (int i = 1; i < 100; i++) {
float horPlot = miu * x * (1.0f - x);
*(ptr + i * 6) = horPlot;
*(ptr + i * 6 + 1) = horPlot;
*(ptr + i * 6 + 2) = 0.0f;
float verPlot = miu * horPlot * (1.0f - horPlot);
*(ptr + i * 6 + 3) = horPlot;
*(ptr + i * 6 + 4) = verPlot;
*(ptr + i * 6 + 5) = 0.0f;
x = verPlot;
}
}
int main() {
float CobwebPlot[606];
cobwebDiagmramForLogistics(0.2f, 3.6f, &CobwebPlot[0]);
unsigned int positions[1212];
for (int i = 0; i < 606; i++) {
positions[i] = i;
positions[i + 1] = i + 1;
}
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "Cobweb_Diagram", NULL, NULL);
if (window == NULL) {
cout << "Failed to create GLFW window" << endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
unsigned int cobwebBuffer;
unsigned int bufferArray;
unsigned int elementArray;
glGenVertexArrays(1, &bufferArray);
glGenBuffers(1, &cobwebBuffer);
glGenBuffers(1, &elementArray);
glBindBuffer(GL_ARRAY_BUFFER, cobwebBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(CobwebPlot), CobwebPlot, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArray);
glBufferData(GL_ELEMENT_ARRAY_BARRIER_BIT, sizeof(positions), positions,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 lineColor;\n"
"void main()\n"
"{\n"
" lineColor = vec4(1.0f, 0.1f, 0.2f, 1.0f)"
"}\n";
unsigned int shaderProgram =
createShaderProgram(vertexShaderSource, fragmentShaderSource);
glUseProgram(shaderProgram);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
cout << "Failed to initialize GLAD" << endl;
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while (!glfwWindowShouldClose(window)) {
closeWindow(window);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(bufferArray);
glDrawElements(GL_LINE_STRIP, 1212, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) needs to be called before the very first OpenGL instruction. Call it right after glfwMakeContextCurrent(window):
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
cout << "Failed to initialize GLAD" << endl;
return -1;
}
There is also a problem in your shader code. A semicolon is missing at the end of lineColor = vec4(1.0f, 0.1f, 0.2f, 1.0f). I suggest using raw string literals:
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 lineColor;
void main()
{
lineColor = vec4(1.0f, 0.1f, 0.2f, 1.0f);
}
)";
I need to code the fragment shader so that the triangle has a simple gradient effect. That is, so that its transparency decreases from left to right.
I tried this but it fails:
#version 120
uniform float startX = gl_FragCoord.x;
void main(void) {
gl_FragColor[0] = 0.0;
gl_FragColor[1] = 0.0;
gl_FragColor[2] = 1.0;
gl_FragColor[3] = startX / gl_FragCoord.x;
}
The full code:
#include <cstdlib>
#include <iostream>
using namespace std;
#include <GL/glew.h>
#include <SDL.h>
GLuint program;
GLint attribute_coord2d;
bool init_resources(void)
{
GLint compile_ok, link_ok = GL_FALSE;
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
const char* vs_source = R"(
#version 120
attribute vec2 coord2d;
void main(void) {
gl_Position = vec4(coord2d, 0.0, 1.0);
}
)";
glShaderSource(vs, 1, &vs_source, NULL);
glCompileShader(vs);
glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_ok);
if (!compile_ok) {
cerr << "Error in vertex shader" << endl;
return false;
}
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
const char* fs_source = R"(
#version 120
uniform float startX = gl_FragCoord.x;
void main(void) {
gl_FragColor[0] = 0.0;
gl_FragColor[1] = 0.0;
gl_FragColor[2] = 1.0;
gl_FragColor[3] = startX / gl_FragCoord.x;
}
)";
glShaderSource(fs, 1, &fs_source, NULL);
glCompileShader(fs);
glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_ok);
if (!compile_ok) {
cerr << "Error in fragment shader" << endl;
return false;
}
program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
if (!link_ok) {
cerr << "Error in glLinkProgram" << endl;
return false;
}
const char* attribute_name = "coord2d";
attribute_coord2d = glGetAttribLocation(program, attribute_name);
if (attribute_coord2d == -1) {
cerr << "Could not bind attribute " << attribute_name << endl;
return false;
}
return true;
}
void render(SDL_Window* window)
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glEnableVertexAttribArray(attribute_coord2d);
GLfloat triangle_vertices[] = {
0.0, 0.8,
-0.8, -0.8,
0.8, -0.8,
};
glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, triangle_vertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(attribute_coord2d);
SDL_GL_SwapWindow(window);
}
void free_resources()
{
glDeleteProgram(program);
}
void mainLoop(SDL_Window* window)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
while (true)
{
SDL_Event ev;
while (SDL_PollEvent(&ev))
{
if (ev.type == SDL_QUIT)
return;
}
render(window);
}
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("My First Triangle", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
SDL_GL_CreateContext(window);
GLenum glew_status = glewInit();
if (glew_status != GLEW_OK) {
cerr << "Error: glewInit: " << glewGetErrorString(glew_status) << endl;
return EXIT_FAILURE;
}
if (!init_resources())
return EXIT_FAILURE;
mainLoop(window);
free_resources();
return EXIT_SUCCESS;
}
How to do it right?
vYou can not initialize a uniform with gl_FragCoord.x. A uniform initialization is determined at link time.
uniform float startX = gl_FragCoord.x;
uniform float startX;
You have to set the unform with glUniform1f.
gl_FragCoord.xy are not the vertex coordinates. gl_FragCoord.xy are the window coordinate in pixels. You have to divide gl_FragCoord.xy by the size of the viewport:
#version 120
void main(void) {
gl_FragColor = vec4(0.0, 0.0, 0.0, gl_FragCoord.x / 640.0);
}
Or passing coord2d to the fragment shader:
#version 120
attribute vec2 coord2d;
varying vec2 coord;
void main(void) {
coord = coord2d;
gl_Position = vec4(coord2d, 0.0, 1.0);
}
#version 120
varying vec2 coord;
void main(void) {
float alpha = 2.0 / (1.0 - coord.y);
gl_FragColor = vec4(0.0, 0.0, 1.0, alpha);
}
Or use a color attribute:
#version 120
attribute vec2 coord2d;
attribute vec4 attrColor;
varying vec4 color;
void main(void) {
color = attrColor;
gl_Position = vec4(coord2d, 0.0, 1.0);
}
#version 120
varying vec4 color;
void main(void) {
gl_FragColor = color;
}
attribute_color = glGetAttribLocation(program, "attrColor");
GLfloat triangle_colors[] = {
0.0f, 0.0f, 1.0f, 0.5f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
glEnableVertexAttribArray(attribute_color);
glVertexAttribPointer(attribute_color, 4, GL_FLOAT, GL_FALSE, 0, triangle_colors);
Here is my code:
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.8f, 0.3f, 0.02f, 1.0f);\n"
"}\n\0";
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window;
int windowWidth, windowHeight, resAnswer, aspectRatFirst, aspectRatSecond, aspectRatDeformation;
do {
std::cout << "Choose the preset for window resolution:" << std::endl;
std::cout << " 1. 800x800 (1:1)" << std::endl;
std::cout << " 2. 1024x768 (16:9)" << std::endl;
std::cout << "Answer: "; std::cin >> resAnswer;
} while (resAnswer != 1 && resAnswer != 2);
switch (resAnswer)
{
case 1:
windowWidth = 800;
windowHeight = 800;
aspectRatFirst = 1;
aspectRatSecond = 1;
break;
case 2:
windowWidth = 1024;
windowHeight = 768;
aspectRatFirst = 16;
aspectRatSecond = 9;
break;
}
aspectRatDeformation = aspectRatSecond / aspectRatFirst;
int shapeAnswer;
do {
std::cout << std::endl;
std::cout << "Choose your shape:" << std::endl;
std::cout << " 1. Triangle" << std::endl;
std::cout << " 2. Square" << std::endl;
std::cout << "Answer: "; std::cin >> shapeAnswer;
} while (shapeAnswer != 1 && shapeAnswer != 2);
64 GLfloat preVertices[];
if (shapeAnswer == 1) {
preVertices = {
-0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //B
0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //C
0.0f, 0.5f * float(sqrt(3)) * 2 / 3, 0.0f //A
};
}
else if (shapeAnswer == 2) {
preVertices = {
-0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //B
0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f, //C
0.0f, 0.5f * float(sqrt(3)) * 2 / 3, 0.0f //A
};
}
81 GLfloat vertices[] = preVertices;
window = glfwCreateWindow(windowWidth, windowHeight, "OpenGLCourse", NULL, NULL);
if (window == NULL) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
gladLoadGL();
glViewport(0, 0, windowWidth, windowHeight);
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
119 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glClearColor(0.07f, 0.13f, 0.17f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
My problem is between lines 64-81 and the line 119.
What I am trying to do is to create an array "vertices" for the specified shape vertices coordinates. The problem is that the triangle shape has 3 vertices and the square has 4 vertices, the array tho can only have one number of elements. I have another array "preVertices" just because I tried a lot of things to fix this problem.
The code wasn't working mainly because at line 119 I have to get the size of vertices, and the vertices seems to be undefined (and i think its because its getting defined inside of an if statement, or it was, at first, as i said, i changed a lot of things trying to resolve the problem), now, I think one solution would be just to make two different arrays with the different arrays and actually use an if statement to determine which i need at line 119, but I was wondering if there exists a solution with only one array, cuz I m thinking if there would be 100 different shapes it would be more time consuming to make 100 different arrays and it will also occupy more ram than needed, am I right?
Here is a piece of code that I've been experimenting with:
#include <unistd.h>
#include "GL/gl3w.h"
#include "GLFW/glfw3.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
class application {
private:
static void APIENTRY debug_callback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
GLvoid* userParam);
public:
application() {}
virtual ~application() {}
// virtual void run(application* the_app)
void run()
{
bool running = true;
// app = the_app;
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
return;
}
init();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, info.majorVersion);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, info.minorVersion);
if (info.flags.robust)
{
glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, GLFW_LOSE_CONTEXT_ON_RESET);
}
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, info.samples);
glfwWindowHint(GLFW_STEREO, info.flags.stereo ? GL_TRUE : GL_FALSE);
{
window = glfwCreateWindow(info.windowWidth, info.windowHeight, info.title, info.flags.fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
if (!window)
{
fprintf(stderr, "Failed to open window\n");
return;
}
}
glfwMakeContextCurrent(window);
gl3wInit();
startup();
do
{
render(glfwGetTime());
glfwSwapBuffers(window);
glfwPollEvents();
running &= (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_RELEASE);
running &= (glfwWindowShouldClose(window) != GL_TRUE);
} while (running);
shutdown();
glfwDestroyWindow(window);
glfwTerminate();
}
virtual void init()
{
strcpy(info.title, "OpenGL SuperBible Example");
info.windowWidth = 800;
info.windowHeight = 600;
info.majorVersion = 4;
info.minorVersion = 5;
info.samples = 0;
info.flags.all = 0;
info.flags.cursor = 1;
}
virtual void startup() { }
virtual void render(double currentTime) { }
virtual void shutdown() { }
void setWindowTitle(const char * title) { glfwSetWindowTitle(window, title); }
virtual void onResize(int w, int h)
{
info.windowWidth = w;
info.windowHeight = h;
}
void getMousePosition(int& x, int& y)
{
double dx, dy;
glfwGetCursorPos(window, &dx, &dy);
x = static_cast<int>(floor(dx));
y = static_cast<int>(floor(dy));
}
public:
struct APPINFO
{
char title[128];
int windowWidth;
int windowHeight;
int majorVersion;
int minorVersion;
int samples;
union
{
struct
{
unsigned int fullscreen : 1;
unsigned int vsync : 1;
unsigned int cursor : 1;
unsigned int stereo : 1;
unsigned int debug : 1;
unsigned int robust : 1;
};
unsigned int all;
} flags;
};
protected:
APPINFO info;
static application * app;
GLFWwindow* window;
};
class tessellatedtri_app : public application
{
void init()
{
static const char title[] = "OpenGL SuperBible - Tessellated Triangle";
application::init();
memcpy(info.title, title, sizeof(title));
}
virtual void startup()
{
static const char * vs_source[] =
{
"#version 450 core \n"
"layout (location = 0) in vec4 offset; \n"
"layout (location = 1) in vec4 color; \n"
"out vec4 vs_color; \n"
"void main(void) \n"
"{ \n"
" const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0), \n"
" vec4(-0.25, -0.25, 0.5, 1.0), \n"
" vec4( 0.25, 0.25, 0.5, 1.0)); \n"
" \n"
" gl_Position = vertices[gl_VertexID] + offset; \n"
" vs_color = color; \n"
"} \n"
};
static const char * tcs_source[] =
{
"#version 450 core \n"
"layout (vertices = 3) out; \n"
" in vec4 vs_colors [];\n"
" out vec4 tcs_colors [3];\n"
"patch out vec4 patch_color; \n"
"void main(void) \n"
"{ \n"
// gl_TessLevelInner and gl_TessLevelOuter should only be set once
" if (gl_InvocationID == 0) \n"
" { \n"
" gl_TessLevelInner[0] = 3.0; \n"
" gl_TessLevelOuter[0] = 2.0; \n"
" gl_TessLevelOuter[1] = 2.0; \n"
" gl_TessLevelOuter[2] = 2.0; \n"
" } \n"
// " patch_color = vec4(.2, .3, .8); \n"
// " patch_color = vs_colors [gl_InvocationID]; \n"
// " tcs_colors[gl_InvocationID] = vs_colors[gl_InvocationID]; \n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; \n"
"} \n"
};
static const char * tes_source[] =
{
"#version 450 core \n"
"layout (triangles, equal_spacing, cw) in; \n"
// "patch in vec4 patch_color; \n"
// " out vec4 tes_color; \n"
"void main(void) \n"
"{ \n"
" gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) + \n"
" (gl_TessCoord.y * gl_in[1].gl_Position) + \n"
" (gl_TessCoord.z * gl_in[2].gl_Position); \n"
// " tes_color = patch_color; \n"
"} \n"
};
static const char * fs_source[] =
{
"#version 450 core \n"
"in vec4 tes_color; \n"
"out vec4 color; \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.2, 0.2, .4, 1.0); \n"
// " color = tes_color;"
"} \n"
};
program = glCreateProgram();
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);
GLuint tcs = glCreateShader(GL_TESS_CONTROL_SHADER);
glShaderSource(tcs, 1, tcs_source, NULL);
glCompileShader(tcs);
GLuint tes = glCreateShader(GL_TESS_EVALUATION_SHADER);
glShaderSource(tes, 1, tes_source, NULL);
glCompileShader(tes);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);
glAttachShader(program, vs);
glAttachShader(program, tcs);
glAttachShader(program, tes);
glAttachShader(program, fs);
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
virtual void render(double currentTime)
{
float color_var = ((float)sin(currentTime) + 1.f) / 2.f;
bg_color[0] = color_var;
glClearBufferfv(GL_COLOR, 0, bg_color);
glUseProgram(program);
float offset[] = {
(float) sin(currentTime) * .5f,
(float) cos(currentTime) * .5f,
(float) cos(currentTime) * .5f,
0.0f
};
glVertexAttrib4fv(0, offset);
fg_color[2] = color_var;
glVertexAttrib4fv(1, fg_color);
glDrawArrays(GL_PATCHES, 0, 3);
}
virtual void shutdown()
{
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
}
private:
float bg_color[3] = {1.f, .7f, .8f};
float fg_color[3] = {.2f, .7f, .2f};
GLuint program;
GLuint vao;
};
int main(int argc, const char ** argv)
{
tessellatedtri_app *app = new tessellatedtri_app();
app->run();
delete app;
return 0;
}
I'm just trying to vary the color of the wireframe by time, but somehow I couldn't pass the color attribute through the stages after many attempts. Any suggestions? Thanks.
You need an input and an output for the attribute which you want to pass through in ever stage:
Vertex shader:
layout (location = 1) in vec4 color;
out vec4 vs_color;
void main(void)
{
vs_color = color;
// ...
}
In the Tessellation Control Shader the attribute can be passed through:
in vec4 vs_color[];
out vec4 tcs_colors[];
void main(void)
{
tcs_colors[gl_InvocationID] = vs_color[gl_InvocationID];
// ...
}
In the Tessellation Evaluation Shader you have to calculate the "tessellated" attribute from the per vertex input:
in vec4 tcs_colors[];
out vec4 tes_colors;
void main(void)
{
tes_colors = gl_TessCoord.x * tcs_colors[0] +
gl_TessCoord.y * tcs_colors[1] +
gl_TessCoord.z * tcs_colors[2];
// ...
}
Fragment shader:
in vec4 tes_colors;
I'm using Eclipse, MinGW, and I have compiled freeglut and glew and copied their libraries, DLLs, and header files into the proper locations (MinGW/include/GL, MinGW/lib, Windows/SysWOW64). I have also linked the libraries (freeglut64, opengl32, glew32, glu32) in Eclipse under the MinGW C++ Linker. Here is my code...
--CharGame.cpp--
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "CharGame.h"
#define WINDOW_TITLE "CharGame"
int CurrentWidth = 800,
CurrentHeight = 600,
WindowHandle = 0;
unsigned FrameCount = 0;
GLuint VertexShaderId,
FragmentShaderId,
ProgramId,
VaoId,
VboId,
ColorBufferId;
int main(int argc, char* argv[]) {
Initialize(argc, argv);
glutMainLoop();
exit(EXIT_SUCCESS);
}
const GLchar* VertexShader =
{
"#version 400\n"\
"layout(location=0) in vec4 in_Position;\n"\
"layout(location=1) in vec4 in_Color;\n"\
"out vec4 ex_Color;\n"\
"void main(void)\n"\
"{\n"\
" gl_Position = in_Position;\n"\
" ex_Color = in_Color;\n"\
"}\n"
};
const GLchar* FragmentShader =
{
"#version 400\n"\
"in vec4 ex_Color;\n"\
"out vec4 out_Color;\n"\
"void main(void)\n"\
"{\n"\
" out_Color = ex_Color;\n"\
"}\n"
};
void Initialize(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitContextVersion(4, 0);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutInitWindowSize(CurrentWidth, CurrentHeight);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
WindowHandle = glutCreateWindow(WINDOW_TITLE);
if (WindowHandle < 1) {
fprintf(stderr, "Error: Could not create a render window.\n");
exit(EXIT_FAILURE);
}
glutReshapeFunc(Resize);
glutDisplayFunc(Render);
glutIdleFunc(Idle);
glutTimerFunc(0, Timer, 0);
fprintf(stdout, "Info: OpenGL Version: %s\n", glGetString(GL_VERSION));
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
void Resize(int width, int height) {
CurrentHeight = height;
CurrentWidth = width;
glViewport(0, 0, CurrentWidth, CurrentHeight);
}
void Render(void) {
++FrameCount;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
glutSwapBuffers();
glutPostRedisplay();
}
void Idle(void) {
glutPostRedisplay();
}
void Timer(int value) {
if (0 != value) {
char* TempString = (char*) malloc(512 + strlen(WINDOW_TITLE));
sprintf(TempString, "%s: %d Frames Per Second # %d x %d", WINDOW_TITLE, FrameCount*4, CurrentWidth, CurrentHeight);
glutSetWindowTitle(TempString);
free(TempString);
}
FrameCount = 0;
glutTimerFunc(250, Timer, 1);
}
--End CharGame.cpp--
--CharGame.h--
#ifndef CHARGAME_H_
#define CHARGAME_H_
void Initialize(int, char*[]);
void InitWindow(int, char*[]);
void Resize(int,int);
void Render(void);
void Timer(int);
void Idle(void);
#endif
--End CharGame.h--
I believe I have done everything right, however, Eclipse throws the error "Type 'GLchar' could not be resolved" on VertexShader and FragmentShader. Did I make a mistake in my code or miss a required step?
You're not declaring string constants the right way. You don't need curly braces there. And watch out for empty lines betwreen the strings - either remove them (see below) or add the "\" there.
Include the "GL/GL.h" file before "glew.h", this might help also.
Use this with ordinary chars:
const char* VertexShader =
"#version 400\n"\
"layout(location=0) in vec4 in_Position;\n"\
"layout(location=1) in vec4 in_Color;\n"\
"out vec4 ex_Color;\n"\
"void main(void)\n"\
"{\n"\
" gl_Position = in_Position;\n"\
" ex_Color = in_Color;\n"\
"}\n";
const char* FragmentShader =
"#version 400\n"\
"in vec4 ex_Color;\n"\
"out vec4 out_Color;\n"\
"void main(void)\n"\
"{\n"\
" out_Color = ex_Color;\n"\
"}\n";
This is just expanding on my comment on another answer:
const char* VertexShader =
R"(#version 400
layout(location=0) in vec4 in_Position;
layout(location=1) in vec4 in_Color;
out vec4 ex_Color;
void main(void)
{
gl_Position = in_Position;
ex_Color = in_Color;
}
)";