How does one interpolate opengl colors yourself?

I know that openGl will interpolate colors assuming the fragment shader is set correctly, between two vertices given two starting colors. It does this automatically.
But what if you want to do this yourself?
For example, I want all vertices at -0.5 to be colored as 0,0,0.8f (i.e. blue) and all vertices at 0.0 to be colored 0,0.8f,0 (i.e. green) and those at +0.5 to be colored 0.8f,0,0 (i.e. red). I know if I draw a line for example from <0,-0.5, 0> to <0,0,0> it will be color interpolated between blue and green with nice shades in between.
But, what if I have a line from <0,-0.5 , 0> to <0, -.25, 0>? The final color would have to be set to a color that is some mix of blue and green. Is there a way to do this?
I realize, that perhaps it can’t be done as smoothly as opengl, I may have to pick a range such as one color at< 0, -0.4,0> and then another at <0,-0.3,0> etc.
Is there a way?
Thanks, Tom

I did find a reference to interpolating colors. Seems you have to convert to HSL values, interpolate and then go back to RGB. I used an online calculator.
So since I need colors for about 200,000 verticies all of which can be different in real time I hard coded ranges of colors as follows:


    if (height < 0.1)
    {
        colorVertex.X = 0.0f;
        colorVertex.Y = 0.0f;
        colorVertex.Z = 0.08f;

        return colorVertex;
     }

     if (height < 0.2)
       etc.....

The problem is that for 200,000 vertices this takes about 18ms. Yikes! i can create a triangle strip with 200,000 vertices and 500,000 or so indices in under 3 ms.
There has to be a better way!
Any suggestions? Is there anything in a fragment shader that will assign colors based on the Y value?
Thanks

I am not really sure, but you might be interested in this. This is a more common way to render such kind of terrain-like meshes.

If you want to stay with your way, I would suggest you to find a function that will replace all your if and else conditions. Maybe something like:


color.z = height*0.8 + (height-0.2)*0.3 + ...;

[QUOTE=tomb18;1285404]I know that openGl will interpolate colors assuming the fragment shader is set correctly, between two vertices given two starting colors. It does this automatically.
[/QUOTE]
More precisely, any fragment shader input variables which aren’t (implicitly or explicitly) “flat”-qualified are obtained by interpolating the corresponding output variables from the vertex/geometry/tessellation shader.

If you want to perform your own interpolation, the most general) approach is to add a variable for barycentric coordinates.

Bear in mind that, by default, interpolation is performed in clip space (affine to eye space). If you want to interpolate in NDC (affine to screen space), you need to use the “noperspective” qualifier.

If you aren’t using a perspective projection (i.e. all vertices’ clip coordinates have the same value for the W component), there is no difference between interpolating in clip space and NDC.

Both interesting answers.
However, now I am not sure that this will be an issue…
When I initially did the timing tests I got an average of 18ms. However, now that all the code is in place, I find that the OnRender callback where I set vertices for 200,000 vertices and then color all of them takes only 2 ms. This is plenty good enough. I guess this might have been an artifact of the testing. Nonetheless, it always pays to make the code as good as possible so thanks for these hints.

I have managed to get things to work with an equation for the colors. However, I believe my approach is not valid overall. One thing that happens is that that if I color a peak whose vector starts at -1 and goes to 1, the color assigned will be blue to red in my setup. However that is not what I want. The midpoint should be green.
Here is an example of what I am trying to do.

I have everything working except for the color. How does one do this? Any hints?
Thanks

Ok, so this is a beginners forum…I’m a beginner! I just read about textures in particular 1D and 2D.
I understand how to apply a 2D texture to a quad for example. But I have triangle vertices that were generated in a X,Z grid programatically (left to right, then the next row etc) and then I have indices to tell the drawing sequence… I then draw this with glDrawElements, triangleStrip etc.
Now I understand that I need to provide UV vectors which in this case should be just each vertex all with the Y value. For example if I have a vertex at 0,0.5,0 then the UV should be 0.5,0.5,0.5. Am I correct? It would then pick up the texture color at u = 0.5. Am I doing this correctly?
Also how does one make a 1D texture out of my jpg, which is just a gradient of colors? Or can I actually use a 2D texture in this case?
Thanks

[QUOTE=tomb18;1285425]I have managed to get things to work with an equation for the colors. However, I believe my approach is not valid overall. One thing that happens is that that if I color a peak whose vector starts at -1 and goes to 1, the color assigned will be blue to red in my setup. However that is not what I want. The midpoint should be green.
Here is an example of what I am trying to do.

