我對OpenGL ES相當陌生,我試圖給當前場景添加一些陰影。我決定在cubemap的幫助下做到這一點。我使用的是OpenGL ES 2.0,因此我無法使用幾何着色器或gl_FragDepth變量。我搜索了一些,所以我對該主題有了一些見解,並且閱讀(http://www.cg.tuwien.ac.at/courses/Realtime/repetitorium/2010/OmnidirShadows.pdf)證明非常有用。基本上我依靠這個鏈接的文檔。Opengl-es 2.0與立方體貼圖的陰影映射
但是我的代碼有些問題,因爲渲染場景中的每個像素都在陰影之下。我認爲這個問題可以在我的着色器中找到,但我在這裏粘貼我所有的相關代碼,以清楚地看到一切。
設置幀緩衝和創建立方體貼圖:
GLuint FBO;
GLuint cubeTexture;
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
// Depth texture
glGenTextures(1, &cubeTexture);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // no GL_TEXTURE_WRAP_R
// right, left, top, bottom, front, back
for (int face = 0; face < 6; ++face) {
// create space for the textures, content need not to be specified (last parameter is 0)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT16, 1024, 768, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
}
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
在顯示功能,我儘量做到6渲染過程,填補了陰影貼圖(立方體的6面)。
渲染:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepthf(1.0f);
glm::vec3 camPos = ... // position of the camera, it is in world space
glm::vec4 lightPos = ... // position of the light source, it is in world space
// 1. render into texture
float zNear = 0.1f;
float zFar = 100.0f;
// or should I use ortho instead of perspective?
glm::mat4 projMatrix = glm::perspective(90.0f, (float)esContext->width/esContext->height, zNear, zFar);
// The 6 cameras have to be placed to the light source and they need the proper view matrices
glm::mat4 cubeMapMatrices[6]; // contains six basic and defined rotation matrices for the six directions
cubeMapMatrices[0] = glm::make_mat4(rotPositiveX);
cubeMapMatrices[1] = glm::make_mat4(rotNegativeX);
cubeMapMatrices[2] = glm::make_mat4(rotPositiveY);
cubeMapMatrices[3] = glm::make_mat4(rotNegativeY);
cubeMapMatrices[4] = glm::make_mat4(rotPositiveZ);
cubeMapMatrices[5] = glm::make_mat4(rotNegativeZ);
glm::vec4 translation = lightPos;
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
for (int face = 0; face < 6; ++face) {
glClear(GL_DEPTH_BUFFER_BIT); // do I need this here?
cubeMapMatrices[face][3] = translation; // the translation part is the same for all
cubeMapMatrices[face] = projMatrix * cubeMapMatrices[face]; // now it's an mvp matrix
glUniformMatrix4fv(cubeProjectionMatrixID, 1, GL_FALSE, glm::value_ptr(cubeMapMatrices[face]));
// Attach depth cubemap texture to FBO's depth attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubeTexture, 0);
int err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (err != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "Framebuffer error, status: " << err << std::endl;
}
RenderScene(); // do the drawing
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 2. render into screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RenderScene(); // do the drawing
// swap the buffers
所以來這裏不同的着色器。我有一個頂點着色器和一個片段着色器用於深度計算,一個頂點着色器和一個片段着色器用於屏幕渲染。我的問題是我不確定如何寫入立方體貼圖,如果幀緩衝區正在使用中,那麼gl_Position會確定給定立方體面的座標嗎?用於深度計算
頂點着色器:用於深度計算
in vec3 vPosition;
uniform mat4 mModel;
uniform mat4 mCubeProjection;
uniform vec4 vLight;
out vec4 vFrag Position; // world space
out vec4 vLightPosition; // mvp transformed
void main()
{
vec4 position = vec4(vPosition, 1.0);
vFragPosition = mModel* position;
vLightPosition = vLight;
gl_Position = mCubeProjection * vFragPosition;
}
片段着色器:
in vec4 vFragPosition; // world space
in vec4 vLightPosition; // world space
out float depthValue;
void main()
{
depthValue = distance(vFragPosition.xyz, vLightPosition.xyz); // need normalization?
}
頂點着色器用於渲染到屏幕上:
uniform mat4 mModel;
uniform mat4 mView;
uniform mat4 mProjection;
uniform vec4 vLight; // it is in world space
out vec3 lw; // light position in world space
out vec3 pw; // pixel position in world space
void main()
{
vec4 position = vec4(vPosition, 1.0);
lw = vLight.xyz;
pw = (mModel* position).xyz;
gl_Position = mProjection* mView * mModel* position;
}
顯示到屏幕片段着色器:
in vec3 lw;
in vec3 pw;
uniform samplerCube cubeMap;
out vec4 outputColor;
void main()
{
vec3 lookup = pw - lw;
float smValue = texture(cubeMap, lookup).r; // retrieves texels from a texture (d, d, d, 1.0)
float distance = length(lookup); // dist from the fragment to the light
float eps = 0.1;
float shadowVal = 1.0;
if (smValue + eps < distance) {
shadowVal = 0.1; // in shadow
}
// here comes the lighting stuff
// ...
outputColor = outputColor * shadowVal;
}
如此反覆,問題是,每個像素下的陰影下降。從代碼中我排除了一些統一傳遞給着色器,但它們都可以。你能給我一個建議,我應該在代碼中修復什麼?我的着色器(特別是第一遍)是否正確,我是否正確設置了立方體映射的轉換?謝謝。
P.S:這是我的第一個問題,我希望它足夠清楚,並且滿足正確發佈的問題的要求。
感謝您的回答。選項3不是一個選項,因爲gl_FragDepth在es 2.0中不可訪問。正如你所建議我去選項2. – Terrordrone
我改變了相關行glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +面,0,GL_RGB,1024,768,0,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,0);和glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,cubeTexture,0);但我仍然只有0,當我在第二個片段着色器中調用'紋理'功能。對不起,格式不好。 – Terrordrone
我有類似的情況,我發現一些奇怪的東西。如果我只寫gl_FragDepth並且不在shadow fs中輸出任何內容,那麼看起來立方體貼圖根本不會得到任何東西。如果我要寫長度,我可以看到它被正確寫入紅色(我還附加了一個顏色附件)。這是爲什麼發生? – ChaoSXDemon