Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unity用エフェクトシェーダ「NOVA Shader」のOSS化事例と技術的特徴【CADC2...

Unity用エフェクトシェーダ「NOVA Shader」のOSS化事例と技術的特徴【CADC2022】

ゲーム事業部で開発しているUnityのParticle System用の汎用多機能シェーダ「NOVA Shader」を使って、開発が進むにつれて数が多くなってしまいがちなエフェクト用シェーダを共通化する方法について紹介します。共通化されたシェーダを利用することでクオリティの向上と開発効率の向上に取り組んでいます。また、本シェーダはOSSとして公開されており、ライセンスの範囲内ですべてのUnityユーザーが利用することができます。
さらに本セッションでは、Custom Vertex Streams、3Dテクスチャのサンプリング、ポストプロセスディストーション、インラインサンプラーステート、GPUインスタンシングといった、実際にNOVA Shaderの実装に使われている技術の解説も行います。

CyberAgent

March 24, 2022
Tweet

More Decks by CyberAgent

Other Decks in Technology

Transcript

  1. γΣʔμͰ஋Λड͚औΔ w ஋Λड͚औΓํ͸ɺجຊతʹ͸γΣʔμͰ௖఺σʔλʹΞ Ϋηε͢Δ͚ͩ // ௖఺γΣʔμ΁ͷೖྗߏ଄ମ struct Attributes { float4

    positionOS : POSITION; // Custom Vertex Streamsͷ஋͕౉ͬͯ͘Δ float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; }; // ௖఺γΣʔμ Varyings vert(Attributes IN) { Varyings OUT; OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); // CustomVertexStreamsͷ஋Λड͚औͬͯࣗ༝ʹ࢖͑Δ float3 color1 = IN.texcoord1.xyz; float3 color2 = IN.texcoord2.xyz; return OUT; }
  2. ൚༻తͳ࣮૷ w ϓϩύςΟͷ஋Λ࢖ͬͯରԠ͢Δ஋Λऔಘ w ࣮ࡍʹ͸(16Πϯελϯγϯάͷؔ܎Ͱ΋͏গ͠ෳࡶ // Ξχϝʔγϣϯ༻ͷϓϩύςΟ float _Foo; //

    ௖఺γΣʔμ Varyings vert(Attributes IN) { Varyings OUT; OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); // ௖఺৘ใΛ٧Ίͨ഑ྻΛ࡞੒ float4 customCoords[] = { float4(0.0, 0.0, 0.0, 0.0), IN.texcoord1, IN.texcoord2 }; // ϓϩύςΟΛσίʔυͯ͠഑ྻ͔Βదͨ͠஋Λऔಘ float fooIntensity = customCoords[_Foo % 10][_Foo / 10]; OUT.intensity = fooIntensity; return OUT; }
  3. ςΫενϟ഑ྻͷαϯϓϦϯά w ʙͷ஋ͰϑϦοϓϒοΫͷਐḿΛ੍ޚ͢ΔͨΊʹҎԼͷ Α͏ʹγΣʔμͰॲཧ͢Δ w @4MJDF$PVOU͸ઃఆ͞ΕͨςΫενϟͷ৘ใ͔Β6OJUZΤσ Ολ্Ͱࣄલʹऔಘࣗ͠ಈతʹઃఆ͓ͯ͘͠ // 0ʙ1Ͱදͨ͠ਐḿ //

    1͸࠷ޙͷςΫενϟΛ͍ࣔͨ͠ͷͰ0.999·ͰʹؙΊ͓ͯ͘ float progress = _Progress; progress = clamp(progress, 0, 0.999); // Texture2DArrayͷΠϯσοΫεΛࣔ͢஋ʹՃ޻͢Δ progress = frac(progress); progress *= _SliceCount; progress -= 0.5; // αϯϓϦϯά return SAMPLE_TEXTURE2D_ARRAY(_Texture2DArray, ɹɹɹɹsampler_Texture2DArray, uv, progress);
  4. %ςΫενϟͷαϯϓϦϯά w ʙͷ஋ͰϑϦοϓϒοΫϒϨϯσΟϯάͷਐḿΛ੍ޚ͢ ΔͨΊʹҎԼͷΑ͏ʹγΣʔμͰॲཧ͢Δ w @4MJDF$PVOU͸ઃఆ͞ΕͨςΫενϟͷ৘ใ͔Β6OJUZΤσ Ολ্Ͱࣄલʹऔಘࣗ͠ಈతʹઃఆ͓ͯ͘͠ // 0ʙ1Ͱදͨ͠ਐḿ float

    progress = _Progress; // Texture3Dͷz஋Λࣔ͢஋ʹՃ޻͢Δ float progressOffset = 1.0 / _SliceCount * 0.5; progress = clamp(progress, 0, 1.0); progress = lerp(progressOffset, 1.0 - progressOffset, progress); // αϯϓϦϯά return SAMPLE_TEXTURE3D_LOD(_Texture3D, sampler_Texture3D, float3(IN.uv, progress), 0);
  5. γΣʔμ w σΟετʔγϣϯΦϒδΣΫτʹઃఆ͞Ε͍ͯΔςΫενϟ Λݩʹɺͷ஋ͰॳظԽͨ͠σΟετʔγϣϯϚοϓʹ67 Φϑηοτ஋ΛՃࢉ͍ͯ͘͠ w ࣮ࡍʹ͸΋ͬͱଟػೳͳͷͰ͍ΖΜͳॲཧΛ͍ͯ͠Δ half4 frag(Varyings input)

    : SV_Target { // σΟετʔγϣϯ༻ͷςΫενϟͷR஋ͱG஋Λ࢖͏ half2 distortion = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).xy; // ͦΕͧΕͷ஋͕0.5͔Βԕ͍΄Ͳ࿪Έ͕ڧ͘ͳΔ distortion = distortion * 2.0 - 1.0; // ڧ౓Λ൓ө distortion *= 0.1 * _DistortionIntensity; // σΟετʔγϣϯϚοϓͷR஋ͱG஋ʹॻ͖ࠐΉ return half4(distortion, 0, 1); }
  6. γΣʔμ w σΟετʔγϣϯϚοϓʹॻ͖ࠐ·Εͨ஋Λऔಘ w 67ͷΦϑηοτ஋Λ͔͚ͭͭ͜͜·ͰͷϨϯμϦϯά݁Ռ Λද͢ςΫενϟΛαϯϓϦϯά͢Δ half4 frag(Varyings IN) :

    SV_Target { // σΟετʔγϣϯςΫενϟ͔Β஋Λऔಘ half2 dist = SAMPLE_TEXTURE2D(_DistTex, sampler_DistTex, IN.uv).xy; // σίʔυ dist = dist.xy * 2.0 - 1.0; // UV஋ͷΦϑηοτͱͯ͜͜͠·ͰͷϨϯμϦϯά݁ՌͷςΫενϟΛαϯϓϦϯά half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv + dist); return col; }
  7. ΠϯϥΠϯαϯϓϥʔεςʔτ w γΣʔμͰαϯϓϥʔεςʔτΛϋʔυίʔσΟϯά͢Δ ػೳ w ςΫενϟͷΠϯϙʔτઃఆΛγΣʔμଆͰΦʔόʔϥΠ υͰ͖Δ // ςΫενϟ TEXTURE2D(_BaseMap);

    // ΠϯϥΠϯαϯϓϥʔεςʔτ // ͜͜Ͱ͸Wrap ModeΛPointʹɺFilter ModeΛMirrorʹ͍ͯ͠Δ SamplerState sampler_point_mirror; half4 frag(Varyings IN) : SV_Target { // ΠϯϥΠϯαϯϓϥʔεςʔτΛ࢖ͬͯαϯϓϦϯά return _BaseMap.Sample(sampler_point_mirror, IN.uv); }
  8. Πϯελϯε͝ͱͷσʔλ w (16Πϯελϯγϯά͸ڞ௨͢ΔύϥϝʔλΛ࢖͍ճͯ͠ ඳըॲཧΛߴ଎Խ͢Δख๏ w Πϯελϯε͝ͱʹҟͳΔσʔλ͸ઐ༻ͷߏ଄ମʹఆٛͯ͠ औΓग़͢ඞཁ͕͋Δ // Πϯελϯε͝ͱͷσʔλΛఆٛͨ͠ߏ଄ମ #define

    UNITY_PARTICLE_INSTANCE_DATA MyInstanceData struct MyInstanceData { float3x4 transform; float3 foo; }; // தུ // ௖఺ɾϑϥάϝϯτγΣʔμͰΠϯελϯε͝ͱͷσʔλΛऔಘ͢Δ UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID]; output.foo = data.foo;