自己皇帝感

をください

Unity 2Dレンダラで3Dオブジェクトをライティングする

qiita.com
ノーマルマップがないモデルだといい感じにライティングされなかったからこれ多分モデルにノーマルマップがあるときの事例だと思う(未検証)

頂点のノーマルだけで事足りる場合もあるのでちょっと改変した

〜
shader "Universal Render Pipeline/2D/Sprite-Lit-3D"
{
    Properties
    {
        [MainTexture] _MainTex("Diffuse", 2D) = "white" {}
        [MainColor] _BaseColor("Color", Color) = (1,1,1,1)
        [HDR] _EmissionColor("Emission", Color) = (0,0,0,0)
        _MaskTex("Mask", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}

        // Legacy properties. They're here so that materials using this shader can gracefully fallback to the legacy sprite shader.
        [HideInInspector] _Color("Tint", Color) = (1,1,1,1)
        [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1)
        [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1)
        [HideInInspector] _AlphaTex("External Alpha", 2D) = "white" {}
        [HideInInspector] _EnableExternalAlpha("Enable External Alpha", Float) = 0
    }

    HLSLINCLUDE
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    ENDHLSL

    SubShader
    {
        Tags {"Queue" = "Geometry" "RenderType" = "Opacue" "RenderPipeline" = "UniversalPipeline" }

        Blend SrcAlpha OneMinusSrcAlpha
        Cull Back
        ZWrite On

        Pass
        {
            Tags { "LightMode" = "Universal2D" }
            HLSLPROGRAM
            #pragma prefer_hlslcc gles
            #pragma vertex CombinedShapeLightVertex
            #pragma fragment CombinedShapeLightFragment
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_0 __
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_1 __
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_2 __
            #pragma multi_compile USE_SHAPE_LIGHT_TYPE_3 __

            struct Attributes
            {
                float3 positionOS   : POSITION;
                float4 color        : COLOR;
                float2  uv           : TEXCOORD0;
            };

            struct Varyings
            {
                float4  positionCS  : SV_POSITION;
                float4  color       : COLOR;
                float2  uv          : TEXCOORD0;
                float2  lightingUV  : TEXCOORD1;
            };

            #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl"

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            TEXTURE2D(_MaskTex);
            SAMPLER(sampler_MaskTex);
            TEXTURE2D(_NormalMap);
            SAMPLER(sampler_NormalMap);
            half4 _MainTex_ST;
            half4 _NormalMap_ST;
            half4 _BaseColor;
            half4 _EmissionColor;

            #if USE_SHAPE_LIGHT_TYPE_0
            SHAPE_LIGHT(0)
            #endif

            #if USE_SHAPE_LIGHT_TYPE_1
            SHAPE_LIGHT(1)
            #endif

            #if USE_SHAPE_LIGHT_TYPE_2
            SHAPE_LIGHT(2)
            #endif

            #if USE_SHAPE_LIGHT_TYPE_3
            SHAPE_LIGHT(3)
            #endif

            Varyings CombinedShapeLightVertex(Attributes v)
            {
                Varyings o = (Varyings)0;

                o.positionCS = TransformObjectToHClip(v.positionOS);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                float4 clipVertex = o.positionCS / o.positionCS.w;
                o.lightingUV = ComputeScreenPos(clipVertex).xy;
                o.color = v.color * _BaseColor;
                return o;
            }

            #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/CombinedShapeLightShared.hlsl"

            half4 CombinedShapeLightFragment(Varyings i) : SV_Target
            {
                half4 main = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                half4 mask = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex, i.uv);

                return CombinedShapeLightShared(main, mask, i.lightingUV)+main*_EmissionColor;
            }
            ENDHLSL
        }

        Pass
        {
            Tags { "LightMode" = "NormalsRendering"}
            HLSLPROGRAM
            #pragma prefer_hlslcc gles
            #pragma vertex NormalsRenderingVertex
            #pragma fragment NormalsRenderingFragment

            struct Attributes
            {
                float3 positionOS   : POSITION;
                float3 normalOS     : NORMAL;//ここで頂点の法線を取得
                float4 color        : COLOR;
                float2 uv           : TEXCOORD0;
                float4 tangent      : TANGENT;
            };

            struct Varyings
            {
                float4  positionCS      : SV_POSITION;
                float4  color           : COLOR;
                float2  uv              : TEXCOORD0;
                float3  normalWS        : TEXCOORD1;
                float3  tangentWS       : TEXCOORD2;
                float3  bitangentWS     : TEXCOORD3;
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            TEXTURE2D(_NormalMap);
            SAMPLER(sampler_NormalMap);
            float4 _NormalMap_ST;  // Is this the right way to do this?

            Varyings NormalsRenderingVertex(Attributes attributes)
            {
                Varyings o = (Varyings)0;

                o.positionCS = TransformObjectToHClip(attributes.positionOS);
                o.uv = TRANSFORM_TEX(attributes.uv, _NormalMap);
                o.uv = attributes.uv;
                o.color = attributes.color;
                o.normalWS = TransformObjectToWorldDir(attributes.normalOS);
                o.tangentWS = TransformObjectToWorldDir(attributes.tangent.xyz);
                o.bitangentWS = cross(o.normalWS, o.tangentWS) * attributes.tangent.w;
                return o;
            }

            #include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/NormalsRenderingShared.hlsl"

            float4 NormalsRenderingFragment(Varyings i) : SV_Target
            {
                float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                float3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, i.uv));
                //return NormalsRenderingShared(mainTex, normalTS, i.tangentWS.xyz, i.bitangentWS.xyz, i.normalWS.xyz);
                half3 normalVS = TransformWorldToViewDir(i.normalWS.xyz);//頂点の法線情報をそのまま使う
                half4 normalColor;
                    
                normalColor.rgb = 0.5 * ((normalVS)+1);
                normalColor.a = i.color.a;  // used for blending

                return normalColor;
            }
            ENDHLSL
        }
        Pass
        {
            Tags { "LightMode" = "UniversalForward" "Queue"="Geometry" "RenderType"="Opacue"}

            HLSLPROGRAM
            #pragma prefer_hlslcc gles
            #pragma vertex UnlitVertex
            #pragma fragment UnlitFragment

            struct Attributes
            {
                float3 positionOS   : POSITION;
                float4 color        : COLOR;
                float2 uv           : TEXCOORD0;
            };

            struct Varyings
            {
                float4  positionCS      : SV_POSITION;
                float4  color           : COLOR;
                float2  uv              : TEXCOORD0;
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            float4 _MainTex_ST;

            Varyings UnlitVertex(Attributes attributes)
            {
                Varyings o = (Varyings)0;

                o.positionCS = TransformObjectToHClip(attributes.positionOS);
                o.uv = TRANSFORM_TEX(attributes.uv, _MainTex);
                o.uv = attributes.uv;
                o.color = attributes.color;
                return o;
            }

            float4 UnlitFragment(Varyings i) : SV_Target
            {
                float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                return mainTex;
            }
            ENDHLSL
        }
    }

    FallBack "Universal Render Pipeline/Unlit"
}
〜