I have everything working except for the color. How does one do this? Any hints?
Thanks[/QUOTE]

Well. Hard to tell. Color gradients might be what you’re looking for.

[QUOTE=tomb18;1285426]Ok, so this is a beginners forum…I’m a beginner! I just read about textures in particular 1D and 2D.
I understand how to apply a 2D texture to a quad for example. But I have triangle vertices that were generated in a X,Z grid programatically (left to right, then the next row etc) and then I have indices to tell the drawing sequence… I then draw this with glDrawElements, triangleStrip etc.
Now I understand that I need to provide UV vectors which in this case should be just each vertex all with the Y value. For example if I have a vertex at 0,0.5,0 then the UV should be 0.5,0.5,0.5. Am I correct? It would then pick up the texture color at u = 0.5. Am I doing this correctly?
Also how does one make a 1D texture out of my jpg, which is just a gradient of colors? Or can I actually use a 2D texture in this case?
Thanks[/QUOTE]

If I understood your post correctly, the color will change according to the height, and not the “plane location”. In that case you might use a simple 1D texture (depicting gradient colors), and in your fragment shader just get the color from your texture according to the height, so no need to deal with texture coordinates (as a vertex attribute meaning) at all. You’ll certainly have to normalize the height between [0…1].

[QUOTE=tomb18;1285425]Here is an example of what I am trying to do.

what you want is a functionality to get a vec4 (RGBA) out of a float (height value, normalized), you can use a pre-calculated color texture:

unsigned char mytexturedata[] = {
0x00, 0xFF, 0x00, 0xFF, // green
0xFF, 0xFF, 0x00, 0xFF, // yellow
0xFF, 0x00, 0x00, 0xFF, // red
};

mytexturedata[0] = green, that means if you sample from the 1D texture with “float u = 0.0f;” you’ll get green
mytexturedata[max = 2] = red, that means if you sample from the 1D texture with “float u = 1.0f;” you’ll get red

these are the boundaries

if you sample from the 1D texture with “float u = 0.5f;” you’ll get yellow

but what if you sample from the 1D texture with “float u = 0.249999f;” ??
that depends on what “texture parameters” or “sampler parameters” you’ve set for your texture
the parameter responsible for that is GL_TEXTURE_WRAP_S:
– setting it to GL_NEAREST will give you exactly green, because green is the nearest texel to your texture coordinate
– setting it to GL_LINEAR will give you a linear interpolation between green and yellow (thats what you want)

but what if you sample from the 1D texture with “float u = -5.2f;” or “float u = +5.2f;” ?? (in other words: out of scope [0;1])
that depends on what “texture parameters” or “sampler parameters” you’ve set for your texture
the parameter responsible for that is (i think) GL_TEXTURE_MIN_FILTER: (or …MAG_FILTER ?)
however, setting it to GL_CLAMP_TO_EDGE will give you either green or red, depending on what border texel it next to the coordinate, setting it to GL_REPEAT will give you the same as if you’d have selected float u = +/-0.2f

https://www.khronos.org/opengl/wiki/Texture

example 1D texture:

you’d have to use “GL_RGBA8” as internal format instead if “GL_R8”

Great! This should be everything I need. Off to work!

@Silence, @John,
I’m having no success here.
So the first question is do you I need to supply texture coordinates? If so what format are they in?
What I have is vertices (Vector3) for the triangle strip where z and z are regularly spaced and a Y value that varies.

This is what I have for the shaders:

        #region Shaders
        public static string VertexShader = @"
        #version 130
        in vec3 vertexPosition;
        in vec4 myTextureData;
        out vec4 myTextureData;

        uniform mat4 projection_matrix;
        uniform mat4 view_matrix;
        uniform mat4 model_matrix;

        void main(void)
        {
            myTextureData = myTextureData;
            gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
        }
        ";

        public static string FragmentShader = @"
        #version 130
        uniform sampler1D texture;
        in vec4 myTextureData;
        
        out vec4 fragment;
        void main(void)
        {
            fragment = texture1D(texture, myTextureData);
        }
        ";

