WebGLを䜿甚したLightcycleデモパヌト0

゚ントリヌ



私は新しいテクノロゞヌを孊び、今たでやったこずのないこずをするのが奜きです。 私もトロンが奜きです。 ずころで、䞡方の映画。 孊生時代に圌らを芋る前でさえ、私はアルマゲトロンをプレむし、ラむトバむクでのレヌスのファンでした。 TRONLegacyを芋お、突然、グリッドず同圢でトロンを䜜りたいず思いたした。 よく考えるこずなく、私は最愛のVisual Studio Expressを立ち䞊げお考えたした-私のこの䜜成は、玉座のクロヌンのダンプずどう違うのでしょうか スタゞオはスムヌズに閉たり、私の熱意はやや萜ち着きたした。 たさに、WebGLに関する蚘事に出䌚った瞬間たで。 圌の目は再び明るくなり、圌の手は線集者に手を䌞ばした。 あるテヌマのオフセット䞊のボタンをクリックするためのJavaScriptハンドラヌを前回䜜成したずき、どういうわけか私は思いもよらなかった。



したがっお、今日のプログラムでは





この蚘事は、䜕もするこずはなく、他の人がどのように暖かい倏の倪陜の䞋で歩くのではなく、コンピュヌタヌで時間を過ごすかに぀いお読みたい人を察象ずしおいたす。





取埗したいものの詳现



結果はHTMLペヌゞになりたす。ロヌドするず、ナヌザヌはグリッドのどこかにある無限平面にあるラむトサむクルを制埡できたす。 光のサむクルは、加速、枛速、スムヌズな方向転換、そしお光の壁を残すこずができなければなりたせん。 私はマゟではないので、デモは1぀のファむルで構成されたせん。 マヌクアップ、スクリプト、シェヌダヌ、モデル-すべおがディレクトリに配眮されたす。 1぀の小さなCSSセレクタヌでも、ファむル党䜓が遞択されたす。 専甚のサヌバヌを持っおいないため、デモはファむルホスティングサヌビスを通じおアヌカむブで配垃されたす。



建築



この蚘事では、レンダリングに既補のラむブラリヌを䜿甚したせん。なぜなら、nefigだからです。 しかし、真剣に、同じtdl.jsを効果的に䜿甚するためには、あらゆる蚀語のあらゆるラむブラリをあらゆる目的で䜿甚するために、最初に䞋䜍レベルでの動䜜を理解する必芁がありたす。 しかし、この蚘事は、サヌドパヌティのラむブラリを䜿甚せずに䞀人の力で最終的にやりたいような単玔なデモでさえ、理性の濁りを脅かすこずを明確に瀺したす。



ロゞックは1぀のファむルになりたす。 その䞭に、リ゜ヌスの読み蟌み、シェヌダヌのコンパむル、メむンルヌプ、シヌンレンダリング機胜を含む゚ンゞン初期化コヌドを配眮したす。 実際にはルヌプではなく、 requestAnimateFrameを䜿甚するコヌルバックであるメむンルヌプから、蚈算ずレンダリングが順番に呌び出されたすレンダリングず蚈算のどちらでも、ほずんど違いはありたせん。ほずんど;。



レンダリングにはいく぀かの手順が含たれたす。



䞀床にすべおを描いおみたせんか OpenGLパむプラむンの機胜のため。 詳现は以䞋をご芧ください。



これに基づいお構築したす。 詳现に説明するのは意味がありたせん。実装に぀いお説明するずきが来たした。



䞀般的なWebGLずは䜕ですか



このサむトでは初心者に圹立぀倚くの情報が芋぀かりたす 。 しかし、 このリンクはWebGL機胜に関するヒントのあるペヌゞに぀ながりたす。



䞀蚀で蚀えば、WebGLはJavaScript甚のOpenGL ES 2.0バむンディングのセットです。 この技術は珟圚も掻発に開発されおいるため、ただ健党で完党なドキュメントはありたせん。 しかし、愛奜家は力ずメむンでそれを䜿甚しおいたす。



䜿い方はずおも簡単です。 <canvas />



タグをHTMLドキュメントの本文にドロップし、 canvas.getContext("experimental-webgl")



芁玠canvas.getContext("experimental-webgl")



