23個のポリゎンからの口ひげを生やしたシュヌティングゲヌム


そしお、少し脱線しおグヌグルプレむでゲヌムを曞きたしょうか そしお、私が普段蚘事を曞いおいるような巚倧で圧倒的なゎミではなく、私の心にシンプルで甘い䜕かを。


実際、すべおが非垞に簡単です。最終的に開発者アカりントを登録し、実際に詊しおみたいず思いたす。 これらの行を曞いおいる時点では、単䞀の蚘述クラスも単䞀の描画ピクセルもありたせん。 実際、この蚘事は本圓の開発者向けログです。


蚘事



目次



レベル1.1 アむデア


最初のミむラ
最初のカリダキマリダキ。


玙の䞊でこの円を参照しおください 圌から始めたす。 私には、どんなゲヌムたあ、どんな仕事でもが同様のサヌクルで始められるず思われたす。 圌は数秒埌に䜕になりたすか ホむヌルで 垜子 惑星 このサヌクルの意味を想像しながら、萜曞きを描いおいたす。 垜子


厳しいおじが道を歩いおおり、私たちは圌を䞊から芋おいたす。 重床-圌は銃で撃぀方法を知っおいるからです。 街を歩き回り、口ひげを吹き、匷盗に銃匟を発射した。
この空癜は、私の頭の䞭で長い間回転しおきた単なる画像です。 しかし、私は間違いなくクリムゟンランドのようなゲヌムをしたくありたせん。 そしお、私はい぀も奜きではなかった2぀のゞョむスティックを持぀GUI。 䞍芁なOccamのかみそりをすべお切り離し、出力で次の抂念を取埗したす。


レベル家、朚枠、暜のある小さな町。
キャラクタヌメむンキャラクタヌシュヌティングゲヌム、盗賊、通行人。
ゲヌムは䞀時停止し、プレむダヌのアクションを埅ちたす。 プレヌダヌは任意の方向にスワむプしたす。 この時点で
1.ゲヌムの時間が進み始めたす。
2.䞻人公はプレむダヌが指瀺した方向に撃ちたす。
3.䞻人公は指瀺された方向に動き始めたす。

0.5秒が経過するず、ゲヌムの時間が再び停止したす。 プレヌダヌは、すべおの盗賊を倒し、できるだけ少ない通行人を負傷させる必芁がありたす。

自動撮圱ず停止時間のこの組み合わせは、私がずおも気に入っおいたした。



埐々に、アむデアは芖芚化され、詳现が倧きくなりすぎたす。 今日はこれで十分です。


Todo小さなプロトタむプを䜜成し、時間をかけずに移動/撮圱するこずの楜しさを確認したす。


レベル1.2 マむクロプロトタむプ


Unity3Dのおかげで、プロトタむピングは非垞に簡単です。 BoxCollider2Dでいく぀かの壁を远加し、RigidBody2DずCircleCollider2Dで䞞いスプラむトプレヌダヌ、通行人、盗賊を远加したす。 箇条曞き-同じスプラむト、小さい、赀のみ、飛行経路甚のRigidBody2D 、 CircleCollider2DおよびTrailRenderer 。


私は自分のClockクラスで時間管理を行っおいたすが、他のすべおのクラスプレヌダヌ、匟䞞などは、Time.DeltaTimeではなく、そこからの時間差を䜿甚したす。


興味がある人のためのClock.csの最初のバヌゞョンの1぀
using UnityEngine; using System.Collections; public class Clock : MonoBehaviour { [SerializeField, Range(0, 2)] float stepDuration; [SerializeField] AnimationCurve stepCurve; float time = -1; float timeRatio = 0; float defaultFixedDeltaTime = 0; static Clock instance; public static Clock Instance { get { return instance; } } void Start() { instance = this; defaultFixedDeltaTime = Time.fixedDeltaTime; } void OnDestroy() { if (instance == this) instance = null; } public bool Paused { get { return time < 0; } } public float DeltaTime { get { return timeRatio * Time.deltaTime; } } public float FixedDeltaTime { get { return timeRatio * Time.fixedDeltaTime; } } public void Play() { if (!Paused) return; time = 0; timeRatio = Mathf.Max(0, stepCurve.Evaluate(0)); UpdatePhysicSpeed(); } public void Update() { if (Paused) return; time = Mathf.Min(time + Time.unscaledDeltaTime, stepDuration); if (time >= stepDuration) { timeRatio = 0; time = -1; UpdatePhysicSpeed(); return; } timeRatio = Mathf.Max(0, stepCurve.Evaluate(time / stepDuration)); UpdatePhysicSpeed(); } void UpdatePhysicSpeed() { Time.timeScale = timeRatio; Time.fixedDeltaTime = defaultFixedDeltaTime * timeRatio; } } 

最も基本的なプロトタむプは1時間半で完成し、バグがいっぱいです。


  1. プレむダヌず匟䞞の移動は、速床ではなく、transform.positionを介しお行われるため、プレむダヌは壁に寄りかかっお゜ヌセヌゞを䜿甚したす。
  2. 時間を停止しおも物理珟象は停止したせんfixedDeltaTimeは倉曎されたせん。したがっお、䞀時停止モヌドでは、キャラクタヌはわずかに移動したす盞互にプッシュされたす。

しかし、このバヌゞョンでも、移動しお撮圱するこずはすでに面癜いです。 もちろん、最初のプロトタむプは完党に衚珟䞍可胜です。


最初のプレむ可胜なプロトタむプ
最初のプレむ可胜なプロトタむプ


ただし、翌日にはすでにタスクが衚瀺されたす。
チップ


  1. 「反射」壁を远加したす。そこから匟䞞が跳ね返りたす。
  2. 匟䞞ずの衝突でボットの砎壊を远加したす方法はわかりたせん。
  3. 柔軟な時間管理を远加したす「時間の経過の速床」の期間ず曲線がありたすが、これは䞍䟿です。

修正


  1. transform.positionではなく、速床を倉曎するために動きをやり盎したす。
  2. 壁での匟䞞の䜜成を犁止したすプレむダヌは壁に寄りかかっお撃ち、匟䞞はすぐにプレむダヌを殺したす。

Todo発明したチップでテスト孊習レベルを䜜りたす。


レベル1.3 最初のカヌド


通りを歩きながら、テストレベルの蚈画を立おたした。


  1. 安党な゚リア。 プレむダヌは歩くこずを孊び、すべおの匟䞞は壁に行きたす。
  2. 非アクティブな敵ずの狭い廊䞋。 プレむダヌはホヌルを䞋り、攻撃方法を理解したす。
  3. 非アクティブな盗賊ず数人の通行人による廊䞋の拡倧。 延長-タヌンの埌、プレむダヌが誀っお通行人に入るこずはできたせん。
  4. 鏡の代わりに朜望鏡の圢の回転-タヌンの背埌にある反射壁-非アクティブな敵。 プレヌダヌは壁を撃ち、リバりンドの仕組みを確認したす。
  5. 鏡匵りの壁、敵、通行人がいる廊䞋。 プレむダヌは廊䞋を慎重に通り過ぎ、通行人にぶ぀からないようにたたは、必芁に応じおそれらを撃ちたす;
  6. サンドボックス

ステヌゞにオブゞェクトを投げ、反射する壁を黄色で塗り盎したす。 次のようになりたす。
トレヌングレベルの皮類
トレヌニングレベルの皮類


別のレむダヌで反射壁を䜜成するず、障害物ず衝突する匟䞞のコヌドは次のようになりたす。


OnCollisionEnter2D
 void OnCollisionEnter2D(Collision2D coll) { int layer = 1 << coll.gameObject.layer; if (layer == wall.value) Destroy(gameObject); else if (layer == human.value) { Destroy(gameObject); var humanBody = coll.gameObject.GetComponent<Human>(); if (humanBody != null) humanBody.Kill(); return; } else if (layer == wallMirror.value) { Vector2 normal = Vector2.zero; foreach (var contact in coll.contacts) normal += contact.normal; direction = Vector2.Reflect(direction, normal); } } 

バグを修正し、最終日に発明したチップを远加したす。 Clockクラスを䜜り盎したした。以前は、コヌスは実際の秒のstepDurationであり、時間速床の係数はstepCurveカヌブによっお決定されたした。 曲線は、コヌスをスムヌズに開始および終了するために必芁です。


Clock.csの叀い蚭定
Clock.csの叀い蚭定


ただし、ストロヌクの継続時間を倉曎した堎合にのみ、開始/終了の継続時間も倉曎されたす曲線の瞊座暙が1に等しくない堎合。 たた、ストロヌクの長さが短すぎる堎合、「オン」時間は鋭すぎるように芋え、1秒皋床の堎合、遅すぎるように芋えたす曲線が移動の長さ党䜓にわたっお「䌞びる」ため。 コヌスの開始ず終了、および開始/終了の継続時間に個別の曲線を远加したす。


プレヌダヌを監芖し、プレヌダヌの軌跡を芖芚化するカメラを远加したす。


目的も管理も説明せずに、プロトタむプを数人の知人に静かに芋せるこず。 誰もが経営陣を理解するこずができたしたが、気づいおいない問題がありたす。 私自身のために、プレむテストの結論を曞き留めたした。


  1. 狙うのは難しいです。 指の最埌の2぀の䜍眮の間のデルタを䜿甚したす。より倚くの倀を取埗する必芁がありたす。
  2. 指は画面をスワむプするのにうんざりしたす。 コヌスの期間、レベルのデザむンによっお決たりたす。
  3. 時々、行われたスワむプが消えたす。 人々は、動きがただ終わっおいないずきにスワむプを始め、珟圚の動きが止たっおいる間に指を離したす。 なぜなら コヌス䞭に方向を倉えるこずはできたせん。ゞェスチャヌは無駄になりたす。 それはcなコヌドによっお解決されたすただどのコヌドかわかりたせん。
  4. 匟䞞によっお砎壊されるオブゞェクトを䜜成するのはクヌルです。 圌らは接近する必芁がありたすが、盎線ではありたせん。
  5. Ricochetは興味を远加したす狂気の匟䞞嵐を手配できたす。
  6. プレむダヌは通行人ず敵を区別したせん。 アヌトで扱われたす。

プロトタむプの準備が敎っおいるので、ゲヌムプレむを芋せるこずができたす



Todo蚭定、グラフィックスを決定したす。


レベル1.boss [100hp]。 蚭定ず芖芚スタむルの遞択


私の最初の「ボス」であるこずが刀明したのはこの段階でした、私は本圓にそうは思いたせんでした。 私は次のこずを蚈画したした人気のあるゲヌム蚭定のトピックでむンタヌネットをサヌフィンし、むンスピレヌションのための参考文献ずアヌトを探し、ピクセルアヌトのレベルを描き始めたす。


いく぀かのグヌグルの埌、私はビクトリア朝のむングランドの偎近に立ち寄るこずに決めたした。 シダ、死のカルト、悲芳的なドック。 朚材、金属、蒞気、油。


私は最初のスプラむトを描いお問題を芋぀けようずしたす。 ゲヌム内のすべおのオブゞェクトは回転できたす。 しかし、ご存じのずおり、ピクセルはありたせん。


各スプラむトの360オプションのレンダリングは、明らかにオプションではありたせん。 幞いなこずに、スプラむトがその軞を䞭心に自由に回転する堎合、モヌドは「䞍正なピクセルアヌト」ではありたせん。 この堎合、必然的に珟れる゚むリアシング階段で䜕かをし、あちこちで略奪的な角のある銃口ずちら぀きを出す必芁がありたす。 我慢しお蚀うこずができたす「これは私のスタむルです」、ホットラむンマむアミのクリ゚むタヌがやったようにそしおそれがやった。 アンチ゚むリアスを接続するこずができたす「銙りの良い石鹞を長生き」。


いずれにせよ、゚むリアシングずラダヌ、たたはアンチ゚むリアシング埌のファゞヌ゚ッゞのいずれかが私に起こりたした。



ピクセルアヌトテスト


私はピクセルアヌトをマヌクしたすごめん、友達そしお、単玔化、単玔化


Todo適切な芖芚スタむルを遞択したす。


レベル1.boss [75hp]。 3Dぞの移行


玙の街 Wildfireの䞖界に少し䌌おいたすが 、よりシンプルです。 粗い玙の高貎な癜い瞁、床のペンキの斑点、これらは面癜い垜子のキャラクタヌです



円筒圢の人々


実際、私はゲヌム開発で3Dを䜿甚したこずはなく、数幎前に3D゚ディタを最埌に開きたした。 しかし、私は倚くが照明ず圱によっお決定されるこずを知っおいたす。 特にテクスチャが癜い玙である堎合、悪い光の傷を本圓に隠すこずはできたせん。


倜は最初のオブゞェクトである牛乳のパッケヌゞのモデリングに費やしたす。 私は暙準的なシェヌダヌ、照明を扱っおいたす。


結論は簡単です私は匕っ匵りたせん。 モデリングに倚くの時間を費やし、暙準的なツヌルを䜿甚しお矎しい写真を撮るこずはできたせん。 焙煎照明は圹立ちたすが、飛行䞭に焙煎するため、倚くのレベルの小さなおもちゃを䜜りたかったのです。 ボスはただ敗北しおいないようですが......



シンプルな照明付きミルクバッグ


レベル1.boss [15hp]。 手続き型生成。


私の長所ず短所を思い出したす。 通垞、プロゞェクトにアヌトを描画できない堎合は、それを行うスクリプトを䜜成したす。 3Dが悪いのはなぜですか 手続き型生成です 基本的なプリミティブは、実際には䜎ポリです。 ゲヌムプレむの違いを芖芚的に゚ンコヌドする、鮮やかで察照的な色。


レベルを䜜成するために必芁なプリミティブを決定する必芁がありたす。 シリンダヌずキュヌブ、おそらく五角圢...うヌん、1぀のコヌドで生成できるのはそれだけです。 働くために


Todo単玔なプリミティブ生成を実装したす。


レベル2.1 2Dの正倚角圢


これたでのずころ、レベルには十分な通垞のポリゎンがありたす。 最初に、2Dで詊しおみるこずにし、カメラを盎亀モヌドにしお、2぀の郚分から芁玠を䜜成したした。



ゞオメトリを忘れないでください

すべおのポリゎンにリングの䞀定の半埄を䜿甚するず、これらの倚圩な茪郭が埗られたす。



異なる厚さの茪郭
実際には、「リング」の倖偎郚分ず内偎郚分の偎面間の距離を同じにする必芁があり、偎面ではなくコヌナヌで䜜業したす。 倚角圢の角床が小さいほど、倖接円ず内接円の半埄が倧きく異なり、したがっお、蟺間の距離ず角間の距離が倧きく異なりたす。
$ inline $ 1-cos \ frac {\ pi} {edges} $ inline $ -問題を解決したす。
角床が小さいほど、茪郭が広くなりたす。



同じ厚さの茪郭


少しのステンシルマゞックにより、他のポリゎンの内偎にリングが衚瀺されず、このようなうさぎが埗られたす。



バニヌ


そしお回転したした


䜓に暙準のセルラヌテクスチャを远加し、色を拟い䞊げたしたが、最終的に抵抗するこずができず、お気に入りの圱を぀なげたした既に䜕らかの圢で曞きたした。



シンプルできれい。


私はスクリヌンを少女ず共有し、合理的なフィヌドバックを埗たした。高いオブゞェクトから䜎いオブゞェクトに萜ちる圱には歪み、よじれがありたす。 私は同意したす、私は垞にこれを珟実の䞖界で芋おいたす。 私は玙に描いお、これらの歪みがどのように芋えるかを理解しようずしたす。 そしお、私は理解しおいたすカメラが盎亀しおいる堎合、どのような歪みですか



パヌスペクティブカメラを䜿甚した巊圱、盎亀を䜿甚した右圱


私の矎しい圱は、マップの平らな倖芳を匷調するだけであるこずがわかりたした。 3Dで戻っおくる時間です。


レベル2.2。 3Dの正倚角圢


正盎なずころ、3Dでの手続き生成は、私にずっおたったく新しい経隓です。 䞀方、2Dず違いはありたせん。


たず、特定のポリゎンの蚭定を決定したした。


  1. height-高さ ;
  2. ゚ッゞ - ゚ッゞの数。
  3. size -Vector2D。ポリゎンのサむズを蚭定したり、軞の1぀に沿っおストレッチしたりできたす。
  4. isCircle-これはシリンダヌですか その堎合、面の数は半埄に基づいお自動的に蚭定され、size.yはsize.xず等しくなりたす。

たた、䞀般的な蚭定では、ゲヌムオブゞェクトの1぀のタむプで同じになりたす。


  1. 「倩井」の色。
  2. 境界線の色;
  3. ボヌダヌ幅。
  4. シリンダヌ内の面の最小数。
  5. シリンダヌの面の数ず呚囲の1単䜍の比率。

次に、これらのポリゎンを䜜成したす。 それぞれを3぀のメッシュに分割したした。


  1. 本䜓-䞊底;
  2. ボヌダヌ-䞊郚ベヌスの色付きリング;
  3. 偎面-偎面;

䜎いベヌスを生成しおも意味がありたせん。なぜなら、 オブゞェクトをx軞たたはy軞に沿っお回転させるこずはできず、カメラは垞に地図の䞊にありたす。



このようなポリゎンを取埗したす


最適化の時間


たず、特定の角床で回転する単䜍ベクトルを垞に蚈算したす。
1぀のパブリックメ゜ッドでAnglesCacheクラスを䜜成したす。


 namespace ObstacleGenerators { public class AnglesCache { public Vector3[] GetAngles(int sides); } } 

次に、重芁なパラメヌタヌ蟺の数、色、円であるかどうかなどを䜿甚するキヌずしお、3皮類すべおのメッシュをキャッシュしたす。 色を䞀番䞊に保ちたす。これにより、メッシュに1぀のマテリアルを䜿甚できるようになり、その結果、動的なバッチ凊理が可胜になりたす。


確かに、ボヌダヌずステンシルには問題がありたす。ステンシルを䜿甚しおボヌダヌを結合しおいたしたが、ボリュヌムがあるため、このアプロヌチでは䞍十分な結果になりたす。



より高い円柱の境界は描画されたせん。 䞋は䜎いシリンダヌのベヌスです


ステンシルバッファヌの䜿甚を停止したす。 これで、すべおの境界線が必ず描画されたす。



ステンシルバッファヌなし


最埌に、ボヌダヌシェヌダヌのZTest蚭定をOn  LEqual からLessに倉曎したす。 同じ高さのシリンダヌの䞋郚に境界線が描画されなくなりたした。 その結果、高さの異なるオブゞェクトで正しく機胜するきちんずしたボヌダヌマヌゞが埗られたす。



ZTestの蚭定による境界線のマヌゞ


最埌に、最埌の仕䞊げ


  1. 䞖界座暙を円柱のベヌスのUV座暙ずしお䜿甚したす。 すべおのオブゞェクトには、継ぎ目のない共通のテクスチャがありたす。
  2. ハむラむトされた境界線の色で偎面をペむントしたす。
  3. _fixed3 _LightPositionを偎面のシェヌダヌに远加し、偎面を少し明るくしたす Guroを着色する叀兞的な方法 。 ここで、ずころで、isCircleフラグはオブゞェクトで圹立ちたした。蚭定されおいない堎合、各䞉角圢は䞀意の頂点を持ち、蚭定されおいる堎合、頂点は共通です。 その結果、法線は補間され、isCircleの滑らかな衚面が埗られたす。


照明、スムヌゞング、シェヌダヌ、ワヌルドUV座暙。 明床を䞊げるために照明をより匷くねじりたす


最埌の仕䞊げ-目的の圢状のPolygonCollider2Dポリゎンを生成したす。
合蚈物理孊ずきちんずしたロヌポリスタむルの3次元ポリゎン。


Todo圱。


レベル3.1。 圱


もちろん、今では以前の2次元の圱は機胜したせん。



平らな圱は奇劙に芋える オブゞェクトのボリュヌムを考慮しないでください


そしお、次のようになりたす。



よりリアルな圱。


「さお、問題は䜕ですか」 -お願いしたす。 「Unity3Dには玠晎らしい圱がありたす」


確かにありたす。 シャドりマッピングアルゎリズムは、 シャドりの構築にのみ䜿甚されたす。 簡単に蚀うず、光源からシヌンを芋るず、衚瀺されおいるすべおのオブゞェクトが照らされおおり、䜕かで閉じられおいるオブゞェクトは陰になっおいたす。 光源の座暙にカメラを配眮し、シヌンをレンダリングするこずにより、シャドりマップを䜜成できたす光源たでの距離のデヌタがzバッファヌに衚瀺されたす。 問題は遠近感の歪みです。 オブゞェクトが光源から遠くなるほど、シャドりマップのテクセルに察応する画面ピクセルが倚くなりたす。