and the texture is:


            //here is the texture for the spectrum

            myTextureData[0].X = 0x00;      //blue
            myTextureData[0].Y = 0x00;
            myTextureData[0].Z = 0xFF;
            myTextureData[0].W = 0xFF;

            myTextureData[0].X = 0xFF;      //yellow
            myTextureData[0].Y = 0xFF;
            myTextureData[0].Z = 0x00;
            myTextureData[0].W = 0xFF;

            myTextureData[0].X = 0xFF;      //red
            myTextureData[0].Y = 0x00;
            myTextureData[0].Z = 0x00;
            myTextureData[0].W = 0xFF;

I’m sure the error is in the fragment shader…

its in the vertex shader ^^


        #version 130
        in vec3 vertexPosition;
        in vec4 myTextureData;
        out vec4 myTextureData;

ou cannot have 2 variables with he same name

by the way, shader error checking works like this
https://www.khronos.org/opengl/wiki/Shader_Compilation#Example

and your indices where you setup the texturedata are also wrong

sending a vec4 to the vertexshader makes so sense, i personally would do it like tis:
– send 2 uniform float to the vertexshader: “lowerlimit” and “upperlimit”
– calculate the relation of your vertex-z-value to those limits
– send the relation to the fragmentshader
in the fragmentshader:
– use the relation (a float) to sample from your 1D texture


#version 450 core

in layout (location = 0) vec3 vertexposition;

uniform mat4 MVP = mat4(1);

uniform float upperlimit = 10.0f;
uniform float lowerlimit = -10.0f;

out float texcoord;

void main()
{
    gl_Position = MVP * vec4(vertexposition, 1);

    // calculate the texture coordinate
    texcoord = (vertexposition.z - lowerlimit) / (upperlimit - lowerlimit);
}


#version 450 core

in float texcoord;

layout (binding = 3) uniform sampler1D tex1;

out layout (location = 0) vec4 fragmentcolor;

void main()
{
    fragmentcolor = texture(tex1, texcoord);
}

note: i explicitly set the texture unit to 3 in the shader code, that means you have to bind your 1Dtexture to that unit like this:

glActiveTexture(GL_TEXTURE0 + 3);
glBindTexture(GL_TEXTURE_1D, mytexture);

Hi
Ok now i’m totally confused. In a previous message you mentioned a 1d texture as


unsigned char mytexturedata[] = {
0x00, 0xFF, 0x00, 0xFF, // green
0xFF, 0xFF, 0x00, 0xFF, // yellow
0xFF, 0x00, 0x00, 0xFF, // red
}; 
 

and then mentioned that a mytexture[2] would give red.???
As far as I can see an index into that array gives 0 at [2]. So I assumed you missed something there. So I looked on the web and saw a number of references to setting up a [3,3] array to do this. So I assumed that a vector 4 would work. I guess not. So what is the right way to do this? If a multi-dimensional array is wrong what’s right for a 1d texture?

The next thing is you mention that I should calculate my “vertex z” values? Did you mean Y values? I’m plotting a surface grid with vertices placed at x and z in x-z plane and the height at that point is given by Y not Z.
Also everything I send is between 0 and 1. Everything, vertices and all. So what is the -10 and + 10?
So at this point I’m totally confused.

[QUOTE=tomb18;1285447]Ok now i’m totally confused. In a previous message you mentioned a 1d texture as


unsigned char mytexturedata[] = {
0x00, 0xFF, 0x00, 0xFF, // green
0xFF, 0xFF, 0x00, 0xFF, // yellow
0xFF, 0x00, 0x00, 0xFF, // red
}; 
 

[/QUOTE]

oops! you’re right!
what i means is something like that:


struct Texel { unsigned char r, g, b, a; };

Texel mytexturedata[] = {
    {0x00, 0xFF, 0x00, 0xFF}, // green
    {0xFF, 0xFF, 0x00, 0xFF}, // yellow
    {0xFF, 0x00, 0x00, 0xFF}, // red
};

[QUOTE=tomb18;1285447]The next thing is you mention that I should calculate my “vertex z” values? Did you mean Y values? I’m plotting a surface grid with vertices placed at x and z in x-z plane and the height at that point is given by Y not Z.
Also everything I send is between 0 and 1. Everything, vertices and all. So what is the -10 and + 10?
So at this point I’m totally confused.[/QUOTE]

depends on your coordinate system, you’re right
these min/max values are the limits of your “y-values” (!), the range in which they all are, if your range is [0;1] for all y-coordinate, then its all fine, just pass the y-value as “texcoord”

texcoord = (vertexposition.z - lowerlimit) / (upperlimit - lowerlimit);
… is just a more general description of the same, lets say your vertices y-coordinate are all in the range of [-5;+20], then you’d have to set the uniform values to -5 / +20, you can set / override uniform values from your application:

GLint location = glGetUniformLocation(program, "lowerlimit");
gl [Program] Uniform1f(location, -5.0f);

location = glGetUniformLocation(program, "upperlimit");
gl [Program] Uniform1f(location, +20.0f);

https://www.opengl.org/sdk/docs/man/html/glProgramUniform.xhtml
https://www.opengl.org/sdk/docs/man/html/glUniform.xhtml

[QUOTE=tomb18;1285440]

public static string FragmentShader = @"
        #version 130
        uniform sampler1D texture;
        in vec4 myTextureData;
        
        out vec4 fragment;
        void main(void)
        {
            fragment = texture1D(texture, myTextureData);
        }
        ";

texture1D expects the texture coordinate as the second argument. So just give it the current height which should be given as a varying by the vertex shader (then a simple float should suffice).

I’ve spent the last 5 hours on this with no luck at all. There are no basic tutorials anywhere on how to do this. So this is what I have at the moment. It’s everything related to the texture. Texel is just a class that replaces the C++ struc


            byte[] data = new byte[]
            {
                255, 0, 0, 255,
                0, 255, 0, 255,
                0, 0, 255, 255
            };
            
            Gl.Enable(EnableCap.Texture1D);
            Gl.PixelStorei(PixelStoreParameter.UnpackAlignment, 1);

            // Create a texture name
            var textureID = Gl.GenTexture();

            IntPtr myTexturePtr = Marshal.AllocHGlobal(data.Length);
            Marshal.Copy(data, 0, myTexturePtr, data.Length);

            Gl.BindTexture(TextureTarget.Texture1D, textureID);

            Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureWrapS, TextureParameter.Repeat);
            Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureWrapT, TextureParameter.Repeat);

            Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureMinFilter, TextureParameter.Linear);
            Gl.TexParameteri(TextureTarget.Texture1D, TextureParameterName.TextureMagFilter, TextureParameter.Linear);
            Gl.TexImage1D(TextureTarget.Texture1D, 0, PixelInternalFormat.Three, 3, 0, PixelFormat.Rgb, PixelType.UnsignedByte, myTexturePtr);

            //texture
            plottingProgram.Use();
            
            Gl.Uniform1i(3, 0);
            Gl.ActiveTexture(TextureUnit.Texture0);
            Gl.BindTexture(TextureTarget.Texture1D, textureID);

       uint samplerLocation = Gl.GetUniformLocation(plottingProgram, "ColorRamp");
        Gl.Uniform1i(samplerLocation, 0);
        Gl.ActiveTexture(TextureUnit.Texture0);
        Gl.BindTexture(TextureTarget.Texture1D, textureID);


The vertex shader

        public static string VertexShader = @"
        #version 130
        in vec3 vertexPosition;
        out float height;

        uniform mat4 projection_matrix;
        uniform mat4 view_matrix;
        uniform mat4 model_matrix;

        void main(void)
        {
            height = vertexPosition.y;
            gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
        }
        ";

and the fragment shader

        public static string FragmentShader = @"
        #version 130
        layout (binding = 3) uniform sampler1D colorRamp;
        in float height;
        
        out vec4 fragment;
        void main(void)
        {
            fragment = texture(colorRamp, height);
        }
        ";

I’m finding it real difficult to find ANY info on the code used in the fragment and vertex shaders.
I’m a total beginner at this, so when you don’t find a tutorial it’s really difficult.

This shouldn’t even compile, as you don’t have a variable named “position”.

Ensure that you’re checking for compilation and linking errors: glGetShader(GL_COMPILE_STATUS) and glGetProgram(GL_LINK_STATUS) for the status, glGetShaderInfoLog() and glGetProgramInfoLog() for the messages.

[QUOTE=tomb18;1285456]I’m finding it real difficult to find ANY info on the code used in the fragment and vertex shaders.
I’m a total beginner at this, so when you don’t find a tutorial it’s really difficult.[/QUOTE]

maybe you find this example useful
https://sites.google.com/site/john87connor/texture-object/1-2-texture-1d

Hi I updated the program above with an example I found for c#. However, the last couple of lines gives an error in this line that the parameters are incorrect.

uint samplerLocation = Gl.GetUniformLocation(plottingProgram, “colorRamp”);

Anyways, I will check out your example. Nice and clear.
Thanks