Запутался в поведении шейдеров в OpenGL — переключение объявлений создает ошибки и сбои

#c #opengl #input #shader #glfw

#c #opengl #ввод #шейдер #glfw

Вопрос:

Я создаю функции для загрузки шейдеров, создания сеток и тому подобного, Поэтому я запустил простую программу для тестирования добавляемых функций, одну за другой, и я обнаружил проблему с этим битом:

 const char* vertexShader = prm.LoadShader ( "simple_vs.glsl" ).c_str ();
const char* fragmentShader = prm.LoadShader ( "simple_fs.glsl" ).c_str ();

GLuint vs = glCreateShader ( GL_VERTEX_SHADER );
glShaderSource ( vs, 1, amp;vertexShader, NULL );
glCompileShader ( vs );
GLuint fs = glCreateShader ( GL_FRAGMENT_SHADER );
glShaderSource ( fs, 1, amp;fragmentShader, NULL );
glCompileShader ( fs );
  

Если бы я попытался скомпилировать его, я бы не получил ошибок, но был бы черный экран. Если бы я удалил фрагментный шейдер, он отображал бы треугольник, как и предполагалось, без каких-либо цветов. Если я поменял два объявления, как в:

 const char* fragmentShader = prm.LoadShader ( "simple_fs.glsl" ).c_str ();
const char* vertexShader = prm.LoadShader ( "simple_vs.glsl" ).c_str ();
  

Я бы получил сообщение об ошибке, и моя программа потерпела бы крах:

 Error code #3: Shader info for shader 1: WARNING: 0:1: '#version' : 
version number deprecated in OGL 3.0 forward compatible context driver
ERROR: 0:1: '#extension' :  'GL_ARB_separate_shader_objects' is not
supported
  

Однако, если я сформулирую это так:

 const char* vertexShader = prm.LoadShader ( "simple_vs.glsl" ).c_str ();

GLuint vs = glCreateShader ( GL_VERTEX_SHADER );
glShaderSource ( vs, 1, amp;vertexShader, NULL );
glCompileShader ( vs );

const char* fragmentShader = prm.LoadShader ( "simple_fs.glsl" ).c_str ();

GLuint fs = glCreateShader ( GL_FRAGMENT_SHADER );
glShaderSource ( fs, 1, amp;fragmentShader, NULL );
glCompileShader ( fs );
  

Это работает отлично. Я совершенно не понимаю, почему это так, поскольку я запускал исходный код без проблем в предыдущих версиях моей программы. Я уже проверил функцию prm.LoadShader, она работает нормально и возвращает ожидаемое значение. Ни одно из изменений, которые я внес в программу, не касается шейдеров, поэтому меня смущает это странное поведение. Может ли кто-нибудь с большим опытом объяснить, почему именно это происходит?

Комментарии:

1. Помимо ошибки, указанной @Joseph, сообщение журнала шейдеров кажется довольно ясным о проблеме. Что #version вы добавляете к шейдерам? И на какую версию OpenGL вы ориентируетесь? Кроме того, если GL_ARB_separate_shader_objects он недоступен на вашем компьютере, вам просто придется вернуться к таким старым шейдерным программам.

2. Версия 400. Дело в том, что, как я уже упоминал, это случается только иногда, вот в чем дело. Проблема заключалась в том, как я поступал при передаче строки, содержащей текст шейдера, а не самого OpenGL.

3. Значит, он работал нормально до того, как вы изменили код загрузки шейдера?

4. Все работало нормально, пока я не начал переписывать код. Теперь я закончил переработку способа передачи шейдера для компиляции, и теперь все работает нормально.

Ответ №1:

Предположительно prm.LoadShader возвращает std::string значение by . Вызов c_str дает вам внутреннее хранилище символов a std::string , которое живет только до тех пор, пока std::string работает. К концу каждой LoadShader строки std::string возвращенный объект уничтожается, поскольку он был временным объектом, а сохраненные вами указатели больше не указывают на допустимые массивы символов.

Вы можете легко обойти это, сохранив локальную копию возвращаемых строк.

 std::string vertexShader = prm.LoadShader ( "simple_vs.glsl" );
const char* cVertexShader = vertexShader.c_str();
std::string fragmentShader = prm.LoadShader ( "simple_fs.glsl" );
const char* cFragmentShader = vertexShader.c_str();

GLuint vs = glCreateShader ( GL_VERTEX_SHADER );
glShaderSource ( vs, 1, amp;cVertexShader, NULL );
glCompileShader ( vs );
GLuint fs = glCreateShader ( GL_FRAGMENT_SHADER );
glShaderSource ( fs, 1, amp;cFragmentShader, NULL );
glCompileShader ( fs );
  

Комментарии:

1. То, что вы сказали, верно, но тогда как это работает для последнего фрагмента? Разве это все равно не выйдет за рамки? Или это просто совпадение?

2. @MKII Это технически неопределенное поведение. Однако я полагаю, что причина, по которой это не работает, когда они вместе, заключается в том, что два временных std::string s занимают одно и то же пространство. Когда у вас есть отдельный, вам просто очень повезло, что внутренние строковые данные хранятся в памяти достаточно долго.

3. Я вижу. У меня есть только второй вопрос: предоставленный вами код не работает, он возвращает эту ошибку: не удается преобразовать ‘const char *’ в ‘const GLchar ** {он же const char **}’ при передаче аргумента

4. @MKII Ой, я забыл, что он принимает массив строк. Я это исправлю.

5. Все еще не работает, я уже пытался передать его по ссылке, прежде чем вы отредактировали свой пост.