Creating texture from HDR image

Hi, I’m having trouble with setting up a texture which I’ve read from the OpenEXR file. It’s a HDR light probe image and I’m trying to set it as a texture of a big sphere for showing it as my background. The problem is that the color is not right and only a light blue color is visible. I used OpenExr library for reading the image file and stored it like this:


InputFile file(Filename);
  Box2i dw = file.header().dataWindow();
  m_iWidth  = dw.max.x - dw.min.x + 1;
  m_iHeight = dw.max.y - dw.min.y + 1;
  half *rgb = new half[3 * m_iWidth * m_iHeight];
  FrameBuffer frameBuffer;
  frameBuffer.insert("R", Slice(HALF, (char *)rgb,
   3*sizeof(half), m_iWidth * 3 * sizeof(half), 1, 1, 0.0));
  frameBuffer.insert("G", Slice(HALF, (char *)rgb+sizeof(half),
   3*sizeof(half), m_iWidth * 3 * sizeof(half), 1, 1, 0.0));
  frameBuffer.insert("B", Slice(HALF, (char *)rgb+2*sizeof(half),
   3*sizeof(half), m_iWidth * 3 * sizeof(half), 1, 1, 0.0));
  file.setFrameBuffer(frameBuffer);
  file.readPixels(dw.min.y, dw.max.y);
  m_Image = new Color[m_iWidth * m_iHeight];
  for (int i = 0; i < m_iWidth * m_iHeight; ++i) {
   float frgb[3] = { rgb[3*i], rgb[3*i+1], rgb[3*i+2] };
   m_Image[i] = frgb;


where color contains float R, G , B.

and this is how i create a texture:

glGenTextures(1 , &texture);
glBindTexture(GL_TEXTURE_2D,texture);

glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);

glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, light_tex.m_iWidth, light_tex.m_iHeight, 0, GL_RGBA, GL_FLOAT, light_tex.m_Image);

You told OpenGL that you were uploading four components. But your data only seems to have three (unless Color is a 4-vector).

Also, your conversion from half to float is… dubious. I mean, you have this line:


float frgb[3] = { rgb[3*i], rgb[3*i+1], rgb[3*i+2] };

rgb is a half*; an array of half. So unless half has some implicit conversion to float, this isn’t going to work. It’d be much easier (and a lot less confusing) to just do this:


m_Image[i][0] = ConvertToFloat(rgb[3*i + 0]);
m_Image[i][1] = ConvertToFloat(rgb[3*i + 1]);
m_Image[i][2] = ConvertToFloat(rgb[3*i + 2]);

Lastly, what’s the point of loading half-floats from the file (which is what I assume you’re doing), just to convert them to 32-bit floats, all so that you can make OpenGL convert them back to half-floats?

Just give OpenGL half-float data with GL_HALF_FLOAT instead of GL_FLOAT.

Just give OpenGL half-float data with GL_HALF_FLOAT instead of GL_FLOAT.

I’ve tried what you said, and it is still not working, actually the code for reading the file is taken from PBRT and I’m sure it is correct, but I don’t know how I have to assign in to a texture. I’ve attached the result I get with each try.

I did this last month

GLuint loadTexture(const char *path)
{
   Imf::Rgba * pixelBuffer;
   try
   {
     Imf::RgbaInputFile in(path);

     Imath::Box2i win = in.dataWindow();
     GLuint width  = win.max.x - win.min.x+1;
     GLuint height = win.max.y - win.min.y+1;
     Imath::V2i dim(win.max.x - win.min.x + 1,
                    win.max.y - win.min.y + 1);

     pixelBuffer = new Imf::Rgba[dim.x * dim.y];

     int dx = win.min.x;
     int dy = win.min.y;

     int order = in.lineOrder();

     in.setFrameBuffer(pixelBuffer - dx - (dy * dim.x), 1, dim.x);
     in.readPixels(win.min.y, win.max.y);
   }
   catch(Iex::BaseExc & e)
   {
     std::cerr << e.what() << std::endl;

     delete[]pixelBuffer;
     return GL_INVALID_VALUE;
   }
   GLuint texture;
   glGenTextures(1, &texture);
   glBindTexture(GL_TEXTURE_RECTANGLE, texture);

   glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_HALF_FLOAT, pixelBuffer);

   delete[]pixelBuffer;
   return texture;
}

