2013-08-21 110 views
0

我正在嘗試編寫一個簡單的陰影映射引擎,它使用兩個分離且不同的着色器,分別使用OpenGL和LWJGL。它完全使用VAO/VBO。相機旋轉時出現問題。就像陰影旋轉兩倍於相機一樣。OpenGL陰影映射雙着色器

我首先在原點創建一個簡單的立方體,並在立方體下面創建一個2D平面。

[代碼由於省略以長度]

我然後創建一個「太陽」(可移動一段時間內),它使用正投影來創建陰影圖。

光源投影矩陣(接近爲1,遠爲100):

lightMatrixStore.getProjectionMatrix().m00 = 1; 
lightMatrixStore.getProjectionMatrix().m11 = 1; 
lightMatrixStore.getProjectionMatrix().m22 = -2f/(100-1); 
lightMatrixStore.getProjectionMatrix().m23 = -((100+1f)/(100-1f)); 
lightMatrixStore.getProjectionMatrix().m33 = 1; 
lightMatrixStore.getProjectionMatrix().m32 = 0; 

設置幀緩衝器/渲染/質地:

depthTextureId = glGenTextures(); 
glBindTexture(GL_TEXTURE_2D, depthTextureId); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

glTexParameteri(GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.5f); 
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 

glTexImage2D(
     GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapWidth, shadowMapHeight, 0, 
     GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, (ByteBuffer) null 
); 
glBindTexture(GL_TEXTURE_2D, 0); 
shadowMapWidth = 2048; 
shadowMapHeight = 768*2; 

rboId = glGenRenderbuffers(); 
glBindRenderbuffer(GL_RENDERBUFFER, rboId); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, shadowMapWidth, shadowMapHeight); 

fboId = glGenFramebuffers(); 
glBindFramebuffer(GL_FRAMEBUFFER, fboId); 

glDrawBuffer(GL_NONE); 
glReadBuffer(GL_NONE); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTextureId, 0); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboId); 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

int fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
if (fboStatus != GL_FRAMEBUFFER_COMPLETE) { 
    System.err.print("Framebuffer error " + fboStatus + " : " + gluErrorString(glGetError())); 
} 

陰影圖頂點着色器:

#version 150 core 

uniform mat4 projectionMatrix; 
uniform mat4 viewMatrix; 
uniform mat4 modelMatrix; 

in vec4 in_Position; 
in vec4 in_Color; 
in vec2 in_TextureCoord; 

out vec4 pass_Color; 
out vec2 pass_TextureCoord; 

void main(void) { 
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position; 
    pass_Color = in_Color; 
    pass_TextureCoord = in_TextureCoord; 
} 

和陰影貼圖着色器:

#version 150 core 

uniform sampler2D texture_diffuse; 

in vec4 pass_Color; 
in vec2 pass_TextureCoord; 

out vec4 out_Color; 

void main(void) { 
    out_Color = pass_Color; 
} 

該程序從光線的角度呈現場景並創建陰影貼圖,然後第二個渲染通道進行環境光照,鏡面光照和陰影嘗試。

最後的頂點着色器:

#version 150 core 

varying vec4 varyingVertex; 
varying vec4 projectionVertex; 
varying vec3 varyingNormal; 
varying vec3 varyingPosition; 
varying vec4 shadowCoord; 

uniform mat4 projectionMatrix; 
uniform mat4 viewMatrix; 
uniform mat4 modelMatrix; 
uniform mat4 lightViewMatrix; 
uniform mat4 lightProjectionMatrix; 

in vec4 in_Position; 
in vec4 in_Color; 
in vec2 in_TextureCoord; 
in vec3 in_Normal; 

out vec4 pass_Color; 
out vec2 pass_TextureCoord; 

void main() { 
    varyingVertex = in_Position; 
    varyingNormal = in_Normal; 
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position; 
    varyingPosition = gl_Position; 

    pass_Color = in_Color; 
    pass_TextureCoord = in_TextureCoord; 
    shadowCoord = 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) * lightProjectionMatrix * lightViewMatrix *  inverse(viewMatrix) * modelMatrix * in_Position; 
} 

最後片段着色器:

#version 150 

uniform sampler2D ShadowMap; 

varying vec4 varyingVertex; 
varying vec4 projectionVertex; 
varying vec3 varyingNormal; 
varying vec3 varyingPosition; 
varying vec4 shadowCoord; 

uniform mat4 projectionMatrix; 
uniform mat4 viewMatrix; 
uniform mat4 modelMatrix; 

in vec4 pass_Color; 
in vec2 pass_TextureCoord; 

out vec4 out_Color; 