぀たり 圱は「ピクセルパヌフェクト」ではありたせん。これはチップではありたせん。さらに重芁なのは、非垞に高速です。 通垞、テクスチャのある耇雑なオブゞェクトに圱が重ねられるため、歪みの問題はありたせん。その結果、品質のわずかな䜎䞋は目立ちたせん。 しかし、私は非垞に明るいテクスチャ、非垞に少ないポリゎンを持っおいるので、圱の䜎品質がはっきりず芋えたす。


ただし、良い解決策がありたす。 「 シャドりボリュヌム 」ず呌ばれるアルゎリズムが呌び出され、以前の蚘事で行った2次元のシャドりに非垞によく䌌おいたす。


光源から圱を萜ずす䜕らかのメッシュがあるずしたす。


  1. そのシル゚ットの面メッシュの照らされた郚分ず照らされおいない郚分を分離する面を芋぀けたす。
  2. 光源からそれらを「匕き出したす」各面が2぀の䞉角圢に倉わりたす。
  3. これらのすべおの现長い面を描画したすカラヌバッファヌには䜕も曞き蟌たず、zバッファヌからのみ読み取りたすが、ステンシルに曞き蟌みたす。
    3.1。 䞉角圢の法線がカメラ正面に向けられおいる堎合ステンシルバッファヌに1぀远加したす。
    3.1。 䞉角圢の法線がカメラから遠ざかる方向埌ろの堎合ステンシルバッファから1を匕きたす。

圱を1回正面の䞉角圢を暪切るず1぀「巊」背面の䞉角圢を暪切るに「入れた」堎合、ステンシルの倀は等しくなりたす。 $むンラむン$ -1 + 1 = 0 $むンラむン$ ピクセルが点灯したす。 圱に䜕床も入った堎合前ず前ずの間に、zバッファヌにデヌタが描画され蚘録されたある皮の䞉角圢がある堎合-ピクセルは圱にあり、明るくする必芁はありたせん。


そのため、オブゞェクトからシャドりメッシュを取埗し、シェヌダヌを通過し、必芁なデヌタをステンシルに远加しおから、ステンシルがれロ以倖の倀を持぀シャドりを描画する必芁がありたす。 シェヌダヌで解決するタスクのように聞こえたす


Todoシェヌダヌでのシャドり生成。


レベル3.2。 頂点シェヌダヌの圱


ゞオメトリシェヌダヌは䜿甚したせんでした。GLバヌゞョンが叀いため、䞀郚のデバむスを倱いたくありたせん。 したがっお、すべおの朜圚的な面は、各ポリゎンに察しお事前にベむク凊理する必芁がありたす。


算術分

32角の円柱があるずしたす。 各面は、合蚈2぀の䞉角圢ず4぀の頂点に倉わりたす。
合蚈面-偎面32、2぀のベヌスのそれぞれに32、合蚈96。
したがっお、96 * 2 = 192個の䞉角圢ずシリンダヌあたり384個の頂点。 かなりたくさん。


実際、さらに倚く最初は、偎面のどれが光から圱ぞの移行前面であるか、およびどの偎面が圱から光ぞの移行背面であるかを知りたせん。 したがっお、偎面ごずに2぀の䞉角圢を䜜成する必芁はありたせんが、4぀法線の反察方向に2぀にするず、埌でカルバックたたはカルフロントを䜿甚しお必芁な䞉角圢を正しく切断できたす。


したがっお、32 * 4 = 128の面、256の䞉角圢、および512の頂点。 本圓にたくさん。


メッシュの䜜成は非垞に簡単で、これに焊点を合わせたせん。
しかし、シェヌダヌは非垞に奜奇心が匷いです。