Tags { "LightMode" = "NormalsRendering"}
のPassで
頂点シェーダで法線情報をもらって
NormalsRenderingFragmentでそのままつかっただけ

f:id:stalagmite:20210829170155p:plain

白いCubeは3dモデルだけど松明のLight2D(PointLight)の光を受けている

uraymarchingメモ

コード例

#ifndef VERT_FRAG_DEFERRED_OBJECT_STANDARD_H
#define VERT_FRAG_DEFERRED_OBJECT_STANDARD_H

#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"

#include "./Structs.cginc"
#include "./Raymarching.cginc"
#include "./Utils.cginc"

int _Loop;
float _MinDistance;
fixed4 _Color;
float _Glossiness;
float _Metallic;

#ifdef FULL_SCREEN

struct v2f
{
    float4 pos         : SV_POSITION;
    float4 projPos     : TEXCOORD0;
    float4 lmap        : TEXCOORD1;
#ifdef LIGHTMAP_OFF
    #if UNITY_SHOULD_SAMPLE_SH
    half3 sh           : TEXCOORD2;
    #endif
#endif
};

#else

struct v2f
{
    float4 pos         : SV_POSITION;
    float3 worldPos    : TEXCOORD0;
    float3 worldNormal : TEXCOORD1;
    float4 projPos     : TEXCOORD2;
    float4 lmap        : TEXCOORD3;
#ifdef LIGHTMAP_OFF
    #if UNITY_SHOULD_SAMPLE_SH
    half3 sh           : TEXCOORD4;
    #endif
#endif
};