In my case i didn’t do any conversion. I know that the exr image was stored as float16. In your code you are doing a lot of useless conversion.
you read the image as float16, then you convert it as float32, then you convert the float32 to Color (can I see the layout of Color?) and then you use as internal format float16, so you are asking to openGl :
“I have this float data in RGBA, to convert it again in float16.”

First tnx for your help! I also tried your code but I can’t see the image any more, I know I’m mixing sth with these conversions…

this is my Color class:


class Color
{
public:

	float R , G , B/* , A*/;
	Color(const Color& col);
	Color();
	virtual ~Color(void);
	Color(const float r,const float g, const float b);
	void Set(const float r, const float g, const float b);
    
	friend Color operator * (const float s, const Color c);
	Color& operator=(const Color& c);
	Color& operator=(const float& c);
	Color& operator=(const float c[3]);
	//Color& operator=(const Lib3dsByte& c);
	Color operator*(const Color& c);
	Color operator*(float d) const;
	Color operator/(float d) const;
	void operator*=(const float s);
    void operator/=(const float s);
    Color& operator+=(const Color& c);
	Color operator+(const Color& vec3) const;
	bool operator==(const float c) const;
	//Color mult(const Color& c) const;
	void normalize(void);
	Color ColorNorm(void)const;
	void Bind();
	
	Color Mult(const Color &c);
	void MultScalar(const float a);	
};


and I want to pass this texture to the shader and use latitude-longitude for mapping it on a sphere.

this is how i pass it to the shader in my display function:


qobj = gluNewQuadric(); 
	gluQuadricTexture(qobj,GL_TRUE); 


	glEnable(GL_CULL_FACE);
	
	glFrontFace(GL_CW /* or GL_CCW */);	//default is GL_CCW

	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glDisable(GL_LIGHTING);
	glDisable(GL_LIGHT0);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0f, 20.0f, 50.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

	glPushMatrix();
	glTranslatef(tx,ty,0);
	glRotatef(rotx,1,0,0);
	glRotatef(roty,0,1,0);

	LShader.bind();
	glEnable(GL_TEXTURE_2D );
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D , texture);

	int texture_location = glGetUniformLocation(LShader.GetID(), "color_texture");
	glUniform1i(texture_location, texture_location);
	
 	gluSphere(qobj,10000,30,30);
 	gluDeleteQuadric(qobj); 

	glDisable(GL_TEXTURE_2D);
	LShader.unbind();
	glPopMatrix();


	glutSwapBuffers();

and this is my fragment shader :



varying vec3 oVertexP;


uniform sampler2D color_texture;

void main()
{

	float pi = 3.1415;
	float x , y, z;
	vec3 viewVec = normalize(oVertexP);
	x = viewVec.x;
	y = viewVec.y;
	z = viewVec.z;
	
	//Latitude-longitude
	float	u = 1.0 + (1.0/pi) * atan(x,-z); u /= 2.0;
	float	v = acos(y) / pi;
  
    vec4 color = vec4(  texture2D(color_texture, vec2(u,v)) );
	gl_FragColor = vec4(pow(color.xyz,1.0/2.2),1.0); //Tone mapping
}



one other thing is that I changed GL_TEXTURE_RECTANGLE to GL_TEXTURE_2D in your code, but still I can’t see any result! :frowning:

Problem solved!! I made a stupid mistake by creating the texture before initializing glut!! you code works perfectly Rosario Leonardi! tnx a lot! :slight_smile:

No problem. :slight_smile:
Your code didn’t work cause your Color class have only RGB information.
So in memory you have
RGBRGBRGBRGBRGBRGBRGBRGB…
but when you use

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, light_tex.m_iWidth, light_tex.m_iHeight, 0, GL_RGBA, GL_FLOAT, light_tex.m_Image);

you are telling openGl that your image data are GL_RGBA
so, openGL expect data as RGBARGBARGBARGBA… messing up everything.

Passing the data in the right format also avoid a lot of work to openGl speed up the code.

If you are going to use my code, that was a fast test to check the best HDR format for my after effect, so, no mipmap, no filter. If you are going to use that as a texture probably you need some filter. Also keep in mind that float16 picture use an huge amount of memory.

it’s always good to know where you’re making mistake! tnx a lot for your explanation! :slight_smile: