Autor Wątek: Błąd bindowania UBO  (Przeczytany 875 razy)

Offline Novi

  • Użytkownik

# Wrzesień 18, 2016, 16:25:21
Cześć, mam problem z bindowaniem kilku UBO.
Pierwsze UBO (zawiera macierze mvp itp.):
Camera::Camera()
{
//...

//Tworzę pierwsze UBO w konstruktorze klasy Camera
glGenBuffers(1, &UBO);
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
glBufferData(GL_UNIFORM_BUFFER, sizeof(transform), &transform, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, UBO);
}

void Camera::BindBuffer(const GLuint& program, const GLuint& index) const
{
// Binduję pierwsze UBO
glUniformBlockBinding(program, glGetUniformBlockIndex(program, "Transform"), index);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, UBO);
}

gdzie transform wygląda tak:
mutable struct
{
math::Matrix4f viewProjectonMatrix;
math::Matrix4f viewMatrix;
math::Vector3f position;
} transform;



Drugie UBO (zawiera informacje o świetle):
GameEngine::Light::Light() : blockIndex(0)
{
Init();
}
GameEngine::Light::Light(const GLuint& blockIndex) : blockIndex(blockIndex)
{
Init();
}
GLvoid GameEngine::Light::Init()
{
directionalLight.Color = math::Vector3f(1.0f, 1.0f, 1.0f);
directionalLight.Direction = math::Vector3f(0.0f, 0.0f, -1.0f);
directionalLight.AmbientIntensity = 1.2f;;
directionalLight.DiffuseIntensity = 1.0f;
directionalLight.SpecularIntensity = 1.0f;
directionalLight.SpecularPower = 1.0f;

//Tworzę drugie UBO (klasy Light)
glGenBuffers(1, &directionalLightLocation);
glBindBuffer(GL_UNIFORM_BUFFER, directionalLightLocation);
glBufferData(GL_UNIFORM_BUFFER, sizeof(directionalLight), &directionalLight, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, directionalLightLocation);

//...
}

GLvoid GameEngine::Light::BindBuffer(const GLuint& program) const
{
// Binduję drugie UBO
glUniformBlockBinding(program, glGetUniformBlockIndex(program, "Light"), blockIndex);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, directionalLightLocation);
}

gdzie directionalLight wygląda tak:
struct DirectionalLight
{
math::Vector3f Color;
math::Vector3f Direction;

GLfloat AmbientIntensity;
GLfloat DiffuseIntensity;

GLfloat SpecularIntensity;
GLfloat SpecularPower;
};

DirectionalLight directionalLight;


A wywołanie metod bindujących wywołuję w klasie Terrain:
camera->BindBuffer(**terrainPO);
light.BindBuffer(**terrainPO);

Problem w tym, że directonalLight nie jest widoczne w shaderach.
Tak wyglądają bloki w shaderach:
// vertex shader - brak bloku Light
layout(std140) uniform Transform
{
mat4 vpMatrix;
mat4 vMatrix;
vec3 eyeWorldPosition;
};


// fragment shader
layout(std140) uniform Transform
{
mat4 vpMatrix;
mat4 vMatrix;
vec3 eyeWorldPosition;
};

layout(std140) uniform Light
{
vec3 Color;
vec3 Direction;

float AmbientIntensity;
float DiffuseIntensity;

float SpecularIntensity;
float SpecularPower;
};

Test przeprowadziłem mnożąc kolor fragmentu przez SpecularPower - musi wynosić 0.0, zamiast 1.0 jak to zostało ustawione.
"uniform Transform" wszystko jest ok, gdy jednak zbinduję najpierw Light, potem Transform, "uniform Transform" będzie miało błędne wartości ...

W czym jest problem?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Dab

  • Moderator
    • blog

# Wrzesień 19, 2016, 10:18:06
Ile bajtów ma math::Vector3f? Jeżeli 12 (3 x float) to struktura się rozjedzie między C++ a OpenGL, bo std140 zakłada 16 bajtów na vec3 (If the member is a three-component vector with components consuming N basic machine units, the base alignment is 4N). Najprostsze rozwiązanie to dodanie paddingu po stronie C++, chociaż dla własnego spokoju użyłbym wszędzie po prostu vec4, żeby nie trafić kiedyś na dziwny bug w źle napisanym driverze. :)

[edit] + dodatkowo, glBindBufferBase też potrzebuje indeksu UBO, jeżeli chcesz używać kilku.

Offline Novi

  • Użytkownik

# Wrzesień 19, 2016, 18:03:19
Jestem własnie po lekturze z UBO (miałem braki) - binduje sie juz ok, tylko dane się rozjeżdżają (wyrównanie), tak jak pisałeś :)
« Ostatnia zmiana: Wrzesień 19, 2016, 18:05:27 wysłana przez Novi »