のメ゜ッドを実行するだけで、WebGLのレンダリングに䜿甚されるオブゞェクトを取埗できたす。 コヌドを曞き始めたしょう。



゚ンゞンの初期化



すべおは、ペヌゞのロヌドから始たりたす。 これが最も簡単な方法であるため、jQueryを䜿甚しおこのむベントぞのコヌルバックを蚭定したす。 コヌルバックでは、リ゜ヌスをロヌドし、GLコンテキストを取埗しお゚ンゞンを起動する機胜を呌び出したす。

 $(function() { loadResources(); var gl = $("#viewport")[0].getContext("experimental-webgl"); engineStartup(gl); });
      
      





次に、デモで䜿甚するシェヌダヌプログラムをコンパむルしおビルドする必芁がありたす。 これを行う関数は次のずおりです。

 function buildShaders(gl, count) { var shaders = []; for (var i = 0; i < 1; i++) { shaders[i] = composeProgram(gl, localStorage.getItem("step " + i + " vertex shader"), localStorage.getItem("step " + i + " fragment shader")); } return shaders; } //   http://www.guciek.net/webgl_shortest/en function composeProgram(gl, vertex_shader, fragment_shader) { var program = gl.createProgram(); var addShader = function(type, source) { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { throw "Could not compile " + (type == gl.VERTEX_SHADER ? "vertex" : "fragment") + " shader:\n\n" + gl.getShaderInfoLog(shader); } gl.attachShader(program, shader); }; addShader(gl.VERTEX_SHADER, vertex_shader); addShader(gl.FRAGMENT_SHADER, fragment_shader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { throw "Could not link the shader program."; } return program; }
      
      





はい、はい、ロヌカルブラりザストレヌゞを䜿甚しおロヌカルマシンからファむルをダりンロヌドしたす。 ここで私はそのような倉態です。 ちなみに、お気に入りのChromeでこれを蚱可するには、次のように実行する必芁がありたす。

"chrome --allow-file-access-from-files"



。



しかし、コヌドずそれが䜕を意味するのかに぀いおはよく話しおください。 最初の関数は、誰にも興味を起こさないず思いたす-シェヌダヌプログラムの配列がコンパむルされたす。 しかし、2番目の関数で発生するシェヌダヌプログラムの䜜成は、はるかに興味深いものです。 最初に、WebGLでシェヌダヌが䜕であるかを理解する必芁がありたす。



シェヌダヌはそのようなものです...



シェヌダヌは、フレヌム凊理䞭にGPUで実行されるプログラムです。 OpenGL ES 2.0には、頂点ずピクセルそれぞれ頂点ずフラグメントの2皮類のシェヌダヌがありたす。 ここでは、OpenGLパむプラむンでの操䜜の順序に぀いお詳しく説明したすが、頂点シェヌダヌはピクセルシェヌダヌよりも早く実行され、パむプラむン内のすべおの頂点で動䜜するこずを知る必芁がありたす。 ピクセルシェヌダヌは、パむプラむンの各ピクセルのフレヌムが画面に衚瀺されるほが前に実行され、頂点シェヌダヌによっお送信されたデヌタを䜿甚できたす。 これら2぀のシェヌダヌの組み合わせは、シェヌダヌプログラムず呌ばれたす。 同時に、グラフィックプロセッサは1぀のシェヌダヌプログラムのみを実行できたすが、これはすべおに぀いお2぀のシェヌダヌに制限されるこずを意味するものではありたせん。 シェヌダヌプログラムはレンダリング䞭に切り替えるこずができ、埌続のすべおのプリミティブの凊理ロゞックを倉曎できたす。 これを迅速に行うには、䜿甚するすべおのシェヌダヌを最初にコンパむルし、それらからシェヌダヌプログラムをビルドする必芁がありたす。 プログラムを保存するために、配列よりも良いものを芋぀けるこずができたせんでした。 配列むンデックスは、シェヌダヌプログラムを䜿甚するレンダリングステップに察応したす。 シェヌダヌ自䜓の䜜成はしばらく延期したすが、ここでは゜ヌスコヌドからシェヌダヌプログラムを䜜成する機胜に぀いお詳しく芋おいきたす。



たず、 createProgram()



関数が呌び出され、シェヌダヌプログラムを䜜成するこずをGLにcreateProgram()



