tags : MSP, Matteo Marson Max Tutorials, Jitter, GLSL
URL
patron - Tutorial 21: Geometry shaders, vimeo - Tutorial 21: Geometry shaders
文字起こし
0:52
Okay, here we are guys, we’ll continue tutorial. Today’s video is about Geometry shaders. And what I want to discuss with you is what they are, how to use them. Why are they useful. So if you’ve never heard anything about geometry shader, this is a good place to start, I guess, I think we should start from how shaders work as a whole. So let’s move to the board. So first of all, let’s break down very quickly how shaders work. As you know, shaders are programs that are directly computed on the GPU. And they are structured like this, they are divided into three main parts. The first one is the vertex shader. This part of the program takes some positions expressed as x, y, and Zed coordinates. So you can, for example, define some points in a 3d space and pass to the vertex shader, that position of each point in the form of a three component vector inside the vertex shader, you can manipulate these values, for example, you can move a point somewhere else, or you can do all sorts of stuff. But concerning single vertices, now here, I’m referring to this positions as points but nothing doubles me up to this stage of the shader, how I want to display these vertices, because I may decide to displace those as points as lines as triangles. So all we can do inside the vertex shader, is to manipulate this single values also, because as you know, the vertex shader as all the other parts of the shader are computed in parallel. So the code you write to operate on a single vertex is repeated, identical for all the other vertices. And that’s no way to instances of the same shader can communicate, so everything is parallel. Now, here comes into play the next step, that is the geometry shader. Here, we take what the vertex shader process, so these coordinates, and we decide how to connect those, how to connect these vertices. So we can decide, for example to represent some points, or we can decide to connect these vertices through line segments like this, or you can draw triangles or whatever you want. All this kind of decisions are taken here at this stage inside the geometry shader.
さて、チュートリアルの続きです。 今日のビデオはジオメトリ・シェーダについてです。 ジオメトリシェーダとは何か、どのように使うか、について説明します。 なぜ便利なのか。 もしあなたがジオメトリ・シェーダについて何も聞いたことがないのであれば、これは手始めとして良い場所だと思います。 では、ボードに移りましょう。 ではまず、シェーダーがどのように動くのか、ごく簡単に分解してみましょう。 ご存知の通り、シェーダーはGPU上で直接計算されるプログラムです。 そして、このような構造になっており、大きく3つの部分に分かれています。 まず1つ目はバーテックスシェーダーです。 この部分は、x,y,zの座標で表されるいくつかの位置を受け取ります。 例えば、3次元空間にいくつかの点を定義して、その点の位置を3成分ベクトルの形で頂点シェーダに渡せば、その値を操作して、例えば、点を別の場所に移動させたり、いろいろなことができるようになるわけです。 しかし、単一の頂点に関しては、ここでは、この位置を点として参照していますが、シェーダのこの段階まで、これらの頂点をどのように表示したいのか、何も私を倍加させるものはありません。 頂点シェーダの内部でできることは、この単一の値を操作することだけです。 ご存知のように、頂点シェーダはシェーダの他の部分と同様に並列に計算されるからです。 そのため、ひとつの頂点を操作するために書いたコードは、他のすべての頂点に対して同じように繰り返されます。 そして、同じシェーダーのインスタンスが通信することはありえないので、すべてが並列になります。 さて、ここで次のステップ、つまりジオメトリシェーダが登場します。 ここでは、頂点シェーダが処理したもの、つまりこれらの座標を受け取り、それらをどのように接続するか、これらの頂点をどのように接続するかを決定します。 たとえば、点を表現することもできますし、このように線分を使って頂点を結ぶこともできますし、三角形を描くこともできますし、何でもできます。 このような決定はすべて、この段階でジオメトリシェーダの中で行われます。
3:30
together with some other cool stuff you can do. But let’s say that the main goal is to decide how to display this vertices. Then if you want actual to display those, you need the next step that is a fragment shader. This part of the program is responsible for what is known as rasterization. So let’s say this is our window. And you want to visualize this thing. So a line going like this, and another line like this. Now, this shape is represented in vector form, so it is infinitely defined. But since we want to display that on a screen that is made of pixels, you we need to make that discrete. So there is the recession process color’s each pixel, according to this vectorial image. So these are the three steps you need. Now one thing I want to stress is that in the vertex shader, each instance of the of this shader is not aware of what is going on for the other instances. And the same goes for the fragment shader. Each fragment is independent and treated like that. The only stuff that makes sort of an exception is the geometry shader. So let’s see how that works. So in the vertex shader, we managed to create some vertices. So we pass a matrix containing these three component vectors. Now if you want to decide To draw these vertices, we cannot consider single vertices. Otherwise, all we can do is to create some points, right. But if you want to draw a line for example, we must be aware of where that line starts and where that line should hand these groups of vertices are known as primitives. Okay, so what are primitives primitives are groups of vertices. And more specifically, there are five kinds of primitives. And they differ for the amount of vertices taken into account. So, the first kind of primitive is points, this primitive takes into account only one vertex. Okay, so if you want to draw points, you can just set these kinds of primitive inside the geometry shader. And what it does is simply takes the vertices and best those to the fragment shader in a way. The second kind is lines, and this kind of primitive requires two vertices to work. So, what this kind of primitive does, it takes groups of two elements and connects that elements through straight lines. So, these kinds of primitive considers groups made of two elements, this doesn’t mean that we necessarily need to draw some lines, we can do other stuff, as we will see, but the geometry shader is now aware of the position of two vertices at the same time. Now, let’s move to the third kind, I’ll leave the last two for later. The third kind is triangles. And triangles are made of three vertices. So if we set this kind of primitive now, the geometry shader is aware of three vertices at the same time. Now give a look at this primitives. All this names are something you already so in GGL mesh, right. In fact, every time you decide a certain draw mode, that’s the name of the attribute DRO underscore mode, you decide which kinds of primitive to use. So in a way, you’re compiling, in an implicit way, a geometry shader and you decide how big is the group is face group of vertices you want to take into account. So if you say draw mod points, the geometry shader only takes into account a single vertex lines, two vertices, triangles, three vertices. So in a way this is in place it. But let’s focus now on something else, very important. Here, I’m talking about what is coming in the geometry shader. I’m not talking about how to draw this vertices. In fact, the kinds of primitive inputs primitive doesn’t oblige you to draw that shape, using the same kinds of output primitive.
と一緒に、他のクールなこともできます。 しかし、主な目的は、この頂点をどのように表示するかを決めることだとしましょう。 そして、実際にそれらを表示したいのであれば、次のステップであるフラグメントシェーダが必要です。 この部分は、いわゆるラスタライズを担当するプログラムです。 たとえば、これが私たちのウィンドウだとします。 これを視覚化したいわけです。 つまり、このように進む線と、このように進む別の線があります。 さて、この図形はベクトル形式で表現されますから、無限に定義できます。 しかし、ピクセルでできている画面に表示したいので、これを離散化する必要があります。 そこで、このベクトル画像に従って、各画素に色をつけるという後退処理が行われます。 これが必要な3つのステップです。 ここでひとつ強調しておきたいのは、バーテックスシェーダでは、このシェーダの各インスタンスは、他のインスタンスで何が起こっているかを意識していない、ということです。 フラグメントシェーダも同様です。 それぞれのフラグメントは独立しており、そのように扱われます。 唯一、ジオメトリシェーダだけは例外のようなものです。
それでは、ジオメトリシェーダがどのように動作するか見てみましょう。 頂点シェーダでは、いくつかの頂点を作成することができました。 そこで、これら3つの成分ベクトルを含む行列を渡します。 さて、これらの頂点を描画することを決定したい場合、単一の頂点を考慮することはできません。 そうでなければ、できるのはいくつかの点を作成することだけです。 でも、例えば線を描こうと思ったら、その線がどこから始まって、どこを通るのかを意識しなければならない。 このような頂点の集まりをプリミティブと呼びます。 さて、ではプリミティブとは何かというと、プリミティブは頂点の集まりです。 具体的には、5種類のプリミティブがあります。 そして、それぞれ考慮する頂点の量が異なる。 まず、最初のプリミティブは、頂点が1つしか考慮されない点プリミティブです。 つまり、ポイントを描画したい場合は、ジオメトリシェーダ内でこの種類のプリミティブを設定すればいいわけです。 このプリミティブが行うのは、単に頂点を取り、それらをある方法でフラグメントシェーダーに最適化することだけです。 2番目の種類は線で、この種のプリミティブは動作するために2つの頂点を必要とします。 この種のプリミティブが行うのは、2つの要素のグループを取り、その要素を直線で接続することです。 つまり、この種のプリミティブは、2つの要素からなるグループを考慮します。 これは、必ずしも線を描く必要があるということではなく、これから見るように、他のこともできますが、ジオメトリシェーダは2つの頂点の位置を同時に認識するようになりました。 さて、3番目の種類に移りましょう。 最後の2つは後回しにします。 3番目の種類は三角形です。 三角形は3つの頂点からできています。 つまり、この種のプリミティブを設定すると、ジオメトリ・シェーダは3つの頂点を同時に認識することになります。 さて、このプリミティブを見てみましょう。 この名前はすべて、jit.gl.meshのメッシュですでにそうなっているものですね。 実は、ある描画モード(draw_modeの属性名)を決めるたびに、どの種類のプリミティブを使うかを決めているのです。 つまり、ある意味では、暗黙のうちにジオメトリシェーダをコンパイルして、考慮する頂点のグループの大きさを決めているわけです。 つまり、draw_modeポイントを描画する場合、ジオメトリシェーダは1頂点の線、2頂点、三角形、3頂点のみを考慮します。 つまり、ある意味、これは所定の位置にあるわけです。 しかし、ここで別の、非常に重要なことに焦点を当てましょう。 ここでは、ジオメトリシェーダで何が行われるかということを話しています。 この頂点をどのように描くかについて話しているのではありません。 実際、入力プリミティブの種類は、同じ種類の出力プリミティブを使用して、その形状を描くことを義務づけていません。

