狠狠撸

狠狠撸Share a Scribd company logo
絶対に
シェーダーに
合格する
第12日目
第7章
シャドウマップと影
by murata
本日の内容
?ひまわり本 第7章
- シャドウマッピングで物体に影を付ける
- ランダムサンプリングで影をいい感じに
- SSAO
- 適宜Unity用に読み替えていけばUnityでも可
シャドウ マッピング
?シャドウマッピング
- 光の角度による影は既に実装した
https://en.wikibooks.org/wiki/GLSL_Programming/Unity/Smooth_Specular_Highlights
- オブジェクト同士の相互作用による
影を付けたい
シャドウ マッピング
?手順
1. ライトに仮想的にカメラをセット
2. ライトから見たZ軸方向の距離をテクスチャに保存
3. メインカメラで それを影情報として利用
シャドウ マッピング
?1. ライトに仮想的にカメラをセット
1. Directional Light に Camera を付ける
- Clear Flags : Solid Color
- BackGround : RGB(255,255,255)
にしておくと見やすい
- Projection を Orthrographicにすると
(何故か)深度が取れないのでPerspectiveにする
- Target Texture を設定する
- ここでRenderTextureを設定すると,
カメラの映像をテキスチャーに保存できる.
シャドウ マッピング
?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);
}
}
シャドウ マッピング
?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
}
}
シャドウ マッピング
?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
}
}
}
シャドウ マッピング
?よく見ると結構荒くてドットっぽい
シャドウマッピング
?解決方法
- 保存するテクスチャの解像度を上げる
- 単純だがその分処理が重くなる
- 影に使う情報を増やす(PCF)
- 近隣の深度ピクセルも利用する
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);
ランダムサンプリング
?ランダムサンプリング
- 各点を中心とした円からランダムにサンプリング
ランダムサンプリング
?ランダムサンプリング
- ひまわり本ではランダム点を先に計算しておいて
テキスチャーに保存して利用している
- 毎回計算するのは時間がかかるため
- 各点毎に16個のサンプル点の情報を記憶
- GLSLをうまく使って一つのテクスチャに
RGBA以上(float*4)の情報を保存している
- Unityでは任意深度のテクスチャを生成できないので
今回はシェーダ側で計算した
ランダムサンプリング
?ランダムサンプリング
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);//結構影っぽい
}
ランダムサンプリング
?完成!!
過去にやったDiffuseColorと掛けあわせて完成

More Related Content

ひまわり本7章