void main() { 
    vec3 vertexPosition = (modelMatrix * viewMatrix * varyingVertex).xyz; 
    vec3 surfaceNormal = normalize((mat3(1) * varyingNormal).xyz); 
    vec3 lightDirection = normalize(gl_LightSource[0].position.xyz - vertexPosition); 
    float diffuseLightIntensity = max(0, dot(surfaceNormal, lightDirection)); 
    out_Color.rgb = diffuseLightIntensity * pass_Color.rgb; 
    out_Color += gl_LightModel.ambient; 
    vec3 reflectionDirection = normalize(reflect(-lightDirection, surfaceNormal)); 
    float specular = max(0.0, dot(surfaceNormal, reflectionDirection)); 
    if (diffuseLightIntensity != 0) { 
    float fspecular = pow(specular, 128); 
    out_Color += fspecular; 
    } 

    vec4 shadowCoordinateWdivide = shadowCoord/shadowCoord.w ; 
    shadowCoordinateWdivide.z += 0.0005; 
    float distanceFromLight = texture2D(ShadowMap,shadowCoordinateWdivide.st).z; 

    float shadow = 1.0; 
    if (shadowCoord.w > 0.0) 
    shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 : 1.0 ; 

    out_Color = shadow * out_Color; 
} 

我得承認,我覺得我是一個有點超過我的頭,當談到了解整個過程,已經從各種來源拼湊起來。這個問題似乎很簡單,但我無法弄清楚。

以下是圖像:

不旋轉:

enter image description here

旋轉的:

enter image description here

編輯:

更改陰影貼圖片段着色器:

#version 150 core 

layout(location=0) out float fragmentdepth; 

void main(void) { 
    fragmentdepth = gl_FragCoord.z; 
} 
+0

這是什麼語言? –

+0

它使用Java(LWJGL) – Chris

+0

好吧。我在問,因爲沒有語言標籤。我注意到有人添加了** c **標籤,我發現這是不正確的。這就是你不包含語言標籤時所得到的結果。 ;) –

回答

0

這是令人難以置信的愚蠢的我,但我發現這個問題...

當我旋轉的攝像頭,我僅旋轉視圖矩陣,而不是模型矩陣。將旋轉應用於模型矩陣並解決問題。

謝謝你的幫助和時間!指針和建議很好。

1

有撞擊我在你的代碼奇怪的幾件事情。

首先,如果有着色器,爲什麼要使用glTexGen?一切glTexGen可用於,使用片段着色器更容易完成。

然後,您的陰影貼圖生成和生成的陰影貼圖不是您想要的陰影貼圖。首先,你不要在陰影地圖中設置「顏色」。實際上,在渲染陰影貼圖時,不需要首先對紋理進行採樣或寫入「彩色」組件。實際放置在陰影圖中的是距光線的距離,即與原點(點光源)或任意平面(方向光源)的距離。生成的圖片是一個深度圖,幾乎所有幾何圖形都具有梯度(除了平行於投影平面的面)。在你的「陰影地圖」中,你獲得了純色。 這是錯的!而原因是,你只是設置一些恆定的顏色(每個對象),而不是發射每片段距離。那麼,然後你也面臨着挑戰的問題;你的影子地圖看起來不像它應該是的立方體。

那麼,在你的照明着色器到達世界空間之後,你變成了反視空間?爲什麼他的名字是你做的?這就是你的額外輪換來自哪裏。你應該用inverse(lightprojection * lightview)來改變它。

那麼,然後是文體挑剔。我很驚訝那些着色器編輯。 inout說明符已在更高版本的GLSL中引入,替換varying說明符。你不應該混淆它們(如果我沒有弄錯的話 - 我必須重新閱讀這個規範 - 你不能將它們混合在一個核心配置文件中)。

+0

謝謝datenwolf - 就像我說過的,我認爲我對此很感興趣,並且找不到使用這種方法的樣本。我無法相信我在我最初的陰影貼圖中忽略了這一點。在陰影貼圖中選中正面以消除我已閱讀過的雙重陰影效果。我將照明着色器更改爲您的建議,但根本沒有出現陰影 - 我將更多地使用這些,您的建議絕對有幫助,並澄清這一點。我根據關於一般shadowmapping的教程反轉了攝影機視圖,該教程聲明矩陣應該是 – Chris

+0

LightProjection * LightView * CameraView^-1。我也沒有意識到GLSL規範 - 我也會解決這個問題。再次感謝您的幫助,並希望我能得到這個工作。 – Chris

+0

實際上,在這個問題上思考,陰影貼圖着色器不會有問題(編程方式,不一定是性能方面),因爲輸出顏色無論如何都會被忽略,紋理僅使用深度組件保存?這樣,保存的應該只是深度緩衝區,即距光線的距離? – Chris