Так что мне удалось создать карты теней для направленного света (расширенный на бесконечности). Теперь я пытаюсь создать точечный светлый куб с тенями, чтобы тени распространялись в направлении света-> фрагмент. Я создал новый FBO так:
//gen new fbo
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
//gen color texture
glGenTextures(1, &texture_color);
glBindTexture(GL_TEXTURE_2D, texture_color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
//gen cubemap
glGenTextures(1, &shadow_cubemap);
glBindTexture(GL_TEXTURE_2D_ARRAY, shadow_cubemap);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
//bind color texture
unsigned int attachment_index_color_texture = 0;
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+attachment_index_color_texture, texture_color,0);
//add attachments
std::vector<GLenum> drawbuffers;
drawbuffers.push_back(GL_COLOR_ATTACHMENT0+attachment_index_color_texture);
glDrawBuffers(drawbuffers.size(),&drawbuffers[0]);
//check the fbo state
if(glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE){
std::cout<<"Error.FBO not integral."<<std::endl;
std::cin.get();
std::terminate();
}
//Unbind
glBindFramebuffer(GL_FRAMEBUFFER,0);
Эта функция вызывается после изменения формы (так можно сказать, во время инициализации). Изменение формы вызывается один раз при запуске программы.
Затем я создаю свои матрицы light_view, каждое представление для отдельной грани куба и свою матрицу проекции следующим образом:
//view matrix for +x
lightView_matrix[0]=glm::lookAt(light_position,light_position+glm::vec3(1,0,0),glm::vec3(0,1,0));
//view_matrix for -x
lightView_matrix[1]=glm::lookAt(light_position,light_position+glm::vec3(-1,0,0),glm::vec3(0,1,0));
//view_matrix for +z
lightView_matrix[2]=glm::lookAt(light_position,light_position+glm::vec3(0,0,1),glm::vec3(0,1,0));
//view_matrix for -z
lightView_matrix[3]=glm::lookAt(light_position,light_position+glm::vec3(0,0,-1),glm::vec3(0,1,0));
//view_matrix for +y
lightView_matrix[4]=glm::lookAt(light_position,light_position+glm::vec3(0,1,0),glm::vec3(0,0,-1));
//view_matrix for -y
lightView_matrix[5]=glm::lookAt(light_position,light_position+glm::vec3(0,-1,0),glm::vec3(0,0,1));
lightProjection_matrix = glm::perspective(90.0f, 1.0f, 0.5f, 140.0f);
Матрица проекции в порядке? Должна ли быть перспектива при создании кубической карты вместо ортографической, как я сделал для направленного света? Я не знаю, в порядке ли значения: вот то, что у меня есть, ширина и высота текстуры — 1366 x 768, что является размером моего окна, вся моя сцена — от -70 до 70 по оси z, так что всего 140 Я выбрал поле зрения пи / 4.
Переходим к первому этапу — будем надеяться, что получим 6 граней кубической карты:
cube_fbo.bind();
{
for(int i=0;i<6;i++){
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_fbo.shadow_cubemap, 0);
//clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//use shader
glUseProgram(program_shader);
//send uniform values
glUniformMatrix4fv(glGetUniformLocation(program_shader,"light_view_matrix"),1,false,glm::value_ptr(lightView_matrix[i]));
glUniformMatrix4fv(glGetUniformLocation(program_shader,"light_projection_matrix"),1,false,glm::value_ptr(lightProjection_matrix));
//draw my objects with textures,i also have an alpha texture hence the has_alpha in the shaders (will post below )
}
}
//unbind fbo
cube_fbo.unbind();
Теперь второй проход, который должен рисовать тени на основе позиции фрагмента (я должен сделать это в функции рисования или в шейдере?)
{
//clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program_shadow);
//send uniform values
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"view_matrix"),1,false,glm::value_ptr(view_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"projection_matrix"),1,false,glm::value_ptr(projection_matrix));glUniformMatrix4fv(glGetUniformLocation(program_shadow,"light_view_matrix"),1,false,glm::value_ptr(light_view_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"light_projection_matrix"),1,false,glm::value_ptr(light_projection_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"BiasMatrix"),1,false,glm::value_ptr(BiasMatrix));
glUniform3f(glGetUniformLocation(program_shadow,"light_position"),light_position.x,light_position.y,light_position.z);
//sphere at light position for reference------------------------
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(light_model_matrix));
lab::drawSolidSphere(2,6,6);
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
//ground----------------------------
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(ground_model_matrix));
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, ground_texture);
glUniform1i( glGetUniformLocation(program_shadow, "textura1"), 1 );
glUniform1i( glGetUniformLocation(program_shadow, "has_alpha"), 0);
//glDisable(GL_CULL_FACE);
//send cubemap texture(GLuint bound in the first part (shadow_cubemap))
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_fbo[0].getCubeMapTexture());
glUniform1i(glGetUniformLocation(program_shadow, "textura_depth"), 2);
glBindVertexArray(ground_vao);
glDrawElements(GL_TRIANGLES, ground_num_indices, GL_UNSIGNED_INT, 0);
//bamboo(s)----------------------------
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, bamboo_texture_color);
glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, bamboo_texture_alpha);
glUniform1i( glGetUniformLocation(program_shadow, "textura1"), 1 );
glUniform1i( glGetUniformLocation(program_shadow, "textura2"), 2 );
glUniform1i( glGetUniformLocation(program_shadow, "has_alpha"), 1);
//send cubemap texture
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, cube_fbo[0].getCubeMapTexture());
glUniform1i(glGetUniformLocation(program_shadow, "textura_depth"), 3);
glBindVertexArray(bamboo_vao);
for(int i=0;i<10;i++) for(int j=0;j<10;j++) {
if(j==5){
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(bamboo_model_matrix[i*10+j]));
glDrawElements(GL_TRIANGLES, bamboo_num_indices, GL_UNSIGNED_INT, 0);
}
}
}
Как вы можете видеть в этой последней части, я рисую с позиции камеры и перехожу к шейдеру, который кубическая карта генерирует с первого прохода. У меня есть несколько недоразумений и, возможно, некоторые ошибки до этого момента.
Что я возвращаю с первого прохода (из шейдера), когда я сделал отображение теней для направленного света, я возвратил глубину (glFragcoord.z), но теперь я должен вернуть направление vec3? Как мне это вычислить. Нужно ли что-то еще для передачи в шейдер?
Вторая часть в порядке? Должен ли я просто нарисовать объекты и передать кубическую карту шейдеру и позволить ему вычислить, какой фрагмент находится относительно света? Если так, как я могу вычислить это?
Вот мой шейдер для первого прохода (поэтому сгенерируйте кубическую карту из 6 легких видов):
#version 330 /*VERTEX SHADER*\
layout(location = 0) in vec3 in_position;
layout(location = 2) in vec2 in_texcoord;
uniform mat4 model_matrix;
uniform mat4 light_view_matrix,light_projection_matrix;
out vec2 texcoord;
out vec4 v_position;
void main(){
texcoord = in_texcoord;
gl_Position = light_projection_matrix*light_view_matrix*model_matrix*vec4(in_position,1);}
#version 330 /*FRAGMENT SHADER*\layout(location = 0) out vec4 out_color;
//layout(location = 1) out float depth;
uniform sampler2D textura1;
uniform sampler2D textura2;
uniform int has_alpha;
in vec2 texcoord;
in vec4 v_position;
void main(){vec3 tex1 = texture(textura1, texcoord).xyz;
vec3 tex2 = texture(textura2, texcoord).xyz;
if(has_alpha>0.5) if((tex2.r<0.1) && (tex2.g<0.1) && (tex2.b<0.1)) discard;
out_color = vec4(tex1, 1);
}
И шейдер для второго прохода (пытался вычислить тень, получая vec3 из положения пикселя в мировом пространстве — положения света в мировом пространстве)
#version 330 core /*VERTEX SHADER*\
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_texcoord;
out vec3 lightPosw;
out vec3 pixelPosw;
out vec2 texcoord;
uniform mat4 model_matrix,view_matrix,projection_matrix;
uniform vec3 light_position;
void main(){
texcoord=in_texcoord;
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);
lightPosw= (model_matrix * vec4(light_position,1)).xyz;
pixelPosw = (model_matrix * vec4(in_position, 1)).xyz;
}
#version 330 core /*FRAGMENT SHADER*\
in vec3 lightPosw;
in vec3 pixelPosw;
in vec2 texcoord;
out vec4 out_color;
uniform samplerCube textura_depth;
uniform sampler2D textura1,textura2;
uniform mat4 view_matrix,model_matrix;
uniform int has_alpha;void main(){
vec3 lightToPixel=pixelPosw-lightPosw;
vec3 tex1 = texture(textura1, texcoord).xyz;
vec3 tex2 = texture(textura2, texcoord).xyz;
if(has_alpha>0.5) if((tex2.r<0.1) && (tex2.g<0.1) && (tex2.b<0.1)) discard;
float shadowDepth = texture(textura_depth, normalize(lightToPixel));
float shadowFactor=1.0;
if(length(lightToPixel) < shadowDepth)
shadowFactor=0.5;
out_color = vec4(tex1*shadowFactor,1);
}
Извините за стену кода, я хотел опубликовать все соответствующие материалы, чтобы я мог получить лучшую помощь. Моя проблема в том, что все отрисовывается полушерным, потому что я установил выходной цвет в фрагментном шейдере на 0,5, а если нет, то все будет рендерить черный.
Задача ещё не решена.
Других решений пока нет …