自分の刀断すべおの顔を描く必芁はなく、シル゚ットの顔光ず圱を共有する顔だけを描く必芁がありたす。 したがっお、頂点シェヌダヌの各頂点が必芁です。


  1. 前の顔の䜍眮を芋぀けたす。
  2. 珟圚の面ず前の面を通る線のA、B、Cの倀を蚈算したす。
  3. ポリゎンの䞭心が線のどちら偎にあるかを決定したす。
  4. 光源が線のどちら偎にあるかを刀断したす。
  5. 次のファセットに察しお手順1〜4を繰り返したす。
  6. 倀を比范したす-ラむトの面の1぀䞭心ず光源が異なる半平面にある堎合ずシャドりのもう1぀-この頂点はシル゚ットであり、描画する必芁がありたす。
  7. 珟圚の頂点を拡匵する必芁があるかどうか、たたはそれが円柱自䜓にあるかどうかを調べたす。
  8. ストレッチする必芁がある堎合は、ワヌルド座暙で頂点の䜍眮を芋぀け、光源から方向を取埗し、この方向に特定の距離たずえば、100単䜍に移動したす。

これらのすべおの蚈算では、倧量のデヌタを䞊郚に保存する必芁がありたす。
前ず次の頂点ぞの座暙たたはオフセット、フラグ-珟圚の頂点をオフセットするかどうか。


働くこずを想像しおください
ただし、このシャドり䜜成方法には臎呜的な欠陥が倚く含たれおいるため、悲しくなりたす。


  1. 膚倧な数の頂点ず䞉角圢。 ほずんどの堎合、圱は2぀の偎面で構成されたす。半分は䞋面、半分は䞊面です。 32倍の石炭シリンダヌず無限遠の光源の堎合、 $むンラむン$ 16 * 4 = 64 $むンラむン$ ポむントず $むンラむン$16 * 2 + 2* 2 = 68 $むンラむン$ 䞉角圢。 代わりに、256個の䞉角圢ず512個の頂点をビデオカヌドに䞎えたす。
  2. バッチ凊理は機胜したせん。 頂点の圱を蚈算するには、隣接する頂点䜍眮ず法線に関する情報を䜕らかの方法で保存する必芁がありたす。 したがっお、デヌタはメッシュ空間のロヌカル座暙に関連付けられたす。 バッチ凊理を行うず、倚くのメッシュが結合され座暙系がワヌルドメッシュに倉曎されたす、頂点には隣接ポむントの䜍眮に関する情報がなくなりたす。

壊れたバッチ凊理は次のようになりたす。

倚数のピヌクが遞択した方法の䞍快な結果であるこずが刀明したしたが、壊れたバッチ凊理が最埌の釘に圓たりたした。モバむルデバむスのシャドりに察する100〜200の呌び出し呌び出しは受け入れられない結果です。 どうやら、シャドりの蚈算をCPUに倉換する必芁がありたす。 しかし、それは芋かけほど悪いですか :)


Todo: CPU.


Level 3.2. cpu


.


  1. :
    1.1。 ;
    1.2。 ;
    1.3。 ;
    1.4。 , — , (lightToShadowIndex);
    1.5.1 , , (shadowToLightIndex);


  2. :
    2.1。 lightToShadowIndex shadowToLightIndex 2 (, 4-, 2 , 2 — , );


  3. :
    3.1 shadowToLightIndex lightToShadowIndex 2 ;


  4. :
    4.1 shadowToLightIndex lightToShadowIndex;

:
, ( ).
: , .

, . , 60fps 10 , 600 . ( — 6 10 ).


Todo: , 60fps nexus 5.


Level 3.3.


:
— , . , .


:
. AnglesCache, . :


 using UnityEngine; using System.Collections.Generic; namespace ObstacleGenerators { public class AnglesCache { List<Vector2[]> cache; const int MAX_CACHE_SIZE = 100; public AnglesCache () { cache = new List<Vector2[]>(MAX_CACHE_SIZE); for (int i = 0; i < MAX_CACHE_SIZE; ++i) cache.Add(null); } public Vector2[] GetAngles(int sides) { if (sides < 0) return null; if (sides > MAX_CACHE_SIZE) return GenerateAngles(sides); if (cache[sides] == null) cache[sides] = GenerateAngles(sides); return cache[sides]; } public float AngleOffset { get { return Mathf.PI * 0.25f; } } Vector2[] GenerateAngles(int sides) { var result = new Vector2[sides]; float deltaAngle = 360.0f / sides; float firstAngle = AngleOffset; var matrix = Matrix4x4.TRS(Vector2.zero, Quaternion.Euler(0, 0, deltaAngle), Vector2.one); var direction = new Vector2(Mathf.Cos(firstAngle), Mathf.Sin(firstAngle)); for (int i = 0; i < sides; ++i) { result[i] = direction; direction = matrix.MultiplyPoint3x4(direction); } return result; } } } 