8:14
So for example, let’s say, I want to take into account for some reasons, three vertices at the same time, but I don’t want to draw a triangle, I want to draw for example, some lines connecting these three vertices, you can do that in a in a geometry shader. You can not do that using simply draw mode. But for example, you can take triangles and display some lines. So this can be done because we don’t only have input primitives, but we also have sort of output primitives. The correct name to refer to those are input layout qualifier and output layout qualifier. So we said that we can input five different kinds of primitives. Now we so just three of those, but let’s start from this. So you can have let’s say three kinds of inputs, layout qualifiers, the first one is points, then we have lines and then we have triangles. And for what concerns the output layout qualifier, we can decide how to draw these group of vertices. In fact, we have three kinds of output layout qualifiers that are points. Again, if you want to take any group of vertices and display that group using just points. Then we have line underscore strip and this is the kind of output layout qualifier you may use if you want to take a group of vertices and connect that vertices through line segments. And then we have a triangle strip that allows you to take any group have input elements again and draw some triangles connecting them. Okay, so before moving on to other kinds of input layout qualifiers, let’s move to max because I want to show you how some simple Geometry shaders work. So maybe that becomes clearer to you. Okay, so here I prepared a patch to show our Geometry shaders work. First of all, you see that we have some vertices numbered from one to six, here, you can increase or decrease the amount of vertices, they are moving, floating around rotating in this 3d environment. Now, let’s create the presentation mode. Here, you see that we have a GL mesh objects that displays these points. And here, I prepared five different shaders that implement five different kinds of Geometry shaders. So through these messages, here, I’m changing the draw mode for this GL mesh objects. So let’s start from points. As you can see, here, we have six points floating around. Let’s give a look at the shader. Let’s start from the vertex shader. This is the classic standard vertex shader. That’s actually the default shader. So let’s move down to the geometry program. And let’s give a look at how it works. Okay, so here we have the input layout, and the output layout. As you can see, the input layout here is points. Because I want to consider vertex by vertex, so each vertex individually and what they want to draw, I want to draw points the so the output layout qualifiers is exactly points, let’s go a step back. Here, I want to output from the vertex shader the position of each vertex, and I’m doing that like this, I take the model view projection matrix to display that correctly. And I multiply that by the position. So here we have our correct GL position. Now this variable is passed automatically, to the geometry shader, without without the need to express that here in the GTE per Vertex Output structure. So in the geometry shader, the third position is accessible like this, you need to write this stuff. GL underscore in
12:36
this thing that I talked about in a second, and then GL underscore position, don’t worry if you don’t remember that that’s exactly what is written inside the default shader. So just copy that. So what is going on with this brackets and with this number, we said before that the geometry shader can take the groups of vertices, and it manages these groups in an array form. So it considers a group of vertices as an array. As you know, an array is a structure that can contain multiple elements. So the elements that this kind of array contains our vertices, and each element is identified by an index starting from zero. So if you use a lay layout, qualifier for the inputs, like points, you know that this array only contains one element, because we are considering one vertex at a time. So the way to retrieve that value is to set in this array, the first element element zero. But how can we now draw something? Or better how can we decide to draw something inside the geometry shader once we took this position from the vertex shader, and we know that’s the first element of this array, because we are only considering one vertex at the time, we pass this value to, again, GL underscore position. Okay, this is the same name, the same built in variable we use in the vertex shader. Now this GL position is then passed to the fragment shader that can then color that and display that and display it in our window. But we need something else. Now don’t mind about this line. I’ll talk about this later. What we need to do is to create this GL position and then declare that this position is a vertex and we can do that with this line and meet vertex. So this means that here we are creating a vertex in correspondence of this position. Okay. Once we are done creating vertices, we can end our primitive with this order line. So we take the position the first element of the array because in fact these array contains only one element because we are using points as layout qualifier, then we pass this value as the new position to create to emit a new vertex. And once we meet this vertex, we can end this primitive. Okay, and now, the fragment shader knows exactly where to draw something for what concerns face line. Instead, you must know that each each vertex inside that geometry shader can be qualified by some other arbitrary values. That’s exactly what happens in the vertex shader as well. So for example, here we assign a certain color to ascertain vertex. And here we do the same. The only difference is that all the accessory information that we can decide inside the vertex shader, like the color in this case, are passed as well in an array form. So you’ll need again to refer to the first element of that array. So given a group of vertices, you refer to the first one, and you retrieve the variable named color that you output here in the vertex shader from this GTE per Vertex Output structure.
16:32
And then you can assign this color to this vertex. So after you decided all this stuff for this vertex, you can omit that. And once you’re done meeting all the vertices, you can then end the primitive. So this way, you can create one point, let’s go to this second shader, Here I select lines. Okay, so now the selected row mode is lines. As you can see, now, lines are interpret like this, you take a matrix in this kind is matrix made of six columns and one row, and elements are connected like this one is connected to a 23245 to six. Okay, let’s give a look at how this geometry shader works. Let’s open it. And here, the vertex shader is exactly the same, we just take each position and pass that to the geometry shader. But let’s give a look. Now here, first of all, the layout qualifier for the input is now lines. Because I don’t want to consider each vertex individually, I want to say groups of two vertices, so the correct layout is lines, then I want to draw some lines connecting these points. So the layout qualifier for the output is line strip is not points anymore. And now give a look at this. Here, we said that now are combining two vertices at the same time, and they are arranged inside an array. If you want to retrieve each value contained in data array individually, you need again to use the fist structure, but this time, we use the index zero to take the first element and the index one to retrieve the second element. Okay, so this way, what we are doing, actually is to take the position of the first instance of the vertex shader and me to vertex in correspondence of that. And then we take the second element that produced by the second Easterns of this vertex shader, and we are creating another vertex there. And then we can end the primitive and connect these two vertices through a line strip, because we decided that that’s kind of output layout qualifier. So now, the fragment shader knows that these two positions should be drawn with a straight line connecting them. So in a way, the geometry shader doesn’t work per vertex, but it works per primitive per group. So we were saying before that we come from a matrix containing six elements, right? So we will have six instances of this vertex shader running. But then we come down here with a side that we have an input layout qualifier that is lines, so we know that it runs on couples, it deals with groups of two vertices at the same time. In fact, we will only have three instances of geometry shader, that first Easterns will work on Phase Two vertices that are the first and the second element of our matrix. And in fact, we can see this line connecting the first element to the second. Then the second instance of this geometry shader works on another couple, the third element of the matrix and the fourth element of the matrix that are that are referred the same, because they are still the first element of this array and the second element of this array. And then we can display this other line connecting the third element to the fourth element. And last, we have the same structure, creating a line connecting that fifth element to the sixth element. So this kind of layout qualifiers works like this connects the first and the second element, the third, and the fourth, and so on. Now, let’s give a look at these other kinds of draw mode, lines strip. Okay, line strip takes all this elements from one to six, and connects each one with a line. So now, he doesn’t work. With couples, it doesn’t work connecting, like creating a line connecting one, two, and then three, four, then five, six, but creates lines connecting one to two, two to three, three to four, and so on. Let’s give a look at the shader again.
21:30
Okay, this is the same shader. In fact, nothing changed. We always have lines because we want to work on groups of two vertices, we still want to draw some lines. So output qualifier is line strip, what changes is face draw mode, that tells the geometry shader that now this elements are changed. Because now the geometry shader takes the first element. So let’s say element one. And the first instance of this geometry shader calls that element zero inside this array, and takes the second element refer this one into the face, right, and creates a line connecting these two points, then we move to the second instance. But this time, thanks to this kind of draw mode line stripe. We are not taking into account vertices three and four, but we are taking into account verses two and three. So for this second instance of the geometry shader, the first elemental phaser rate is the elements numbered two. And the elements number with index one is element three. Okay, so it changes the interpretation of this array, or the grouping if you prefer. So let’s say it is something like this. Here, we have some points, the draw mode lines, groups, these vertices like this, that draw mode, line, strip groups, this vertices inside the geometry shader, like this. This is the first group, this is the second group, this is the third group. And then we have these last kind of draw mode, that is line loop. The only difference is that now points one and six vertices one and six are connected. So what happens, of course, here, the code is the same. The only difference is that now let’s write that down here. Line on the score. Look, we still have these four vertices that are connected exactly like the line striped row mode, except that now even the last element and the first are connected. Let’s give a look now at these other kinds of draw mode triangles. So let’s open this shader. Again, the vertex shader is exactly the same. What changed is this geometry shader. First of all, the layout, qualifier for the input is triangles. So I’m expecting to receive groups of three vertices at the same time. And the layout output qualifier is triangle strip because I want to draw some triangles and give a look at this and meet vertex functions. Here we take the first element of this array, let’s say vertex one, here, the second vertex two and here the third vertex three. we omit a vertex in correspondence of each one, and then we end our primitive and we pass for each vertex, the corresponding color. So that’s exactly the same thing, right? We now we just taken into account, three vertices. And what if I don’t want to, to draw this elements through triangles, but I want to draw lines, I just need to change the face layout qualifier. So let’s say line strip. Okay, emphases third result, here I’m drawing a line connecting one
25:27
to two, and two, to three. Okay, so you can see that the kind of drawing is totally independent on the kinds of input layout, you may want to take triangles for some reasons, and you want to display lines, that’s totally legit. Let’s say now I want to connect phase point one to the point three, we can do that in this way, we just need to take this first element, this first vertex, and put that again here. So the idea here is to create a line strip connecting the first element of this array to the second to the third. And then from the third element, connect again, the first one. So let’s try to save that. And nothing changed. Why? Because here we have an attribute we need to change. The layout qualifier contains the maximum amount of vertices that this geometry shader can contain. Before we were using just three vertices, right, but if you want to display one more, we need to change this maximum value, for example, to Feb two, four. Okay, and here we have the line again. So this tells us a very important concept within the geometry shader. Not only you can decide how to draw something out to connect the vertices, you can actually create vertices, you can create any amount of vertices you want. For example, let’s take this shape. And I want to create a line connecting each point to the origin. How can you do that? Let’s start from here. I want to create a line connecting the vertex one to the origin. So I may pass as position avec four
27:43
in the origin, let’s see what changes. Okay, we need to augment face maximum vertices. Let’s go for 20. So we don’t have to worry about that. Okay, so now we have a line going from point one to the origin. And then from the origin to point two. Then from point two to point three, and let’s add another vertex. So let’s go to the origin again.
28:25
Let’s decrease the amount of vertices just take three. So let’s remove these last element. So now we have position one connected to the origin, then the origin goes to position two. Then let’s add a connection to the origin here as well. Say now, position two goes to the origin, that goes to position three. Okay, can skip this last one, because that’s the same exact path. Okay, so you can manipulate the face position. However you want. Not only you can change modify face values, but you can create lines or triangles from nothing. Or more than that. You can also avoid creating vertices. So you can, for example, send a bunch of vertices but then only if certain conditions are true, then you can display that vertex. Otherwise, you can totally skip that. Let’s make a test. Let’s go back to having our lines as they were before, connect the first element of this array with the second element with the third element. Okay, and this was our starting condition. Now what if you want to miss a line? Let’s also connect this last one Okay, so let’s right angle is complete. Now, let’s say I do want to draw something. How can you do that, for example, we can connect some points based on distance. So if two vertices are too far away over a certain threshold, I don’t want to draw any line. So let’s say that I want to compute the distance. So let’s declare a float variable. dist, that equals length of so the distance between the position of the first vertex and the second vertex, okay, so this function works on three component vectors. So we need to take just the xy and z components, save, we have no error. Okay, fine. So this should work. Now, let’s say that I want to set a threshold. And I want to draw this line connecting the first element to the second only when this distance is less than a certain threshold. So we can do something like if deste is less than either no 0.3, then do something. And we can encapsulate this part inside this condition. Okay, so for example, here, I change this x y Zed to just xy. So in considering the distance only in this plane, and if the distance is less than this threshold value, then I want to create this line. Otherwise, I want to skip that. So within the geometry shader, you can also decide if to draw something or not. And that’s very precious. It is something that you can use in multiple processes, like we did in the last tutorial. So in tutorial number 20. If you remember, we created a bunch of vertices, and then we didn’t, we didn’t expect to draw them old, we just use the vertices that followed a certain condition like in this situation. Now let’s try to increase the amount of vertices let’s go for 24.
32:27
Now some lines appeared. And these appeared depending on the distance, let’s try to increase this one a bit more. Let’s go for seven. Okay, so depending on the distance now, some lines are drawn or not. So these are some kinds of stuff you can do with geometry shader. So you can decide how to draw things you can create or discard some vertices. You can displace vertices, and you can do all the other stuff you can do inside the vertex shader. So for example, you can access a texture, or you can use a vase matrices directly into the geometry shader, if it makes sense for some kind of process. So they are extremely powerful. You can also use for cycles. So let’s say you just provide a point. So you use a layout qualifier like point. And then you may have for example, a texture and through a four cycle, you look up from that texture and create an amount of vertices. So any amount of vertices you want. So let’s make another experiments at the removal of this, and let’s roll this. First off, always. Okay, so here we are back to our triangles. Let’s go back again to three vertices, okay. Now, here we created a single primitive, right, because we immediate four vertices, and we decided to connect those and and the primitive here, but you can also create more than one primitive. So for example, this is a primitive, but you can also decide to take this border, the line connecting the first element to the second and create a third vertex connecting these two points to the center. So for example, let’s do that. Let me copy this. Let’s move down here. Based and here we can say that face points one must be connected to the center. So let’s copy that again. The center is imposition back four zeros, zeros 01. And then connected back to the point two. And of course, we need to end this new primitive.
35:20
And here this, we have generated these other triangle. Let’s do the same for for these other two sides. So four vertices of index, one and two. So one, two. And again, four vertices of index, two, and three. Sure you’re on my ear, I’m getting an error, because, of course, vertex three doesn’t exist. And here, the error says, index, sorry, array index out of bounds. Because with this kinds of input primitive, that is triangles, we don’t have any fourth vertex. Okay, and here you can see a face shape is created. So you can create whatever shape you want. Now, if you increase the amount of vertices all the new shapes are connected the same way to the center. Now, if you want to create the triangles, instead, you just need to take to change this line straight to triangle strip. And here it is. You created some triangles following the same principle. Okay, creating this sort of pyramids. And let’s also say you want to color the points at the center, sorry, to vertex at the center differently. So let’s take where here, okay, I want to make the points at the center white. So let’s create a vector that contains the color white. And let’s copy that everywhere else. Okay. Now, I’m expecting these points at the middle to be white. And that should be true for any amount of vertices with the sides wet. So, now the video is getting quite long, maybe it’s not that bad. If I leave these two other kinds of input primitives to you to discover they are exactly the same, the only thing the only thing that changes is that instead of taking into account four vertices, these lines adjacency takes into account for and based triangles adjacency takes into account six, but the idea is exactly the same. So here instead of having an array going from the index zero to the index two, we will have something going from zero to three, four lines adjacency, and from zero to five, four triangles adjacency. But then the concept remains the same. If you want to meet a vertex, you can, you should do that, like face. And if you want to meet, if you want to end that primitive, you just need to add this line. But give a look at all this other shaders here you can find everything in detail. So I invite you to study this step of shaders, because you can do a lot of stuff with it. The next tutorials we will see we will use these step they stage the geometry shader a lot. So you can see that in its full and glorious power. But study and check out face examples and try to make something with Geometry shaders. Try to experiment with those because through Geometry shaders, you can do stuff like for example MTL is In Depth of Field motion blur, and all the eye candy we know and love. So they are very important and we will meet them a lot. So hope you liked this tutorial. Hope you enjoyed that. As always, thank you so much for your support. And see you next
39:46
time.
Transcribed by https://otter.ai