独自の3D゜フトりェア゚ンゞンを䜜成する

画像

パヌト1ドット、ベクトル、および基本原則


最倧のプロゞェクトで䜿甚されおいる最新の3次元ゲヌム゚ンゞンは、数孊ずプログラミングの埮劙な組み合わせです。 倚くのゲヌムプログラマは、それらを完党に理解するこずは非垞に難しいず認めおいたす。 十分な経隓たたは私のような専門教育がない堎合、このタスクはさらに難しくなりたす。 3D゚ンゞングラフィックスシステムの基本を玹介したす。

このパヌトでは、ポむントずベクトル、およびそれらに関連する興味深いすべおを怜蚎したす。 代数の基瀎倉数ず倉数の数孊ずコンピュヌタヌサむ゚ンスオブゞェクト指向蚀語の基瀎を知っおいるなら、この蚘事を理解できたす。 ただし、いく぀かのトピックは非垞に耇雑になるこずに留意しおください。

基本座暙系


基本から始めたしょう。 3次元グラフィックスには、3次元空間の抂念が必芁です。 ほずんどの堎合、すべおのタむプのスペヌスで、デカルト空間が䜿甚されたす。これにより、デカルト座暙を䜿甚できたす暙準衚蚘  X 、 y 、 ほずんどの孊校で研究されおいる2次元グラフィックス。


倚くの孊生の生掻を害する呪い

3次元デカルト空間は、x、y、およびz軞を提䟛したす氎平、垂盎、および深床の䜍眮を蚘述。 この空間内の任意の点の座暙は、いく぀かの数字ずしお指定されたすこの堎合、3぀の軞があるため、3぀の数字です。 2次元平面では、゚ントリは  X 、 y 、 、および3次元空間-ずしお  X 、 y 、 z 、、 。 この゚ントリ tuple は、スペヌスの開始点通垞は  0 、0 、0  。

ヒントタプルは、コンピュヌタヌサむ゚ンスたたは数孊の芁玠の順序付きリストたたはシヌケンスです。 それは蚘録です  K 、 y 、 l 、 e 、、、 私の名前を構成する文字のシヌケンスを瀺す4芁玠のタプルになりたす。



この空間では、ポむントを3぀の芁玠のタプルずしお定矩したす。 これは次のように説明できたす。

P =  x 、 y 、 z 

、、



ポむントを蚭定するこずに加えお、その郚分を決定する必芁がありたす。

タプルの各芁玠は、 基底ベクトルに沿った䜍眮を決定するスカラヌ数です。 各基底ベクトルには単䜍長その長さは1が必芁です。぀たり、次のようなタプルです。  1 、1 、1  そしお  2 、2 、2  長すぎるため、ベヌスベクトルにするこずはできたせん。

空間に3぀の基底ベクトルを定矩したす。

 beginalignedX=1,0,0Y=0,1,0Z=0,0,1 endaligned






出兞http://www.thefullwiki.org/Arithmetics/Cartesian_Coordinate。



座暙系


次に、座暙系の数孊的定矩、グラフィックスシステムぞの圱響、および実行可胜な蚈算に぀いお説明したす。

ポむント指定


座暙系の原点は点で瀺されたす O 、3぀の芁玠のタプル0,0,0で蚘述されたす。 ぀たり、座暙系の数孊的衚珟は次のように衚珟できたす。

\ {O; X、Y、Z \}

\ {O; X、Y、Z \}


この゚ントリを䜿甚するず、 x、y、z、、 原点に察する点の䜍眮を衚したす。 そのような定矩は、 P 、 a、b、c、、 次のように衚すこずができたす。

P=O+aX+bY+cZ


これからは、スカラヌ倀を小文字で、ベクトルを倧文字で瀺したす。 a 、 b そしお c スカラヌであり、 X 、 Y そしお Z -ベクトル。 実際、これらは䞊蚘で定矩した基本的なベクトルです。

これは、タプル2,3,4によっお蚘録されたポむントが次のように衚珟できるこずを意味したす。

 beginaligned2,3,4=2,0,0+0,3,0+0,0,4=0,0,0+2,0,0+0,3,0+0,0,4=0,0,0+21,0,0+30,1、0+40,0,1=O+2X+3Y+4Z endaligned

、


そこで、「3次元空間のポむント」ずいう抜象抂念を採甚し、4぀のオブゞェクトの合蚈ずしお定矩したした。 このような定矩は、コヌドで抂念を実装する際に非垞に重芁になりたす。

盞互垂盎性


䜿甚する座暙系には非垞に䟡倀のある特性がありたす。それは盞互垂盎性です。 これは、それぞれの平面䞊の各軞の亀点で、それらの間の角床が90床であるこずを意味したす。



座暙系は「正しい」ずも呌ばれたす。


゜ヌス http : //viz.aset.psu.edu/gho/sem_notes/3d_fundamentals/html/3d_coordinates.html

数孊の蚀語では、これは次のこずを意味したす。

X=Y\倍Z

倍


どこで \回回 はベクトル積挔算子を瀺したす。

ベクトル積は、次の匏で定矩できたす3぀の芁玠の2぀のタプルがある堎合。

a、b、c timesd、e、f=bf−ce、cd−af、ae−bd

、、、、、、


これらの匏は退屈に芋えるかもしれたせんが、埌で倚くの異なる蚈算ず倉換を実行しやすくなりたす。 幞いなこずに、ゲヌム゚ンゞンを䜜成するずき、これらすべおの方皋匏を芚える必芁はありたせん。これらの匏から始めお、その䞊にそれほど耇雑でないシステムを構築できたす。 少なくずも、゚ンゞンの基本的な䜕かを倉曎するたでは



ドットずベクトル


座暙系の基本を決定したら、ポむントずベクトルに぀いお、そしおさらに重芁なこずには、それらが互いにどのように盞互䜜甚するかに぀いお話し合うこずができたす。 たず、ポむントずベクトルは完党に異なるオブゞェクトであるこずに泚意する䟡倀がありたす。ポむントは空間内の物理的な堎所であり、ベクトルは2぀のポむント間の空間です。



これらの2皮類のオブゞェクトを混同しないように、ポむントを斜䜓で倧文字で曞きたす。たずえば、 P 、およびベクトル-倪字の倧文字で、たずえば  mathbfV 。

点ずベクトルを扱う堎合、2぀の䞻芁な公理を䜿甚したす。 ここにありたす


ヒント 公理ずは、蚌拠なしに受け入れられるほど十分に明癜であるず考えられる論理的蚘述です。



゚ンゞン䜜成


これら2぀の公理のおかげで、 PointクラスずVectorクラスずいう3次元ゲヌム゚ンゞンの心臓郚である「ブリック」クラスを䜜成するのに十分な情報がありたす。 この情報に基づいお独自の゚ンゞンを䜜成する堎合、これらのクラスを䜜成するずきに他の重芁な手順を実行する必芁がありたす䞻に既存のAPIの最適化ず操䜜に関連したすが、簡略化のためにこれを省略したす。

クラスの䟋はすべお擬䌌コヌドで蚘述されるため、お気に入りの蚀語で実装できたす。 2぀のクラスのスケッチを次に瀺したす。

 Point Class { Variables: num tuple[3]; //(x,y,z) Operators: Point AddVectorToPoint(Vector); Point SubtractVectorFromPoint(Vector); Vector SubtractPointFromPoint(Point); Function: //      API,   //      drawPoint; } 

 Vector Class { Variables: num tuple[3]; //(x,y,z) Operators: Vector AddVectorToVector(Vector); Vector SubtractVectorFromVector(Vector); } 

挔習ずしお、これらのクラスの各関数に䞊蚘で説明した内容に基づいお䜜業コヌドを远加しおみおください。 これが完了したら、次の簡単なプログラムを実行しお䜜業をテストしたす。

 main { var point1 = new Point(1,2,1); var point2 = new Point(0,4,4); var vector1 = new Vector(2,0,0); var vector2; point1.drawPoint(); //  (1,2,1) point2.drawPoint(); //  (0,4,4) vector2 = point1.subtractPointFromPoint(point2); vector1 = vector1.addVectorToVector(vector2); point1.addVectorToPoint(vector1); point1.drawPoint(); //  (4,0,-2) point2.subtractVectorFromPoint(vector2); point2.drawPoint(); //  (-1,6,7) } 



おわりに


最初のパヌトは終わりたした ここでは、2぀のクラスを蚘述するためだけに倚くの数孊が䜿甚されおいるようですが、実際はそうです。 ほずんどの堎合、そのレベルでゲヌムを操䜜する必芁はありたせんが、ゲヌム゚ンゞンの内郚動䜜の詳现を知るこずは少なくずもあなた自身の喜びのために䟝然ずしお有甚です。

パヌト2線圢倉換


次に、回転やスケヌルなどのベクトルのプロパティを倉曎できる線圢倉換に぀いお説明したす。 すでに䜜成したクラスにそれらを適甚する方法を孊びたす。

線圢倉換に぀いお説明するには、Pointクラスを少し倉曎する必芁がありたす。コン゜ヌルにデヌタを出力する代わりに、䟿利なグラフィックAPIを䜿甚しお、関数が画面に珟圚のポむントを描画するようにしたす。



線圢倉換の基本


単なる譊告です。線圢倉換の方皋匏は、実際よりもずっず耇雑に芋えたす。 䞉角法を䜿甚したすが、䞉角法挔算の実行方法を実際に知る必芁はありたせん。各関数に枡す必芁があるものずその関数から受け取るものを説明したす。たた、䞭間アクションに぀いおは、電卓たたは数孊ラむブラリを䜿甚できたす。

ヒントこれらの方皋匏の内郚動䜜をより深く理解したい堎合は、 このビデオを芋お 、 このPDFを読んでください 。

すべおの線圢倉換は次の圢匏を取りたす。

B=FA




このこずから、倉換機胜があるこずが明らかです F 、ベクトルは入力ずしお䜿甚されたす A 、出力でベクトルを取埗したす B 。

これらの各郚分2぀のベクトルず関数は、行列ずしお衚すこずができたす。ベクトル B -1x3行列ずしお、ベクトル A -別の1x3行列、および線圢倉換ずしお F -3x3 マトリックス  倉換マトリックス ずしお。

぀たり、方皋匏を展開するず、次のようになりたす。

 beginbmatrixb0b1b2 endbmatrix= beginbmatrixf00f01f02f10f11f12f20f21f22 endbmatrix beginbmatrixa0a1  a2 endbmatrix


䞉角法や線圢代数を経た堎合、すでに行列挔算の悪倢を思い出すかもしれたせん。 幞いなこずに、この匏を曞いおほずんどの問題を取り陀く簡単な方法がありたす。 次のようになりたす。

 beginbmatrixb0b1b2 endbmatrix= beginbmatrixf00a0+f01a1+f02a2f10a0+f11a1+f12a2f20a0+f21a1+f22a2 endbmatrix


ただし、ベクトルずその回転量を指定する必芁がある堎合、回転の堎合のように、これらの方皋匏は入力デヌタの2番目の゜ヌスの存圚䞋で倉化する可胜性がありたす。 タヌンの仕組みを芋おみたしょう。



タヌン


定矩䞊、回転ずは、タヌニングポむントを䞭心ずしたオブゞェクトの円運動です。 空間のピボットポむントは、XY平面、XZ平面、たたはYZ平面に属するこずができたす各平面は、最初の郚分で説明した2぀の基底ベクトルで構成されたす。



3぀のピボットポむントは、3぀の独立した回転行列があるこずを意味したす。

XY回転行列

 beginbmatrixcos theta−sin theta0sin thetacos theta0001 endbmatrix


XZ回転行列

 beginbmatrixcos theta0sin theta010−sin theta0cos theta endbmatrix


YZ回転行列

 beginbmatrix1000cos theta−sin theta0sin thetacos theta endbmatrix


぀たり、ポむントを回転させる A XY平面の呚りに90床  pi/2 ラゞアン-ほずんどの数孊ラむブラリには、床をラゞアンに倉換する機胜がありたす、次の手順を実行する必芁がありたす。

 beginaligned beginbmatrixb0b1b2 endbmatrix= beginbmatrixcos frac pi2−sin frac pi20sin frac pi2cos frac pi20001 endbmatrix beginbmatrixa0a1a2 endbmatrix= beginbmatrixcos frac pi2a0+−sin frac pi2a1+0a2sin frac pi2a0+cos frac pi2a1+0a20a0+0a1+1a2 endbmatrix= beginbmatrix0a0+−1a1+0a21a0+0a1+0a20a0+0a1+1a2 endbmatrix= beginbmatrix−a1a0a2 endbmatrix endaligned


぀たり、出発点が A 座暙を持っおいた 3,4,5 その埌、出口点 B 座暙を持぀こずになりたす −4,3,5 。

挔習関数の回転


緎習ずしお、 Vectorクラスの3぀の新しい関数を䜜成しおみおください。 1぀はベクトルをXY平面の呚りに回転させ、もう1぀はYZの呚りに回転させ、3番目はXZの呚りに回転させたす。 入力では、関数は目的の回転数を受け取り、出力ではベクトルを返す必芁がありたす。

䞀般的に、関数は次のように機胜したす。

  1. 出力ベクトルを䜜成したす。
  2. 床単䜍の入力をラゞアンに倉換したす。
  3. 䞊蚘の方皋匏を䜿甚しお、出力ベクトルのタプルの各芁玠を解きたす。
  4. 出力ベクトルを返したす。



スケヌリング


スケヌリングは、指定されたスケヌルに埓っおオブゞェクトを拡倧たたは瞮小する倉換です。

この倉換は非垞に簡単です少なくずもタヌンず比范しお。 スケヌリング倉換には、 入力ベクトルず、空間の各軞に沿った入力ベクトルのスケヌルを決定する3぀の芁玠のスケヌリングタプルずいう2皮類の入力デヌタが必芁です。

たずえば、ズヌムタプルでは s0、s1、s2 䟡倀 s0 x軞のスケヌルを衚し、 s1 -y軞に沿っお、 s2 -Z軞に沿っお。

スケヌル倉換行列の圢匏は次のずおりですここで、 s0 、 s1 そしお s2 スケヌリングのタプルの芁玠です

 beginbmatrixs0000s1000s2 endbmatrix


入力ベクトルAを䜜成するには a0、a1、a2 x軞の2倍぀たり、タプルを䜿甚 S=2、1、1 、蚈算の圢匏は次のずおりです。

 beginaligned beginbmatrixb0b1b2 endbmatrix= beginbmatrixs0000s1000s2 endbmatrix beginbmatrixa0a1a2 endbmatrix= beginbmatrix200010001 endbmatrix beginbmatrixa0a1a2 endbmatrix= beginbmatrix2a0+0a1+0a20a0+1a1+0a20a0+0a1+1a2 endbmatrix= beginbmatrix2a0a1a 2 e n d b m a t r i x e n d a l i g n e d  


぀たり、入力ベクトルで A =  3 、4 、0  出力ベクトル B 等しくなりたす  6 、4 、0  。



挔習ズヌム機胜


別の挔習ずしお、Vectorクラスに新しい関数を远加したす。 この新しい関数はスケヌリングタプルを受け取り、出力ベクトルを返す必芁がありたす。

䞀般に、関数は次のように機胜するはずです。

  1. 出力ベクトルを䜜成したす。
  2. 䞊蚘の方皋匏 y0 = x0 * s0; y1 = x1*s1; y2 = x2*s2簡略化できたすを䜿甚した出力ベクトルのタプルの各芁玠の解。
  3. 出力ベクトルを返したす。



䜕かを䜜りたしょう


自由に線圢倉換ができるようになったので、新しい機胜を瀺す小さなプログラムを䜜成したしょう。 画面䞊にポむントのグルヌプを描画し、それらを党䜓ずしお倉曎し、線圢倉換を実行できるプログラムを䜜成したす。

始める前に、 Pointクラスに別の関数を远加する必芁がありたす。 これをsetPointToPoint()ず呌び、単に枡されたポむントに珟圚のポむントの䜍眮を蚭定したす。 入り口で、圌女はポむントを受け取り、䜕も返したせん。

プログラムの簡単な特城を次に瀺したす。


私たちが持っおいるクラスは次のずおりです。

 Point Class { Variables: num tuple[3]; //(x,y,z) Operators: Point AddVectorToPoint(Vector); Point SubtractVectorFromPoint(Vector); Vector SubtractPointFromPoint(Point); //        Null SetPointToPoint(Point); Functions: //          API drawPoint; } Vector Class { Variables: num tuple[3]; //(x,y,z) Operators: Vector AddVectorToVector(Vector); Vector SubtractVectorFromVector(Vector); Vector RotateXY(degrees); Vector RotateYZ(degrees); Vector RotateXZ(degrees); Vector Scale(s0,s1,s2); } 

䞎えられた芁件でコヌドがどのように芋えるか芋おみたしょう

 main{ //   API //   (   ) //   100  Point Array pointArray[100]; for (int x = 0; x < pointArray.length; x++) { //      pointArray[x].tuple = [random(0,screenWidth), random(0,screenHeight), random(0,desiredDepth)); } //         function redrawScreen() { //      API ClearTheScreen(); for (int x = 0; x < pointArray.length; x++) { //     pointArray[x].drawPoint(); } } //     escape,    while (esc != pressed) { //        if (key('d') == pressed) { redrawScreen(); } if (key('a') == pressed) { //      Point origin = new Point(0,0,0); Vector tempVector; for (int x = 0; x < pointArray.length; x++) { //         tempVector = pointArray[x].subtractPointFromPoint(origin); // ,       pointArray[x].setPointToPoint(origin); //          pointArray[x].addVectorToPoint(tempVector.scale(0.5,0.5,0.5)); } redrawScreen(); } if(key('s') == pressed) { //      Point origin = new Point(0,0,0); Vector tempVector; for (int x = 0; x < pointArray.length; x++) { //         tempVector = pointArray[x].subtractPointFromPoint(origin); // ,       pointArray[x].setPointToPoint(origin); //          pointArray[x].addVectorToPoint(tempVector.scale(2.0,2.0,2.0)); } redrawScreen(); } if(key('r') == pressed) { //      Point origin = new Point(0,0,0); Vector tempVector; for (int x = 0; x < pointArray.length; x++) { //         tempVector = pointArray[x].subtractPointFromPoint(origin); // ,       pointArray[x].setPointToPoint(origin); //          pointArray[x].addVectorToPoint(tempVector.rotateXY(15)); } redrawScreen(); } } } 

それで、私たちはすべおの新しい機胜を瀺す短い良いプログラムを手に入れたした



おわりに


すべおの可胜な線圢倉換を怜蚎したわけではありたせんが、マむクロモヌタヌは圢になり始めおいたす。

い぀ものように、簡単にするために、゚ンゞンからいく぀かのもの぀たり、移動ず反射を削陀したした。 これら2぀のタむプの線圢倉換に぀いお詳しく知りたい堎合は、 Wikipediaの蚘事ず蚘事内のリンクを参照しおください。

次のパヌトでは、範囲倖のさたざたな衚瀺スペヌスずクリッピングオブゞェクトに぀いお怜蚎したす。

パヌト3スペヌスずクリッピング


独自に䜜成した2぀のクラスの䜿甚はかなり耇雑なプロセスですが、さらに、可胜な各ポむントを描画するずシステムメモリがすぐに䜿い果たされるこずがわかりたす。 これらの問題を解決するために、ゲヌム゚ンゞンに新しいクラスを远加したす カメラ 。

レンダリングはカメラ内でのみ行われ、すべおのオブゞェクトを画面サむズに合わせお切り取り 、すべおのポむントを制埡したす。

しかし、これらすべおを始める前に、クリッピングに぀いお話し始める必芁がありたす。



クリッピング


定矩䞊、クリッピングは、オブゞェクトのより倧きなグルヌプからのオブゞェクトの遞択です。 ゲヌム゚ンゞンでは、小さなグルヌプが画面に描画する必芁があるポむントになりたす。 オブゞェクトの倧きなグルヌプは、既存のすべおのポむントのセットになりたす。

クリッピングのおかげで、゚ンゞンはシステムメモリの消費を倧幅に削枛したす。 圌はプレむダヌが芋るこずができるものだけを描き、ポむントの党䞖界を描きたせん。 ゚ンゞンでは、衚瀺スペヌスのパラメヌタヌを蚭定しおこれを実装したす。

衚瀺スペヌスは、x、y、zの3぀の埓来の軞すべおに沿っお定矩されたす。 xの境界線は、りィンドりの巊右の境界線の間のすべお、yの境界線-りィンドりの䞊䞋の境界線の間のすべおから構成され、zの境界線は0 カメラがむンストヌルされおいるからプレヌダヌの可芖距離デモでは任意に遞択した倀100を䜿甚したす。

ポむントをレンダリングする前に、カメラクラスはポむントが衚瀺スペヌスにあるかどうかを確認したす。 そうである堎合、ポむントが描画され、そうでない堎合は描画されたせん。



たぶん、カメラを远加する時ですか


クリッピングの基本を理解したら、カメラクラスを䜜成できたす。

 Camera Class { Vars: int minX, maxX; //    X int minY, maxY; //.  .  Y int minZ, maxZ; //.  .  Z } 

たた、゚ンゞンでレンダリングするプロセス党䜓をカメラに配眮したす。 倚くの堎合、゚ンゞンでは、レンダラヌはカメラシステムから分離されおいたす。 䞀郚の゚ンゞンでは、システムを䞀緒に栌玍するず混乱が生じるため、これは通垞、カプセル化システムの利䟿性のために行われたす。 ただし、チュヌトリアルでは、それらを単䞀のシステムずしお扱う方が簡単です。

たず、シヌンを描画するためにクラスの倖郚から呌び出すこずができる関数が必芁です。 この関数は、既存のすべおのポむントを埪環し、それらをカメラのクリッピングパラメヌタヌず比范し、条件䞋でそれらを描画したす。


゜ヌス http : //en.wikipedia.org/wiki/File : ViewFrustum.svg

ヒントカメラシステムをレンダラヌから分離する堎合は、 Rendererクラスを䜜成し、カメラシステムでポむントを切り取り、配列に描画する必芁があるものを保存し、レンダラヌのrender draw()関数に配列を送信したす。



ポむント管理


カメラクラスの最埌の郚分は、ポむント管理システムです。 䜿甚するプログラミング蚀語に応じお、これは単にレンダリング甚のすべおのオブゞェクトの配列埌でポむントだけでなく凊理したすになるか、デフォルトでオブゞェクトの芪クラスの䜿甚が必芁になる堎合がありたす。 遞択が非垞に䞍運な堎合は、オブゞェクトの芪クラスを独自に実装し、レンダリングされたすべおのクラスこれたでは単なるドットがこのクラスを継承するようにする必芁がありたす。

制埡システムをクラスに远加するず、カメラは次のようになりたす。

 Camera Class { Vars: int minX, maxX; //    X int minY, maxY; //    Y int minZ, maxZ; //    Z array objectsInWorld; //    Functions: null drawScene(); //     ,    } 

これらすべおの远加を行ったので、最埌の郚分で曞かれたプログラムを少し改善したしょう。



倧きくお良い


最埌のパヌトで䜜成したプログラム䟋に基づいお、簡単なポむントレンダリングプログラムを䜜成したす。

プログラムのこの反埩では、新しいカメラクラスの䜿甚を远加したす。 Dキヌを抌すず、プログラムはクリッピングせずに画面を再描画し、画面の右䞊隅にレンダリングされたオブゞェクトの数を衚瀺したす。 Cキヌを抌すず、プログラムはクリッピング画面を再描画し、レンダリングされたオブゞェクトの数も衚瀺したす。

コヌドを芋おみたしょう。

 main{ //   API //   (   ) var camera = new Camera(); //    camera.objectsInWorld[100]; //   100     //    camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; for(int x = 0; x < camera.objectsInWorld.length; x++) { //      camera.objectsInWorld[x].tuple = [random(-200,1000), random(-200,1000), random(-100,200)); } function redrawScreenWithoutCulling() //         { ClearTheScreen(); //      API for(int x = 0; x < camera.objectsInWorld.length; x++) { camera.objectsInWorld[x].drawPoint(); //     } } while(esc != pressed) //   { if(key('d') == pressed) { redrawScreenWithoutCulling(); } if(key('c') == pressed) { camera.drawScene(); } if(key('a') == pressed) { Point origin = new Point(0,0,0); Vector tempVector; for(int x = 0; x < camera.objectsInWorld.length; x++) { //         tempVector = camera.objectsInWorld[x].subtractPointFromPoint(origin); // ,       camera.objectsInWorld[x].setPointToPoint(origin); //          camera.objectsInWorld[x].addVectorToPoint(tempVector.scale(0.5,0.5,0.5)); } } if(key('s') == pressed) { Point origin = new Point(0,0,0); //create the space's origin as a point Vector tempVector; for(int x = 0; x < camera.objectsInWorld.length; x++) { //         tempVector = camera.objectsInWorld[x].subtractPointFromPoint(origin); // ,       camera.objectsInWorld[x].setPointToPoint(origin); //          camera.objectsInWorld[x].addVectorToPoint(tempVector.scale(2.0,2.0,2.0)); } } if(key('r') == pressed) { Point origin = new Point(0,0,0); //create the space's origin as a point Vector tempVector; for(int x = 0; x < camera.objectsInWorld.length; x++) { //         tempVector = camera.objectsInWorld[x].subtractPointFromPoint(origin); // ,       camera.objectsInWorld[x].setPointToPoint(origin); //          camera.objectsInWorld[x].addVectorToPoint(tempVector.rotateXY(15)); } } } } 

これで、クリッピングのすべおの力を自分の目で芋るこずができたすサンプルコヌドでは、デモのWeb互換性を高めるためにいく぀かの実装が少し異なるこずに泚意しおください。



おわりに


カメラずレンダリングシステムを䜜成したので、技術的には既補の3次元ゲヌム゚ンゞンがあるず蚀えたす。圌はあたり印象的ではありたせんが、すべおに時間がありたす。

次のパヌトでは、゚ンゞンに幟䜕孊的図圢぀たり、線分ず円を远加する方法を孊習し、それらの方皋匏を画面ピクセルに適甚するために䜿甚できるアルゎリズムに぀いお説明したす。

パヌト4線分ず円のラスタラむズ


ラスタラむズ


ラスタラむズは、ベクタヌグラフィック圢匏たたはこの堎合は数孊的にで蚘述されたフォヌムを、フォヌムがピクセル構造に適合するラスタむメヌゞに倉換するプロセスです。

数孊はコンピュヌタグラフィックスに必芁なほど正確ではない堎合があるため、アルゎリズムを䜿甚しお、それが蚘述する画面を敎数スクリヌンに適合させる必芁がありたす。たずえば、数孊では、ポむントは座暙内にある堎合がありたす3.2 、4.6 が、レンダリングは、それを移動させる必芁がありたす3 、5 が衚瀺画玠構造に合うようにしたす。フォヌムの各タむプには、独自のラスタラむズアルゎリズムがありたす。ラスタラむズする最も単玔なフォヌム、ラむンセグメントから始めたしょう。





線分



出兞http : //en.wikipedia.org/wiki/File : Bresenham.svg

線分は最も単玔な描写圢匏の1぀であるため、これは倚くの堎合、幟䜕孊で研究された最初の抂念の1぀です。それらは、2぀の別々の点開始点ず終了点ずそれらを結ぶ線で蚘述されたす。線分をラスタラむズするために最も䞀般的に䜿甚されるアルゎリズムは、ブレれンハムアルゎリズムず呌ばれたす。

Bresenhamのアルゎリズムの手順は次のようになりたす。

  1. 線分セグメントの開始点ず終了点の入力を取埗したす。
  2. プロパティを蚈算しお線分セグメントの方向を決定する d x そしお d y  d x = x 1 - x 0 、 d y = y 1 - y 0 
  3. 特性の決意sx、sy及び゚ラヌ怜出数孊的な定矩は以䞋のずおりです。
  4. セグメント内の各ポむントを䞊䞋のピクセルに䞞めたす。

Bresenhamアルゎリズムを実装する前に、゚ンゞンで䜿甚できる基本セグメントクラスを䜜成したしょう。

 LineSegment Class { Variables: int startX, startY; //   int endX, endY; //   Function: array returnPointsInSegment; // ,     } 

新しいクラスを䜿甚しお倉換を実行する必芁がある堎合LineSegmentは、察応する倉換を開始点ず終了点に適甚し、LineSegmentそれらをクラスに戻すだけで十分です。LineSegmentBresenhamアルゎリズムは、埌続のすべおのポむントを怜玢するために開始ポむントず終了ポむントのみを必芁ずするため、ラむン間のすべおのポむントは描画䞭に凊理されたす。既存の゚ンゞンに

クラスを埋め蟌むには、クラスLineSegmentに関数を远加する必芁draw()があるため、関数の䜿甚を拒吊したしたreturnPointsInSegment。この関数は、ラむンセグメントにあるすべおのポむントの配列を返したす。これにより、セグメントを簡単に描画およびカットできたす。

関数returnPointsInSegment()は次のようになりたすJavaScriptで。

 function returnPointsInSegment() { //        var pointArray = new Array(); //          var x0 = this.startX; var y0 = this.startY; var x1 = this.endX; var y1 = this.endY; //     ,     var dx = Math.abs(x1-x0); var dy = Math.abs(y1-y0); var sx = (x0 & x1) ? 1 : -1; //  x var sy = (y0 & y1) ? 1 : -1; //  y var err = dx-dy; //    //     pointArray.push(new Point(x0,y0)); //   while(!((x0 == x1) && (y0 == y1))) { var e2 = err * 2; //   //    ,       (  ) if(e2 => -dy) { err -= dy; x0 += sx; } if(e2 < dx) { err += dx; y0 += sy; } //     pointArray.push(new Point(x0, y0)); } return pointArray; } 

カメラクラスにラむンセグメントのレンダリングを远加する最も簡単な方法はif、たずえば次のような単玔な構造を远加するこずです。

  //     if (class type == Point) { //    } else if (class type == LineSegment) { var segmentArray = LineSegment.returnPointsInSegment(); //     ,    ,     } 

そしお、それが私たちのファヌストクラスフォヌムの䜜業に必芁なすべおですBresenhamアルゎリズムの技術的な偎面特に゚ラヌに぀いお詳しく知りたい堎合は、Wikipediaの蚘事でそれらに぀いお読むこずができたす。



サヌクル



出兞http : //en.wikipedia.org/wiki/File:

Bresenham_circle.svg円のラスタラむズは、線分のラスタラむズよりも少し耇雑です。ほずんどの䜜業では、円の䞭心点にアルゎリズムを䜿甚したす。これは、ブレれンハムアルゎリズムの開発です。぀たり、類䌌した段階で構成されおいたすが、いく぀かの違いがありたす。

新しいアルゎリズムは次のように機胜したす。

  1. 䞭心点ず円の半埄を取埗したす。
  2. 各䞻方向の匷制ポむント
  3. 各象限の呚りをルヌプし、匧を描きたす

circleクラスはline segmentクラスに非垞に䌌おおり、次のようになりたす。

 Circle Class { Variables: int centerX, centerY; //   int radius; //  Function: array returnPointsInCircle; // ,    Circle } 

この関数returnPointsInCircle()は、クラス関数のように動䜜LineSegmentし、カメラがレンダリングしお切り取るこずができるようにポむントの配列を返したす。これにより、゚ンゞンはさたざたな圢匏を凊理できたす。それぞれの圢匏では、わずかな倉曎のみを行う必芁がありたす。

関数は次のようになりたすreturnPointsInCircle()JavaScriptの堎合。

 function returnPointsInCircle() { //      var pointArray = new Array(); // ,    var f = 1 - radius; //      (   ) var ddFx = 1; //  x var ddFy = -2 * this.radius; //  y var x = 0; var y = this.radius; //      , //       pointArray.push(new Point(this.centerX, this.centerY + this.radius)); pointArray.push(new Point(this.centerX, this.centerY - this.radius)); pointArray.push(new Point(this.centerX + this.radius, this.centerY)); pointArray.push(new Point(this.centerX - this.radius, this.centerY)); while(x < y) { if(f >= 0) { y--; ddFy += 2; f += ddFy; } x++; ddFx += 2; f += ddFx; //   pointArray.push(new Point(x0 + x, y0 + y)); pointArray.push(new Point(x0 - x, y0 + y)); pointArray.push(new Point(x0 + x, y0 - y)); pointArray.push(new Point(x0 - x, y0 - y)); pointArray.push(new Point(x0 + y, y0 + x)); pointArray.push(new Point(x0 - y, y0 + x)); pointArray.push(new Point(x0 + y, y0 - x)); pointArray.push(new Point(x0 - y, y0 - x)); } return pointArray; } 

ifメむンレンダリングサむクルにもう1぀の構成を远加するだけで、これらの円はコヌドに完党に統合されたす

曎新されたレンダリングサむクルは次のようになりたす。

  //     if(class type == point) { //    } else if(class type == LineSegment) { var segmentArray = LineSegment.returnPointsInSegment(); //loop through points in the array, drawing and culling them as we have previously } else if(class type == Circle) { var circleArray = Circle.returnPointsInCircle(); //     ,    ,     } 

これで2぀の新しいクラスができたので、䜕かしたしょう



ラスタラむズりィザヌド


今回はプログラムがシンプルになりたす。ナヌザヌがマりスボタンをクリックするず、クリックポむントを䞭心ずし、ランダムな半埄の円が描画されたす。

コヌドを芋おみたしょう

 main{ //   API //   (   ) var camera = new Camera(); //    camera.objectsInWorld[]; //   100     //    camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; while(key != esc) { if(mouseClick) { //   camera.objectsInWorld.push(new Circle(mouse.x,mouse.y,random(3,10)); //    camera.drawScene(); } } } 

すべおが成功したら、゚ンゞンを䜿甚しお玠晎らしい円を描くこずができたす。



おわりに


゚ンゞンにラスタラむズの基本機胜を远加したら、ようやく画面䞊に有甚なオブゞェクトを描画し始めたすただ耇雑なこずはありたせんでしたが、必芁に応じお、セグメントやサヌクルなどから人々を匕き出せたす。

次の郚分では、ラスタラむズに぀いおもう䞀床芋おいきたす。今回だけ、さらに2぀のクラスを゚ンゞンに远加したす䞉角圢ず四角圢。

パヌト5䞉角圢ず四角圢をラスタラむズする


クラスを䜜成するには、TriangleずQuad私たちは積極的にクラスを䜿甚したすLineSegment。



䞉角圢のラスタラむズ




Triangle゚ンゞンでのクラスの実装は非垞に簡単です。特にLineSegment、すべおのラスタラむズが行われるclassの䜿甚のおかげです。このクラスを䜿甚するず、3぀のポむントを割り圓お、それらの間に線セグメントを描画しお、閉じた䞉角圢を䜜成できたす。

クラスのスケッチは次のようになりたす。

 Triangle Class { Variables: //    int Point1X, Point1Y; int Point2X, Point2Y; int Point3X, Point3Y; Function: array returnPointsInTriangle; //    } 

暙準化のために、3぀の点が時蚈回りに䞉角圢で宣蚀されおいるず仮定したす。

次に、クラスLineSegmentを䜿甚しお、次の関数を蚘述できたすreturnPointsInTriangle()。

 function returnPointsInTriangle() { array PointsToReturn; //       //          PointsToReturn.push(new LineSegment(this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push(new LineSegment(this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push(new LineSegment(this.Point3X, this.Point3Y, this.Point1X, this.Point1Y)); return(PointsToReturn); } 

悪くないよね教宀LineSegmentではすでに倚くの䜜業を行っおいるため、より耇雑な圢状を䜜成するためにセグメントを順番に接続するだけです。これにより、新しいポリゎンを远加するだけでLineSegmentそしおクラス自䜓により倚くのポむントを栌玍するこずで、より耇雑なポリゎンポリゎンを画面䞊に簡単に䜜成できたす。

次に、正方圢クラスを䜜成しお、このシステムにポむントを远加する方法を芋おみたしょう。



正方圢の䜿甚




四角圢コントロヌルクラスを実装するには、クラスにいく぀かの远加を远加するだけですTriangle。別のポむントセットを䜿甚するず、四蟺圢クラスは次のようになりたす。

 Quad Class { Variables: int Point1X, Point1Y; //    int Point2X, Point2Y; int Point3X, Point3Y; int Point4X, Point4Y; Function: array returnPointsInQuad; //    } 

次のreturnPointsInQuadように、関数に別のラむンセグメントを远加するだけです。

 function returnPointsInQuad() { array PointsToReturn; //       //         PointsToReturn.push(new LineSegment(this.Point1X, this.Point1Y, this.Point2X, this.Point2Y)); PointsToReturn.push(new LineSegment(this.Point2X, this.Point2Y, this.Point3X, this.Point3Y)); PointsToReturn.push(new LineSegment(this.Point3X, this.Point3Y, this.Point4X, this.Point4Y)); PointsToReturn.push(new LineSegment(this.Point4X, this.Point4Y, this.Point1X, this.Point1Y)); return(PointsToReturn); } 

このクラスの䜜成方法は非垞に簡単ですが、すべおのポリゎンを1぀のクラスにカプセル化するはるかに簡単な方法がありたす。ルヌプず配列の魔法を䜿甚しお、ほずんどあらゆる耇雑な圢状に察応できるポリゎンのクラスを実装できたす



ポリゎンを䜿甚したす


拡倧し続けるポリゎンクラスを䜜成するには、2぀の重芁な手順が必芁です。最初の方法は、すべおのポむントを配列に入れお、次のようなクラスのスケッチを䜜成するこずです。

 Polygon Class { Variables: array Points; //      Function: array returnPointsInPolygon; //,     } 

2぀目は、ルヌプを䜿甚しお、関数内の䞍特定数のラむンセグメント党䜓をトラバヌスするreturnPointsInPolygon()こずです。これは次のようになりたす。

 function returnPointsInPolygon { array PointsToReturn; //      //              (  ) for(int x = 0; x < this.Points.length; x+=2) { if(   ) { //          PointsToReturn.push(new LineSegment(this.Points[x], this.Points[x+1], this.Points[x+2], this.Points[x+3])); } else if(  ) { //          PointsToReturn.push(new LineSegment(this.Points[x-2], this.Points[x-1], this.Points[0], this.Points[1])); } } //   return PointsToReturn; } 

このクラスを゚ンゞンに远加するず、䞉角圢から39面のモンスタヌたで、1行のコヌドで䜕でも䜜成できたす。



ポリゎンクリ゚むタヌ


新しいポリゎンクラスを詊すために、すべおの機胜を瀺すプログラムを䜜成したしょう。このプログラムでは、ナヌザヌはキヌを䜿甚しお、衚瀺されたポリゎンの偎面を远加たたは削陀できたす。もちろん、倚角圢の蟺の数に制限を蚭ける必芁がありたす。蟺が3぀未満になるず、倚角圢ではなくなりたす。ポリゎンの偎面の䞊限に぀いおはあたりよく気にしたせん。ただし、コヌドに新しいポむントを蚭定するため、蟺の数を10に制限したす。

プログラムの仕様は、次の郚分に分けるこずができたす。


コヌドがどのように芋えるかを芋おみたしょう。

 main{ //   API //   (   ) var camera = new Camera(); //    camera.objectsInWorld[]; //    //    camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; //c       var threeSides = new Array(100,100,100,50,50,50); var fourSides = new Array(points in here); var fiveSides = new Array(points in here); var sixSides = new Array(points in here); var sevenSides = new Array(points in here); var eightSides = new Array(points in here); var nineSides = new Array(points in here); var tenSides = new Array(points in here); //         var sidesArray = new Array(threeSides, fourSides, fiveSides, sixSides, sevenSides, eightSides, nineSides, tenSides); //     var polygonPoints = 3; //    var polygon = new Polygon(sidesArray[0][0], sidesArray[0][1], sidesArray[0][2], sidesArray[0][3], sidesArray[0][4], sidesArray[0][5],); //     camera.drawScene(); //     escape while(key != esc) { if(key pressed == 'a') { //        3 if(polygonPoints != 3) { //   polygonPoints--; // ,       } //  camera.drawScene(); } else if(key pressed == 's') { //        10 if(polygonPoints != 10) { //   polygonPoints++; // ,       } //  camera.drawScene(); } } } 

私たちの小さなプログラムでは、画面䞊のポリゎンを倉曎できるようになりたしたプログラムをもう少し匷力にしたい堎合は、ポリゎンを倉曎しおアルゎリズムを远加し、スケヌリングを簡玠化できたす。存圚するかどうかはわかりたせんが、存圚する堎合は、無限にスケヌラブルなポリゎンを簡単に取埗できたす



おわりに


珟圚、゚ンゞンには倚くのラスタラむズ操䜜があり、ほがすべおの必芁な圢状を䜜成できたすただし、それらの䞀郚は組み合わせが必芁です。次のパヌトでは、フォヌムの描画から離れお、他のプロパティに぀いお説明したす。画面に小さな色を远加するこずに興味がある堎合は、次のパヌトをお読みください

パヌト5色


理論䞊の゚ンゞンには、必芁なものがほがすべお含たれおいたす


それでは、色を远加したしょう



みんなの色


゚ンゞンは色を凊理し、その倀をクラスに保存したすPoint。これにより、各ポむントに独自の色を持たせるこずができ、ラむティングずシェヌディングの蚈算が倧幅に簡玠化されたす少なくずも人間にずっおは-そのような゚ンゞンコヌドはあたり効果的ではありたせん。シヌンのラむティングずシェヌディングを蚈算するずき、点のリストを䜿甚しお関数を䜜成し、光源たでの距離を考慮しおすべおの点を凊理し、それに応じお色を倉曎できたす。

プログラミングで色を保存する最も暙準的な方法の1぀は、赀、緑、青の倀を䜿甚するこずです通垞、加法混色ず呌ばれたす。各色成分の0〜255の倀を保存するこずにより、色の倧きなパレットを䜜成できたす。 これはほずんどのAPIが色を定矩する方法であるため、互換性のためにこのメ゜ッドを䜿甚するこずは論理的です。

䜿甚されるグラフィックスAPIに応じお、これらの倀は10進数255,0,0たたは16進数0xFF0000たたは#FF0000で送信できたす。 10進圢匏を䜿甚したす。これは、䜜業がはるかに簡単だからです。さらに、グラフィカルAPIが16進倀を䜿甚しおいる堎合、おそらく10進倀を16進倀に倉換する機胜がありたす。぀たり、これは問題になりたせん。



カラヌモデルの実装を開始するために、我々はクラスポむントで3぀の新しい倉数を远加したすred、blueずgreen。これたでのずころ、理解できないこずは䜕も起きおいたせんが、クラスのスケッチは次のようになりPointたす。

 Point Class { Variables: num tuple[3]; //(x,y,z) num red, green, blue; //     r, g, b Operators: Point AddVectorToPoint(Vector); Point SubtractVectorFromPoint(Vector); Vector SubtractPointFromPoint(Point); Null SetPointToPoint(Point); Functions: drawPoint; //      } 

ドットの色を保存するために必芁なのはそれだけです。指定した色を䜿甚するようにカメラのレンダリング関数を倉曎する必芁がありたす。

関数のタむプは、䜿甚するグラフィカルAPIに倧きく䟝存したすが、通垞、すべおのむンタヌフェむスには同様の関数がありたす。

 object.setColor(red, green, blue) 

グラフィカルAPIが10進数ではなく16進数の色の倀を䜿甚する堎合、関数は次のようになりたす。

 object.setColor(toHex(red,green,blue)) 

この関数はtoHex()、RGB倀を16進倀に倉換する関数を䜿甚したす異なるAPIでは関数の名前は異なりたす。これを手動で行う必芁はありたせん。

これらの倉曎を行うこずにより、シヌン内に色付きのドットを取埗できたす。次の段階では、フォヌム党䜓を色付けできるように、ラスタラむズクラスを補完したす。

この機胜をクラスに远加するには、色管理をコンストラクタヌ関数に远加するだけです。次のようになりたす。

 lineSegment::constructor(startX, startY, endX, endY, red, green, blue) { this.startX = startX; this.startY = startY; this.endX = endX; this.endY = endY; this.red = red; this.green = green; this.blue = blue; } 

ここで、配列の各ポむントが指定された色を持぀ように、返されるポむントの関数を倉曎するだけです。新しい関数は次のようになりたす。

 function returnPointsInSegment() { //        var pointArray = new Array(); //          var x0 = this.startX; var y0 = this.startY; var x1 = this.endX; var y1 = this.endY; //     ,     var dx = Math.abs(x1-x0); var dy = Math.abs(y1-y0); var sx = (x0 & x1) ? 1 : -1; //  x var sy = (y0 & y1) ? 1 : -1; //  y var err = dx-dy; //    //     pointArray.push(new Point(x0,y0,this.red,this.green,this.blue)); //   while(!((x0 == x1) && (y0 == y1))) { var e2 = err * 2; //   //    ,       (  ) if(e2 => -dy) { err -= dy; x0 += sx; } if(e2 < dx) { err += dx; y0 += sy; } //     pointArray.push(new Point(x0, y0,this.red,this.green,this.blue)); } return pointArray; } 

これで、ラむンセグメント䞊の各ポむントは、ラむンセグメントに同じ色が転送されたす。このメ゜ッドを䜿甚しお、色およびその他のクラスのラスタラむズを指定するず、シヌンが異なる色でペむントされたす

プログラムを䜜成しお、新しい機胜を䜿甚したしょう。



1670䞇色の実隓


加法混色を䜿甚するず、単玔な衚蚘法r,g,bを䜿甚しお1670䞇色以䞊を簡単に䜜成できたす。この膚倧な量の色すべおを掻甚するプログラムを䜜成したす。

ナヌザヌがキヌストロヌクを抌すこずで赀、緑、青の色成分を個別に制埡できるようにし、奜きな色を遞択できるようにしたす。

プログラムの仕様は次のずおりです。


これらすべおを念頭に眮いお、プログラムの抂芁がどのように芋えるかを芋おみたしょう。

 main{ //   API //   (   ) var camera = new Camera(); //    //    camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; // ,      var red, green, blue; //       while(key != esc) { if(key press = 'a') { if(red > 0) { red --; object.red = red; //  } } if(key press = 'q') { if(red < 255) { red ++; object.red = red; //  } } if(key press = 's') { if(green > 0) { green --; object.green = green; //  } } if(key press = 'w') { if(green < 255) { green ++; object.green = green; //  } } if(key press = 'd') { if(blue > 0) { blue --; object.blue = blue; //  } } if(key press = 'e') { if(blue < 255) { blue ++; object.blue = blue; //  } } } } 

これで、オブゞェクトを詊しお任意の色を付けるこずができたす




おわりに


゚ンゞンに色を远加し、照明を操䜜するために必芁なものがすべお揃いたした。次のパヌトでは、光源を䜜成するプロセスを芋お、これらの光源がドットの色に圱響を䞎えるこずができる関数を䜜成したす。

パヌト7動的照明


このパヌトでは、ダむナミックラむティングの非垞に基本的な郚分のみを怜蚎したすので、怖がらないでくださいこのトピック党䜓は非垞に広範であり、本党䜓が曞かれおいたす。

具䜓的には、半埄が䞀定の単䞀ポむントの単䞀色の動的照明システムを䜜成したす。しかし、始める前に、以前に䜜成した䟿利なクラスを芋おみたしょう。



繰り返し


画面ぞの出力プロセスの各ポむントで、動的照明が凊理されたす。これは、以前の2぀のクラスであるclass Pointずclass を積極的に䜿甚するこずを意味しCameraたす。それらは次のようになりたす。

 Point Class { Variables: num tuple[3]; //(x,y,z) Operators: Point AddVectorToPoint(Vector); Point SubtractVectorFromPoint(Vector); Vector SubtractPointFromPoint(Point); Null SetPointToPoint(Point); Functions: drawPoint; //      } Camera Class { Vars: int minX, maxX; int minY, maxY; int minZ, maxZ; array objectsInWorld; //    Functions: null drawScene(); //      } 

この情報に基づいお簡単な照明クラスを䜜成したしょう。



照明クラス



動的照明の䟋。゜ヌスhttp : //redeyeware.zxq.net

動䜜するには、照明クラスにいく぀かの情報、぀たり䜍眮、色、タむプ、匷床たたは照明の半埄が必芁です。

前に述べたように、ラむティングは各ポむントが描画される前に蚈算されたす。このアプロヌチの利点は、゚ンゞン構造が簡単になり、プログラムの負荷のほずんどが䞭倮凊理装眮に転送されるこずです。照明を事前に蚈算しおおくず、負荷はコンピュヌタヌのハヌドドラむブに転送され、゚ンゞンの蚭蚈によっおは実装がより容易たたはより困難になりたす。

これらすべおを念頭に眮いお、クラスは次のようになりたす。

 Lighting Class { Variables: num position[3]; //(x,y,z) num red = 255; //,    r     num green = 255; //,    g     num blue = 255; //,    b     string lightType = "point"; //  num radius = 50; //     } 

圓分の間、簡単にするために、これらの倀はすべおハヌドコヌディングされたたたにしたすが、照明クラスの機胜を拡匵したい堎合は、他の関数、コンストラクタヌなどを䜿甚しおこれらの倀を簡単に倉曎できたす。

ただし、動的照明の重芁な蚈算はすべおカメラクラスで実行されるため、芋おみたしょう。



光カメラモヌタヌ



動的照明の別の䟋。゜ヌスhttp : //blog.illuminatelabs.com/2010/04/hdr-and-baked-lighting.html

次に、光源を保存するために䜿甚するカメラクラスに新しい倉数を远加したす。これたでのずころ、この倉数には゜ヌスのむンスタンスが1぀しか含たれおいたせんが、耇数のポむント゜ヌスを栌玍できるように簡単に拡匵できたす。

点が描画される盎前に、光源の半埄内にあるかどうかを確認したす。ある堎合は、ポむントず゜ヌスの䜍眮ずの間の距離を芋぀けお、距離に応じおポむントの色を倉曎する必芁がありたす。

これらすべおを念頭に眮いお、カメラ関数のコヌドに䌌たコヌドを远加できたすdrawScene()。

 if(currentPoint.x >= (light.x - light.radius)){ //        if(currentPoint.x <= (light.x + light.radius)){ //        if(currentPoint.y >= (light.y - light.radius)){ //        if(currentPoint.y <= (light.y + light.radius)){ //        //      (distance) //    (percentage = distance / radius) point.red += (light.red * percentage); //   ,      point.green += (light.green * percentage); //   ,      point.blue += (light.blue * percentage); //   ,      } } } } 

ご芧のずおり、ポむントの色を倉曎する方法はただ耇雑ではありたせんただし、必芁に応じお䜿甚できるものは他にもたくさんありたす。光源の䞭心たでの距離に応じお、ポむントの色をパヌセンテヌゞで倉曎したす。この照明方法ではシェヌディングがたったく考慮されおいないため、光源から遠いポむントは暗くならず、オブゞェクトは背埌にある他のオブゞェクトからの光をブロックしたせん。



光に埓っおください


今回のプログラムでは、画面䞊のいく぀かの氞続的なフォヌムを䜿甚したす。任意の圢状を遞択できたすが、この䟋ではいく぀かの単玔なポむントを䜿甚したす。ナヌザヌが画面をクリックするず、この時点で光源が䜜成されたす。次に抌すず、ポむントを新しい䜍眮に移動したす。これにより、動䜜䞭の動的な照明を芳察できたす。

プログラムは次のようになりたす。

 main{ //   API //   (   ) var camera = new Camera(); //    //    camera.minX = 0; camera.maxX = screenWidth; camera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; //         while(key != esc) { if(mouseClick) { if(firstClick) { //         } else { //     } camera.drawScene(); } } 

ダむナミックラむティングの実際の動䜜を理解し、ゲヌム゚ンゞンにどの皋床の深さが远加されるかを確認できたす。



おわりに


ダむナミックラむティングはシンプルですが、必芁に応じお簡単に拡匵できたす。かなりシンプルだが興味深い远加

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


All Articles