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?
CodePudding user response:
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);