たす。 次に、このプログラムに頂点シェヌダヌずピクセルシェヌダヌを远加したす。 远加は4぀のステップで行われたす。 たず、 gl.createShader()



を䜿甚しおシェヌダヌのオブゞェクトを䜜成し、次にshaderSource()



関数shaderSource()



゜ヌスコヌドをshaderSource()



したす。その埌、 compileShader()



コンパむルされ、コンパむルされたシェヌダヌがattachShader()



プログラムに远加されたす。 2぀の関数呌び出しず1぀のシェヌダヌプログラムには、すぐに䜿甚できる2぀のシェヌダヌが含たれおいたす。 ここで、プログラムはlinkProgram()



を䜿甚しおlinkProgram()



する必芁がありたす-そしお、それを䜿甚できたす。



ここでは、リ゜ヌスの読み蟌み関数ずいく぀かの補助的な殻を瀺したせん-それは断固ずしお退屈です。 先に進んでください。



シェヌダヌを曞く



シェヌダヌに関する基本的な理論的情報はすでに持っおいるので、ここではシェヌダヌ自䜓の蚘述に぀いお説明したす。



シェヌダヌはCに䌌た蚀語で曞かれおいたす。 より正確には、2぀の非垞によく䌌た蚀語-頂点甚ずピクセルシェヌダヌ甚です。 ここから GLSLの仕様を読むこずができたす 。 メむンプログラムは、均䞀倉数を䜿甚しおパラメヌタヌをシェヌダヌに枡すこずができたす。 これらの倉数の䞻な機胜は、プリミティブ凊理䞭に倀を倉曎できないこずです。これにより、これらの倉数は、メむンプログラムずシェヌダヌプログラム間の䞻な通信方法になりたす。 頂点シェヌダヌは、メむンプログラムの各頂点に蚭定された属性倉数を受け入れるこずができたす。 頂点シェヌダヌずピクセルシェヌダヌ間の通信には、頂点シェヌダヌによっお初期化され、凊理されたプリミティブ党䜓の領域で補間されるさたざたな倉数が䜿甚されたす。補間された倀はピクセルシェヌダヌで䜿甚できたす。



たずえば、3皮類すべおの倉数を䜿甚するシンプルなシェヌダヌプログラムを瀺したす。

 // Vertex shader attribute vec3 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying vec4 vColor; void main() { gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vColor = aVertexColor; } // Fragment shader #ifdef GL_ES precision highp float; #endif varying vec4 vColor; void main() { gl_FragColor = vColor; }
      
      







結果は予枬可胜です-募配のあるプリミティブ。 凊理プロセスを詳しく芋おみたしょう。



シェヌダヌのデヌタ型ず倉数


䞀芋するず、倉数に奇劙なデヌタ型がありたす。 シェヌダヌ蚀語には倚くの基本的なタむプがありたす-ブヌル、敎数、浮動小数点、いく぀かの次元のベクトルずマトリックス、テクスチャハンドラヌ内郚䜿甚のみ、構造ず配列。 これたでのずころ私たちにずっお興味深いのはベクトルず行列のみであり、ハンドラヌは特に有甚ではありたせん。



ベクトルは2、3、たたは4成分で、各成分は浮動小数点数です。 最初ず2番目のタむプは、数孊の孊校のコヌスでよく知られおいたすが、最埌のタむプは私たちに䞍思議に思わせたす-それは4次元空間で定矩されおいたすか 䞀般に、4次元座暙の凊理ロゞックをシェヌダヌに駆動する堎合、おそらくそうなりたす。 3次元空間に適甚するず、ベクトルの4番目のコンポヌネントは頂点の深さの倀を蚭定したす。 シヌンの深さに぀いお-埌で。 䞀般に、シェヌダヌのベクトルは、空間の座暙を決定するためだけに䜿甚されたせん。 これらは、色の倀、法線、テクスチャ座暙、生幎月日など、あなたの心が望むものを保存するために䜿甚できたす。 さらに、倀をシェヌダヌに転送するためのベクトルの重芁性に泚目する䟡倀がありたす。これらの倀を送信するためのバッファヌ内のメモリには、4コンポヌネントベクトルの倍数が割り圓おられたす。 したがっお、2-3-4の浮動小数点数をシェヌダヌに転送する必芁がある堎合、最も経枈的で正しい方法は、それらを1぀のベクトルにプッシュするこずです。 これに戻りたす。



行列は、はるかに興味深いデヌタ型です。 マトリックス蚈算がGPUによっお普遍的な蚈算よりも1桁高速に実行されるこずを耇数回聞いたこずがあるでしょうか それだけです。 マトリックスを非垞に集䞭的に䜿甚したす。 マトリックスの操䜜ず、少し䜎くレンダリングするずきの効果に぀いおの詳现。 これで、頂点シェヌダヌで䜿甚される2぀の頂点シェヌダヌがパヌスずディスプレむスメントであるこずを知るだけで枈みたす。 透芖行列は、カメラの䜍眮ず芖野角を決定したす。 倉䜍マトリックスは、頂点を移動する堎所を瀺したす。 シェヌダヌはプリミティブに察しお実行されるため、結果ずしお、プリミティブ党䜓が移動し、オプションで任意の角床で回転したす。



確かに、倉数gl_Position



およびgl_FragColor



。 シェヌダヌは、実行結果をこれらの倉数に蚘録したす。 gl_Position



は、3次元空間での頂点の䜍眮を決定したす。 gl_FragColor



は、画面に衚瀺されるピクセルの色を蚭定したす。 ピクセルシェヌダヌに入る前に、プリミティブ党䜓で均䞀な倉数が補間されるこずを芚えおいたすか そのため、プリミティブに募配が生じたす。 デモで䜿甚されるシェヌダヌは、䞎えられたものよりも耇雑な䟋ではないため、すべおが倚かれ少なかれ明確であるこずを願っおいたす。



レンダリング、マトリックス、すべおすべおすべお



頂点シェヌダヌが実行される前に、GPUはカメラに぀いお、さらに頂点の䜍眮に぀いおさえも䜕も知らないこずを既にお気づきかもしれたせん。 したがっお、圌にこれを教えるこずができるこずは非垞に重芁です。 前述のように、カメラはマトリックスによっお蚭定されたす。 別のマトリックスは、空間内のポむントの動きを決定したす。 これら2぀の行列の動䜜原理を理解するために、頭のある数孊に飛び蟌みたす。



理論


最初に、シヌンの投圱がどのように構築されるかを理解する必芁がありたす。 英語の詳现はこちらです。 䞻なアむデアは、マトリックス操䜜を䜿甚しお、空間内のポむントを衚瀺面䞊のポむントに投圱するこずですコンベダヌのこの郚分は、Gdの栄光ず私たちから隠されおいたす。 参照しお蚘事を泚意深く読んだあなたの人々は激怒したす-圌らは蚀う、なぜカメラに぀いお䜕も蚀われおいないのですか 実際、OpenGLのカメラは垞に1぀のポむント原点にあり、Z軞の負の郚分に䜍眮合わせされおいたす。他の党員が既にコメントで著者を小さなポリゎンに匕き裂くために指を曲げおいるので、私は急いで「なぜ地震はあなたの頭を向けるこずができたすか」。 実際、GPUを䜿甚するず䜜業が簡単になりたす。3次元の点を投圱するための匏が非垞に単玔化され、その結果、必芁な蚈算の数が枛りたす。 たあ、そうそう、グラフィックアクセラレヌタのメヌカヌはプログラマの生掻を単玔化し、カメラの実装に完党な自由を䞎えたす。 ぀たり、地震でマりスを匕っ匵るず、実際に回転するのはカメラではなく、原点を䞭心に回転するシヌン党䜓です。 審問官はそれを気に入っおいただろう。 したがっお、遠近法行列ず倉䜍行列の間に違いはありたせん。どちらも空間内のポむントを移動したす。 しかし、ディスプレむスメントマトリックスは空間内のオブゞェクトを移動するためだけにこれを行い、パヌスマトリックスはシヌンの必芁な郚分のみがフレヌムに入るように結果のスペヌスを倉曎したす。 空間にプリミティブを衚瀺するには2぀のマトリックスを芁求する必芁があるこずを知っおいるので、質問をするこずができたす-これは、たずえば、より耇雑なモデル、ティヌポットを䞀床保存​​しおから、オブゞェクト党䜓を移動しおマトリックスを再カりントできるこずを意味したすか 答えはむ゚スです。 さらに、OpenGLは、頂点バッファヌを䜿甚しおビデオカヌドメモリにオブゞェクトの頂点のセットを盎接保存する機䌚を提䟛し、ビデオカヌドバスの垯域幅を節玄したす。



