# ASL: Geometry & Tessellation-Shader

Last entry:

https://www.gamedev.net/blog/1930/entry-2260794-acclimate-shading-language/

After a long time of not being productive again, I've finally come around to fully implement the current-gen API features to my engines shading language, now called "ASL" (acclimate shading language).

One thing I noticed when learning geomentry, domain and hull shaders in DX11 was that those had quite some bulky syntax. IDK, its straightforward and not that overly complicated to understand, but there is quite a lot to remember about the exact syntactical structure of those things. So in my own implementation, I tried to keep the requirements for coding any of those shaders as simple as possible.

For the following shaders, I assume you already have at least a basic understanding of the concepts.

Geometry-Shader:

So lets have a look at how a geometry-shader looks like, shall we?

This is a simple geometry-shader, expanding a point to an floor-aligned quad. The input block, as known previously, offers cbuffer-variables supplied from the application side.

The "primitives" block is new and geometry-shader only, and is there for definition of what primitives the geometry-shader gets, and what it should output.

Inside the "main" block, you can access vertex shader output via "in[X]" (uses the vertexShader-blocks "out" definition not seen here), and write to "out", calling "Append()" after each vertex is written. "Restart()" can be called to emit the next (seperate) primitive.

The geometryShader can eigther output its own vertex structure to the pixel shader by specifying an "out" block, otherwise it will use the previous shaders output structure.

So in conclusion, geometry-shaders using is quite easy using the ASL. Note that this also parses to OpenGL4 (unfortunately I havn't implementated OpenGL-support for the upcoming shader-types, so I can't say for sure they will work there also).

Tessellation-Shader (Hull & Domain):

Tessellation was one of the key-features for current-gen hardware. Especially those always deterred me from getting started with it, since there is really a whole lot of things to keep in mind for both Hull & Domain-Shader, at least in DX11. You have a constant hull function, the regular hull shader function, with inputs of multiple vertices as well as the constant data, with PointID/PatchID and UV-coordinates for the Domain-Shader... lets just say, its even more little things to keep in mind syntactically than the geometry-shader.

Hull-Shader:

But lets have a look at how you write them with ASL:

The "settings" block obviously is hull-shader specific, as you define the tessellation-paramters.

"constOut" and "constFunc" are the constFunction, which is a completely seperate function in DX11. There, you calculate the tessellation factors, and any other data that is shared between the entire patch. Note that the "Inside/Edges" are defined for you automatically based on what domain you specify.

in the main-function you have a few things defined for you. Obviously "in" is the output of the vertex shader, as an array with as many elements as you specified as "inputcontrolpoints". PointID is the ID of the current vertex, and there is also a PatchID for the ID of the entire patch.

Domain-Shader:

And now for the domain-shader:

So there is really little special about that here. You have an "in" block with as many controlpoints as you specified in "outputcontrolpoints", using the hull-shaders "output" for the vertex elements. "UV" is defined for you, depending on what you have got - for a quad its float2, for a triangle it would be float3. In the "functions"-block, I've specified a Bilerp-function, which could probably be somewhat pulled in the standard-repertoir of the shading-language, as it is probably needed extremely often.

And thats it! You can do all your displacement-mapping etc.. here, since the domain-shader also has access to a "textures"-block, and so on...

Conclusion:

So for those of you familiar with the Domain/Hull-Shader, I think it should be clear that my shading language is taking quite a bit of work. From what I've seen during building the parser for those, you normally have to specifiy lots of duplicated data, e.g. while "outputcontrolpoints" exists in DX11 also, you still have to manually write it as the array-size in the hull/domain-shader input signature. You also always have to figure out the correct combination of Inside/Edge-Tessellation-Factors yourself, as well as what UV you want as input in the domain-shader.

So thats it for now. Next time, I'll probably talk about some more specific block-types that are needed for developing shaders, like "constans", "extentions", and probably also more complicated stuff like templating shaders (which I partially still have to implement). Thanks for reading, and up until next time, I've attached a somewhat complete shader example of the tessellation terrain shader I'm currently working on, based on the Terrain Tessellation example from NVIDIAS DX11 SDK.

PS:

For those of you that reguarely work with plain HLSL/GLSL-shaders, I want to ask a question: Given what you have read so far, would you rather write your shaders in a language like mine (given that there is full documentation, etc...) or still rather write your shaders in a plain shader language, and why? Would be very interested to hear some different opinions.

https://www.gamedev.net/blog/1930/entry-2260794-acclimate-shading-language/

After a long time of not being productive again, I've finally come around to fully implement the current-gen API features to my engines shading language, now called "ASL" (acclimate shading language).

One thing I noticed when learning geomentry, domain and hull shaders in DX11 was that those had quite some bulky syntax. IDK, its straightforward and not that overly complicated to understand, but there is quite a lot to remember about the exact syntactical structure of those things. So in my own implementation, I tried to keep the requirements for coding any of those shaders as simple as possible.

For the following shaders, I assume you already have at least a basic understanding of the concepts.

Geometry-Shader:

So lets have a look at how a geometry-shader looks like, shall we?

`geometryShader{ input Stage { matrix mViewProj; } primitives { in: point[1]; out: triangle[4]; } main { float3 vRight = float3(0.0f, 0.0f, 1.0f); float3 vUp = float3(1.0f, 0.0f, 0.0f); vRight *= 0.5f; vUp *= 0.5f; float3 vVerts[4]; vVerts[0] = in[0].vPosition.xyz - vRight - vUp; // Get bottom left vertex vVerts[1] = in[0].vPosition.xyz + vRight - vUp; // Get bottom right vertex vVerts[2] = in[0].vPosition.xyz - vRight + vUp; // Get top left vertex vVerts[3] = in[0].vPosition.xyz + vRight + vUp; // Get top right vertex for(int i = 0; i < 4; i++) { out.vPosition = mul(float4(vVerts, 1.0f), mViewProj); Append(); } }}`

