無失真傳輸的條件為,OpenGL.Shader:12-陰影實現 - 解決陰影失真

 2023-12-09 阅读 27 评论 0

摘要:?OpenGL.Shader:12-陰影實現 - 解決陰影失真 緊接上文的內容,那么怎么解決陰影失真的問題呢?這些問題其實都是不可回避的存在,現代技術只能盡量優化效果已達以假亂真的效果。?首先回到深度紋理的函數renderDepthFBO,地板LandShadow其實是可

?OpenGL.Shader:12-陰影實現 - 解決陰影失真

緊接上文的內容,那么怎么解決陰影失真的問題呢?這些問題其實都是不可回避的存在,現代技術只能盡量優化效果已達以假亂真的效果。?首先回到深度紋理的函數renderDepthFBO,地板LandShadow其實是可以不參與陰影遮擋的深度測試,從而省去很大一部分遮擋測試。

    depthFBO.begin();{glEnable(GL_DEPTH_TEST);glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);//glEnable(GL_CULL_FACE);//glCullFace(GL_FRONT);// 地板不參與陰影遮擋的深度測試 避免造成陰影失真//landShadow.render(mLightProjectionMatrix,mLightViewMatrix,//                  mLightPosition,//                  mLightProjectionMatrix,mLightViewMatrix);cubeShadow.render(mLightProjectionMatrix,mLightViewMatrix,mLightPosition,mLightProjectionMatrix,mLightViewMatrix);//glCullFace(GL_BACK);//glDisable(GL_CULL_FACE);}depthFBO.end();

注銷掉地板的深度測試之后,效果大概是這樣的。但是正方體上還存在失真,這下我們就要認真去了解下為什么會出現陰影失真

陰影貼圖受限于解析度,在距離光源比較遠的情況下,多個片元可能從深度貼圖的同一個值中去采樣。圖片每個斜坡代表深度貼圖一個單獨的紋理像素。你可以看到,多個片元從同一個深度值進行采樣。

無失真傳輸的條件為。雖然很多時候沒問題,但是當光源以一個角度朝向表面的時候就會出問題,這種情況下深度貼圖也是從一個角度下進行渲染的。多個片元就會從同一個斜坡的深度紋理像素中采樣,有些在地板上面,有些在地板下面;這樣我們所得到的陰影就有了差異。因為這個,有些片元被認為是在陰影之中,有些不在,由此產生了圖片中的條紋樣式。?

我們可以用一個叫做陰影偏移(shadow bias)的技巧來解決這個問題,我們簡單的對表面的深度(或深度貼圖)應用一個偏移量,這樣片元就不會被錯誤地認為在表面之下了。

使用了偏移量后,所有采樣點都獲得了比表面深度更小的深度值,這樣整個表面就正確地被照亮,沒有任何陰影。我們可以在shader中這樣實現這個偏移:

float bias = 0.0005;
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;

選用正確的偏移數值,在不同的場景中需要一些像這樣的輕微調校,但大多情況下,實際上就是增加偏移量直到所有失真都被移除的問題。

opengl不顯示圖形?經過調整之后,效果大致如下:

但是地板的左、右、后出現了三塊“不和諧”的陰影呢?

這是因為光照有一個區域,超出該區域就成為了陰影;這個區域實際上代表著深度貼圖的大小,這個貼圖投影到了地板上。發生這種情況的原因是我們創建FBO的將深度貼圖的環繞方式設置成了GL_REPEAT。

我們寧可讓所有超出深度貼圖的坐標的深度范圍是1.0,這樣超出的坐標將永遠不在陰影之中。我們可以把深度貼圖的紋理環繞選項設置為GL_CLAMP_TO_EDGE:

    void    createDepthTexture(){glGenTextures(1, &_depthTexId);glBindTexture(GL_TEXTURE_2D, _depthTexId);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _width, _height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0);}

但是這樣只能解決左右兩邊的陰影,至于在后方的陰影是另外一個原因產生的。

shader graph,那里的坐標超出了光的正交視錐的遠平面。你可以看到這片黑色區域總是出現在光源視錐的極遠處。當一個點比光的遠平面還要遠時,它的投影坐標的z坐標大于1.0。這種情況下,GL_CLAMP_TO_EDGE環繞方式不起作用,因為我們把坐標的z元素和深度貼圖的值進行了對比;它總是為大于1.0的z返回true。解決這個問題也很簡單,只要投影向量的z坐標大于1.0,我們就把shadow的值強制設為0.0:

float ShadowCalculation(vec4 fragPosLightSpace)
{
? ? ? ? [...]
? ? ? ? if(projCoords.z > 1.0) shadow = 0.0;
? ? ? ? return shadow;
}

這樣做意味著,只有在深度貼圖范圍以內的被投影的fragment坐標才有陰影,所以任何超出范圍的都將會沒有陰影。

這下效果應該是最帥的一個了,看看效果是不是這樣?

其實我們還可以把光源位置做成動態效果,這個就非常接近游戲的效果體驗了。

opengl 陰影貼圖?參考代碼:https://github.com/MrZhaozhirong/NativeCppApp? 工程內的ShadowFBORender.cpp? ? CubeShdow.hpp/LandShadow.hpp? IlluminateWithShadow.hpp? ? FramebufferObject.hpp

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/195169.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息