#endif

v2f Vert(appdata_full v)
{
    v2f o;

#ifdef FULL_SCREEN
    o.pos = v.vertex;
#else
    o.pos = UnityObjectToClipPos(v.vertex);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    o.worldNormal = UnityObjectToWorldNormal(v.normal);
#endif
    o.projPos = ComputeNonStereoScreenPos(o.pos);
    COMPUTE_EYEDEPTH(o.projPos.z);

#ifndef DYNAMICLIGHTMAP_OFF
    o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#else
    o.lmap.zw = 0;
#endif

#ifndef LIGHTMAP_OFF
    o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#else
    o.lmap.xy = 0;
    #ifndef SPHERICAL_HARMONICS_PER_PIXEL
        #if UNITY_SHOULD_SAMPLE_SH
    o.sh = 0;
    o.sh = ShadeSHPerVertex(o.worldNormal, o.sh);
        #endif
    #endif
#endif

    return o;
}

GBufferOut Frag(v2f i, GBufferOut o)
{
    RaymarchInfo ray;
    INITIALIZE_RAYMARCH_INFO(ray, i, _Loop, _MinDistance);
    Raymarch(ray);

#ifdef USE_RAYMARCHING_DEPTH
    o.depth = ray.depth;
#endif

    float3 worldPos = ray.endPos;
    float3 worldNormal = 2.0 * ray.normal - 1.0;
    fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));

    SurfaceOutputStandard so;
    UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard, so);
    so.Albedo = _Color.rgb;
    so.Metallic = _Metallic;
    so.Smoothness = _Glossiness;
    so.Emission = 0.0;
    so.Alpha = _Color.a;
    so.Occlusion = 1.0;
    so.Normal = worldNormal;

#ifdef POST_EFFECT
    POST_EFFECT(ray, so);
#endif

    UnityGI gi;
    UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
    gi.indirect.diffuse = 0;
    gi.indirect.specular = 0;
    gi.light.color = 0;
    gi.light.dir = half3(0, 1, 0);
    gi.light.ndotl = LambertTerm(worldNormal, gi.light.dir);

    UnityGIInput giInput;
    UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
    giInput.light = gi.light;
    giInput.worldPos = worldPos;
    giInput.worldViewDir = worldViewDir;
    giInput.atten = 1;

#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
    giInput.lightmapUV = i.lmap;
#else
    giInput.lightmapUV = 0.0;
#endif

#if UNITY_SHOULD_SAMPLE_SH
    #ifdef SPHERICAL_HARMONICS_PER_PIXEL
    giInput.ambient = ShadeSHPerPixel(worldNormal, 0.0, worldPos);
    #else
    giInput.ambient.rgb = i.sh;
    #endif
#else
    giInput.ambient.rgb = 0.0;
#endif

    giInput.probeHDR[0] = unity_SpecCube0_HDR;
    giInput.probeHDR[1] = unity_SpecCube1_HDR;

#if UNITY_SPECCUBE_BLENDING || UNITY_SPECCUBE_BOX_PROJECTION
    giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif

#if UNITY_SPECCUBE_BOX_PROJECTION
    giInput.boxMax[0] = unity_SpecCube0_BoxMax;
    giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
    giInput.boxMax[1] = unity_SpecCube1_BoxMax;
    giInput.boxMin[1] = unity_SpecCube1_BoxMin;
    giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif

    LightingStandard_GI(so, giInput, gi);

    o.emission = LightingStandard_Deferred(so, worldViewDir, gi, o.diffuse, o.specular, o.normal);
#ifndef UNITY_HDR_ON
    o.emission.rgb = exp2(-o.emission.rgb);
