Opengl vertex program




















Each attribute index represents a vector of some type, from 1 to 4 components in length. It can be any number If the vertex shader has fewer components than the attribute provides, then the extras are ignored. If the vertex shader has more components than the array provides, the extras are given values from the vector 0, 0, 0, 1 for the missing XYZW components.

The latter is not true for double-precision inputs OpenGL 4. If the shader attribute has more components than the provided value, the extra components will have undefined values. This type will be converted into the actual type used by the vertex shader. Here is a list of the types and their meanings for each function:. This is somewhat equivalent to a size of 4, in that 4 components are transferred. However, as the name suggests, this "size" reverses the order of the first 3 components.

This special mode is intended specifically for compatibility with certain Direct3D vertex formats. Notice how X comes second and the Z last. The vertex format information above tells OpenGL how to interpret the data.

The format says how big each vertex is in bytes and how to convert it into the values that the attribute in the vertex shader receives. But OpenGL needs two more pieces of information before it can find the data. It needs a byte offset from the start of the buffer object to the first element in the array.

So your arrays don't always have to start at the front of the buffer object. It also needs a stride, which represents how many bytes it is from the start of one element to the start of another. This is in part why it's called glVertexAttrib Pointer , due to old legacy stuff where this was actually a client pointer. So you will need to cast the integer offset into a pointer.

If it is set to 0, then OpenGL will assume that the vertex data is tightly packed. So OpenGL will compute the stride from the given other components. Each array is tightly packed, but independent of one another. Note that each attribute uses the same stride: the size of the Vertex struct. Thus, the size of the Vertex structure is exactly the number of bytes from the start of one element to another, for each attribute.

The macro offsetof computes the byte offset of the given field in the given struct. This is added to the baseOffset , so that each field points to the start of its own data relative to the beginning of the Vertex structure. As a general rule, you should use interleaved attributes wherever possible. Obviously if you need to change certain attributes and not others, then interleaving the ones that change with those that don't is not a good idea.

But you should interleave the constant attributes with each other, and the changing attributes with those that change at the same time. Indexed rendering, as defined above, requires an array of indices; all vertex attributes will use the same index from this index array. Indices can be unsigned bytes, unsigned shorts, or unsigned ints.

The index buffer binding is stored within the VAO. Normally, vertex attribute arrays are indexed based on the index buffer, or when doing array rendering, once per vertex from the start point to the end. However, when doing instanced rendering , it is often useful to have an alternative means of getting per-instance data than accessing it directly in the shader via a Uniform Buffer Object , a Buffer Texture , or some other means.

It is possible to have one or more attribute arrays indexed, not by the index buffer or direct array access, but by the instance count. This is done via this function:. The "current instance" mentioned above starts at the base instance for instanced rendering, increasing by 1 for each instance in the draw call. If no base instance is specified, then the current instance starts with 0. This is generally considered the most efficient way of getting per-instance data to the vertex shader.

However, it is also the most resource-constrained method in some respects. OpenGL implementations usually offer a fairly restricted number of vertex attributes 16 or so , and you will need some of these for the actual per-vertex data. So that leaves less room for your per-instance data.

While the number of instances can be arbitrarily large unlike UBO arrays , the amount of per-instance data is much smaller. However, that should be plenty for a quaternion orientation and a position, for a simple transformation. That would even leave one float the position only needs to be 3D to provide a fragment shader an index to access an Array Texture.

These concepts can be separated, allowing the user to separately specify the format of a vertex attribute from the source buffer. This also makes it easy to change the buffer binding for multiple attributes, since different attributes can pull from the same buffer location. This separation is achieved by splitting the state into two pieces: a number of vertex buffer binding points, and a number of vertex format records.

This will almost certainly be Notice that the stride is uncoupled from the vertex format itself here. Since OpenGL doesn't know the data's format, it cannot compute the stride. So a stride of 0 really means a stride of 0. In OpenGL 4. This is an implementation-defined limitation, but it will be no less than All vertex attributes associated with this binding index will use the same divisor. Vertex formats are associated with vertex buffer bindings from glBindVertexBuffer.

So every vertex format that uses the same vertex buffer binding will use the same buffer object and the same offset. It is effectively added to the buffer binding's offset to get the offset for this attribute. Note that you still have to enable attribute arrays; this feature doesn't change that fact. It only changes the need to use glVertexAttribPointer.

This can be bit confusing, but it makes a lot more sense than the glVertexAttribPointer method once you see it.

The simplest way is to go back to the Vertices example from the interleaving section. We have this struct of vertex data:. Using glVertexAttribPointer , we bound this data like this:. That's much clearer. The base offset to the beginning of the vertex data is very clear, as is the offset from this base to the start of each attribute.

Better yet, if you want to use the same format but move the buffer around, it only takes one function call; namely glBindVertexBuffer with a buffer binding of 0. Indeed, if lots of vertices use the same format, you can interleave them in the same way and only ever change the source buffer. Note again that all of the above state is still VAO state. It is all encapsulated in vertex array objects.

Because all of this modifies how vertex attribute state works, glVertexAttribPointer is redefined in terms of this new division. It is defined as follows. Where CalcStride does what it sounds like. Note that glVertexAttribPointer does use the same index for the attribute format and the buffer binding. So calling it will overwrite anything you may have set into these bindings. Similarly, glVertexAttribDivisor is defined as:. The separation of attribute formats from the buffers that contain storage for them is a powerful mechanism.

However, it is often useful as a developer to maintain the same format while quickly switching between multiple buffers to pull data from.

