Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

Create a Noise Image with GLSL Shader

4.55/5 (11 votes)
6 Jul 2010CPOL2 min read 51K   2.3K  
A simple shader program to create noise effect in an image

NoiseImage/screenshot.jpg

Screenshot of the Noise application

Introduction

This is a simple pixel shader program which changes the input texture coordinate with a noise value and creates a noisy output image.

Background 

Creating any effect in an image is very simple with a pixel shader. This article demonstrates a simple noise effect in an image.  

Using the Code  

A fragment program will be executed for all pixels of a rendering. When rendering an entire texture fragment, the shader will get the corresponding texture coordinates for each pixel of rendering.

If texture lookup is performed with the provided texture coordinates for display, the rendered image will be the same as the input image.

An example shader displaying a texture image same as the input image:

C++
uniform sampler2D ImageTexture;
// Shader for displaying a texture.
void main()
{
    // Lookup image texture with noise texture coordiante.
    gl_FragColor = texture2D(ImageTexture, gl_TexCoord[0].st );
}

gl_TexCoord[0].st holds the texture coordinate which can be used to get texel (a pixel from texture). After getting the texel from ImageTexture, set that color as output color, and we will get the display of ImageTexture in screen.

What will happen if we change the texture coordinate used for texture lookup?

The display of ImageTexture will be slightly changed.

Given below is an example shader displaying texture image with some changes in display of imageTexture

C++
uniform sampler2D ImageTexture;

// Shader for displaying a texture with some change in texture display.
void main()
{    
     // Lookup image texture with small change in texture coordinate.
          // cos( gl_TexCoord[0].s) is added to texture coordinate.
    gl_FragColor = texture2D(ImageTexture, gl_TexCoord[0].st + 
    vec2(0.0, cos( gl_TexCoord[0].s)));
}

This shader can create a change in display of the image, but that’s not good for creating a noisy image. In order to create a noisy output, we need to randomly change the lookup position. That’s why I created a NoiseTexture which contains random offsets that can be used to change the lookup coordinates of ImageTexture. The size of NoiseTexture is the same as that of ImageTexture to avoid repetition of the Noise offset for nearest pixels.

CreateNoise() creates random offsets for filling NoiseTexture.

C++
// This function create a Noise texture of m_nImageWidth and m_nImageHeight.
bool CNoiseDlg::CreateNoise()
{
    srand(time(NULL));
    if( 0 == m_pnRandomIndexes )
    {
        int maxRandom = max( m_nImageWidth, m_nImageHeight );
        m_pnRandomIndexes = new int[maxRandom];
        for (int nIndex = 0; nIndex < maxRandom; nIndex++)
        {
            m_pnRandomIndexes[nIndex] = max( (int)rand() % 256, (int)1.0);
        }
    }
    FillGrad(1);

    BYTE* pbyData = new BYTE[m_nImageWidth * m_nImageHeight *3];
    float NoiseHeight = m_NoiseValue / 100.0 * 25.0;

    // Creating Noise data of of m_nImageWidth and m_nImageHeight.
    for(int i = 0; i<m_nImageHeight; i++)
        for(int j = 0; j<m_nImageWidth; j++)
        {
            int offset = (i*m_nImageWidth+j)*3;
            char value = m_pnRandomIndexes[(j+m_pnRandomIndexes[i]) & 0xFF];
            pbyData[offset] = m_nRandomValues[value & 0x1F][0] * 
        NoiseHeight + min( NoiseHeight, m_NoiseValue );   // Gradient x
            pbyData[offset+1] = m_nRandomValues[value & 0x1F][1] * 
        NoiseHeight + min( NoiseHeight, m_NoiseValue ); // Gradient y
            pbyData[offset+2] = m_nRandomValues[value & 0x1F][2] * 
        NoiseHeight + min( NoiseHeight, m_NoiseValue ); // Gradient z
        }

        // Create texture with m_nImageWidth and m_nImageHeight.
        if( !m_NoiseTexture.Create( m_nImageWidth, m_nImageHeight, pbyData ))
        {
            AfxMessageBox( L"Texture loading failed" );
            return FALSE;
        }
        delete[] pbyData;
        return true;
}

For each pixel, offset values are retrieved from NoiseTexture, and we apply this offset to the original texture coordinate. This new texture coordinate is used for the lookup of ImageTexture and to get a Noisy output of ImageTexture.

Shader for Creating a Noisy Image

C++
uniform sampler2D ImageTexture;
uniform sampler2D NoiseTexture;

// Shader for creating a noise in ImageTexture.
void main()
{
    // Get NoiseValue from Noisetexture.
    vec4 Noise = texture2D(NoiseTexture, gl_TexCoord[0].st );
    vec2 fLookupCoord = 
    gl_TexCoord[0].st + vec2( Noise.r * 0.065,-Noise.g * 0.025 );
    gl_FragColor = texture2D(ImageTexture,fLookupCoord );
}

Points of Interest

In my previous shader program, the release version creates an error while reading the pixel shader from the resource. When I used strlen() to find the length of the resource data, some unexpected data is appended at the end of the resource. Therefore compilation of the shader program fails. I used SizeOfResource() for finding the length of the Resource data, and fixed that issue.

C++
bool GLSLShader::CreateProgram( const int nProgramID_i, GLenum glSlShaderType_i )
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    HRSRC hrResInfo = FindResource( 0, 
    MAKEINTRESOURCE( nProgramID_i ),TEXT("IDR_DATA"));
    if( 0 == hrResInfo )
    {
        return false;
    }
    HGLOBAL hRcResource =  LoadResource(0, hrResInfo );
    const CHAR* pBufferResData = (CHAR* )LockResource( hRcResource );
    // Get Length of shader program. When I used strlen() to get length of string,
    // I got some unexpected data at the end of progrm
    int nLENGTH = SizeofResource( 0, hrResInfo );

    // Shder creation code 
    // .. ... ....
}

History  

  • 4 July, 2010: Initial version.
  • 5 July, 2010: Updated binary, since previous binary had dependency with the Visual Studio 2008 Runtime.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)