#endif

    UNITY_OPAQUE_ALPHA(o.diffuse.a);

    return o;
}

#endif
Shader "Raymarching/Forward_HexFloor"
{

Properties
{
    [Header(PBS)]
    _Color("Color", Color) = (1.0, 1.0, 1.0, 1.0)
    _Metallic("Metallic", Range(0.0, 1.0)) = 0.5
    _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5

    [Header(Pass)]
    [Enum(UnityEngine.Rendering.CullMode)] _Cull("Culling", Int) = 2

    [Header(Raymarching)]
    _Loop("Loop", Range(1, 100)) = 30
    _MinDistance("Minimum Distance", Range(0.001, 0.1)) = 0.01
    _DistanceMultiplier("Distance Multiplier", Range(0.001, 2.0)) = 1.0

    [PowerSlider(10.0)] _NormalDelta("NormalDelta", Range(0.00001, 0.1)) = 0.0001

// @block Properties
[Header(Additional Properties)]
_TopColor("TopColor", Color) = (1, 1, 1, 0)
// @endblock
}

SubShader
{

Tags
{
    "RenderType" = "Opaque"
    "Queue" = "Geometry"
    "DisableBatching" = "True"
}

Cull [_Cull]

CGINCLUDE

#define OBJECT_SHAPE_CUBE

#define USE_RAYMARCHING_DEPTH

#define SPHERICAL_HARMONICS_PER_PIXEL

#define DISTANCE_FUNCTION DistanceFunction
#define POST_EFFECT PostEffect
#define PostEffectOutput SurfaceOutputStandard

#include "Assets\uRaymarching\Shaders\Include\Legacy/Common.cginc"

// @block DistanceFunction
inline float DistanceFunction(float3 pos)
{
    // combine even hex tiles and odd hex tiles

    float radius = 0.2;
    float space = 0.1;
   float wave = 0.1;
    float3 objectScale = GetScale();
    float height = objectScale.y * 0.5 - wave;
    float3 scale = objectScale * 0.5;

    float pitch = radius * 2 + space;
    float3 offset = float3(pitch * 0.5, 0.0, pitch * 0.866);
    float3 loop = float3(offset.x * 2, 1.0, offset.z * 2);
    
   float3 p1 = pos;
    float3 p2 = pos + offset;

    // calculate indices
   float2 pi1 = floor(p1 / loop).xz;
    float2 pi2 = floor(p2 / loop).xz;
   pi1.y = pi1.y * 2 + 1;
    pi2.y = pi2.y * 2;

    p1 = Repeat(p1, loop);
   p2 = Repeat(p2, loop);

    // draw hexagonal prisms with random heights
   float dy1 = wave * sin(10 * Rand(pi1) + 5 * PI * _Time.x);
    float dy2 = wave * sin(10 * Rand(pi2) + 5 * PI * _Time.x);
    float d1 = HexagonalPrismY(float3(p1.x, pos.y + dy1, p1.z), float2(radius, height));
    float d2 = HexagonalPrismY(float3(p2.x, pos.y + dy2, p2.z), float2(radius, height));

    // maximum indices
    loop.z *= 0.5;
    float2 mpi1 = floor((scale.xz + float2(space * 0.5,    radius)) / loop.xz);
    float2 mpi2 = floor((scale.xz + float2(radius + space, radius)) / loop.xz);

    // remove partial hexagonal prisms
    // if (pi1.x >= mpi1.x || pi1.x <  -mpi1.x) d1 = max(d1, space);
    // if (pi1.y >= mpi1.y || pi1.y <= -mpi1.y) d1 = max(d1, space);
    float o1 = any(
        step(mpi1.x, pi1.x) +
        step(pi1.x + 1, -mpi1.x) +
        step(mpi1.y, abs(pi1.y)));
   d1 = o1 * max(d1, 0.1) + (1 - o1) * d1;

    //  if (!all(max(mpi2 - abs(pi2), 0.0))) d2 = max(d2, space);
    float o2 = any(step(mpi2, abs(pi2)));
    d2 = o2 * max(d2, 0.1) + (1 - o2) * d2;

    // combine
    //return min(d1, d2);
return d1;
}
// @endblock

// @block PostEffect
float4 _TopColor;

inline void PostEffect(RaymarchInfo ray, inout PostEffectOutput o)
{
    float3 localPos = ToLocal(ray.endPos);
    o.Emission += smoothstep(0.48, 0.50, localPos.y) * _TopColor;
    o.Occlusion *= 1.0 - 1.0 * ray.loop / ray.maxLoop;
}
// @endblock

ENDCG

Pass
{
    Tags { "LightMode" = "Deferred" }

    Stencil
    {
        Comp Always
        Pass Replace
        Ref 128
    }

    CGPROGRAM
    #include "Assets\uRaymarching\Shaders\Include\Legacy/DeferredStandard.cginc"
    #pragma target 3.0
    #pragma vertex Vert
    #pragma fragment Frag
    #pragma exclude_renderers nomrt
    #pragma multi_compile_prepassfinal
    #pragma multi_compile ___ UNITY_HDR_ON
    ENDCG
}

}

Fallback "Raymarching/Fallbacks/StandardSurfaceShader"

CustomEditor "uShaderTemplate.MaterialEditor"

}

