Create Image Processing Shader For Raspberry Pi 3B+

You need the following Scenome® modules to complete all exercises involving the Raspberry Pi 3B+: Scenome® Platform Binaries, Scenome® Export Module

This exercise teaches you how to create a new Scenome Shader document, implement a GLSL shader module that performs image convolution, and then visualize the results with a fragment shader. The GPU on your Windows® development machine must support GLSL #version 120 in order to complete this exercise. This section assumes that you know how to access a folder on your Raspberry Pi® 3B+ device, and that you have terminal access to the device.

Start The Shader Application

  1. Start the Shader app. (Start » Programs » Scenomics » Shader) or (Windows® key and then type 'Shader' to find the app icon.)

    The application displays a splash screen and then the application desktop appears. The main menu is composed of three items: File, Desktop, and Help. These options provide access to commands relevant to the current context (which is an empty file). The application desktop changes when you create a new file or load a file from disk.

    This is a picture of the desktop.

Create A New Document

  1. Select File » New » Shader from the main menu.

    The software displays a wizard that allows you to specify the parameters of your new shader.

    This is a picture of the new project dialog.
  2. Type Pi3 Image Processing in the field named Name.

    Copy Text To Clipboard

    Pi3 Image Processing

    When the document is saved, the file name will be Pi3 Image Processing.box.

  3. Select 120 in the field named Profile.
  4. Hit ENTER or click OK when you are finished.

    The application creates a new shader document and the main menu options change. In the main application window you can see the hierarchy on the left, the rendered shader with geometry in the middle, and the property sheet on the right.

    This is a picture of the workspace.

    If the shader compiled successfully, you should see a red square in the center of the worksheet.

  5. Select File » Save from the main menu.

    For future reference, the location where this file is saved can be obtained using File » Open Containing Folder, when nothing is selected.

Test Export Functionality

  1. Select File » Export » Raspberry Pi® 3B+ from the main menu.

    The software displays a wizard that allows you to specify export parameters. We'll use the defaults.

    This is a picture of the Raspberry Pi® 3B+ export dialog.
  2. Click OK or hit ENTER to export the document.

    The software exports the document and opens a folder to the location of the exported code.

    This is a picture of the folder containing the exported document.

    The exported document is composed of a few different types of files. We'll discuss one file of each type below.

    File Description
    Application.hA C++ source code file containing a class declaration.
    Application.cppA C++ source code file containing a class definition/implementation.
    MakefileA file containing instructions on how to build the application.
    main.cppThe application source code where the main function is defined.
    Pi3 Image Processing.spa_binary_graphA simplified binary version of the document you made in the Shader application. There is only one of these for each document you export.
    Program-E7274A5C-F421-4C62-9E3F-8E9F58E3E419.spa_binary_nodeA simplified binary version of the <Program> node in the document. Other files ending in .spa_binary_node represent other document nodes.

    Note that each exported document will contain different .h, .cpp, and .spa_binary_node files depending on what's inside the document you export.

  3. Open a Windows® folder to your Raspberry Pi® 3B+ device. This is a picture of a folder on a Raspberry Pi device.
  4. Enter the folder named Home. This is a picture of a folder on a Raspberry Pi device.
  5. Right click on some whitespace and select New » Folder from the listed options.

    This creates a new folder and allows you to set the name of folder.

  6. Set the name of the folder to Pi3-Image-Processing and hit ENTER.
  7. Go inside the new folder. This is a picture of a new, empty folder on a Raspberry Pi device.
  8. Return to the export folder on your Windows® PC. This is a picture of the folder containing the exported document.
  9. Select CTRL + A to select all the files.
  10. Select CTRL + C to copy all the files.
  11. Return to the folder named Pi3-Image-Processing on your Raspberry Pi® 3B+ device.
  12. Select CTRL + V to paste all the files. This is a picture of the folder containing the exported document.

    The files are now copied to your device.

  13. Open a terminal to the root of your Raspberry Pi® 3B+ device. This is a picture of the Raspberry Pi® 3B+ terminal.
  14. Type cd Pi3-Image-Processing to enter the new directory.

    Copy Text To Clipboard

    cd Pi3-Image-Processing
  15. Type make to start the build.

    Copy Text To Clipboard

    make

    The GCC compiler on your device starts to compile the application:

    This is a picture of the Raspberry Pi® 3B+ terminal.

    You receive control of the terminal again when the build is complete.

    This is a picture of the Raspberry Pi® 3B+ terminal.

    Please contact support@scenomics.com if you encounter any compiler or linker errors. In either case, it's likely that you haven't updated existing OpenGL packages on your device.

  16. Type ./Run.sh to start the application.

    Copy Text To Clipboard

    ./Run.sh

    On your Raspberry Pi® 3B+ desktop, you'll see a window that is completely filled with red.

    This is a picture of the Raspberry Pi® desktop.
  17. Return to your terminal and hit CTRL + C to stop the application.

    Now you've exported, compiled, and executed a complete application. Let's create something a little more interesting.

  18. Close the terminal that is open to your Raspberry Pi® 3B+.
  19. Close the folder that is open to your Raspberry Pi® 3B+.
  20. Close the folder that is open to your exported document.
  21. Return to the Shader application.

