Shadow Mapping не работает в OpenGL ES 3.0 на Android
Я пытаюсь реализовать отображение теней в своем проекте почти неделю, и ни один из методов, похоже, не работает. Текстура карты глубины кажется пустой.
Я копал весь интернет, и ничто не помогло мне. Может быть, я что-то упустил в своем коде.
Здесь я начну с создания текстуры FBO и карты глубины:
// create depthMap
int[] depthMapPtr = new int[1];
GLES30.glGenTextures(1, depthMapPtr, 0);
depthMap = depthMapPtr[0];
// use depthMap
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, depthMap);
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH_COMPONENT16, size, size,
0, GLES30.GL_DEPTH_COMPONENT, GLES30.GL_UNSIGNED_SHORT, null);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
// create fbo
int[] fboPtr = new int[1];
GLES30.glGenFramebuffers(1, fboPtr, 0);
fbo = fboPtr[0];
// use fbo
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo);
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER,
GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, depthMap, 0);
// draw/read buffers
int[] buffer = {GLES30.GL_NONE};
GLES30.glDrawBuffers(1, buffer, 0);
GLES30.glReadBuffer(GLES30.GL_NONE);
Затем я определяю глубинные шейдеры для рендеринга моей сцены:
ВЕРТЕКС ШЕЙДЕР ДЛЯ ГЛУБИНЫ:
#version 300 es
layout (location = 0) in vec3 vPos;
uniform mat4 mLightSpace;
uniform mat4 mModel;
void main()
{
gl_Position = mLightSpace * mModel * vec4(vPos, 1.0);
}
ФРАГМЕНТНАЯ ШЕЙДЕР ДЛЯ ГЛУБИНЫ:
#version 300 es
//out float fragDepth;
void main()
{
//fragDepth = gl_FragCoord.z;
}
(комментарии ничего не меняют, результат тот же).
Перед рендерингом сцены с теневой перспективы, я использую этот фрагмент кода, чтобы изменить viewPort, очистить буфер глубины, связать FBO:
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
// clear the depth
GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT);
GLES30.glViewport(0, 0, size, size);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo);
// use the shader program for the shadows
useProgramShadow();
После того, как я закончу рендеринг глубины, я готовлю все, чтобы сделать сцену обычным способом:
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
GLES30.glViewport(0, 0, GLWindow.width, GLWindow.height);
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, depthMap);
useProgram();
Затем я передаю все униформы + матрицу вида / проекции с точки зрения света и отрисовываю сцену.
Я нахожу положение фрагмента с точки зрения света в вершинном шейдере с такими линиями:
const mat4 tMat = mat4(
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
);
/* ... */
vFragPosLight = tMat * mLightSpace * mModel * vec4(vPosition, 1.0);
Чтобы потом получить vFragPosLight
и depthMap
текстура
in vec4 vFragPosLight;
uniform sampler2DShadow depthMap;
... в фрагментном шейдере и вычислите тень с помощью этой строки:
textureProj(depthMap, vFragPosLight);
... который всегда возвращает 0!
Нет ошибок при компиляции шейдеров, нет ошибки привязки текстуры к фреймбуферу, похоже, все работает, find, но глубина Map пуста.
Я очень ценю вас за вашу помощь и спасибо, что нашли время, чтобы прочитать!
3 ответа
Я до сих пор не знаю, в чем именно заключалась проблема, но я прочитал и использовал часть Shadow Mapping в этой книге об OpenGL ES 3.0, которая работала.
Вполне возможно, что мне пришлось отключить все компоненты цветопередачи с glColorMask, установленным в False.
Вы должны очистить буфер глубины кадрового буфера (текстура глубины). Сначала свяжите кадровый буфер с вложением текстуры глубины, затем очистите буфер глубины. Это приводит к тому, что текстура глубины очищается перед рендерингом:
Очистите "теневой" буфер перед рендерингом карты теней
GLES30.glViewport(0, 0, size, size);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo);
GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT);
// use the shader program for the shadows
useProgramShadow();
Обратите внимание, что начальное значение для очистки буфера глубины равно 1 (см. glClearDepth
). По умолчанию это максимальная глубина. Это приводит к тому, что фрагменты, глубина которых меньше 1, проходят проверку глубины, потому что функция глубины по умолчанию GL_LESS
(Увидеть glDepthFunc
).
при создании буфера кадра необходимо проверить, успешно ли создан буфер кадра.
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// set up hardware comparison
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC,
GL_LEQUAL);
//android use GL_DEPTH_COMPONENT16
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT,
GL_UNSIGNED_SHORT,
NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &mDepthFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mDepthFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
glDrawBuffers(1, GL_NONE);
glReadBuffer(GL_NONE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);
if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
LOGI("frame buffer success");
} else {
LOGI("frame buffer fail");
}
У меня такая же проблема с вами, наконец, я обнаружил причину сбоя создания фреймбуфера, поэтому я исправил GL_DEPTH_COMPONENT на GL_DEPTH_COMPONENT16, успех фреймбуфера и карта глубины в порядке!