// Octahedral Unit Vector encoding
// Intuitive, fast, and has very little error.
vec2 EncodeUnitVector(vec3 vector) {
	// Scale down to octahedron, project onto XY plane
	vector.xy /= abs(vector.x) + abs(vector.y) + abs(vector.z);
	// Reflect -Z hemisphere folds over the diagonals
	return vector.z <= 0.0 ? (1.0 - abs(vector.yx)) * vec2(vector.x >= 0.0 ? 1.0 : -1.0, vector.y >= 0.0 ? 1.0 : -1.0) : vector.xy;
}

vec3 DecodeUnitVector(vec2 encoded) {
	// Exctract Z component
	vec3 vector = vec3(encoded, 1.0 - abs(encoded.x) - abs(encoded.y));
	// Reflect -Z hemisphere folds over the diagonals
	float t = max(-vector.z, 0.0);
	vector.xy += vec2(vector.x >= 0.0 ? -t : t, vector.y >= 0.0 ? -t : t);
	// Normalize and return
	return normalize(vector);
}

vec4 encodeRGBE8(vec3 rgb) {
    float exponentPart = floor(log2(max(max(rgb.r, rgb.g), max(rgb.b, exp2(-127.0))))); // can remove the clamp to above exp2(-127) if you're sure you're not going to input any values below that
    vec3  mantissaPart = clamp((128.0 / 255.0) * exp2(-exponentPart) * rgb, 0.0, 1.0);
          exponentPart = clamp(exponentPart / 255.0 + (127.0 / 255.0), 0.0, 1.0);

    return vec4(mantissaPart, exponentPart);
}

vec3 decodeRGBE8(vec4 rgbe) {
    cFloat add = log2(255.0 / 128.0) - 127.0;
    return exp2(rgbe.a * 255.0 + add) * rgbe.rgb;
}