Examine The New Document

  1. Examine the main menu and select Desktop » Clear Output. ( Or hit ALT + D + C ).
  2. Examine the main menu and select Graph » State » Expand All Tree Items. ( Or hit ALT + X ).

    This expands the graph so that you can see all the nodes.

    NOTE: You can hover over each node icon, in the image below, for a description of the node and its function.

    That covers the basic information about the graph.

Examine The <Program>

  1. In the running Shader app, move the cursor over the <Program> node named Program.

    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. We can see that the shader uses GLSL #version 120 as we requested when we created the document.

    This is a picture of the Program node info tip.

Copy Fragment Shader Path

  1. Return to the running Shader application and examine the hierarchy.
  2. Right click over the <Program> node named Program and select Copy Source Path » Fragment Shader from the listed options. This is a picture of the hierarchy.

    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. Select pi3_image_processing_fragment_shader.glsl and click OK

    This is a picture of the source code used by the <Program> node fragment shader.

Modify Fragment Shader

  1. Start text editor such as Notepad++ or Microsoft Visual Studio and choose the File » Open command.
  2. Hit CTRL + V to paste the file path into the file path text field and open the file.

    The file pi3_image_processing_fragment_shader.glsl opens. Your fragment shader looks like this.

    // #version 120
    // The version number is automatically injected by the application.
    // It is included above for reference purposes only.
    #include <SPA_Version.glsl>
    
    varying vec4 fs_position;
    varying vec2 fs_texcoord;
    varying vec3 fs_normal;
    varying vec4 fs_color;
    varying vec3 fs_normalViewspace;
    varying vec3 fs_positionViewspace;
    
    void main(void)
    {
       gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
    }
  3. Replace the contents of the fragment shader with the following shader code:

    Copy Text To Clipboard

    // #version 120
    // The version number is automatically injected by the application.
    // It is included above for reference purposes only.
    #include <SPA_Version.glsl>
    
    varying vec4 fs_position;
    varying vec2 fs_texcoord;
    varying vec3 fs_normal;
    varying vec4 fs_color;
    varying vec3 fs_normalViewspace;
    varying vec3 fs_positionViewspace;
    
    uniform mat3 convolution_kernel;
    uniform int grayscale_enabled;
    uniform float convolution_strength;
    uniform float step_w;
    uniform float step_h;
    
    const int KERNEL_SIZE = int( 9 );
    float kernel[KERNEL_SIZE];
    vec2 offset[KERNEL_SIZE];
    
    uniform sampler2D src_data;
    
    void main(void)
    {
       vec4 convolution;
       vec4 temp;
       float sum = 1.0;
    
       offset[0] = vec2( -step_w, -step_h );    offset[3] = vec2( -step_w, 0.0 );     offset[6] = vec2( -step_w, step_h );
       offset[1] = vec2( 0.0, -step_h );        offset[4] = vec2( 0.0, 0.0 );         offset[7] = vec2( 0.0, step_h );
       offset[2] = vec2( step_w, -step_h );     offset[5] = vec2( step_w, 0.0 );      offset[8] = vec2( step_w, step_h );
    
       kernel[0] = convolution_kernel[0][0] * convolution_strength;
       kernel[1] = convolution_kernel[0][1] * convolution_strength;
       kernel[2] = convolution_kernel[0][2] * convolution_strength;
       kernel[3] = convolution_kernel[1][0] * convolution_strength;
       kernel[4] = convolution_kernel[1][1] * convolution_strength;
       kernel[5] = convolution_kernel[1][2] * convolution_strength;
       kernel[6] = convolution_kernel[2][0] * convolution_strength;
       kernel[7] = convolution_kernel[2][1] * convolution_strength;
       kernel[8] = convolution_kernel[2][2] * convolution_strength;
    
       if( fs_texcoord.s < 0.5 )
       {
          for( int i = 0; i < KERNEL_SIZE; i++ )
          {
             temp = texture2D( src_data, fs_texcoord.st + offset[i] );
    
             // If the grayscale flag is enabled, calculate the filter
             // based on the intensity of the pixels rather than the color value.
             // Otherwise process the rgb channels.
             if( grayscale_enabled > 0 )
             {
                float intensity = ( ( 0.299 * temp.r ) + ( 0.587 * temp.g ) + ( 0.114 * temp.b ) );
                convolution += vec4( intensity ) * kernel[i];
             }
             else
             {
                convolution += temp * kernel[i];
             }
    
             sum += kernel[i];
          }
    
          sum = max( sum, 1.0 );
          convolution = clamp( convolution / sum, vec4( 0.0 ), vec4( 1.0 ) );
       }
       else
       if( fs_texcoord.s > 0.502 )
       {
          convolution = texture2D( src_data, fs_texcoord.xy );
       }
       else
       {
          convolution = vec4( 1.0, 0.0, 0.0, 1.0 );
       }
    
       gl_FragColor = convolution;
    }
  4. Save the shader source code in the text editor.

    Now we need to rebuild the document.