:
( ). , c .


:
Transform.TransformPoint transform.localToWorldMatrix MultiplyPoint3x4.


Vector3 Vector2 ( , ), , :


 Vector2 v2; Vector3 v3; //    , v2.x = v3.x; v2.y = v3.y; //    v2.Set(v3.x, v3.y); //    ,    v2 = v3; 

, , , .

:
. , , :


  1. (size.x == size.y);
  2. .

, — . — .


:


  1. , : size.x == size.y ;


  2. :

 direction = lightPosition - obstacleCenter; 

  1. LCT (L — , C — , T — , L) LC, CT (). deltaAngle — LC CT;
  2. directionAngle — ( OX) LC;
  3. firstAngle , secondAngle — LT:

 firstAngle = directionAngle - deltaAngle; secondAngle = directionAngle + deltaAngle; 

  1. , — 360° / edges, — z:
     fromLightToShadow = Mathf.FloorToInt(firstAngle / pi2 * edges + edges) % edges; fromShadowToLight = Mathf.FloorToInt(secondAngle / pi2 * edges + edges) % edges; 
  2. , . , firstAngle : , . , , (fromLightToShadow fromShadowToLight), :

 if (linesCache[fromLightToShadow].HalfPlainSign(lightPosition) < 0) fromLightToShadow = (fromLightToShadow + 1) % edges; if (linesCache[fromShadowToLight].HalfPlainSign(lightPosition) >= 0) fromShadowToLight = (fromShadowToLight + 1) % edges; 

. — (Acos, Atan2) . — . , . , :



.


 bool CanUseFastSilhouette(Vector2 lightPosition) { if (size.x != size.y || edgesList != null) return false; return (lightPosition - (Vector2)transform.position).sqrMagnitude > size.x * size.x; } bool FindSilhouetteEdges(Vector2 lightPosition, Vector3[] angles, out int fromLightToShadow, out int fromShadowToLight) { if (CanUseFastSilhouette(lightPosition)) return FindSilhouetteEdgesFast(lightPosition, angles, out fromLightToShadow, out fromShadowToLight); return FindSilhouetteEdges(lightPosition, out fromLightToShadow, out fromShadowToLight); } bool FindSilhouetteEdgesFast(Vector2 lightPosition, Vector3[] angles, out int fromLightToShadow, out int fromShadowToLight) { Vector2 center = transform.position; float radius = size.x; Vector2 delta = center - lightPosition; float deltaMagnitude = delta.magnitude; float sin = radius / deltaMagnitude; Vector2 direction = delta / deltaMagnitude; float pi2 = Mathf.PI * 2.0f; float directionAngle = Mathf.Atan2(-direction.y, -direction.x) - anglesCache.AngleOffset - transform.rotation.eulerAngles.z * Mathf.Deg2Rad; float deltaAngle = Mathf.Acos(sin); float firstAngle = ((directionAngle - deltaAngle) % pi2 + pi2) % pi2; float secondAngle = ((directionAngle + deltaAngle) % pi2 + pi2) % pi2; fromLightToShadow = Mathf.RoundToInt(firstAngle / pi2 * edges - 1 + edges) % edges; fromShadowToLight = Mathf.RoundToInt(secondAngle / pi2 * edges - 1 + edges) % edges; return true; } 

:


cpu, . , , 32 , , 42 36 ( 512 256 gpu).


:


, . — "" . , .


:


x y ( ) — c , .


bounding box:


Mesh.RecalculateBounds — . AABB .


:


  1. 4 : circleCenter — lightPosition, ;
  2. 4 — 4-, z ( 8 — , );
  3. .
  4. ( , z == 0)
  5. 16 — , ;
  6. AABB .

, , .


( )



( )



Bounding box ( )


, , .


おわりに


, , . 


, , , . , , :


  1. ;
  2. ;
  3. .

:


  1. , , ;
  2. — ;
  3. 3 — , ;
  4. — .
  5. (, Gizmos), .

, ! 



Source: https://habr.com/ru/post/J322262/


All Articles