仕組み

  • vertexシェーダでprojPosにComputeNonStereoScreenPosでスクリーン上の座標を入れとくことで後のポストエフェクトに使いやすくしている(利便性のためzはEYE_DEPTHを適用してビュー空間上の深度に変換している。)
  • PostEffect関数で返すべきデータの種類がレンダリングモードに応じて適切に選択できるように、PostEffectOutputをdefineしている(どう変わるかはhttps://github.com/hecomi/uRaymarching/blob/master/Documents/Legacy.md のPostEffectを参照)

unity shader

  1. [Unity] 邪道なDeferredの使い方で苦しんだ話(昼夜のドット絵で夕焼けアニメ:2) - Qiita
  2. https://qiita.com/Shinoda_Naoki/items/31bde73218b0295b8778

Unity でオブジェクトスペースの Raymarching をフォワードレンダリングでやってみた - 凹みTips

アニメCG

CGのノート

Wについて

シェーダを触るとき頂点情報にWがついている。Wの役目をまとめる。
1. 3次元空間の頂点に対する変形行列のため
wの次元があることで3x3行列では表せられない平行移動を4x4行列で表すことができる。MV行列まではこの役割しかない。

2. 透視投影をするときの深度除算をするためにwにカメラからの距離(=ビュー空間でのz座標)を保存しておく。
http://marupeke296.com/DXG_No70_perspective.html

3. ラスタライザをするときに、頂点情報をパースペクティブコレクトに補間するための深度情報としてもっておく。
かなり調査に時間をかけた。
ラスタライザをするときに、線分上や面上の法線情報やUV座標情報は、その線分や面を構成する頂点に付加された情報で補間しなければならない。しかし、画面上の位置関係で補間すると遠近間が正しく反映されないので歪む。これはPS1などの時代にあった問題であり、ポリゴン分割を工夫するなどでごまかしていた*1*2

これを解決するための方法を示した論文がある
https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf
具体的には、頂点A,Bがスクリーン上に映っているとき、AB間をスクリーン上でs,1-sで内分する点Tでの頂点情報を補間によってもとめるには
1. Tでの(クリッピング空間での)深度Ztを求める(論文中の(1)から(12)まで)。 
Z_t = \frac{1}{\frac{1}{Z_a} + s(\frac{1}{Z_b} - \frac{1}{Z_a})}
2. Tでの頂点情報Itを求める。 
I_{t}=\left(\frac{I_{1}}{Z_{1}}+s\left(\frac{I_{2}}{Z_{2}}-\frac{I_{1}}{Z_{1}}\right)\right) / \frac{1}{Z_{t}}
2についてはZtを経由せずに求めることもできる
I_{t}=\left(\frac{I_{1}}{Z_{1}}+s\left(\frac{I_{2}}{Z_{2}}-\frac{I_{1}}{Z_{1}}\right)\right) /\left(\frac{1}{Z_{1}}+s\left(\frac{1}{Z_{2}}-\frac{1}{Z_{1}}\right)\right)

2式は変形でき,「頂点情報については、頂点情報を深度で割ったものでスクリーン上の線形補間を行えばよい」と解釈できる。

\frac{I_{t}}{Z_t} =\frac{I_{1}}{Z_{1}}+s\left(\frac{I_{2}}{Z_{2}}-\frac{I_{1}}{Z_{1}}\right)
実際の実装については
社内勉強会「レンダリング合宿1」 ソフトウェアラスタライザー基本実装編 07.パースペクティブコレクト - Qiita
が参考になりました。
「HLSLのSV_Positionや、OpenGLのgl_Positionは、XYZ要素がW除算され、NDC空間の値としてフラグメントシェーダに渡される。このときはスクリーン上の線形補間がされる(式1)」
「HLSLのTEXCOORDや、OpenGLのvarying変数などは、パースペクティブ補間され(式2)、View空間での値としてフラグメントシェーダに渡される」



深度値と頂点情報のラスタライズの計算の違い

zバッファには、「ビュー空間での深度=Zview」ではなく「射影変換した後(=正規化デバイス空間(NDC))での深度=Zndc」が入っている。このため、「物体の現実世界の奥行きの距離(=Zview)とZndcの値には線形関係がない」単純な発想として、zバッファに「Zviewの値を0~1にスケールしたもの」を使えばよさそうである。しかし、Zndcの値を使うには理由がある。
1. 「物体の前後関係を調べるだけならZndcの大小関係の情報だけでよく、線形性は必要でない」ため
2. near平面からfar平面に分布するZndcの値が非線形に分布し、nearに多く分布する。カメラに近いほど深度の精度を要求したいという要求にあったため。
しかし、「zバッファに浮動小数点を使い、かつnearに0、farに1を割り当てた」場合、Zndcの非線形分布と浮動小数点数のレンジの関係で、遠い面での深度の精度が落ちてしまうという問題があった。
これを改善するためにreversed z sortが提案された 
Depth Precision Visualized | NVIDIA Developer


3. ラスタライズするときに、Zndcはスクリーン上の線形補間だけで計算できるため(というか、Zndcは正規化デバイス空間での値なので、パースペクティブコレクトとかを考える必要がない)。
具体的に言うと、zバッファを作る際ピクセルシェーダに渡されたSV_Positionやgl_FragCoordのZ要素をそのまま使えるということである。特別な処理が必要でないので、zバッファはOpenGLDirectXでは設定一つで勝手に作ってくれる。
たとえばこの例*3では、zバッファを使ったシャドウマッピングを行う際(depthBuffer == Trueのとき)、深度バッファの値としてピクセルシェーダに渡されたgl_FragCoord.zをgl_FragColorに直接代入している。なぜならgl_Positionは勝手にW除算されてgl_FragCoordに渡されるため、フラグメントシェーダに渡されるZ座標がそのままZndcを示しているからだ。
(記事では,zバッファにFragCoord.zを入れた場合(depthBuffer == Trueの場合)と、ビュー空間での深度(varyingで頂点情報を保存してフラグメントシェーダに渡す。式2に該当)(depthBuffer == Falseの場合)を代入した場合で場合分けしている。場合分け変数名がdepthBufferなのは違和感がある...おそらく「FragCoord.zはOpenGLが勝手に作成したzバッファのz値と一致していて、それを利用している」という意味であるとおもう。depthBuffer==Trueのとき、「シャドウマッピングのための深度バッファはOpenGLの作ったzバッファの値を使う。(直接OpenGLのzバッファにアクセスしているわけではない)」。depthBuffer == falseのとき、「シャドウマッピングのための深度バッファは頂点情報から自前で計算したZviewの値を使う」という意味で考えてそう)

HamachiとOpenSSHで別のPCのアドレスでブラウザを開く

両方Hamachiを入れとく
リモートはsshdを動かしとく
ブラウズするPCで
ssh -f -N -D 10080 user@Hamachi上でのリモートPCのアドレス

これするとlocalhostの10080のポートがリモートのPCにつながる
なのでブラウズするPCのプロキシ設定では、
アドレス: localhost
ポート: 10080
と設定する