Rebuild The Document

  1. Return to the running Shader application.

    Your shader 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 any values for any textures or uniforms. We're going to rebuild the document, which will add the uniforms we declared to the document so we can set their values.

  2. Select Graph » Build All from the main menu.

    The application rebuilds the document and displays build information in the output window.

    --- <Building Project 'D:\Release6\Content\Library\Shader\Pi3 Image Processing\Pi3 Image Processing.box'> ---
    
    Rebuilding Shader Resource Documents...
    
    Rebuild succeeded: D:\users\dorbanhakatan\library\shader\pi3 image processing\120\pi3_image_processing_vertex_shader.glsl
    Rebuild succeeded: D:\users\dorbanhakatan\library\shader\pi3 image processing\120\pi3_image_processing_fragment_shader.glsl
    
    Updating document contents...
    
    Adding to <UniformPaletteNode> 'Uniforms' <Float32MatrixNode> 'uniform mat3x3 convolution_kernel'
    Adding to <UniformPaletteNode> 'Uniforms' <Int32Node> 'uniform int grayscale_enabled'
    Adding to <UniformPaletteNode> 'Uniforms' <Float32Node> 'uniform float convolution_strength'
    Adding to <UniformPaletteNode> 'Uniforms' <Float32Node> 'uniform float step_w'
    Adding to <UniformPaletteNode> 'Uniforms' <Float32Node> 'uniform float step_h'
    Adding to <SamplerPaletteNode> 'Samplers' <SamplerNode> 'uniform sampler2D src_data'
    
    Build completed.
    

