You need the following Simdify® modules to complete this exercise: Simdify® Free Edition, Microsoft® Visual Studio® 2017 or newer (to compile exported application).
In this exercise you'll learn to create a simple workload that renders geometry with a vertex and fragment shader. After creating the workload, you'll learn how to export it and run it with the Simdify runtime.
The application displays a splash screen and then the application desktop appears. The main menu is composed of three items since this is an empty document. Additional interface options become available when you create a new file or load a file from disk.
The software displays a wizard that allows you to specify the parameters of your new workload. The Profile shown below is 460 core, but you will see the highest GLSL version available on your machine. In this case, we're specifying the GLSL version for the visual shader, which is what displays results on the screen.
NOTE: You will not see video or compute shader options in the wizard dialog if you have not purchased the compute or video add-on modules.
New Workload
The application creates a new workload. Notice that the main menu options have changed. You can see the hierarchy on the left, the rendered shader with geometry in the middle, and the property sheet on the right. GLSL compiler messages are shown in the output window below. The workload sets the fragment color to red and does no other work.
If the shader compiled successfully, you should see a red square in the center of the worksheet.
This expands the graph so that you can see all the nodes. As you can see, this application is made from a set of nodes. Nodes are atomic types because there is no smaller element that can be used in the layout.
In this simple example, <Program> and <ParametricMesh> resources are declared inside invisible sections of the document. Then in the visible sections, the shader is activated and uniform values are set. Finally, the mesh is rendered. This is the most important pattern in any workload: declare resources, bind them, activate them, and render the results (if applicable).
Notice that you can see the GLSL version, profile, and source code locations. Many nodes, but not all of them, display useful information if you hover over them.
This displays a dialog that allows you to select GLSL shader source code (and any include files). The file path of the source item you select will be copied to the Windows® clipboard so you can open it in a text editor.
This copies the absolute path to the fragment shader source code to the Windows® clipboard. For example, a file path like the following:
C:\Users\MyUserName\MyDocuments\Scenomics\Shader\Simple Workload\460\visual_fragment_shader.glsl
is copied to the clipboard.
This is the fragment shader. Note that your #version 460 declaration might be different, depending on the highest GLSL version on your machine. You can still follow this exercise even if the shader code is different. Just follow the steps below and make the same changes in the same locations.
// #version 460
// The version number is automatically injected by the application.
// It is included above for reference purposes only.
#include <SPA_Version.glsl>
#include <SPA_Constants.glsl>
#include <Modules/SPA_EditStateFragmentColorOverride.glsl>
#include "visual_attributes.glsl"
in Data { vertexData attributes; } DataIn;
out vec4 fragColor;
void main(void)
{
fragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
SPA_EditStateFragmentColorOverride( fragColor );
}
Simdify supports #include for GLSL. This makes life a lot easier when you're writing shader code. You can dump the fully assembled translation unit at any time if you need to see all your shader code, or when you are ready to take the shader code and use it in your own applications.
Notice that there is a line #include <Modules/SPA_EditStateFragmentColorOverride.glsl> and a corresponding line SPA_EditStateFragmentColorOverride( fragColor ); at the end of the shader. This is necessary for the Magnifier draw mode to work. The Magnifier draw mode powers the compute shader and texture debugging tools. If you're using these shaders for other purposes, or if you don't need to debug, you can remove the include statement and the call to SPA_EditStateFragmentColorOverride( fragColor ). Removing this code won't affect how your shader works.
fragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
fragColor = vec4( DataIn.attributes.texcoord, 1.0, 1.0 );
Note that if you're using an older version of GLSL in this exercise, the replacement code might be something like this:
// Older versions of GLSL would use:
fragColor = vec4( fs_texcoord, 1.0, 1.0 );
Leave the fragment shader open in the text editor.
The color has changed from red to a blue, white, and purple gradient, which shows us the shader pipeline is active and that we can make more changes.
uniform vec4 tint_color;
Your fragment shader code looks like this:
// #version 460
// The version number is automatically injected by the application.
// It is included above for reference purposes only.
#include <SPA_Version.glsl>
#include <SPA_Constants.glsl>
#include <Modules/SPA_EditStateFragmentColorOverride.glsl>
#include "visual_attributes.glsl"
in Data { vertexData attributes; } DataIn;
uniform vec4 tint_color;
out vec4 fragColor;
void main(void)
{
fragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
SPA_EditStateFragmentColorOverride( fragColor );
}
fragColor = vec4( DataIn.attributes.texcoord, 1.0, 1.0 ) * tint_color;
Your fragment shader main function looks like this:
void main(void)
{
fragColor = vec4( DataIn.attributes.texcoord, 1.0, 1.0 ) * tint_color;
SPA_EditStateFragmentColorOverride( fragColor );
}
Leave the fragment shader open in the text editor. The rendered geometry is going to turn black when you return to the application. This is normal.
The rendered geometry is going to turn black when you return to the application. Depending on the behavior of your graphics driver you may see other colors as well. This is because we have not yet set a value for uniform vec4 tint_color. We're going to create a resource for this uniform next.
This binds the program to the rendering device and activates it. Once the program is in an active state, we can set uniforms and do other things.
The software presents a dialog that allows you to add resources that have been declared in your GLSL code.
The software adds a <Float32VectorNode> named uniform vec4 tint_color to the layout.
This displays the <Float32VectorNode> property editor.
The worksheet looks like this:
This is generally how you set uniform values. You declare them in the shader and then add then to the document. In versions of GLSL higher than 120, you can also initialize uniforms when you declare them. If initialized in GLSL, the values of the <VariableNode> in the Layout app will match the initializer values you typed in the shader code. You can then configure the values of the new nodes to suit your purpose. Many uniform values are set by the user, as we just did, but later you'll learn about using <DataCapture> objects to capture values from the document and use them as uniform values. The other way to create uniforms, uniform buffers, is discussed in a subsequent exercise (but it requires the Simdify Compute+ Module).
uniform sampler2D diffuse_texture;
Your fragment shader code looks like this:
// #version 460
// The version number is automatically injected by the application.
// It is included above for reference purposes only.
#include <SPA_Version.glsl>
#include <SPA_Constants.glsl>
#include <Modules/SPA_EditStateFragmentColorOverride.glsl>
#include "visual_attributes.glsl"
in Data { vertexData attributes; } DataIn;
uniform vec4 tint_color;
uniform sampler2D diffuse_texture;
out vec4 fragColor;
void main(void)
{
vec4 diffuse_color = texture( diffuse_texture, DataIn.attributes.texcoord );
fragColor = vec4( DataIn.attributes.texcoord, 1.0, 1.0 ) * tint_color;
SPA_EditStateFragmentColorOverride( fragColor );
}
vec4 diffuse_color = texture( diffuse_texture, DataIn.attributes.texcoord );
Your fragment shader main function looks like this:
void main(void)
{
vec4 diffuse_color = texture( diffuse_texture, DataIn.attributes.texcoord );
fragColor = diffuse_color * tint_color;
SPA_EditStateFragmentColorOverride( fragColor );
}
This code samples a texture using the texture coordinates computed by the vertex shader.
fragColor = diffuse_color * tint_color;
Your fragment shader main function looks like this:
void main(void)
{
vec4 diffuse_color = texture( diffuse_texture, DataIn.attributes.texcoord );
fragColor = diffuse_color * tint_color;
SPA_EditStateFragmentColorOverride( fragColor );
}
Leave the fragment shader open in the text editor.
The software presents a dialog that allows you to add resources that have been declared in your GLSL code.
The software adds a <SamplerNode> to the layout.
This displays the file open dialog, which allows you to choose a 2D texture from the hard disk. There is a list of folders that organize textures by pixel format.
IPF_8888_ARGB
IPF_8888_ARGB.png
The software adds a <Texture> node named IPF_8888_ARGB to the document and connects the <SamplerNode> to the new texture.
You can see the texture modified by the tint color. If you change the tint color uniform, then the results on screen will change.
The software displays a dialog that allows you to export the application layout to the Simdify runtime format.
By default, the export is configured to generate the exported document in a sub-directory of the folder containing the .BOX document that implements the shader.
The software exports the document, generating all the binary files needed for the runtime. This could take 30-60 seconds depending on what you're doing. When the export is complete, the software opens the folder containing the exported document.
This shows your OpenGL workload running in real-time.
This is the basic process that you'll use every time you export a workload from the Layout application.