2

Can I use glColor3f(), glVertex3f() or other API functions with shader? I wrote a shader for draw a colorful cube and it works fine. My vertex shader and fragment shader look like this

#vertext shader
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
out vec4 vertexColor;
void main()
{
    gl_Position = proj * view * model * vec4(aPos.x, aPos.y, aPos.z, 1.0);
    vertexColor = vec4(aColor, 1.0);
};

#fragment shader
#version 330 core
in vec4 vertexColor;
out vec4 FragColor;
void main(){
    FragColor = vertexColor;
};

Noe, I try to use gl functions along with my colorful cube. Let's say I have some draw code like this.

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, -1, 0, 0, 0, 0, 1, 0);
glColor3f(1.0, 0.0, 0.0);
glLineWidth(3);
glBegin(GL_LINES);
glVertex3f(-1, -1, 0);
glVertex3f(1, 1, 0);

Since I used glUseProgram() to use my own shader. The above gl functions doesn't seems to work as expect (coordinates and color are both wrong). How does function like glVertex3f() pass vertex to shader? And how do the shaders should look like when using gl function to draw?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Josh Chiu
  • 832
  • 2
  • 7
  • 14
  • old API `glBegin/glEnd` can be used with core shaders **however its not safe** unless you have **nVidia GL/GLSL implementation** as to my knowledge only they have well defined [default attribute locations](https://stackoverflow.com/a/20574219/2521214) in their specs and other than that IIRC all other implementation have only `glVertex` defined to comply with GLSL specs and the rest might be at any locations not consistent among driver versions. – Spektre Jan 13 '22 at 09:23

2 Answers2

4

Can I use glColor3f(), glVertex3f() or other API functions with shader?

Yes you can.

However, you need to use a Compatibility profile OpenGL Context and you are limited to a GLSL 1.20 vertex shader and the Vertex Shader Built-In Attributes (e.g. gl_Vertex, gl_Color). You can combine a GLSL 1.20 vertex shader with your fragment shader. The matrices in the fixed function matrix stack can be accessed with Built-In Uniforms like gl_ModelViewProjectionMatrix.
All attributes and uniforms are specified in detail in the OpenGL Shading Language 1.20 Specification.

A suitable vertex shader can look like this:

#version 120

varying vec4 vertexColor;

void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    vertexColor = gl_Color;
};
#version 330

in vec4 vertexColor;
out vec4 FragColor;

void main(){
    FragColor = vertexColor;
};
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
1

The glBegin()/glEnd() directives are used in compatibility profile of OpenGL as opposed to core profile which is more modern. However you are compiling your shaders in core profile using the line #version 330 core.

Even if the shaders are not compiled in the core profile, I don't think they'll work since I believe you can't pass vertex attributes with location indices (aPos, aColor) using glVertex3f.

I would recommend using the core Opengl for render calls. That means you should not use you glBegin()...glEnd() and pass vertex coordinates in every render cycle. Instead, the cube coordinates to GPU before-hand and let your shaders access those values:

  1. Create VertexBuffer objects using glGenBuffers().
  2. Store your vertex data in the buffer using glBufferData().
  3. Extract the aPos and aColor attributes from the buffer and assign them indices of 0 and 1 respectively using glVertexAttribPointer().

This should work and no changes to your shader code would be necessary.

EDIT:

For rendering in compatibility profile, the data provided within glBegin/glEnd is ran through a default shader pipeline. You can't customize the pipeline using explicit shader code (like you did now), but you can modify some basic things in the pipeline (such as color, phong lighting, texture). So if you want to get the results your shader code represents, you need to do something like this:

glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-1.0f,-0.25f,0.0f); //First vertex
glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-0.5f,-0.25f,0.0f); // Second vertex
...
glEnd();

This way of sending full object details during render call is called Immediate mode. For adding lighting, you need glEnable(GL_LIGHTING), add normal info for each vertex and a bunch of other stuff.

If you use core profile, you can define your own shaders but you can't use Immediate mode during the render calls. You need to pass the vertex data before your rendering loop. Basically glBegin,glEnd,'glVertex3f' are not supported in core profile and you need to use the 3 points above to store the data in your graphics device before your render anything (which is done using glDrawArrays()). This tutorial provides a good introduction to these concepts and can help you draw the cube you want using core profile.

  • Does compatibility profile has nothing to do with shaders? What happend If I use compatibility profile functions without specify any shaders? Does the vertices and colors in glVertex3f() and glColor3f() go through any shader pipleline? or it's completly different system between compatibility profile and core profile? Really confused... Thanks for the reply. – Josh Chiu Dec 19 '21 at 07:01
  • Added additional details in the answer. Yeah it is kinda confusing at first. I highly recommend moving to core profile since immediate mode is obsolete, and may be deprecated in some higher opengl versions. Only use it if your objects have low vertex counts and you only need basic lighting. Moving to core profile gives you full freedom of customizing your shaders and can be significantly more efficient when rendering complex geometry. You will also find much more online resources for core profile than compatibility. – Gurkirat Singh Bajwa Dec 19 '21 at 08:38
  • *"This way of sending full object details during render call ..."* - No. The light model (BRDF) is a function of incident light, normals and line of sight. Therefore, the lighting will not work without set normal vectors. – Rabbid76 Dec 19 '21 at 08:54
  • Ah right. I have edited that line now. The previous line gave the wrong assumption that the `glEnable(...)` command is sufficient for enabling the lighting in compatibility profile. – Gurkirat Singh Bajwa Dec 19 '21 at 09:51
  • @GurkiratSinghBajwa The combination of the fixed function pipeline lighting with a shader does not work automatically. The light setting can be called up via the built-in uniform `gl_LightSource`. The shader is limited to GLSL 1.20. – Rabbid76 Dec 19 '21 at 10:33