Witam,
chciałbym żeby moje renderowanie było na osobnym wątku.
Okno oraz kontekst tworzę przy pomocy biblioteki SDL2, a za funkcje opengl odpowiada glew
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL);
glContext = SDL_GL_CreateContext(window);
initContext = SDL_GL_CreateContext(window);
glewExperimental = true;
glewInit();
w taki sposób chciałbym wykonać to renderowanie w wątku
void mainloop()
{
std::thread* thread = nullptr;
std::mutex mutex;
Cube cube;
std::lock_guard<std::mutex> guard(mutex);
thread = new std::thread([&]() {
while (!quit) {
SDL_GL_MakeCurrent(window, glContext);
glCall(glClearColor(0, 0, static_cast<float>(15) / 255, 1));
glCall(glClear(GL_COLOR_BUFFER_BIT));
cube.Render({ 1280.0f, 720.0f });
SDL_GL_SwapWindow(window);
}
});
}
buffory są tworzone przez klasę Buffor, która jest matką klasy GLBuffor i metodę Create(), która zwraca stworzony pointer
Buffor* vbo = nullptr;
Cube()
{
vbo = vbo->Create();
}
//rodzaj bufora, czy to array, czy to element array | sposób użycia - static draw, dynamic draw, copy itd.
Buffer* Buffer::Create(BUFFOR buffor, USAGE usage)
{
//Konstruktor GLBuffor wywołuje glGenBuffers i glBindBuffer dla odpowiedniego buffora
retrun new GLBuffor(buffor, usage);
}
shader działa bardzo podobnie:
class Shader
{
public:
Shader* Create()
{
//ctor GLShadera wywołuje Begin()
return new GLShader();
}
//klasa GLShader nadpisuje Begin() i wywołuje w tej metodzie glCreateProgram(...)
virtual void Begin() {}
//tworzy shader o podanym typie - wywołuje glCreateShader, glShaderSource, glCompileShader i glAttachShader
//wynik końcowy chcemy zapisać do tablicy, razem na przykład z shaderem fragmentów, którą potem podamy do metody End
virtual int ShaderFromSource(const char* shader, SHADER type) {}
//Bierze tablice z shaderami i wywołuje - glLinkProgram
virtual void End(const int* shaders, int count) {}
}
Shadery oraz buffory są tworzone w konstruktorze klasy Cube
, konstruktor jest wywoływany w głównym wątku (czyli nie w tym renderującym).
metoda Cube::Render(...)
potrzebuje mieć dostęp do tych buforów i shaderów stworzonych w konstruktorze - żeby użyć takich rzeczy jak Shader::UseProgram()
- czyli proste glUseProgram(...)
, Shader::UniformXXX(....)
czy nawet DrawArrays(...)
czy DrawElements(...)
.
Gdy wywołuje Cube::Render(...)
w wątku renderującym, wyskakuje mi
dokładnie klasa Cube
wygląda tak
class Cube
{
public:
Cube();
~Cube();
void Render(const Vector2& windowSize);
VertexArray* vao = nullptr,
* lightVao = nullptr;
Buffer* vbo = nullptr;
Shader* shader = nullptr;
Camera camera;
};
Cube::Cube()
{
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
vao = vao->Create();
vbo = vbo->Create(Array_Buffer, Static_Draw);
vbo->AddData(sizeof(vertices), vertices);
vbo->AddAttribute(0, 3, FLOAT, false, 6 * sizeof(float), (const void*)(0));
vbo->AddAttribute(1, 3, FLOAT, false, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
lightVao = lightVao->Create();
vbo->BindBuffer();
vbo->AddAttribute(0, 3, FLOAT, false, 6 * sizeof(float), 0);
shader = shader->Create();
const int shaders[2] = {
shader->ShaderFromSource(vs, VERTEX),
shader->ShaderFromSource(fs, FRAGMENT)
};
shader->End(shaders, 2);
}
void Cube::Render(const Vector2& windowSize)
{
struct Material
{
Vector3 ambient{ 1.0f, 0.5f, 0.31f }, diffuse{ 1.0f, 0.5f, 0.31f }, specular = 0.5f;
int shininess = 32;
} static material;
struct Light {
Vector3 ambient = 0.2f, diffuse = 0.5f, specular = 1.0f;
} static light;
shader->UseProgram();
Vector3 lightPosition{ 0.0f, 0.0f, 0.0f };
shader->Uniform3fv("lightPosition", 1, &lightPosition.x);
Vector3 viewPosition = 0.0f;
shader->Uniform3fv("viewPosition", 1, &camera->Position.x);
Vector3 objectColor{ 1.0f, 0.5f, 0.31f };
shader->Uniform3fv("objectColor", 1, &objectColor.x);
Vector3 lightColor{ 1.0f, 1.0f, 1.0f };
shader->Uniform3fv("lightColor", 1, &lightColor.x);
shader->Uniform3fv("material.ambient", 1, &material.ambient.x);
shader->Uniform3fv("material.diffuse", 1, &material.diffuse.x);
shader->Uniform3fv("material.specular", 1, &material.specular.x);
shader->Uniform1f("material.shininess", static_cast<float>(material.shininess));
shader->Uniform3fv("light.ambient", 1, &light.ambient.x);
shader->Uniform3fv("light.diffuse", 1, &light.diffuse.x);
shader->Uniform3fv("light.specular", 1, &light.specular.x);
Mat4 projection = Mat4(1.0f);
projection = glm::perspective(45.0f, ratio, 0.001f, 1000.0f);
Mat4 view = Mat4(1.0f);
view = camera->GetViewMatrix();
Mat4 model = Mat4(1.0f);
{
Mat4 rotate = Rotate(-(SDL_GetTicks() / 100.0f), Vector3(0.0f, 1.0f, 0.0f));
model = rotate;
}
Mat4 mvp = Mat4(1.0f);
mvp = projection * view * model;
shader->UniformMatrix4fv("u_camera", mvp);
shader->UniformMatrix4fv("u_model", model);
shader->UniformMatrix4fv("u_normalModel", glm::transpose(glm::inverse(model)));
shader->Uniform1i("index", 0);
vao->DrawArrays(Triangles, 0, 36);
model = Mat4(1.0f);
{
Mat4 traslate = Translate(lightPosition);
Mat4 scale = Scale(Vector3(0.2f));
model = traslate * scale;
}
mvp = projection * view * model;
shader->UniformMatrix4fv("u_camera", mvp);
shader->Uniform1i("index", 1);
lightVao->DrawArrays(Triangles, 0, 36);
}
Dlaczego tak się dzieje? W jaki sposób mogę to naprawić?