You need the following Simdify® modules to complete this exercise: Simdify® Free Edition
In this exercise you'll learn to use the Outline app and the Module app to create a shader module that implements additive blending. The following table shows the skills required to complete this exercise.
Skill | Description |
---|---|
Starting Applications | You need to be able to access the Windows Start Menu, find applications, and start them. |
Opening Files | You need to be able to open files from disk. |
Tree View | You need to be able use a Windows tree view to expand and contract nodes. You need to be able to right click on the nodes to access node command menus. |
Text Editor | You need to be able to start a text editor such as Notepad, Notepad++, or Visual Studio and open a text file from the hard disk. You need to be able to edit the text file and save the changes. |
The application displays a splash screen and then the application desktop appears.
The application presents the file open dialog in the Outline application library folder.
This finds the Module library folder and selects it so that it's easy to see.
The Simdify Data project contains all the information associated with your Simdify installation. Think of it like the 'north star' for everything you're doing with Simdify. In this project you can always find all your documents.
FBO Image Processing Tiles
The software creates the folder on disk and adds a new folder to the hierarchy.
The software presents a dialog that allows you to create a new shader module.
Additive-Blend-Module
Implements a shader module for additive blending.
The application creates the new shader module.
You can see all the files associated with the new shader module.
The Module application starts and loads the file.
The hierarchy editor displays the contents of your shader module, which gives you information about when shader module items are executed. The rendering loop starts at the root of the document and traverses nodes using a breadth-first search, rendering each node as it is traversed. This means you can make certain assumptions about how your shader module behaves by looking at the hierarchy.
The hierarchy is delineated into two main sections: Data and Execution. The Data section refers to data such as textures and meshes that do not need an active shader program to operate. There are other data such as storage containers for inputs and outputs. These will be used to specify input and output constraints if this shader module is used in a workload layout.
The Execution section requires an active shader program. Notice that the nodes in the execution section are stored below <ShaderResourceNode> objects. You can see the <ProgramBindNode> named Bind Visual is the first useful item in the Execution section. After the shader program is bound, you can see that we are able to set uniforms and do other things related to that shader program. We could bind another shader program and then do similar things. The pattern is pretty clear: bind a shader program and then do work. This basic process is how you build all shader modules.
Finally, order of operations definitely matters. You usually want to adhere to the structure of the Data section shown in this document. Of course, you are free to be much more creative in the Execution section as long as you make sure to follow the basic pattern of binding a shader program and then binding its resources.
The software displays a dialog that allows you to select the source file you wish to open. This includes any files #included by the shader. (While GLSL itself doesn't automatically support preprocessing shader source code, Simdify design applications DO allow you to use #include to create modular shaders.)
The application displays a dialog box that informs you the path has been copied to the clipboard.
You'll see path such as: C:\Users\Installer Test 0\Documents\Scenomics\Library\Module\FBO Image Processing Tiles\Additive-Blend-Module\430\fragment_shader.glsl
All shaders are separated into two sections. Declarations are stored at global scope. The fragment shader itself is stored inside void main(void). Later, when we add nodes to the document to build our shader module, we're only going to be concerned with things declared at global scope. The body of all shaders is effectively invisible to Simdify design applications such as Module.
// #version 430
// 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 "vertex_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 );
}
Although you can't see it in your shader code, the OpenGL shader compiler on your machine also "inserts" built-in variables so they are visible to your shader.
fragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
This line assigns red to the fragment shader output.
fragColor = vec4( 0.0, 1.0, 0.0, 1.0 );
This line assigns green to the fragment shader output.
// #version 430
// 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 "vertex_attributes.glsl"
in Data { vertexData attributes; } DataIn;
layout( binding = 0 ) uniform sampler2D lhs;
layout( binding = 1 ) uniform sampler2D rhs;
uniform float blend_opacity;
out vec4 fragColor;
vec4 add_images( vec4 base, vec4 blend, float opacity )
{
return ( base * opacity ) + blend * ( 1.0 - opacity );
}
void main(void)
{
vec4 lhs_sample = texture( lhs, DataIn.attributes.texcoord );
vec4 rhs_sample = texture( rhs, DataIn.attributes.texcoord );
vec4 res = add_images( lhs_sample, rhs_sample, blend_opacity ); // Performs additive blending using a standard algorithm.
fragColor = res;
SPA_EditStateFragmentColorOverride( fragColor );
}
layout( binding = 0 ) uniform sampler2D lhs;
layout( binding = 1 ) uniform sampler2D rhs;
uniform float blend_opacity;
In the next section, we'll create nodes that represent these declarations.
The new shader code is running, but we haven't provided the textures and uniforms needed to generate a result. You might see white or black depending on your GPU.
The software presents a dialog that shows you items that have been declared in your shader.
The software adds the items to the hierarchy. You'll notice some of the new items have red lines underneath them. This means that there is an error.
Move your mouse over the <SamplerNode> named layout( binding = 0 ) uniform sampler2D lhs. You'll see a tooltip appear that displays information the error.
To make a long story short, both of the <SamplerNode> objects expect a <Texture>.
Enter the folder named IPF_8888_ARGB.
IPF_8888_ARGB
IPF_8888_ARGB.png
The software adds a <Texture> node to the document and connects the <SamplerNode> to the new <Texture> node.
Note that the box in the middle of the worksheet may change color. It may become black. This is because we've provided only a single texture and the shader requires two textures.
You can see the new <Texture> node named IPF_8888_ARGB.