Examine The Document

  1. Select Graph » State » Expand All Tree Items from the main menu.

    The graph looks like this. There are new uniforms that match the declarations in the shader source code. In the image below, the new nodes are highlighted red for illustrative purposes (but they aren't highlighted in your document).

    This is a picture of the graph.
  2. Select File » Save from the main menu.

Load Texture From Disk

  1. Examine the hierarchy and right click over the new <SamplerNode> named uniform sampler2D src_data.
  2. Select Load Texture From Disk... from the menu.

    The software displays a dialog that allows you to select a texture from the hard disk.

  3. Find the folder named IPF_8888_ARGB and enter it.

    Copy Text To Clipboard

    IPF_8888_ARGB
  4. Type california_central_valley.png and click Open or hit ENTER when you are finished.

    Copy Text To Clipboard

    california_central_valley.png
  5. Select Graph » State » Expand All Tree Items from the main menu.

    The graph looks like this. A new <Texture> has been added to the document.

    This is a picture of the graph.

    Next we'll build some local declarations.

Create 'image_width' Declaration

  1. Examine the hierarchy and find the <DataPaletteNode> named Locals.

    It's near the top of the document.

  2. Right click over the <DataPaletteNode> named Locals and select Add Local Variable... from the listed options.

    The software displays a list of objects that can be created.

    This is a picture of a dialog.
  3. Type Int32Node and click OK or hit ENTER when you are finished.

    Copy Text To Clipboard

    Int32Node

    The software displays a dialog that lets you specify the name for the new variable.

    This is a picture of a dialog.
  4. Type image_width and click OK or hit ENTER when you are finished.

    Copy Text To Clipboard

    image_width

    The software adds a new <Int32Node> named image_width to the document.

  5. Examine the main menu and select Graph » State » Expand All Tree Items. ( Or hit ALT + X ). This is a picture of the hierarchy.

Add <DataCapture>: int image_width

  1. Examine the hierarchy and right click over the new <Int32Node> named int image_width.
  2. Select Add Single Data Capture... from the menu.

    This displays a dialog that allows you to create objects that capture data from nodes in the document. Notice that the last two options are grayed out. You have to select a <DataCapture> type before you can edit anything else.

    This is a picture of the data capture dialog.
  3. Select TextureDataCaptureWidth from the <DataCapture> Type drop down list.

    Examine the dialog. It looks like the third option has been chosen. This isn't the case. This is just the first option in the list.

    This is a picture of the data capture dialog.
  4. Select uniform sampler2D src_data from the <DataCapture> Target Node dropdown.
  5. Click OK or hit ENTER when you are finished.

    The software adds the <DataCapture> objects to the <Int32Node>. Now the value of the <Int32Node> will be set to the width of any <Texture> node connected to the <SamplerNode>.

  6. Move the mouse over the <Int32Node> named int image_width.

    You'll notice its value is 512. This means the <Texture> source is 512 pixels wide.

    This is a picture of the Int32Node tooltip.

    If your value does not match, right click on the <Int32Node> named int image_width and select Clear Data Capture from the listed options. The start this section over.

  7. Select File » Save from the main menu.

Create 'image_height' Declaration

  1. Examine the hierarchy and find the <DataPaletteNode> named Locals.

    It's near the top of the document.

  2. Right click over the <DataPaletteNode> named Locals and select Add Local Variable... from the listed options.

    The software displays a list of objects that can be created.

    This is a picture of a dialog.
  3. Type Int32Node and click OK or hit ENTER when you are finished.

    Copy Text To Clipboard

    Int32Node

    The software displays a dialog that lets you specify the name for the new variable.

    This is a picture of a dialog.
  4. Type image_height and click OK or hit ENTER when you are finished.

    Copy Text To Clipboard

    image_height

    The software adds a new <Int32Node> named image_height to the document.

  5. This is a picture of the hierarchy.

Add <DataCapture>: int image_height

  1. Examine the hierarchy and right click over the new <Int32Node> named int image_height.
  2. Select Add Single Data Capture... from the menu.

    This displays a dialog that allows you to create objects that capture data from nodes in the document. Notice that the last two options are grayed out. You have to select a <DataCapture> type before you can edit anything else.

    This is a picture of the data capture dialog.
  3. Select TextureDataCaptureHeight from the <DataCapture> Type drop down list. This is a picture of the data capture dialog.

    Examine the dialog. It looks like the third option has been chosen. This isn't the case. This is just the first option in the list.

  4. Select uniform sampler2D src_data from the <DataCapture> Target Node dropdown.
  5. Click OK or hit ENTER when you are finished.

    The software adds the <DataCapture> objects to the <Int32Node>. Now the value of the <Int32Node> will be set to the height of any <Texture> node connected to the <SamplerNode>.

  6. Move the mouse over the <Int32Node> named int image_height.

    You'll notice its value is 512. This means the <Texture> source is 512 pixels high.

    This is a picture of the Int32Node tooltip.

    If your value does not match, right click on the <Int32Node> named int image_height and select Clear Data Capture from the listed options. The start this section over.

  7. Select File » Save from the main menu.

Create 'reciprocal_numerator' Declaration

  1. Examine the hierarchy and find the <DataPaletteNode> named Locals.

    It's near the top of the document.

  2. Right click over the <DataPaletteNode> named Locals and select Add Local Variable... from the listed options.

    The software displays a list of objects that can be created.

    This is a picture of a dialog.
  3. Type Float32Node and click OK or hit ENTER when you are finished.

    Copy Text To Clipboard

    Float32Node

    The software displays a dialog that lets you specify the name for the new variable.

    This is a picture of a dialog.
  4. Type reciprocal_numerator and click OK or hit ENTER when you are finished.

    Copy Text To Clipboard

    reciprocal_numerator

    The software adds a new <Float32Node> named reciprocal_numerator to the document.

  5. This is a picture of the hierarchy.
  6. Examine the hierarchy and right click over the new <Float32Node> named float reciprocal_numerator.
  7. Select Edit... from the menu.

    This displays a dialog that allows you to edit the value.

    This is a picture of a dialog.
  8. Set Fill Value to 1.0 and click OK or hit ENTER when you are finished.
  9. Move the mouse over the <Float32Node> named float reciprocal_numerator.

    You'll notice its value is 1.0.

    This is a picture of the Float32Node tooltip.
  10. Select File » Save from the main menu.

Set Uniform: uniform mat3x3 convolution_kernel

  1. Examine the hierarchy and right click over the new <Float32MatrixNode> named uniform mat3x3 convolution_kernel.
  2. Select Lambdas... from the menu. (It's near the bottom.)

    The software displays a menu that allows you to select various lambdas for the node.

    This is a picture of the select lambda dialog.
  3. Select SetEmbossFilter from the listed options and click OK or hit ENTER when you are finished.
  4. Move the mouse over the <Float32MatrixNode> named uniform mat3x3 convolution_kernel and you can see the matrix values are no longer all zeros.

    This is a picture of the Float32MatrixNode tooltip.

    Repeat this step if your values do not match the values shown above.

Set Uniform: uniform int grayscale_enabled

  1. Examine the hierarchy and right click over the new <Int32Node> named uniform int grayscale_enabled.
  2. Select Toggle Value 0-1. from the menu.

    This sets the value to 1.

    This is a picture of the Int32Node tooltip.

    Repeat this step if your value does not match the value shown above.

Set Uniform: uniform float convolution_strength

  1. Examine the hierarchy and right click over the new <Float32Node> named uniform float convolution_strength.
  2. Select Edit... from the menu.

    This displays a dialog that allows you to edit the value.

  3. Set Fill Value to 1.0 and click OK or hit ENTER when you are finished. This is a picture of the Float32Node tooltip.

    Repeat this step if your value does not match the value shown above.

Add <DataCapture>: uniform float step_w

  1. Examine the hierarchy and right click over the new <Float32Node> named uniform float step_w.
  2. Select Add Packed Data Capture... from the menu. Note that this time you're selecting Packed not Single.

    This displays a dialog that allows you to create objects that capture data from nodes in the document.

    This is a picture of the data capture dialog.
  3. Select Float32DataCaptureDivision from the <DataCapture> Type drop down list. This is a picture of the data capture dialog.
  4. Select the first Float32DataCaptureScalar from the <DataCapture> Sub-Element Type dropdown.

    This is a picture of the data capture dialog.
  5. Select float reciprocal_numerator from the <DataCapture> Target Node dropdown. This is a picture of the data capture dialog.
  6. Select the second Float32DataCaptureScalar from the <DataCapture> Sub-Element Type dropdown. This is a picture of the data capture dialog.
  7. Select int image_width from the <DataCapture> Target Node dropdown. This is a picture of the data capture dialog.
  8. Click OK or hit ENTER when you are finished.

    This adds a small <DataCapture> hierarchy to the <Float32Node>. The left side of the division points at float reciprocal_numerator and the right side of the division points at int image_width. This produces the expression:

    float reciprocal_numerator / int image_width
    1.0 / 512

    It's important not to do this division in the shader.

  9. Move the mouse over the <Float32Node> named uniform float step_w.

    You'll notice its value is 0.001953. This is the result of 1.0 / 512.0.

    This is a picture of the Float32Node tooltip.

    If your value does not match, right click on the <Float32Node> named uniform float step_w and select Clear Data Capture from the listed options. The start this section over.

  10. Select File » Save from the main menu.

Add <DataCapture>: uniform float step_h

  1. Examine the hierarchy and right click over the new <Float32Node> named uniform float step_h.
  2. Select Add Packed Data Capture... from the menu. Note that this time you're selecting Packed not Single.

    This displays a dialog that allows you to create objects that capture data from nodes in the document.

    This is a picture of the data capture dialog.
  3. Select Float32DataCaptureDivision from the <DataCapture> Type drop down list. This is a picture of the data capture dialog.
  4. Select the first Float32DataCaptureScalar from the <DataCapture> Sub-Element Type dropdown.

    This is a picture of the data capture dialog.
  5. Select float reciprocal_numerator from the <DataCapture> Target Node dropdown. This is a picture of the data capture dialog.
  6. Select the second Float32DataCaptureScalar from the <DataCapture> Sub-Element Type dropdown. This is a picture of the data capture dialog.
  7. Select int image_height from the <DataCapture> Target Node dropdown. This is a picture of the data capture dialog.
  8. Click OK or hit ENTER when you are finished.

    This adds a small <DataCapture> hierarchy to the <Float32Node>. The left side of the division points at float reciprocal_numerator and the right side of the division points at int image_width. This produces the expression:

    float reciprocal_numerator / int image_width
    1.0 / 512

    It's important not to do this division in the shader.

  9. Move the mouse over the <Float32Node> named uniform float step_w.

    You'll notice its value is 0.001953. This is the result of 1.0 / 512.0.

    This is a picture of the Float32Node tooltip.

    If your value does not match, right click on the <Float32Node> named uniform float step_h and select Clear Data Capture from the listed options. The start this section over.

  10. Select File » Save from the main menu.

View Results

  1. Select Desktop » Toggle Panels from the main menu.

    This hides the docking panels.

  2. Examine the worksheet. This is a picture of the worksheet.

    This result looks good!

  3. Select Desktop » Toggle Panels from the main menu.

    This shows the docking panels.

Export To Raspberry® Pi 3B+

  1. Select File » Export » Raspberry Pi 3B+ from the main menu.

    This displays an export dialog:

    This is a picture of the worksheet.

    For now we'll use the default options.

  2. Click OK or hit ENTER to export the document.

    The application displays a dialog that asks you to confirm file overwriting.

    This is a picture of the worksheet.

    We did a test export at the start of this exercise. This means there are already files in the export folder. The application will ask you if you wish to delete these files.

  3. Click YES.

    The software exports the document and opens a folder to the location of the files.

    This is a picture of a Windows folder.
  4. Open a Windows® folder to your Raspberry Pi® 3B+ device. This is a picture of a folder on a Raspberry Pi device.
  5. Enter the folder named Home. This is a picture of a folder on a Raspberry Pi device.
  6. Enter the folder name Pi3-Image-Processing.
  7. Go inside the new folder. This is a picture of a new, empty folder on a Raspberry Pi device.
  8. Return to the export folder on your Windows® PC. This is a picture of the folder containing the exported document.
  9. Select CTRL + A to select all the files.
  10. Select CTRL + C to copy all the files.
  11. Return to the folder named Pi3-Image-Processing on your Raspberry Pi® 3B+ device.
  12. Select CTRL + V to paste all the files. This is a picture of the folder containing the exported document.

    The files are now copied to your device.

  13. Open a terminal to the root of your Raspberry Pi® 3B+ device. This is a picture of the Raspberry Pi® 3B+ terminal.
  14. Type cd Pi3-Image-Processing to enter the new directory.

    Copy Text To Clipboard

    cd Pi3-Image-Processing
  15. Type make to start the build.

    Copy Text To Clipboard

    make

    The GCC compiler on your device starts to compile the application:

    This is a picture of the Raspberry Pi® 3B+ terminal.

    You receive control of the terminal again when the build is complete.

    This is a picture of the Raspberry Pi® 3B+ terminal.

    Please contact support@scenomics.com if you encounter any compiler or linker errors. In either case, it's likely that you haven't updated existing OpenGL packages on your device.

  16. Type ./Run.sh to start the application.

    Copy Text To Clipboard

    ./Run.sh

    On your Raspberry Pi® 3B+ desktop, you'll see a window where the image processing shader is running.

    This is a picture of the Raspberry Pi® desktop.
  17. Return to your terminal and hit CTRL + C to stop the application.

    Now you've exported, compiled, and executed a complete application. This is the process by which you can make shaders for your Raspberry Pi® 3B +.