This is a simple geometry-shader, expanding a point to an floor-aligned quad. The input block, as known previously, offers cbuffer-variables supplied from the application side.

The "primitives" block is new and geometry-shader only, and is there for definition of what primitives the geometry-shader gets, and what it should output.

Inside the "main" block, you can access vertex shader output via "in[X]" (uses the vertexShader-blocks "out" definition not seen here), and write to "out", calling "Append()" after each vertex is written. "Restart()" can be called to emit the next (seperate) primitive.

The geometryShader can eigther output its own vertex structure to the pixel shader by specifying an "out" block, otherwise it will use the previous shaders output structure.

So in conclusion, geometry-shaders using is quite easy using the ASL. Note that this also parses to OpenGL4 (unfortunately I havn't implementated OpenGL-support for the upcoming shader-types, so I can't say for sure they will work there also).

Tessellation-Shader (Hull & Domain):

Tessellation was one of the key-features for current-gen hardware. Especially those always deterred me from getting started with it, since there is really a whole lot of things to keep in mind for both Hull & Domain-Shader, at least in DX11. You have a constant hull function, the regular hull shader function, with inputs of multiple vertices as well as the constant data, with PointID/PatchID and UV-coordinates for the Domain-Shader... lets just say, its even more little things to keep in mind syntactically than the geometry-shader.

Hull-Shader:

But lets have a look at how you write them with ASL:

`hullShader{ settings { domain: QUAD; partitioning: FRAC_EVEN; outputtopology: TRI_CW; outputcontrolpoints: 4; inputcontrolpoints: 4; } out { float3 vPos; } constOut { } constFunc { constOut.Edges[0] = 1.0f; constOut.Edges[1] = 1.0f; constOut.Edges[2] = 1.0f; constOut.Edges[3] = 1.0f; constOut.Inside[0] = 1.0f; constOut.Inside[1] = 1.0f; } main { out.vPos = in[PointID].vPos.xyz; }}`

The "settings" block obviously is hull-shader specific, as you define the tessellation-paramters.

"constOut" and "constFunc" are the constFunction, which is a completely seperate function in DX11. There, you calculate the tessellation factors, and any other data that is shared between the entire patch. Note that the "Inside/Edges" are defined for you automatically based on what domain you specify.

in the main-function you have a few things defined for you. Obviously "in" is the output of the vertex shader, as an array with as many elements as you specified as "inputcontrolpoints". PointID is the ID of the current vertex, and there is also a PatchID for the ID of the entire patch.

Domain-Shader:

And now for the domain-shader:

`domainShader{ input Instance { matrix mWorld; } input Stage { matrix mViewProj; } out { float4 vPos; } functions { float3 Bilerp(float3 v0, float3 v1, float3 v2, float3 v3, float2 i) { float3 bottom = lerp(v0, v3, i.x); float3 top = lerp(v1, v2, i.x); float3 result = lerp(bottom, top, i.y); return result; } } main { float3 vPos = Bilerp( in[0].vPos, in[1].vPos, in[2].vPos, in[3].vPos, UV ); out.vPos = mul(float4(vPos, 1.0f), mul(mWorld, mViewProj)); }}`

So there is really little special about that here. You have an "in" block with as many controlpoints as you specified in "outputcontrolpoints", using the hull-shaders "output" for the vertex elements. "UV" is defined for you, depending on what you have got - for a quad its float2, for a triangle it would be float3. In the "functions"-block, I've specified a Bilerp-function, which could probably be somewhat pulled in the standard-repertoir of the shading-language, as it is probably needed extremely often.

And thats it! You can do all your displacement-mapping etc.. here, since the domain-shader also has access to a "textures"-block, and so on...

Conclusion:

So for those of you familiar with the Domain/Hull-Shader, I think it should be clear that my shading language is taking quite a bit of work. From what I've seen during building the parser for those, you normally have to specifiy lots of duplicated data, e.g. while "outputcontrolpoints" exists in DX11 also, you still have to manually write it as the array-size in the hull/domain-shader input signature. You also always have to figure out the correct combination of Inside/Edge-Tessellation-Factors yourself, as well as what UV you want as input in the domain-shader.

So thats it for now. Next time, I'll probably talk about some more specific block-types that are needed for developing shaders, like "constans", "extentions", and probably also more complicated stuff like templating shaders (which I partially still have to implement). Thanks for reading, and up until next time, I've attached a somewhat complete shader example of the tessellation terrain shader I'm currently working on, based on the Terrain Tessellation example from NVIDIAS DX11 SDK.

PS:

For those of you that reguarely work with plain HLSL/GLSL-shaders, I want to ask a question: Given what you have read so far, would you rather write your shaders in a language like mine (given that there is full documentation, etc...) or still rather write your shaders in a plain shader language, and why? Would be very interested to hear some different opinions.

3

Sign in to follow this

Followers
0

## 3 Comments

## Recommended Comments

## Create an account or sign in to comment

You need to be a member in order to leave a comment

## Create an account

Sign up for a new account in our community. It's easy!

Register a new account## Sign in

Already have an account? Sign in here.

Sign In Now