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

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

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

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

2016ba6b977a2e6691811fa66d5f4336?s=128

CyberAgent
PRO

March 24, 2022
Tweet

More Decks by CyberAgent

Other Decks in Technology

Transcript

  1. None
  2. ໼໺य़थ גࣜձࣾαΠόʔΤʔδΣϯτ ήʔϜɾΤϯλʔςΠϝϯτࣄۀຊ෦ ίΞٕज़ຊ෦ ΫϥΠΞϯταΠυΤϯδχΞ

  3. ࣗݾ঺հ w αΠόʔΤʔδΣϯτʹاը৬Ͱ৽ଔೖࣾ w ΤϯδχΞʹస޲ w %$(पΓͷۀ຿Λ࢝ΊΔ w ୀࣾ͠%F/"΁ w

    αΠόʔΤʔδΣϯτʹ࠶ೖࣾ !IBSVNBL@ )BSVNB, -*()5ʢٕज़ϒϩάʣ
  4. ίΞςΫʹ͍ͭͯ w ήʔϜɾΤϯλʔςΠϝϯτࣄۀ෦ʢ4(&ʣͷٕज़ԣஅ૊ ৫ w ϛογϣϯ͸։ൃޮ཰ͱ඼࣭ͷ࠷దԽ w ڞ௨ج൫։ൃɾύϑΥʔϚϯενϡʔχϯάɾνʔτରࡦ ͳͲ

  5. /07"γΣʔμͷ঺հ

  6. /07"γΣʔμ w 6OJUZͷ1BSUJDMF4ZTUFN༻ͷγΣʔμ w ΤϑΣΫτ੍࡞ͰΑ͘࢖͏ػೳΛ·ͱΊͨ΋ͷ w ΫΦϦςΟͱ։ൃޮ཰޲্ͷͨΊʹ࡞੒ w લ਎ͱͳΔγΣʔμͷػೳΛ੔ཧ631ʹରԠͨ͠΋ͷ IUUQTHJUIVCDPN$ZCFS"HFOU(BNF&OUFSUBJONFOU/PWB4IBEFS

  7. None
  8. None
  9. 044Խʹ͍ͭͯ w ඼࣭޲্ɺۀքߩݙɺಋೖ࣮੷ͳͲΛ໨తͱͯ͠044Ͱެ ։ʢ.*5ϥΠηϯεʣ w (JU)VCʹެ։͍ͯ͠·͢ w ΞηοτετΞʹ΋௥ʑެ։༧ఆ IUUQTHJUIVCDPN$ZCFS"HFOU(BNF&OUFSUBJONFOU/PWB4IBEFS

  10. $VTUPN7FSUFY4USFBNT ͱͷ࿈ܞ

  11. ϓϩύςΟΞχϝʔγϣϯ w ΤϑΣΫτͰ͸γΣʔμͷ֤ϓϩύςΟΛΞχϝʔγϣϯ ͤ͞Δඞཁ͕͋Δ w ΞʔςΟετ͕೚ҙͷϓϩύςΟΛ޷͖ͳΑ͏ʹΞχϝʔ γϣϯͤ͞ΒΕΔͷ͕ཧ૝త

  12. $VTUPN7FSUFY4USFBNT w 1BSUJDMF4ZTUFNͰ࡞੒ͨ͠஋Λ௖఺σʔλͱͯ͠ૹΔػೳ w $VTUPN%BUBͳͲͱ࿈ܞ͢Ε͹ύʔςΟΫϧͷੜଘ࣌ؒʹ Ԡͨ͡ΞχϝʔγϣϯΧʔϒͷ஋Λ౉ͤΔ

  13. $VTUPN%BUBҎ֎ͱͷ࿈ܞ w $VTUPN%BUBҎ֎ͷϞδϡʔϧͱ΋࿈ܞՄೳ w ύʔςΟΫϧ͝ͱʹϥϯμϜͳ஋Λ༩͑Δ w ϊΠζʹΑΓ࡞੒ͨ͠஋Λ౉͢ w ύʔςΟΫϧͷ଎౓Λ஋ͱͯ͠౉͢ɺͳͲ

  14. $VTUPN%BUBҎ֎ͱͷ࿈ܞ w $VTUPN%BUBҎ֎ͷϞδϡʔϧͱ΋࿈ܞՄೳ w ύʔςΟΫϧ͝ͱʹϥϯμϜͳ஋Λ༩͑Δ w ϊΠζʹΑΓ࡞੒ͨ͠஋Λ౉͢ w ύʔςΟΫϧͷ଎౓Λ஋ͱͯ͠౉͢ɺͳͲ

  15. γΣʔμͰ஋Λड͚औΔ 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; }
  16. ൚༻తʹ࢖͑ΔΑ͏ʹ w ΞʔςΟετ͕೚ҙͷϓϩύςΟʹ೚ҙͷ$VTUPN7FSUFY 4USFBNTΛׂΓ౰͍ͯͨ w ϚςϦΞϧͷ*OTQFDUPS͔Βड͚औΔ5&9$003%ͷΠϯσο Ϋεͱ4XJ[[MFΛࢦఆͰ͖ΔΑ͏ʹ͢Δ

  17. ൚༻తͳ࣮૷ 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; }
  18. ςΫενϟ഑ྻ %ςΫενϟ

  19. ςΫενϟ഑ྻͱ͸ʁ w ෳ਺ͷςΫενϟ͕ͭͷΞηοτʹͳͬͨʢΑ͏ͳʣ΋ͷ w 67࠲ඪʹՃ͑ͯ഑ྻΠϯσοΫεΛࢦఆͯ͠αϯϓϦϯά w $VTUPN7FSUFY4USFBNTͱซ༻͢Δ͜ͱͰϑϦοϓϒοΫ ʢύϥύϥΞχϝʣΛ࣮ݱͰ͖Δ

  20. %ςΫενϟͱ͸ʁ w 67஋Ͱ͸ͳ࣍͘ݩ࠲ඪΛ࢖ͬͯαϯϓϦϯά͢Δ w $VTUPN7FSUFY4USFBNTͱซ༻͢Δ͜ͱͰϑϦοϓϒοΫϒ ϨϯσΟϯάʢ׈Β͔ͳύϥύϥΞχϝʣΛ࣮ݱͰ͖Δ

  21. ࡞੒ํ๏ w ࠷ۙͷ6OJUZʢҎ߱ʣͰ͸Πϯϙʔτઃఆ͔Β࡞ΕΔ w ςΫενϟγʔτ͔Βߦͱྻͷ਺Λࢦఆͯ͠࡞੒͢Δ w Ҏલ͸εΫϦϓτ͔Β࡞Δ͔͠ͳ͔ͬͨ

  22. ςΫενϟ഑ྻͷαϯϓϦϯά 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);
  23. %ςΫενϟͷαϯϓϦϯά 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);
  24. ࢖༻Օॴ w ϕʔεςΫενϟ͚ͩͰͳ͋͘ΒΏΔػೳͰ࢖༻Ͱ͖Δ w ৐ࢉ৭༻ͷςΫενϟɺΞϧϑΝτϥϯδγϣϯɺΤϛογ ϣϯͳͲ

  25. ϙετϓϩηε σΟετʔγϣϯ

  26. σΟετʔγϣϯͱ͸ʁ w ۭؒΛ࿪·ͤΔදݱ w ೤೾΍۶ંදݱʹ࢖͏ w લ਎ͷγΣʔμ͔Βେ͖࣮͘૷Λมߋͨ͠෦෼

  27. લ਎ͷσΟετʔγϣϯ w (SBC1BTTʹΑΓϑϨʔϜόοϑΝΛऔಘ w σΟετʔγϣϯ༻ΦϒδΣΫτͷඳը࣌ʹˢΛ࿪Ίͭͭ αϯϓϦϯά͢Δ

  28. ॏͶ͕͚Ͱ͖ͳ͍ w ճσΟετʔγϣϯΛ͔͚Δࡍʹಉ͡ςΫενϟΛࢀর͢ ΔͨΊɺޙʹඳըͨ͠΋ͷͷӨڹ͔͠൓ө͞Εͳ͍ w 631ͷύʔςΟΫϧγΣʔμ΋ຊ࣭తʹ͸ಉ͡໰୊

  29. ϙετϓϩηεσΟετʔγϣϯ w σΟετʔγϣϯ༻ΦϒδΣΫτͷඳը࣌ʹεΫϦʔϯε ϖʔεͷ67Φϑηοτ৘ใΛඳըͨ͠ςΫενϟΛ࡞੒ w ϙετϓϩηεͰ͜ͷσΟετʔγϣϯϚοϓΛ࢖͏

  30. σΟετʔγϣϯϚοϓ࡞੒ύε w 631Ͱ͸(SBC1BTT͕࢖༻Ͱ͖ͳ͍ w ൒ಁ໌ඳըޙʹσΟετʔγϣϯ༻ΦϒδΣΫτΛඳը͢ ΔͨΊͷύεΛࠩ͠ࠐΜͩ w ͜ͷύεͰσΟετʔγϣϯϚοϓ͕࡞ΒΕΔ

  31. γΣʔμ 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); }
  32. ϙετΤϑΣΫτύε w 631Ͱ͸ʢ·ͩʣΧελϜϙετΤϑΣΫτ͕ެ࣮ࣜ૷͞ Ε͍ͯͳ͍ w ϙετΤϑΣΫτΛద༻͢ΔͨΊͷύεΛ࡞੒ w ϨϯμϦϯά݁ՌΛσΟετʔγϣϯϚοϓͰ࿪ΊΔ

  33. γΣʔμ 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; }
  34. ॏͶ͕͚Մೳ w ॏͶ͕͚͢Δࡍʹ͸67Φϑηοτ৘ใ͸Ճࢉ͞Ε͍ͯ͘ w ෳ਺ͷσΟετʔγϣϯΛॏͶͯ΋ޮՌΛಘΒΕΔ

  35. ࣮૷্ͷݶք w खલʹ͋ΔΦϒδΣΫτͷ৭͕൓ө͞Εͯ͠·͏ w ࠓճͷ࣮૷͔ͩΒى͜Δ͜ͱͰ͸ͳ͘ɺલ਎ͷγΣʔμ΍ 631ͷγΣʔμͰ΋ಉ͡ݱ৅͕ൃੜ

  36. ΠϯϥΠϯ αϯϓϥʔεςʔτ

  37. αϯϓϥʔεςʔτͱ͸ʁ w ςΫενϟͷαϯϓϦϯάํ๏Λࢦఆ͢Δ΋ͷ w ςΫενϟͷΠϯϙʔτઃఆͷ8SBQ.PEF΍'JMUFS.PEFͳ Ͳ͕ͦΕʹ౰ͨΔ

  38. ΠϯϥΠϯαϯϓϥʔεςʔτ 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); }
  39. ϛϥʔαϯϓϦϯά w ϚςϦΞϧʹνΣοΫΛೖΕΔ͚ͩͰϛϥʔαϯϓϦϯά Ͱ͖Δػೳͷ಺෦࣮૷ʹ࢖༻

  40. (16Πϯελϯγϯά

  41. (16Πϯελϯγϯάͱ͸ʁ w ෳ਺ͷಉ͡ϝογϡΛ࣋ͭΦϒδΣΫτΛճͷυϩʔίʔ ϧʹ·ͱΊͯඳը͢Δ͜ͱͰॲཧෛՙΛԼ͛Δػೳ w 1BSUJDMF4ZTUFNͰ͸3FOEFS.PEFΛ.FTIʹઃఆ͍ͯ͠Δ ৔߹ͷΈ࢖༻Մೳ

  42. Πϯελϯε͝ͱͷσʔλ 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;
  43. $VTUPN7FSUFY4USFBNT w $VTUPN7FSUFY4USFBNTͰ࢖͏5&9$003%͸Πϯελϯε ݻ༗ͷσʔλͱ͢Δඞཁ͕͋Δ w ϝογϡ(16Πϯελϯγϯά͕༗ޮͳ࣌ʹ͸ͪ͜ΒΛ࢖ ͏Α͏ʹ࣮૷͢Δ #ifdef NOVA_PARTICLE_INSTANCING_ENABLED struct

    DefaultParticleInstanceData { float3x4 transform; uint color; float4 customCoord1; // TEXCOORD1 float4 customCoord2; // TEXCOORD2 }; #endif
  44. 431#BUDIFS w 431Ͱ࢖͑ΔόονϯάγεςϜ w ηοτύείʔϧ͕ݮΔ w ݱ࣌఺Ͱ͸1BSUJDMF4ZTUFNʹ͸ඇରԠ w কདྷతͳରԠΛݟਾ࣮͑ͨ૷Λ͓ͯ͘͠ w

    $#V⒎FS༻ʹϓϩύςΟΛ·ͱΊ͓ͯ͘
  45. ͋Γ͕ͱ͏͍͟͝·ͨ͠