To achieve this, the following function is available:. The difference between such a loop are as follows. Attributes in GLSL can be of matrix types. However, our attribute binding functions only bind up to a dimensionality of 4. If you directly assign an attribute index to a matrix type, it implicitly takes up more than one attribute index. The number of attributes a matrix takes up depends on the number of columns of the matrix: a mat2 matrix will take 2, a mat2x4 matrix will take 2, while a mat4x2 will take 4.

The size of each attribute is the number of rows of the matrix. Each bound attribute in the VAO therefore fills in a single column, starting with the left-most and progressing right. Thus, if you have a 3x3 matrix, and you assign it to attribute index 3, it will naturally take attribute indices 3, 4, and 5. Each of these indices will be 3 elements in size.

Attribute 3 is the first column, 4 is the second, and 5 is the last. OpenGL will allocate locations for matrix attributes contiguously as above. So if you defined a 3x3 matrix, it will return one value, but the next two values are also valid, active attributes. Double-precision matrices where available will take up twice as much space.

So a dmat3x3 will take up 6 attribute indices, two for each column. A vertex shader can read an attribute that is not currently enabled via glEnableVertexAttribArray. Because the attribute is defined by context state, it is constant over the course of a single draw call. Each attribute index has a separate value. This is easy to get wrong or overlook, and is not well explained in the documentation. We use a function called glEnableVertexAttribArray to enable each one. This function only affects the currently bound vertex array object.

This means that when we do this now, it will only affect our attributes, above. We will need to bind every new vertex array and repeat this procedure for those too.

We are using 2 attributes points and colours , and we know that these are numbered 0 points , and 1 colours ; matching the numbers we gave when setting up the vertex attribute pointers, earlier. A little aside about this Other GL incarnations don't have vertex array objects, and need to explicitly enable and disable the attributes every time a new type of object is drawn, which changes the enabled attributes globally in the state machine. We don't need to worry about that in OpenGL 4; the vertex attribute object will remember its enabled attributes.

This isn't clear in the official documentation, nor is it explained properly in other tutorials - it's very easy to get a false-positive misunderstanding of how these things work and run into hair-pulling problems later when you're trying to draw 2 different shapes. I actually figured this out by writing a programme that used the scientific method to try and falsify break in every conceivable way my theory for how the logic of attribute enabling worked; if I'd just tried it until it worked deduction then I'd have been wrong!

I just don't know what to say If you forget to enable an attribute, the shader won't know where to read the data from and you'll get weird results e. I believe attribute 0 is enabled by default, but the second attribute that we added will not be. This process is a bit excessive, and I feel should really be handled internally by OpenGL, but in this version we still need to do it. Now, we want our shader to render using the second vertex buffer, so we need to add a second attribute to the top of the vertex shader.

We are going to add the OpenGL 4 layout prefix to each attribute. This lets us manually specify a location for each attribute - and we are going to match this up to the index that we gave each one in glVertexAttribPointer. If you don't specify a location, the shader programme linker will automatically assign one. You can query this, which we did in Shaders , but I prefer to specify it manually so I can see the values as I write.

This is where it gets interesting. It has no effect on our vertex shader, but outputs it to the next stage in the programmable hardware pipeline. In our case - the fragment shader. You can achieve the exact same effect by telling the shader's linker which variable should have which location.

Right after compiling but before linking , you can call glBindAttribLocation to do this:. You don't need to use both methods - one or the other is fine. The third option is to let the linker decide which location to give each input variable, and then you use a value returned by glGetAttribLocation for the first parameter of calls to glVertexAttribPointer. We can rewrite the fragment shader to use our new colour variable as an input, which will colour each fragment directly.

Note that we add an in prefix to retrieve a variable from a previous stage. Our output fragment colour needs to be r,g,b,a 4 components so we can just add a 1 to the end of our 3-component colour by casting it as a vec4. That's it! Our drawing loop should look the same as with the Hello Triangle demo. Now, remember, our triangle has only 3 vertices , but 1 fragment for every pixel-sized area of the surface.

This means that we have 3 colour outputs from vertex shaders, and perhaps colour inputs to each fragment shader. How does this work? The answer is that each fragment shader gets an interpolated colour based on its position on the surface. The fragment exactly on the red corner of the triangle will be completely red 1.

A fragment exactly half-way between the blue and red vertices, along the edge of the triangle, will be purple; half red, half blue, and no green: 0.

A fragment exactly in the middle of the triangle will be an equal mixture of all 3 colours; 0. Keep in mind that this will happen with any other vertex buffer attributes that you send to the fragment shader; normals will be interpolated, and texture coordinates will be interpolated to each fragment.

This is really handy, and we will exploit it for lots of interesting per-pixel effects. But it's quite common to misunderstand this when getting started with shaders - vertex shader outputs are not sending a constant variable from a vertex shader to all fragment shaders.

We use uniform variables for that. The last thing that you should know about is a built-in rendering optimisation called back-face culling. This gives a hint to GL so that it can throw away the hidden "back" or inside faces of a mesh. This should remove half of the vertex shaders, and half of the fragment shader instances from the GPU - allowing you to render things twice as large in the same time.

It's not appropriate all of the time - you might want our 2d triangle to spin and show both sides. The only things that you need specify are if clock-wise vertex "winding" order means the front, or the back of each face, and set the GL state to enable culling of that side. Our triangle, you can see, is given in clock-wise order.

Most mesh formats actually go the other way, so it pays to test this before wondering why a mesh isn't showing up at all!



0コメント

  • 1000 / 1000