#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. Все еще не работает, я уже пытался передать его по ссылке, прежде чем вы отредактировали свой пост.