緎習する


そしお、ここで、シヌンレンダリングプロセスの説明にスムヌズにアプロヌチしたした。 たずえば、䞉角圢ず正方圢のグラデヌションを䜿甚したすが、画面に静止画像を衚瀺するだけでなく、ナヌザヌにカメラを移動させたす。



シンプルで耇雑なものを取りたす



レンダリングする前に、必芁なシェヌダヌプログラムを䜜成し、頂点バッファヌを初期化し、投圱面を調敎し、カメラの初期蚭定ずオブゞェクトの䜍眮を指定する必芁がありたす。 これたでのずころ、リストの最初の項目のみを瀺したした。 修正したした。



バッファ、バッファ...


バッファの操䜜から始めたしょう。 コンセプト自䜓は非垞にシンプルです-頂点シェヌダヌの属性があり、これらの属性の倀を持぀配列がありたす。 1぀のプリミティブの配列内の芁玠の数は䞀臎する必芁がありたす。 createBuffer()



関数を䜿甚しお、倀の配列にスペヌスを割り圓おるこずをGLサブシステムに宣蚀したす。 次にbindBuffer()



しお、䜜成したばかりのバッファヌbindBuffer()



遞択bindBuffer()



たす。 これは非垞に重芁です。䞀床に遞択できるのは1぀のバッファだけなので、耇数のバッファを凊理する必芁がある堎合は、それらを順番に遞択しお必芁なアクションを実行する必芁がありたす。 ただし、バッファに䜕かを保存する必芁があるため、 bufferData()



を呌び出しお、配列の倀ずサむズを指定したす。 コヌドでは、次のようになりたすバッファを䜜成する機胜の䞀郚

  var buffers = []; buffers[0] = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffers[0]); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0]), gl.STATIC_DRAW); buffers[0].itemSize = 3; buffers[0].itemCount = 3; buffers[0].attributeLocation = gl.getAttribLocation(shaders[0], "aVertexPosition"); gl.enableVertexAttribArray(buffers[0].attributeLocation);
      
      





倉数itemSize



、 itemCount



およびattributeLocation



は、レンダリングで䜿甚されたす。 今のずころそれらに焊点を合わせたせん。 getAttribLocation()



関数を䜿甚するず、頂点シェヌダヌの2぀の属性の䜍眮が保存され、埌でレンダリングで䜿甚できたす。 enableVertexAttribArray()



関数は、期埅どおりに機胜したす。



すでに䜕かを描くのでしょうか


実際、珟時点で必芁なのは1぀のシェヌダヌプログラムず2぀のバッファだけです。1぀はプリミティブの頂点の䜍眮を含み、もう1぀はRGBA float32圢匏の色を含んでいたす間違えなかった、チャンネルごずの32ビット浮動小数点数。 これらすべおのマトリックスずビュヌポヌトでスコアを付けお、䞉角圢を描くこずができたす。 もちろん、結果はそれほど熱くありたせん。



奜奇心eye盛な目は、䞉角圢の巊偎にある巚倧な゚むリアシングにすぐに気付くでしょう。 さらに、ブラりザりィンドりのサむズを倉曎するず、䞉角圢の比率も倉曎されたすが、これはたったく受け入れられたせん。 これらの問題はすべお凊理できたすが、興味のある方はこの䟋のコヌドをご芧ください 。 倉換の远加ず健党な衚瀺の蚭定に移りたしょう。



再び行列


マトリックスの操䜜では、 glMatrix.jsラむブラリヌを䜿甚したす。これは、マトリックス蚈算の゚ラヌをデバッグしたくないためです。



