狠狠撸
Submit Search
ひまわり本7章
?
Download as PPTX, PDF
?
0 likes
?
2,677 views
CHY72
Follow
シェーダーのシャドウマッピングを鲍苍颈迟测で実装する方法が载っています
Read less
Read more
1 of 15
Download now
Download to read offline
More Related Content
ひまわり本7章
1.
絶対に シェーダーに 合格する 第12日目 第7章 シャドウマップと影 by murata
2.
本日の内容 ?ひまわり本 第7章 - シャドウマッピングで物体に影を付ける -
ランダムサンプリングで影をいい感じに - SSAO - 適宜Unity用に読み替えていけばUnityでも可
3.
シャドウ マッピング ?シャドウマッピング - 光の角度による影は既に実装した https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Smooth_Specular_Highlights -
オブジェクト同士の相互作用による 影を付けたい
4.
シャドウ マッピング ?手順 1. ライトに仮想的にカメラをセット 2.
ライトから見たZ軸方向の距離をテクスチャに保存 3. メインカメラで それを影情報として利用
5.
シャドウ マッピング ?1. ライトに仮想的にカメラをセット 1.
Directional Light に Camera を付ける - Clear Flags : Solid Color - BackGround : RGB(255,255,255) にしておくと見やすい - Projection を Orthrographicにすると (何故か)深度が取れないのでPerspectiveにする - Target Texture を設定する - ここでRenderTextureを設定すると, カメラの映像をテキスチャーに保存できる.
6.
シャドウ マッピング ?1. ライトに仮想的にカメラをセット 2.
シェーダーにライトカメラ情報を送るコードを書く - ライトのカメラに深度シェーダーを設定する - カメラ座標のProjectionMatrix * ViewMatrixを 設定する [ExecuteInEditMode()] public class ShadowMapCamera : MonoBehaviour { [SerializeField] Shader m_shadowMapDepthShader ; Camera m_camera; void Start () { m_camera = GetComponent<Camera> (); m_camera.SetReplacementShader (m_shadowMapDepthShader, ""); } void Update(){ var VP = m_camera.projectionMatrix * m_camera.worldToCameraMatrix; Shader.SetGlobalMatrix ("_ShadowMat",VP); } }
7.
シャドウ マッピング ?2. ライトの距離をテクスチャに保存 -
テクスチャには 各色0~1で値を保存. - この例では100m先 までのものに影. SubShader { Tags { "RenderType"="Opaque" } Pass { GLSLPROGRAM #ifdef VERTEX out vec4 position; void main(){ position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_Position = position; } #endif #ifdef FRAGMENT in vec4 position; void main(){ //wで割ると画面Sizeで正規化できる float x = position.x / position.w; float y = position.y / position.w; gl_FragColor = vec4(position.z/100,0,0,0); } #endif ENDGLSL } }
8.
シャドウ マッピング ?3. メインカメラで影情報として利用 Shader
"GLSL shadow map shader" { Properties { _ShadowMap ("Shadow Map", 2D) = "white" {}} SubShader { Pass { GLSLPROGRAM uniform mat4 _Object2World; // is modelMatrix uniform sampler2D _ShadowMap; uniform mat4 _ShadowMat; #ifdef VERTEX out vec4 shadowCoord; void main(){ shadowCoord = _ShadowMat * _Object2World * gl_Vertex ; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } #endif #ifdef FRAGMENT in vec4 shadowCoord; float getZDiff(float x,float y){ return texture2D(_ShadowMap,vec2(x,y)).x *100-shadowCoord.z; } void main(){ float x = shadowCoord.x / shadowCoord.w / 2 +0.5; float y = shadowCoord.y / shadowCoord.w / 2 +0.5; if (x < 0 || x > 1 || y < 0 || y > 1 ) discard; else{ float val = getZDiff(x,y); if(abs(val) <= 0.01 ) gl_FragColor = vec4(1.0); //影ではない else gl_FragColor = vec4(0.72);//影 } } #endif ENDGLSL } } }
9.
シャドウ マッピング ?よく見ると結構荒くてドットっぽい
10.
シャドウマッピング ?解決方法 - 保存するテクスチャの解像度を上げる - 単純だがその分処理が重くなる -
影に使う情報を増やす(PCF) - 近隣の深度ピクセルも利用する
11.
PCF ?PCF - 単純に周り5箇所の平均をとって滑らかにする float sum
= 0; float dx = _Radius /1000; float dy = _Radius /1000; sum += getZDiff(x-dx,y+dy); sum += getZDiff(x-dx,y-dy); sum += getZDiff(x+dx,y+dy); sum += getZDiff(x+dx,y-dy); sum += getZDiff(x,y); sum /= 5; if (abs(sum) <= 0.01) gl_FragColor = vec4(1.0); else gl_FragColor = vec4(0.72);
12.
ランダムサンプリング ?ランダムサンプリング - 各点を中心とした円からランダムにサンプリング
13.
ランダムサンプリング ?ランダムサンプリング - ひまわり本ではランダム点を先に計算しておいて テキスチャーに保存して利用している - 毎回計算するのは時間がかかるため -
各点毎に16個のサンプル点の情報を記憶 - GLSLをうまく使って一つのテクスチャに RGBA以上(float*4)の情報を保存している - Unityでは任意深度のテクスチャを生成できないので 今回はシェーダ側で計算した
14.
ランダムサンプリング ?ランダムサンプリング float GetRandomNumber(vec2 texCoord,
int Seed){ //0f~1f return fract(sin(dot(texCoord.xy, vec2(12.9898, 78.233)) + Seed) * 43758.5453); } float getZRandomDiff(float x,float y,int i){ int thetaNum = 8; int rNum = 4; float theta = 6.2832*(i + GetRandomNumber(vec2(x,y),i))/thetaNum; float r = 1.0- (floor(i/thetaNum)- GetRandomNumber(vec2(x,y),i))/rNum ; float ix = x + _Radius /1000* r * cos(theta); float iy = y + _Radius /1000* r * sin(theta); return getZDiff(ix,iy); } ---------------- int outer = 8; for(int i = 0;i < outer; i++){ sum += getZRandomDiff(x,y,i); } if(abs(sum/outer) <= 0.01 ) gl_FragColor = vec4(1.0); //影では完全にない else if (abs(sum/outer) >= 0.99 ) gl_FragColor = vec4(0.72);//完全に影 else { int RadiusxTheta = 32; for(int i = outer;i < RadiusxTheta; i++){ sum += getZRandomDiff(x,y,i); } if(abs(sum/RadiusxTheta) <= 0.01 ) gl_FragColor = vec4(1.0); //影ではないかも else gl_FragColor = vec4(0.73);//結構影っぽい }
15.
ランダムサンプリング ?完成!! 過去にやったDiffuseColorと掛けあわせて完成
Download