Hi Folks:
I’m sorry for the length of this post. I wish I could tell you it’s a well written and easy read. All I can say is if I had the skill to explain it in simpler terms, I would.
Developing on Windows 10, VS 2017, C++.
Thanks to a lot of generous advice from this forum, and guidance from this tutorial, I’m rendering my first OpenGL image, an early version of a splash screen:
Uh, “1_material_colors.jpg: This is not a valid image file”. That’s the same error that popped up when I tried to insert a PNG image.
How should I interpret this?
Add an Image from your computer
Allowed Filetypes: jpg, jpeg, png, gif
Does MS Paint not create valid PNG and JPG files?
Maybe I’ve used up my quota of dumb questions and I can’t post images.
Ok, a word is worth a thousandth of a picture, so picture this:
Two words in bold Ariel Italic dominate the window, which has a black background. The first, in light blue green, says “Net” and below that is “Results” in blood read.
Rotating leisurely in front of this text is a simple model of a tennis court I made in Blender. It’s drawn large enough to almost touch the right and left edges of the window. The view is across the court. The court and axis of rotation are tilted slightly so the playing surface is can be seen. The application’s name is clearly visible, The lower word “Results” is briefly obscured for part of the court’s rotation.
To my eyes my first OpenGL image is beautiful. The scene is vibrant, colors are straight from the materials defined in the model, unfaded by lighting effects.
I believe the technical term for such an image is “Crap”.
Time to make it look like something from this world.
Here’s how the code’s supposed to work:
I started with two identical sets of shaders, one set for the text and another for the court.
In the code called by the Windows message loop I select the appropriate shader for each task.
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 3) in vec4 color;
out vec4 vertex_Color;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
vertex_Color = color;
}
Here is the fragment shader:
#version 330 core
in vec4 vertex_Color;
out vec4 color;
void main()
{
vec4 fragment_color = vec4(vertex_Color);
if(fragment_color.a < 0.1)
discard;
color = fragment_color;
}
As I develop the image for the court its shaders will evolve.
I don’t have plans for changing the text shaders. I still have 1/2 of the tutorial to grind through, so that could change if I decide to add effects to the text.
The Problem:
Ambient light is implemented by modifying the court’s fragment shader with a uniform for the ambient color. The output color from the fragment shader is the material’s color multiplied by the the ambient color.
Here’s the court’s fragment shader, after ambient light processing has been added:
#version 330 core
in vec4 vertex_Color;
out vec4 color;
uniform vec4 total_ambient_color;
// vec4 total_ambient_color = vec4(0.268582731, 0.382265419, 0.268573165, 1.0);
void main()
{
vec4 fragment_color = vec4(vertex_Color);
if(fragment_color.a < 0.1)
discard;
color = fragment_color * total_ambient_color;
}
I add the necessary uniform code to the application.
And there’s the rotating court, dimmed appropriately. The court’s shader worked.
The problem is that there’s no text displayed, nothing. Just blackness.
Could be a million things, right?
What happens if I hard code the ambient color into the court’s fragment shader?
You see the commented out “vec4 total_ambient_color = vec4(0.268582731…”?
Remove the comment “//”, and comment out the uniform statement.
Run it again and there’s the court, dimly rotating in front of the text, which is nice and bright. This is what I want to see.
So it looks like I’m messing up the uniform call, but I don’t see what I’m doing wrong. At the end of this post, after the C++ setup and loop code, I compare it to similar code form the tutorial, looks the same to me.
Here is the code that set’s up for the graphics:
bool setup_simple_splash_screen(HWND hdlg, HINSTANCE hinstance, PROCESS_RECORD *process_record_ptr,
std::string *message_string_ptr)
{
bool error_found = false;
GRAPHICS_PARAMETER *graphics_parameter_ptr = new GRAPHICS_PARAMETER();
windows_camera_wrapper_basic::CAMERA_WRAPPER *free_camera_wrapper_ptr = NULL;
opengl_camera::CAMERA *camera_ptr = NULL;
vector<Mesh> *meshes_vector_ptr = NULL;
HDC hdc = NULL;
std::string local_message_string;
RECT client_rect;
int width = 0;
int height = 0;
const int PixelFormatAttribList[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, 32,
0 // End of attributes list
};
graphics_parameter_ptr->set_hwnd(hdlg);
graphics_parameter_ptr->set_hrc(init_opengl(hdlg, &hdc, hinstance, 3, 3,
PixelFormatAttribList,
&local_message_string));
if (graphics_parameter_ptr->get_hrc() == NULL)
{
error_found = true;
if (message_string_ptr != NULL)
{
*message_string_ptr += "setup_splash_screen()
";
*message_string_ptr += " HRC is NULL.
";
*message_string_ptr += local_message_string.c_str();
local_message_string.erase();
}
}
else
{
graphics_parameter_ptr->set_hdc(hdc);
if (graphics_parameter_ptr->get_hrc() == NULL)
{
error_found = true;
if (message_string_ptr != NULL)
{
*message_string_ptr += "setup_splash_screen()
";
*message_string_ptr += " OpenGL failed to open.
";
*message_string_ptr += local_message_string.c_str();
local_message_string.erase();
}
}
else
{
process_record_ptr->set_graphics_parameter_ptr(graphics_parameter_ptr);
GetClientRect(hdlg, &client_rect);
width = client_rect.right - client_rect.left;
height = client_rect.bottom - client_rect.top;
graphics_parameter_ptr->set_client_rect(&client_rect);
glViewport(0, 0, width, height);
initialize_cameras(graphics_parameter_ptr, width, height, VK_TAB, VK_TAB, 0.001);
// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
glewExperimental = GL_TRUE;
// Initialize GLEW to setup the OpenGL Function pointers
glewInit();
// Define the viewport dimensions
glViewport(0, 0, width, height);
// Setup some OpenGL options
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
// glEnable(GL_CULL_FACE);
graphics_parameter_ptr->set_non_court_shader_ptr(new SHADER("models\\shaders\ est_non_court_color.shv",
"models\\shaders\ est_non_court_color.shf",
&local_message_string));
if (!local_message_string.empty())
{
error_found = true;
*message_string_ptr += "setup_splash_screen()
";
*message_string_ptr += " Shaders for non-court items failed to load.
";
*message_string_ptr += local_message_string.c_str();
local_message_string.erase();
}
graphics_parameter_ptr->set_court_shader_ptr(new SHADER("models\\shaders\ est_court_color.shv",
"models\\shaders\ est_court_color.shf",
&local_message_string));
if (!local_message_string.empty())
{
error_found = true;
*message_string_ptr += "setup_splash_screen()
";
*message_string_ptr += " Shaders for court failed to load.
";
*message_string_ptr += local_message_string.c_str();
local_message_string.erase();
}
}
}
if (!error_found)
{
graphics_parameter_ptr->set_court_model_ptr(new MODEL("models\\court\\01_1.obj"));
graphics_parameter_ptr->set_net_text_model_ptr(new MODEL("models\ ext\
et.obj"));
graphics_parameter_ptr->set_results_text_model_ptr(new MODEL("models\ ext\\results.obj"));
// Ambient light's color is determined by the colors of the light, playing surface,
// "Net" text and "Results" text.
glm::vec3 color;
graphics_parameter_ptr->setup_diffuse_colors();
graphics_parameter_ptr->set_setup_is_valid(!error_found);
}
else
{
process_record_ptr->set_graphics_parameter_ptr(NULL);
delete graphics_parameter_ptr;
}
return !error_found;
}
This code is called form the message loop:
void process_simple_graphic_transform_timer(HWND hdlg,
GRAPHICS_PARAMETER *graphics_parameter_ptr)
{
if (graphics_parameter_ptr->get_active())
{
glm::mat4 court_model;
SHADER *non_court_shader_ptr = graphics_parameter_ptr->get_non_court_shader_ptr();
// The court image will be influenced by lighting, so it get's it's own shader.
SHADER *court_shader_ptr = graphics_parameter_ptr->get_court_shader_ptr();
windows_camera_wrapper_basic::CAMERA_WRAPPER *selected_camera_wrapper_ptr =
graphics_parameter_ptr->get_free_camera_wrapper_ptr();
if (selected_camera_wrapper_ptr != NULL)
{
opengl_camera::CAMERA *camera_ptr = selected_camera_wrapper_ptr->get_camera();
float width = float(graphics_parameter_ptr->get_client_rect()->right -
graphics_parameter_ptr->get_client_rect()->left);
float height = float(graphics_parameter_ptr->get_client_rect()->bottom -
graphics_parameter_ptr->get_client_rect()->top);
GLfloat court_tilt = glm::radians(COURT_TILT_X_DEGREES);
GLfloat adjusted_rotation_index = 0.0;
// Clear the colorbuffer
// glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
if (graphics_parameter_ptr->get_setup_is_valid())
{
selected_camera_wrapper_ptr->calculate_delta_time();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw the court.
court_shader_ptr->use();
glUniform4f(glGetUniformLocation(court_shader_ptr->Program, "total_ambient_color"),
graphics_parameter_ptr->get_total_ambient_color()->r,
graphics_parameter_ptr->get_total_ambient_color()->g,
graphics_parameter_ptr->get_total_ambient_color()->b, 1.0f);
// Transformation matrices
// glEnable(GL_CULL_FACE);
adjusted_rotation_index = -selected_camera_wrapper_ptr->get_current_frame() / TIMER_THROTTLE_VALUE;
court_model = glm::rotate(court_model, court_tilt, glm::vec3(1.0, 0.0, 0.0));
court_model = glm::rotate(court_model, adjusted_rotation_index, glm::vec3(0.0, 1.0, 0.0));
glUniformMatrix4fv(glGetUniformLocation(court_shader_ptr->Program, "model"),
1,
GL_FALSE,
glm::value_ptr(court_model));
position_free_camera(camera_ptr, court_shader_ptr, width, height);
graphics_parameter_ptr->get_court_model_ptr()->Draw(*court_shader_ptr);
// glDisable(GL_CULL_FACE);
// Draw the "Net" text.
non_court_shader_ptr->use();
glm::mat4 model = glm::mat4();
glUniformMatrix4fv(glGetUniformLocation(non_court_shader_ptr->Program, "model"),
1,
GL_FALSE,
glm::value_ptr(model));
graphics_parameter_ptr->get_net_text_model_ptr()->Draw(*non_court_shader_ptr);
// Draw the "Results" text.
position_free_camera(camera_ptr, court_shader_ptr, width, height);
model = glm::mat4();
glUniformMatrix4fv(glGetUniformLocation(non_court_shader_ptr->Program, "model"),
1,
GL_FALSE,
glm::value_ptr(model));
graphics_parameter_ptr->get_results_text_model_ptr()->Draw(*non_court_shader_ptr);
}
// Swap the buffers
SwapBuffers(graphics_parameter_ptr->get_hdc());
}
}
}
What am I doing that’s different than this fragment of code taken from the tutorial’s sample?
GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
Here’s the fragment shader the sample is talking to:
#version 330 core
out vec4 color;
uniform vec4 ourColor; // We set this variable in the OpenGL code.
void main()
{
color = ourColor;
}
Here’s what looks to me to be a functionally identical fragment from my code:
glUniform4f(glGetUniformLocation(court_shader_ptr->Program, "total_ambient_color"),
graphics_parameter_ptr->get_total_ambient_color()->r,
graphics_parameter_ptr->get_total_ambient_color()->g,
graphics_parameter_ptr->get_total_ambient_color()->b, 1.0f);
The court draws fine when I pass the uniform to it’s fragment shader.
The problem is, that act blows the text, drawn by a different shader, out of the water.
Sorry for the length of this post. I’m stumped.
Thanks
Larry