1
votes

I have a short texture that I want to read from in a shader, webgl does not support short textures so I split the short in to two bytes and send it to the shader:

var ushortValue = reinterval(i16Value, -32768, 32767, 0, 65535);

textureData[j*4] = ushortValue & 0xFF; // first byte
ushortValue = ushortValue >> 8;
textureData[j*4+1] = ushortValue & 0xFF; // second byte
textureData[j*4+2] = 0;
textureData[j*4+3] = 0;

And then I upload the data to the graphic card:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, textureData);

In fragment shader:

vec4 valueInRGBA = texture2D(ctTexture, xy)*255.0; // range 0-1 to 0-255
float real_value = valueInRGBA.r + valueInRGBA.g*256;
real_value  = reinterval(real_value , 0.0, 65535.0,  0.0, 1.0);
gl_FragColor = vec4(real_value, real_value, real_value, 1.0);

But I am lost resolution compared to when I upload the short data in normal opengl that has support for short textures. Can anyone see what I am doing wrong?

enter image description here

Here is another strange different I get between webgl and opengl, with the same data. I a draw the value as above I get the same colors but I little less resolution. And then I add two lines:

ct_value = reinterval(ct_value, 0.0, 65535.0,  -32768.0, 32767.0);
ct_value = reintervalClamped(ct_value, -275.0, 475.0, 0.0, 1.0);
gl_FragColor = vec4(ct_value,ct_value,ct_value,1.0);

In opengl everything looks good but in webgl everything turns white with the exact the same code.

Opengl: enter image description here Webgl: enter image description here

1
shouldn't you multiply in the shader by 255.0 (2^8-1) instead of 254.0?BDL
or even 256, because ushortValue = ushortValue >> 8; is dividing by theratchet freak
I changed it, thank you, but still, the resolution is still badhidayat
Can you add an image?BDL
I cant show you the whole image because its real ct data from a patient, but you can see the bad resolution in this one.hidayat

1 Answers

0
votes

I am solving same problem and it works fine for me. My implementation is in dart, but it is similar. I have 2 possible solutions:

1) Use float texture

gl.getExtension("OES_texture_float")
texture format = GL.LUMINANCE
texture data type = GL.FLOAT

maxValue = (signed)?32767.0:65535.0;
textureData = new Float32List(width*height);
for (int i=0;i<size;i++) {
  textureData[i] = data[i]/maxValue;
}

This solution works great and there is no need to perform any special calculations in shader, but you need OES_float_linear extension to use linear texture interpolation and current version of Chrome does not support it.

2) Use your solution with storing short value to RGB

pixels = new Uint8List(width*height*3);
for (int i=0;i<width*height;i++) {
  int val = (signed)?data[i].abs():data[i];
  textureData[i*3] = val&0xFF;
  textureData[i*3+1] = val>>8;
  textureData[i*3+2] = (signed && data[i]<0)?255:0;
}

And value reconstruction in shader:

float tval = texture2D(imageTex, vUv).r/256.0+texture2D(imageTex, vUv).g; 
if (texture2D(imageTex, vUv).b>0.0) tval = -tval

But this solution has one big issue, when you zoom in and have GL.LINEAR filtering enabled it draws bad data on high constrast edges in image, because red byte and grean byte are interpolated separately.

Conclusion: Both solutions work, but neither is possible to use with linear texture interpolation. Maybe it is possible to perform manual interpolation in fragment shader.