Hi,
I’m having some issues using 3D shaders on an SDL_texture.
Everything is fine except for the z-buffer. When I enable glEnable(GL_DEPTH_TEST);
nothing is rendered to the texture (everything is black).
Here is the example code:
#include <SDL.h>
#include "SDL_opengl.h"
#include <iostream>
#include <chrono>
#include <thread>
#define WIDTH 640
#define HEIGHT 800
const std::string _vert = R"(
#version 320 es
layout(location = 0) in vec3 vertPos;
out vec3 theColor;
uniform float angleX;
uniform float angleY;
const float pi = 3.14159265359;
mat3 rotateX(float angle)
{
angle *= pi / 180.0;
return mat3(
1.0, 0.0, 0.0,
0.0, cos(angle), -sin(angle),
0.0, sin(angle), cos(angle)
);
}
mat3 rotateY(float angle)
{
angle *= pi / 180.0;
return mat3(
cos(angle), 0.0, sin(angle),
0.0, 1.0, 0.0,
-sin(angle), 0.0, cos(angle)
);
}
mat3 rotateZ(float angle)
{
angle *= pi / 180.0;
return mat3(
cos(angle), -sin(angle), 0.0,
sin(angle), cos(angle), 0.0,
0.0, 0.0, 1.0
);
}
void main()
{
theColor = vertPos;
gl_Position = vec4(rotateX(angleX) * rotateY(angleY) * vertPos, 1.0);
}
)";
const std::string _frag = R"(
#version 320 es
precision mediump float;
in vec3 theColor;
out vec4 fragColor;
void main()
{
fragColor = vec4(theColor, 1.0);
}
)";
const GLfloat _vertices[] = {
//Front face
-0.5f, -0.5f, 0.5f, // A
0.5f, -0.5f, 0.5f, // B
-0.5f, 0.5f, 0.5f, // C
0.5f, -0.5f, 0.5f, // B
0.5f, 0.5f, 0.5f, // D
-0.5f, 0.5f, 0.5f, // C
//Bottom face
-0.5f, -0.5f, 0.5f, // A
-0.5f, -0.5f, -0.5f, // E
0.5f, -0.5f, 0.5f, // B
-0.5f, -0.5f, -0.5f, // E
0.5f, -0.5f, -0.5f, // F
0.5f, -0.5f, 0.5f, // B
//Left Face
-0.5f, -0.5f, 0.5f, // A
-0.5f, 0.5f, 0.5f, // C
-0.5f, 0.5f, -0.5f, // G
-0.5f, -0.5f, 0.5f, // A
-0.5f, -0.5f, -0.5f, // E
-0.5f, 0.5f, -0.5f, // G
//Back Face
-0.5f, -0.5f, -0.5f, // E
-0.5f, 0.5f, -0.5f, // G
0.5f, 0.5f, -0.5f, // H
-0.5f, -0.5f, -0.5f, // E
0.5f, -0.5f, -0.5f, // F
0.5f, 0.5f, -0.5f, // H
//Right Face
0.5f, 0.5f, 0.5f, // D
0.5f, 0.5f, -0.5f, // H
0.5f, -0.5f, -0.5f, // F
0.5f, -0.5f, -0.5f, // F
0.5f, -0.5f, 0.5f, // B
0.5f, 0.5f, 0.5f, // D
//Top Face
-0.5f, 0.5f, 0.5f, // C
0.5f, 0.5f, 0.5f, // D
-0.5f, 0.5f, -0.5f, // G
0.5f, 0.5f, 0.5f, // D
0.5f, 0.5f, -0.5f, // H
-0.5f, 0.5f, -0.5f, // G
};
class OpenGlFunctions
{
public:
OpenGlFunctions()
{
_createProgram = getFunction<PFNGLCREATEPROGRAMPROC>("glCreateProgram");
_attachShader = getFunction<PFNGLATTACHSHADERPROC>("glAttachShader");
_linkProgram = getFunction<PFNGLLINKPROGRAMPROC>("glLinkProgram");
_deleteShader = getFunction<PFNGLDELETESHADERPROC>("glDeleteShader");
_getProgramiv = getFunction<PFNGLGETPROGRAMIVPROC>("glGetProgramiv");
_getProgramInfoLog = getFunction<PFNGLGETPROGRAMINFOLOGPROC>("glGetProgramInfoLog");
_createShader = getFunction<PFNGLCREATESHADERPROC>("glCreateShader");
_shaderSource = getFunction<PFNGLSHADERSOURCEPROC>("glShaderSource");
_compileShader = getFunction<PFNGLCOMPILESHADERPROC>("glCompileShader");
_getShaderiv = getFunction<PFNGLGETSHADERIVPROC>("glGetShaderiv");
_getShaderInfoLog = getFunction<PFNGLGETSHADERINFOLOGPROC>("glGetShaderInfoLog");
_depthFunc = getFunction<PFNGLPATHCOVERDEPTHFUNCNVPROC>("glDepthFunc");
_enable = getFunction < void(*)(GLenum) > ("glEnable");
_uniform1i = getFunction<PFNGLUNIFORM1IPROC>("glUniform1i");
_uniform1f = getFunction<PFNGLUNIFORM1FPROC>("glUniform1f");
_clear = getFunction<PFNGLCLIENTATTRIBDEFAULTEXTPROC>("glClear");
_enableVertexAttribArray = getFunction<PFNGLENABLEVERTEXATTRIBARRAYPROC>("glEnableVertexAttribArray");
_disable = getFunction < void(*)(GLenum) > ("glDisable");
_vertexAttribPointer = getFunction<PFNGLVERTEXATTRIBPOINTERPROC>("glVertexAttribPointer");
_drawArrays = getFunction<PFNGLDRAWARRAYSEXTPROC>("glDrawArrays");
_useProgram = getFunction<PFNGLUSEPROGRAMPROC>("glUseProgram");
_getUniformLocation = getFunction<PFNGLGETUNIFORMLOCATIONPROC>("glGetUniformLocation");
_viewport = getFunction < void(*)(GLint, GLint, GLsizei, GLsizei) > ("glViewport");
_getIntegerv = getFunction<void (*)(GLenum, GLint *)>("glGetIntegerv");
_disableVertexAttribArray = getFunction<PFNGLDISABLEVERTEXATTRIBARRAYPROC>("glDisableVertexAttribArray");
}
PFNGLCREATEPROGRAMPROC _createProgram;
PFNGLATTACHSHADERPROC _attachShader;
PFNGLLINKPROGRAMPROC _linkProgram;
PFNGLDELETESHADERPROC _deleteShader;
PFNGLGETPROGRAMIVPROC _getProgramiv;
PFNGLGETPROGRAMINFOLOGPROC _getProgramInfoLog;
PFNGLCREATESHADERPROC _createShader;
PFNGLSHADERSOURCEPROC _shaderSource;
PFNGLCOMPILESHADERPROC _compileShader;
PFNGLGETSHADERIVPROC _getShaderiv;
PFNGLGETSHADERINFOLOGPROC _getShaderInfoLog;
PFNGLPATHCOVERDEPTHFUNCNVPROC _depthFunc;
void (*_enable)(GLenum);
PFNGLUNIFORM1IPROC _uniform1i;
PFNGLUNIFORM1FPROC _uniform1f;
PFNGLCLIENTATTRIBDEFAULTEXTPROC _clear;
PFNGLENABLEVERTEXATTRIBARRAYPROC _enableVertexAttribArray;
void (*_disable)(GLenum);
PFNGLVERTEXATTRIBPOINTERPROC _vertexAttribPointer;
PFNGLDRAWARRAYSEXTPROC _drawArrays;
PFNGLUSEPROGRAMPROC _useProgram;
PFNGLGETUNIFORMLOCATIONPROC _getUniformLocation;
void (*_viewport)(GLint, GLint, GLsizei, GLsizei);
void (*_getIntegerv)(GLenum, GLint*);
PFNGLDISABLEVERTEXATTRIBARRAYPROC _disableVertexAttribArray;
private:
template<class Type>
static Type getFunction(std::string const &procName)
{
if (auto funcPtr = SDL_GL_GetProcAddress(procName.c_str()))
{
return reinterpret_cast<Type>(funcPtr);
}
std::cout << procName << " is unavailable\n";
abort();
}
};
int createShader(std::string const &source, int type, OpenGlFunctions const &openGl)
{
GLuint const shaderID = openGl._createShader(type);
char const *psource = source.c_str();
openGl._shaderSource(shaderID, 1, &psource, nullptr);
openGl._compileShader(shaderID);
GLint success;
openGl._getShaderiv(shaderID, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE)
{
char error[1024];
openGl._getShaderInfoLog(shaderID, 1024, nullptr, error);
std::cout << "Error compiling shader: " << error << std::endl;
throw std::runtime_error(error);
}
return shaderID;
}
int createProgram(int vertexShaderID, int fragmentShaderID, OpenGlFunctions const &openGl)
{
auto programID = openGl._createProgram();
openGl._attachShader(programID, vertexShaderID);
openGl._attachShader(programID, fragmentShaderID);
openGl._linkProgram(programID);
openGl._deleteShader(vertexShaderID);
openGl._deleteShader(fragmentShaderID);
GLint success;
openGl._getProgramiv(programID, GL_LINK_STATUS, &success);
if (success == GL_FALSE)
{
char error[1024];
openGl._getProgramInfoLog(programID, 1024, nullptr, error);
std::cout << "Error compiling shader: " << error << std::endl;
throw std::runtime_error(error);
}
return programID;
}
template<class T>
using Uniform = std::pair<std::string, T>;
template<class U>
void apply(int programID, U &&u, OpenGlFunctions const &openGl)
{
openGl._uniform1f(openGl._getUniformLocation(programID, u.first.c_str()), u.second);
}
int main(int argc, char *argv[])
{
// Initialize SDL
SDL_Init(SDL_INIT_VIDEO);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
#ifdef _WINDOWS
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
#else
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
#endif
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
// Create a window
SDL_Window* window = SDL_CreateWindow("OpenGL Example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
// Create a renderer
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Clear the renderer
SDL_RenderClear(renderer);
auto texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 400, 400);
OpenGlFunctions openGl;
openGl._depthFunc(GL_LESS);
// openGl._enable(GL_DEPTH_TEST);
auto programID = createProgram(createShader(_vert, GL_VERTEX_SHADER, openGl),
createShader(_frag, GL_FRAGMENT_SHADER, openGl), openGl);
float x = 0.0f;
float y = 0.0f;
// Wait for a key press to exit
bool quit = false;
SDL_Event event;
while (!quit)
{
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
SDL_RenderClear(renderer);
SDL_RenderFlush(renderer);
SDL_SetRenderTarget(renderer, texture);
// get previous context
int previousProgramID;
int previousViewport[4]; // x y w h
int previousBlendEnabled;
openGl._getIntegerv(GL_CURRENT_PROGRAM, &previousProgramID);
openGl._getIntegerv(GL_VIEWPORT, (GLint*) &previousViewport);
openGl._getIntegerv(GL_BLEND, &previousBlendEnabled);
openGl._clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
openGl._useProgram(programID);
apply(programID, Uniform<float>("angleX", x), openGl);
apply(programID, Uniform<float>("angleY", y), openGl);
// Update the screen
openGl._viewport(0, 0, 400, 400);
openGl._enableVertexAttribArray(0);
openGl._disable(GL_BLEND);
openGl._vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, _vertices);
openGl._drawArrays(GL_TRIANGLES, 0, 36);
openGl._disableVertexAttribArray(0);
// restore previous context
openGl._useProgram(previousProgramID);
openGl._viewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]);
if (previousBlendEnabled)
{
openGl._enable(GL_BLEND);
}
SDL_SetRenderTarget(renderer, nullptr);
SDL_Rect r;
r.x = 100;
r.y = 100;
r.w = 400;
r.h = 400;
SDL_RenderCopy(renderer, texture, nullptr, &r);
SDL_RenderPresent(renderer);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
else if (event.type == SDL_KEYDOWN)
quit = true;
else if (event.type == SDL_MOUSEMOTION && event.motion.state == SDL_PRESSED)
{
x += event.motion.yrel;
y += event.motion.xrel;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(16)); //give some time
}
// Cleanup and quit
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
With this I can see the cube and rotate it. Howver when I uncomment the line: //openGl._enable(GL_DEPTH_TEST);
I don’t see anything. Why?
However if I don’t use the texture and the renderScope is null the GL_DEPTH_TEST
will work, but I really want to use a texture to facilitate the integration with my application.
Thank you.