Results 1 to 7 of 7

Thread: How to Blend Points to Make a 2D Heat Map

  1. #1
    Newbie Newbie
    Join Date
    Apr 2017
    Posts
    4

    How to Blend Points to Make a 2D Heat Map

    Hi,

    I am trying to make a monochrome heat map which would look something like this

    (LINK: heatmap6.png)

    I am struggling to tackle this problem though, in particular is it (realistically) possible in openGL to blend
    points to get the kind of style shown in the picture? If not how would you approach this challenge?

    Thanks!

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Oct 2004
    Posts
    4,655
    Sure. You can encode your heat map function in a shader and compute the values explicitly, or if you don't have an explicit function but just a set of points that sample the heat map curve, you can encode these into a 1D or 2D texture and let the GPU's texture filtering interpolate neighboring values for you.

  3. #3
    Newbie Newbie
    Join Date
    Apr 2017
    Posts
    4
    Hi Dark Photon,

    Thank you very much for your reply. Happy to know that it is feasible,

    Quote Originally Posted by Dark Photon View Post
    You can encode your heat map function in a shader and compute the values explicitly,.
    If possible could you elaborate a little, I am still fairly new to openGL. Would that involve drawing many very small triangles instead of points so that the shader automatically interpolates the colour similar to the standard "Hello Triangle" tutorials?

    Quote Originally Posted by Dark Photon View Post
    or if you don't have an explicit function but just a set of points that sample the heat map curve, you can encode these into a 1D or 2D texture and let the GPU's texture filtering interpolate neighboring values for you.
    Thanks for the idea, I found this example on open.gl. I think that you mean to setup the texture something like this?
    Code :
     
    // Black/white checkerboard
    float pixels[] = {
        0.0f, 0.0f, 0.0f,   1.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f,   0.0f, 0.0f, 0.0f
    };
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels);
    I will give it a try now

  4. #4
    Senior Member OpenGL Guru
    Join Date
    Oct 2004
    Posts
    4,655
    Quote Originally Posted by sausage View Post
    You can encode your heat map function in a shader and compute the values explicitly, ...
    If possible could you elaborate a little, I am still fairly new to openGL. Would that involve drawing many very small triangles instead of points so that the shader automatically interpolates the colour similar to the standard "Hello Triangle" tutorials?
    What I meant by this first part is if you have an analytic expression for your heat map (e.g. intensity = (value - 1000 ) / 3000, or something considerably more complex), you could just compute this expression in a fragment shader and then use the result it produces directly.

    The main alternative to this is pre-sampling this function (perhaps it's a piecewise linear curve for instance), storing that in the texture, and then doing a texture lookup in your fragment shader to compute the value of this function as opposed to computing it analytically. For this latter case, you'll probably need a little bit of prep work on the domain value to get it to a 0..1 texture coordinate so that you can sample from the texture.

  5. #5
    Newbie Newbie
    Join Date
    Apr 2017
    Posts
    4
    Quote Originally Posted by Dark Photon View Post
    Sure. You can encode your heat map function in a shader and compute the values explicitly, or if you don't have an explicit function but just a set of points that sample the heat map curve, you can encode these into a 1D or 2D texture and let the GPU's texture filtering interpolate neighboring values for you.
    Thank you very much, using your hint about textures I found a helpful tutorial on open.gl. However I can't get textures to work when I am defining them in an array. The code is not too complex are you able to spot what is wrong? I have tried to cut down the code to the essentials. There is no glGetError() and the shader does not return an error on compiling or linking. If I change the fragment shader to return a solid colour instead of a texture then that will work.


    Code :
    //Vertex Data with rectangle co-oordinates and texture co-ordinates
    GLfloat screen2DVertices[] = 
    {	//x, y, z			//u, v
    		-0.8, -0.8, 0,			0, 0,					// bottom left corner
    		-0.8,  0.8, 0,			0, 1,						// top left corner
    		0.8,  0.8, 0,			1, 1,					// top right corner
    		0.8, -0.8, 0,			1, 0,					 // bottom right corner
    };
     
    GLushort screen2DIndices[] = 
    { 
    		0,1,2, // first triangle (bottom left - top left - top right)
    		0,2,3  // second triangle (bottom left - top right - bottom right)
    }; 
     
    //Texture width in pixels
    const int TEXTURE_WIDTH = 20;
    const int TEXTURE_HEIGHT = 20;
     
    //3 RGB values per pixel
    float texturePixels[TEXTURE_WIDTH * TEXTURE_HEIGHT * 3];
     
    //Test with all white r = g = b = 1.0f
    for (int i = 0; i < TEXTURE_WIDTH * TEXTURE_HEIGHT * 3; i++)
    {
    	texturePixels[i] = 1.0f;
    }
     
     
    //Vertex array object
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
     
    //Vertex buffer object
    GLuint vbo;
    glGenBuffers(1, &vbo);
     
    // Create an element array
    GLuint ebo;
    glGenBuffers(1, &ebo);
     
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(screen2DVertices), screen2DVertices, GL_STATIC_DRAW);
     
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(screen2DIndices), screen2DIndices, GL_STATIC_DRAW);
     
     
     
    // Load texture
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
     
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGB, GL_FLOAT, texturePixels);
     
     
    // Specify the layout of the vertex data
    GLint posAttrib = glGetAttribLocation(screenShader.Program, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
     
    GLint texAttrib = glGetAttribLocation(screenShader.Program, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
     
    while (!glfwWindowShouldClose(window))
    {
    	glfwPollEvents();
     
    	glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    	glClear(GL_COLOR_BUFFER_BIT);
     
    	screenShader.Use();
    	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)0);
     
    	glfwSwapBuffers(window);
    }
     
     
    //---------------------------Vertex Shader------------------------------------------
    #version 330 core
     
    in vec3 position;
    in vec2 texcoord;
     
    out vec2 Texcoord;
     
    void main()
    {
    	Texcoord = texcoord;
    	gl_Position = vec4(position, 1.0);
    }
     
    //---------------------------Fragment Shader------------------------------------------
    #version 330 core
     
    in vec2 Texcoord;
    out vec4 outColour;
    uniform sampler2D tex;
     
    void main()
    {
    	outColour = texture(tex, Texcoord) * vec4(1.0f);
    }

  6. #6
    Newbie Newbie
    Join Date
    Apr 2017
    Posts
    4
    Thank you for your reply. Thanks to your hint I was able to get an idea of how to proceed, however I am struggling to get textures working. I know the shader is compiling and linking properly, if I switch the output colour in the fragment shader to just return a solid vec4 colour it works with so I know it must be the texture causing the problem . Any ideas on what I am doing wrong?

    Code cpp:
    //Texture width in pixels
    const int TEXTURE_WIDTH = 20;
    const int TEXTURE_HEIGHT = 20;
     
    //3 RGB values per pixel
    float texturePixels[TEXTURE_WIDTH * TEXTURE_HEIGHT * 3];
     
    //Test with all white r = g = b = 1.0f
    for (int i = 0; i < TEXTURE_WIDTH * TEXTURE_HEIGHT * 3; i++)
    {
        texturePixels[i] = 1.0f;
    }
     
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
     
    // Load texture
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
     
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGB, GL_FLOAT, texturePixels);
     
     
    GLuint vbo;
    glGenBuffers(1, &vbo);
     
    // Create an element array
    GLuint ebo;
    glGenBuffers(1, &ebo);
     
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(screen2DVertices), screen2DVertices, GL_STATIC_DRAW);
     
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(screen2DIndices), screen2DIndices, GL_STATIC_DRAW);
     
     
    // Specify the layout of the vertex data
    GLint posAttrib = glGetAttribLocation(screenShader.Program, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
     
    GLint texAttrib = glGetAttribLocation(screenShader.Program, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
     
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
     
        glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
     
        screenShader.Use();
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)0);
     
        glfwSwapBuffers(window);
    }

    Vertex Shader
    Code glsl:
    #version 330 core
     
    in vec3 position;
    in vec2 texcoord;
     
    out vec2 Texcoord;
     
    void main()
    {
        Texcoord = texcoord;
        gl_Position = vec4(position, 1.0);
    }

    Fragment Shader:
    Code glsl:
    #version 330 core
     
    in vec2 Texcoord;
    out vec4 outColour;
    uniform sampler2D tex;
     
    void main()
    {
        outColour = texture(tex, Texcoord) * vec4(1.0f);
    }

  7. #7
    Senior Member OpenGL Guru
    Join Date
    Oct 2004
    Posts
    4,655
    Quote Originally Posted by sausage View Post
    I am struggling to get textures working.

    I know the shader is compiling and linking properly, if I switch the output colour in the fragment shader to just return a solid vec4 colour it works with so I know it must be the texture causing the problem .

    Any ideas on what I am doing wrong?
    Here are a few ideas:

    First, I don't see a glUniform1i call where you populate a value of 0 for the texture unit number on the "tex" sampler2D uniform.

    I also don't see a glBindFragDataLocation where you set 0 as color number for the "outColour" fragment output. That said, sounds like you're already getting color output from your fragment shader, so this isn't "the" tip you're looking for.

    Also:

    Code cpp:
    ...
    //3 RGB values per pixel
    float texturePixels[TEXTURE_WIDTH * TEXTURE_HEIGHT * 3];
     ...
    // Load texture
    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
     
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGB, GL_FLOAT, texturePixels);
    Here, you're providing RGB FLOAT values (0..1) as input to glTexImage2D. However, you're not requesting a specific internal format. You've only specified GL_RGB, which isn't a specific internal format, so the implementation is free to substitute whatever format it wants. It'd be better to be specific.

    My recommendation would be to use one of these combinations:

    1) internal format = GL_RGB8, format = GL_RGB, type = GL_UNSIGNED_BYTE, OR
    2) internal format = GL_RGB16F or GL_RGB32F, format = GL_RGB, type = GL_FLOAT.

    If you choose #1, then change your input data from an array of floats (0..1) to an array of unsigned chars (0..255).

    Also, since your texture doesn't have MIPmaps, change the GL_TEXTURE_MIN_FILTER to GL_LINEAR (as the default is GL_NEAREST_MIPMAP_LINEAR). The default GL_TEXTURE_MAG_FILTER is already GL_LINEAR.

    You may also want to set the GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T to GL_CLAMP_TO_EDGE, as the default is GL_REPEAT.

Similar Threads

  1. Heat Transfer
    By kemal in forum OpenGL: Basic Coding
    Replies: 2
    Last Post: 10-16-2011, 01:54 PM
  2. Heat effect
    By Hamid Reza in forum OpenGL: Advanced Coding
    Replies: 2
    Last Post: 09-09-2010, 03:12 PM
  3. Make the blend stage to become programmable?
    By imported_Groovounet in forum OpenGL: General
    Replies: 5
    Last Post: 01-07-2009, 07:46 AM
  4. heat effect
    By Alessandro_dup1 in forum OpenGL: Advanced Coding
    Replies: 3
    Last Post: 04-10-2003, 10:59 AM
  5. heat effect
    By Alessandro_dup1 in forum OpenGL: Advanced Coding
    Replies: 17
    Last Post: 03-04-2003, 01:55 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean