I'm trying to figure out how to process images containing non-color data exceeding the 0...1 range (e.g. depth and normal information), but whenever I try to evaluate those images in a SkSL shader, their colors get clamped back to the 0...1 range.
I tried messing around with color spaces, using
makeRawShader, etc., but pretty much whenever there's an image involved the colors get clamped. Same does not happen when the shader itself outputs such values - they remain unclamped.
Is there a way to retain the values outside 0...1 when they are evaluated within a shader without resorting to workarounds (mapping them to 0...1, but losing precision)?
Example (here I used the Python bindings for ease of experimentation):
import struct
import skia
def main():
data = [-0.5, 0.5, 1.5, 1] # 1x1 image
byte_data = struct.pack("f" * 4, *data)
image = skia.Image.MakeRasterData(skia.ImageInfo.Make(skia.ISize(1, 1), skia.ColorType.kRGBA_F32_ColorType, skia.AlphaType.kUnpremul_AlphaType), byte_data, rowBytes=16)
raw_image_shader = image.makeRawShader()
print(f"Original image data:\t\t\t{image.toarray()}")
surface = skia.Surface.MakeRaster(skia.ImageInfo.Make(skia.ISize(1, 1), skia.ColorType.kRGBA_F32_ColorType, skia.AlphaType.kUnpremul_AlphaType), rowBytes=16)
canvas = surface.getCanvas()
paint = skia.Paint()
# shader without an image
paint.setShader(make_shader("""
vec4 main(vec2 coord) {
return vec4(-0.5, 0.5, 1.5, 1.0);
}
""", None))
canvas.drawPaint(paint)
print(f"Out-of-range data from shader:\t\t{surface.makeImageSnapshot().toarray()}")
# shader with an image
paint.setShader(make_shader("""
uniform shader img;
vec4 main(vec2 coord) {
return img.eval(coord);
}
""", raw_image_shader))
canvas.drawPaint(paint)
print(f"Data sampled from image by shader:\t{surface.makeImageSnapshot().toarray()}")
def make_shader(sksl, image):
sksl_effect = skia.RuntimeEffect.MakeForShader(sksl)
shader_builder = skia.RuntimeShaderBuilder(sksl_effect)
if image is not None:
shader_builder.setChild("img", image)
return shader_builder.makeShader()
Results:
Original image data: [[[-0.5 0.5 1.5 1. ]]]
Out-of-range data from shader: [[[-0.5 0.5 1.5 1. ]]]
Data sampled from image by shader: [[[0. 0.5019608 1. 1. ]]]