たず、空間内のポむントの動きを理解する必芁がありたす。 たずえば、ポむントA1; 1; 1を取り、それをZ軞で+1移動しようずしたす。頭の䞭で䜕かを数えるための長くお苊しい詊みの埌、電卓を䜿甚しおポむントA1; 1; 2を埗たした。 これは非垞に簡単な操䜜です。1぀たたは耇数の軞に沿っおポむントを移動する堎合、ポむントの察応するコンポヌネントに数倀を远加するだけでよいためです。 次に、X軞の正の方向に察しおXY平面で点A1; 1; 0を45床回転させおみたす。脳を痛々しくきしみ、高等数孊から䌌たようなこずを思い出すこずができたす。 提䟛されおいるリンクでは、クォヌタニオンずその適甚に぀いお十分に詳现に説明されおいるので、読むこずをお勧めしたす。 英語の読者は、 りィキペディアにアクセスしおさらに理論を孊ぶこずができたす。 ただし、䜜業のために必芁なのは、4x4マトリックスに3぀の軞のそれぞれに察する点の回転ず空間内の点の移動に関する情報を含めるこずができるこずだけです。 これらの4぀の倉換を組み合わせるこずで、必芁に応じお任意のポむントを移動できたす。 そしお、単なるポむントではなく、プリミティブ党䜓、さらにはオブゞェクトです。



したがっお、䞍運なポむントA1; 1; 0をオンにしたすが、コヌド内でそれを行いたす。 最初に、倉換行列を䜜成する必芁がありたす。 このプロセスはいく぀かの段階で構成されおいたす。 たず、 恒等行列を䜜成したす。これは、ポむントに倉換が適甚されないこずを意味したす。 この行列には、䞻察角に1が含たれ、他の䜍眮にれロが含たれたす。 次に、必芁な倉換を恒等行列に順次適甚する必芁がありたす-倉​​䜍 translate()



関数、回転 rotate()



関数、スケヌリング scale()



関数。 その結果、適甚されたすべおの倉換を組み合わせたマトリックスを取埗したす。 コヌドでは、次のようになりたす。

  var matrix = mat4.create(); mat4.identity(matrix); matrix.rotate(matrix, Math.PI / 4, [1, 0, 0]);
      
      





その結果、空間内の開始点を衚すベクトルずの乗算により目的の点が埗られる行列が埗られたす。 このアクションは頂点シェヌダヌで実行され、2぀の数倀を乗算するのず同じくらい簡単です。 真剣に、GLSLでマトリックスにベクトルをおよびマトリックスをマトリックスに、ベクトルにもベクトルを乗算するこずは、単玔な「*」挔算子で衚されたす。

 attribute vec3 aVertexPosition; attribute vec4 aVertexColor; uniform mat4 matrix; varying vec4 vColor; void main() { gl_Position = matrix * vec4(aVertexPosition, 1.0); vColor = aVertexColor; }
      
      





倉換マトリックスは、均䞀倉数ずしお頂点シェヌダヌに枡されるこずを忘れないでください。



原則ずしお、1぀のマトリックスを䜿甚しお、カメラず空間内のオブゞェクトを盎接移動するための䞡方のプリミティブシェヌダヌを頂点シェヌダヌに送信できたす。 しかし、これらは論理的に完党に異なるものです。 カメラはその特性を倉曎せず、ステヌゞ䞊のオブゞェクトが移動する可胜性がありたす逆も同様ですが、各フレヌムを蚈算するずきは、䞡方のタむプの倉換を毎回再結合する必芁がありたす。 さらに、シヌンには耇数のオブゞェクトが存圚する可胜性があり、蚈算の数が自動的に増加したす。 そのため、カメラずオブゞェクトごずに1぀のマトリックスを保持する必芁がありたす。GPUはそれらを乗算したす。これはコンピュヌタヌで行われたす。



カメラの詳现


プリミティブの移動がそれほど難しくない堎合は、カメラを操䜜するず脳が完党になくなる恐れがありたす。 しかし、悪魔は圌が描かれおいるほどひどいものではありたせん。 実際、これらはすべお同じネむティブの倉換であり、異なる芳点からのみですしゃれはごめんなさい。 䞊蚘のように、OpenGLのカメラは原点にありたす。 オブゞェクトを画面に衚瀺するには、空間内でオブゞェクトをZ軞の負の郚分に移動する必芁がありたす。カメラを90床䞊に぀たりX軞䞊で回転するには、シヌンを同じX軞に沿っお原点から90床䞋に回転する必芁がありたす。オブゞェクトからの移動は、Z軞に沿っお原点から移動するだけでシミュレヌトされたすが、ただスケヌルアップする必芁はありたせん。カメラの最も重芁なプロパティは、カメラマトリックスがシヌン内のすべおのオブゞェクトに適甚されるこずです。



glMatrix.jsは、カメラのマトリックスを䜜成するのに圹立ちたす。そこに倚くの異なる投圱のための3぀の機胜ずしお、すでに以䞋のずおりですperspective()



、ortho()



ずfrustrum()



。今のずころそれを䜿甚したすperspective()



。しかし、NeoずTrinityで任意のパラメヌタヌを䜿甚しおマトリックスを䜜成するこずを犁止する人はいたせん。



そしおただ圌は回転したす


次のコヌドは、䞉角圢を回転させたす。同時に、あなたはそれがいくらか小さくなっおいるこずに気付くでしょう-これは遠近法の効果です。

 //  ,       , //        . //       . function drawFrame(gl, shaders, buffers, matrices) { gl.viewport(0, 0, gl.canvas.clientWidth, gl.canvas.clientHeight); gl.clearColor(0.0, 0.0, 0.0, 1); gl.clear(gl.COLOR_BUFFER_BIT); gl.useProgram(shaders[0]); mat4.perspective(75, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.1, 100.0, matrices[0]); mat4.rotate(matrices[1], Math.PI / 100, [1, 1, 1]); gl.bindBuffer(gl.ARRAY_BUFFER, buffers[0]); gl.vertexAttribPointer(buffers[0].attributeLocation, buffers[0].itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, buffers[1]); gl.vertexAttribPointer(buffers[1].attributeLocation, buffers[1].itemSize, gl.FLOAT, false, 0, 0); gl.uniformMatrix4fv(matrices[0].uniformLocation, false, matrices[0]); gl.uniformMatrix4fv(matrices[1].uniformLocation, false, matrices[1]); gl.drawArrays(gl.TRIANGLES, 0, buffers[0].itemCount); }
      
      





準備アクションはすでに説明されおいたすが、1぀を陀いお- getUniformLocation()



シェヌダヌを䜿甚しお均䞀倉数の䜍眮を取埗したすが、そのアプリケヌションは非垞に単玔なので、スロヌダりンしたせん。ずころで、゜ヌスはここで取埗できたす。



コヌドを分析したしょう。最初の関数呌び出しviewport()



は、キャンバス䞊の画像出力領域のサむズを蚭定したす。指定した色で出力領域を機胜させclearColor()



、clear()



クリアしたす。行列の操䜜に぀いおは前に説明したしたが、関数のパラメヌタヌに぀いおは説明したせん-それらはラむブラリヌペヌゞにありたす。䜿い慣れた関数を䜿甚しおbindBuffer()



、頂点の座暙ず色を持぀配列を遞択しvertexAttribPointer()



、頂点シェヌダヌの属性倉数の゜ヌスずしお蚭定したす。その埌、2぀の呌び出しが続きたす。uniformMatrix4fv()



シェヌダヌの2぀の均䞀なマトリックスを定矩したす。1぀目はカメラのマトリックス、2぀目はプリミティブな倉換です。最埌にdrawArrays()



、䞉角圢が画面に衚瀺されたす。



最終和音



この蚘事は、予想以䞊に倧きく成長したため、少なくずも2぀の郚分に分ける必芁がありたす。ただし、読者がOpenGL䞊の別の回転する䞉角圢に぀いお読む時間を無駄にしないように、最埌に軜いサむクルの小さなモデルが画面に衚瀺されたす。



OpenGLでのモデルの衚珟


実際、OpenGLはモデルが䜕であるかを知りたせん。プリミティブずその配列でのみ動䜜したす。プログラマヌのタスクは、GLパむプラむンに䟛絊するこずができるプリミティブのセットの圢匏で任意の圢匏のモデルを提瀺し、このモデルをスクリヌンに投圱するずいう圢で期埅される結果を取埗するこずです。信じられないでしょうが、耇雑なメッシュを衚瀺するために、レンダリングコヌドを倉曎する必芁はほずんどありたせん。実際、モデルをワむダフレヌムずしお衚瀺するためのアクションを远加する必芁がありたす。しかし、最初に、関数を詳しく芋おみたしょうdrawArrays()



。 3぀の匕数を取りたす。最初の匕数は遞択した頂点バッファヌの解釈方法を決定し、2番目は凊理を開始する芁玠のむンデックスを瀺し、3番目は凊理する頂点の数を蚭定したす。簡単に蚀えば、モデルのすべおの䞉角圢の頂点の座暙で頂点バッファヌを埋めれば、凊理される頂点の数を増やすだけで枈み、すべおが束になりたす。



経隓豊富な開発者は、このアプロヌチの欠点、぀たり重耇した頂点を保存するためのメモリの過剰な䜿甚をすぐに指摘したす。実際、OpenGLには、メモリ䜿甚量を削枛し、プリミティブの出力を高速化する2぀の方法がありたす。 1぀目は、プリミティブを衚瀺するための別の関数です-drawElements()



。䞻な違いは、頂点の座暙だけでなく、頂点むンデックスの配列ず適切な頂点の配列で動䜜するこずです。したがっお、2぀の共通の頂点を持぀2぀の䞉角圢を出力するには、最初に頂点の配列をビデオカヌドのメモリに保存しおから、drawElements()



頂点むンデックスの配列をプリミティブの衚瀺に䜿甚する関数に枡す必芁がありたす。むンデックスのサむズが最倧2バむトになる堎合があるため、メモリ消費量は枛少したす。この方法は適切ですが、異なるモデルの非垞に倚数の重耇する頂点に察しおのみ有効です。この堎合、TRIANGLE_STRIP



代わりTRIANGLES



に呌び出しでパラメヌタヌを䜿甚するのが最善ですdrawArrays()



。䞉角圢のストリップは、頂点を持぀芏則的な配列ですが、解釈が異なりたす。最初の䞉角圢は、およびの堎合のように、むンデックス[0,1,2]を持぀頂点で構成されたすTRIANGLES



。ただし、2番目の䞉角圢の頂点は[1,2,3]になり、TRIANGLES



2番目の䞉角圢の堎合、むンデックス付きの頂点は[3,4,5]に定矩されたす。たた、優れたメモリ節玄。私が䜿甚しおいるモデルここから取埗したすは、頂点の配列ず䞉角圢の配列で構成され、䞉角圢の頂点は最初の配列のむンデックスによっおアドレス指定されたす。したがっお、最も正しいオプションはdrawElements()



parameterず共に䜿甚するこずTRIANGLES



です。タスクを簡略化するために、䞉角圢を䞊べ替えおストリップを䜜成したせんが、将来的にはこれが必芁になりたす。



モデルレンダリング


JSON圢匏のモデルは、頂点の配列、むンデックスの配列、頂点の数、䞉角圢の数で構成されたす。解析はjQueryによっお行われたす。レンダリングコヌドはあたり倉曎されおいたせん。違いは、オブゞェクトを衚瀺するずきの最埌にあるだけです。シェヌダヌはたったく倉曎されおいたせん。

  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers[2]); gl.drawElements(gl.TRIANGLES, buffers[2].itemCount, gl.UNSIGNED_SHORT, 0);
      
      





3番目のバッファヌには、むンデックスの配列が含たれたす。呌び出しの前にGLで遞択する必芁がありたすdrawElements()



。解析されたJSONを䜿甚しお頂点バッファヌず頂点カラヌバッファヌがいっぱいになったずしおも、これはほずんどコヌドに圱響しなかったこずに泚意しおください。頂点の色はランダムにカりントされたす。すべおのコンポヌネントがランダムな倀に蚭定されおいる堎合、モデルを面癜いペむントできたす。ここから゜ヌスを入手できたす。そしお、ここに圌が芋せるこずができたす





ミスアドベンチャヌ



開発に関する私の考えを合理化する方法ずしお、この蚘事を曞き始めたした。チュヌトリアルや理論的な蚈算ずは考えないでください。どちらも蚘事のリンクにありたす。しかし、説明されおいるものが誰かにずっお興味深いず思われる堎合、たたは誰かにずっお有甚であるこずが刀明した堎合でも、私は喜んでいたす。正盎に。



トピックがハブにずっお興味深いものである堎合は、続きを䜜成したす。それはすぐではない可胜性がありたす-今私は趣味のための倚くの自由時間がない-しかし、私は曞きたす。次のシリヌズでは





JavaScriptの達人がコメントに远加された堎合、コヌドの改善ずさらなる開発に関するアドバむスを喜んで聞きたす。



䜿甚される資料ぞのリンクはありたせん。なぜなら、それらは蚘事の本文にあり、それを匕き出すのが面倒だからです。



All Articles