You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Fix GLES3 stereo output (sRGB + lens distortion)
This commit is contained in:
@@ -115,31 +115,56 @@ CopyEffects::~CopyEffects() {
|
|||||||
copy.shader.version_free(copy.shader_version);
|
copy.shader.version_free(copy.shader_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyEffects::copy_to_rect(const Rect2 &p_rect) {
|
void CopyEffects::copy_to_rect(const Rect2 &p_rect, bool p_linear_to_srgb) {
|
||||||
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
|
uint64_t specializations = p_linear_to_srgb ? CopyShaderGLES3::CONVERT_LINEAR_TO_SRGB : 0;
|
||||||
|
|
||||||
|
bool success = copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION, specializations);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
|
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION, specializations);
|
||||||
draw_screen_quad();
|
draw_screen_quad();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyEffects::copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod) {
|
void CopyEffects::copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod, bool p_linear_to_srgb) {
|
||||||
ERR_FAIL_COND(p_type != Texture::TYPE_LAYERED && p_type != Texture::TYPE_3D);
|
ERR_FAIL_COND(p_type != Texture::TYPE_LAYERED && p_type != Texture::TYPE_3D);
|
||||||
|
|
||||||
CopyShaderGLES3::ShaderVariant variant = p_type == Texture::TYPE_LAYERED
|
CopyShaderGLES3::ShaderVariant variant = p_type == Texture::TYPE_LAYERED
|
||||||
? CopyShaderGLES3::MODE_COPY_SECTION_2D_ARRAY
|
? CopyShaderGLES3::MODE_COPY_SECTION_2D_ARRAY
|
||||||
: CopyShaderGLES3::MODE_COPY_SECTION_3D;
|
: CopyShaderGLES3::MODE_COPY_SECTION_3D;
|
||||||
|
uint64_t specializations = p_linear_to_srgb ? CopyShaderGLES3::CONVERT_LINEAR_TO_SRGB : 0;
|
||||||
|
|
||||||
bool success = copy.shader.version_bind_shader(copy.shader_version, variant);
|
bool success = copy.shader.version_bind_shader(copy.shader_version, variant, specializations);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, variant);
|
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, variant, specializations);
|
||||||
copy.shader.version_set_uniform(CopyShaderGLES3::LAYER, p_layer, copy.shader_version, variant);
|
copy.shader.version_set_uniform(CopyShaderGLES3::LAYER, p_layer, copy.shader_version, variant, specializations);
|
||||||
copy.shader.version_set_uniform(CopyShaderGLES3::LOD, p_lod, copy.shader_version, variant);
|
copy.shader.version_set_uniform(CopyShaderGLES3::LOD, p_lod, copy.shader_version, variant, specializations);
|
||||||
|
draw_screen_quad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyEffects::copy_with_lens_distortion(const Rect2 &p_rect, float p_layer, const Vector2 &p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ration, bool p_linear_to_srgb) {
|
||||||
|
CopyShaderGLES3::ShaderVariant variant = CopyShaderGLES3::MODE_LENS_DISTORTION;
|
||||||
|
|
||||||
|
uint64_t specializations = p_linear_to_srgb ? CopyShaderGLES3::CONVERT_LINEAR_TO_SRGB : 0;
|
||||||
|
|
||||||
|
bool success = copy.shader.version_bind_shader(copy.shader_version, variant, specializations);
|
||||||
|
if (!success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::LAYER, p_layer, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::LOD, 0.0, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::EYE_CENTER, p_eye_center.x, p_eye_center.y, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::K1, p_k1, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::K2, p_k1, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::UPSCALE, p_upscale, copy.shader_version, variant, specializations);
|
||||||
|
copy.shader.version_set_uniform(CopyShaderGLES3::ASPECT_RATIO, p_aspect_ration, copy.shader_version, variant, specializations);
|
||||||
|
|
||||||
draw_screen_quad();
|
draw_screen_quad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ public:
|
|||||||
~CopyEffects();
|
~CopyEffects();
|
||||||
|
|
||||||
// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
|
// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
|
||||||
void copy_to_rect(const Rect2 &p_rect);
|
void copy_to_rect(const Rect2 &p_rect, bool p_linear_to_srgb = false);
|
||||||
void copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod = 0.0f);
|
void copy_to_rect_3d(const Rect2 &p_rect, float p_layer, int p_type, float p_lod = 0.0f, bool p_linear_to_srgb = false);
|
||||||
|
void copy_with_lens_distortion(const Rect2 &p_rect, float p_layer, const Vector2 &p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ration, bool p_linear_to_srgb = false);
|
||||||
void copy_to_and_from_rect(const Rect2 &p_rect);
|
void copy_to_and_from_rect(const Rect2 &p_rect);
|
||||||
void copy_screen(float p_multiply = 1.0);
|
void copy_screen(float p_multiply = 1.0);
|
||||||
void copy_cube_to_rect(const Rect2 &p_rect);
|
void copy_cube_to_rect(const Rect2 &p_rect);
|
||||||
|
|||||||
@@ -387,18 +387,26 @@ RasterizerGLES3::RasterizerGLES3() {
|
|||||||
RasterizerGLES3::~RasterizerGLES3() {
|
RasterizerGLES3::~RasterizerGLES3() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first) {
|
void RasterizerGLES3::_blit_render_target_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen &p_blit, bool p_first) {
|
||||||
GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target);
|
GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_blit.render_target);
|
||||||
|
|
||||||
ERR_FAIL_NULL(rt);
|
ERR_FAIL_NULL(rt);
|
||||||
|
|
||||||
// We normally render to the render target upside down, so flip Y when blitting to the screen.
|
// We normally render to the render target upside down, so flip Y when blitting to the screen.
|
||||||
bool flip_y = true;
|
bool flip_y = true;
|
||||||
|
bool linear_to_srgb = false;
|
||||||
if (rt->overridden.color.is_valid()) {
|
if (rt->overridden.color.is_valid()) {
|
||||||
// If we've overridden the render target's color texture, that means we
|
// If we've overridden the render target's color texture, that means we
|
||||||
// didn't render upside down, so we don't need to flip it.
|
// didn't render upside down, so we don't need to flip it.
|
||||||
// We're probably rendering directly to an XR device.
|
// We're probably rendering directly to an XR device.
|
||||||
flip_y = false;
|
flip_y = false;
|
||||||
|
|
||||||
|
// It is 99% likely our texture uses the GL_SRGB8_ALPHA8 texture format in
|
||||||
|
// which case we have a GPU sRGB to Linear conversion on texture read.
|
||||||
|
// We need to counter this.
|
||||||
|
// Unfortunately we do not have an API to check this as Godot does not
|
||||||
|
// track this.
|
||||||
|
linear_to_srgb = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
@@ -410,7 +418,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
|
||||||
|
|
||||||
if (p_first) {
|
if (p_first) {
|
||||||
if (p_screen_rect.position != Vector2() || p_screen_rect.size != rt->size) {
|
if (p_blit.dst_rect.position != Vector2() || p_blit.dst_rect.size != rt->size) {
|
||||||
// Viewport doesn't cover entire window so clear window to black before blitting.
|
// Viewport doesn't cover entire window so clear window to black before blitting.
|
||||||
// Querying the actual window size from the DisplayServer would deadlock in separate render thread mode,
|
// Querying the actual window size from the DisplayServer would deadlock in separate render thread mode,
|
||||||
// so let's set the biggest viewport the implementation supports, to be sure the window is fully covered.
|
// so let's set the biggest viewport the implementation supports, to be sure the window is fully covered.
|
||||||
@@ -421,7 +429,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 screen_rect_end = p_screen_rect.get_end();
|
Vector2 screen_rect_end = p_blit.dst_rect.get_end();
|
||||||
|
|
||||||
// Adreno (TM) 3xx devices have a bug that create wrong Landscape rotation of 180 degree
|
// Adreno (TM) 3xx devices have a bug that create wrong Landscape rotation of 180 degree
|
||||||
// Reversing both the X and Y axis is equivalent to rotating 180 degrees
|
// Reversing both the X and Y axis is equivalent to rotating 180 degrees
|
||||||
@@ -431,8 +439,8 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
flip_x = !flip_x;
|
flip_x = !flip_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 p1 = Vector2(flip_x ? screen_rect_end.x : p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y);
|
Vector2 p1 = Vector2(flip_x ? screen_rect_end.x : p_blit.dst_rect.position.x, flip_y ? screen_rect_end.y : p_blit.dst_rect.position.y);
|
||||||
Vector2 p2 = Vector2(flip_x ? p_screen_rect.position.x : screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y);
|
Vector2 p2 = Vector2(flip_x ? p_blit.dst_rect.position.x : screen_rect_end.x, flip_y ? p_blit.dst_rect.position.y : screen_rect_end.y);
|
||||||
Vector2 size = p2 - p1;
|
Vector2 size = p2 - p1;
|
||||||
|
|
||||||
Rect2 screenrect = Rect2(Vector2(flip_x ? 1.0 : 0.0, flip_y ? 1.0 : 0.0), Vector2(flip_x ? -1.0 : 1.0, flip_y ? -1.0 : 1.0));
|
Rect2 screenrect = Rect2(Vector2(flip_x ? 1.0 : 0.0, flip_y ? 1.0 : 0.0), Vector2(flip_x ? -1.0 : 1.0, flip_y ? -1.0 : 1.0));
|
||||||
@@ -450,10 +458,12 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_ONE, GL_ZERO);
|
glBlendFunc(GL_ONE, GL_ZERO);
|
||||||
|
|
||||||
if (rt->view_count > 1) {
|
if (p_blit.lens_distortion.apply && (p_blit.lens_distortion.k1 != 0.0 || p_blit.lens_distortion.k2)) {
|
||||||
copy_effects->copy_to_rect_3d(screenrect, p_layer, GLES3::Texture::TYPE_LAYERED);
|
copy_effects->copy_with_lens_distortion(screenrect, p_blit.multi_view.use_layer ? p_blit.multi_view.layer : 0, p_blit.lens_distortion.eye_center, p_blit.lens_distortion.k1, p_blit.lens_distortion.k2, p_blit.lens_distortion.upscale, p_blit.lens_distortion.aspect_ratio, linear_to_srgb);
|
||||||
|
} else if (rt->view_count > 1) {
|
||||||
|
copy_effects->copy_to_rect_3d(screenrect, p_blit.multi_view.use_layer ? p_blit.multi_view.layer : 0, GLES3::Texture::TYPE_LAYERED, 0.0, linear_to_srgb);
|
||||||
} else {
|
} else {
|
||||||
copy_effects->copy_to_rect(screenrect);
|
copy_effects->copy_to_rect(screenrect, linear_to_srgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
@@ -462,12 +472,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
|
|||||||
// is this p_screen useless in a multi window environment?
|
// is this p_screen useless in a multi window environment?
|
||||||
void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
|
void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) {
|
||||||
for (int i = 0; i < p_amount; i++) {
|
for (int i = 0; i < p_amount; i++) {
|
||||||
const BlitToScreen &blit = p_render_targets[i];
|
_blit_render_target_to_screen(p_screen, p_render_targets[i], i == 0);
|
||||||
|
|
||||||
RID rid_rt = blit.render_target;
|
|
||||||
|
|
||||||
Rect2 dst_rect = blit.dst_rect;
|
|
||||||
_blit_render_target_to_screen(rid_rt, p_screen, dst_rect, blit.multi_view.use_layer ? blit.multi_view.layer : 0, i == 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ protected:
|
|||||||
RasterizerSceneGLES3 *scene = nullptr;
|
RasterizerSceneGLES3 *scene = nullptr;
|
||||||
static RasterizerGLES3 *singleton;
|
static RasterizerGLES3 *singleton;
|
||||||
|
|
||||||
void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first = true);
|
void _blit_render_target_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen &p_blit, bool p_first = true);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RendererUtilities *get_utilities() { return utilities; }
|
RendererUtilities *get_utilities() { return utilities; }
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
|
|||||||
mode_copy_section_source = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define MODE_COPY_FROM
|
mode_copy_section_source = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define MODE_COPY_FROM
|
||||||
mode_copy_section_3d = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_3D
|
mode_copy_section_3d = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_3D
|
||||||
mode_copy_section_2d_array = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_2D_ARRAY
|
mode_copy_section_2d_array = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_2D_ARRAY
|
||||||
|
mode_lens_distortion = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY \n#define USE_TEXTURE_2D_ARRAY \n#define APPLY_LENS_DISTORTION
|
||||||
mode_screen = #define MODE_SIMPLE_COPY \n#define MODE_MULTIPLY
|
mode_screen = #define MODE_SIMPLE_COPY \n#define MODE_MULTIPLY
|
||||||
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
|
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
|
||||||
mode_mipmap = #define MODE_MIPMAP
|
mode_mipmap = #define MODE_MIPMAP
|
||||||
@@ -15,6 +16,8 @@ mode_cube_to_panorama = #define CUBE_TO_PANORAMA
|
|||||||
|
|
||||||
#[specializations]
|
#[specializations]
|
||||||
|
|
||||||
|
CONVERT_LINEAR_TO_SRGB = false
|
||||||
|
|
||||||
#[vertex]
|
#[vertex]
|
||||||
|
|
||||||
layout(location = 0) in vec2 vertex_attrib;
|
layout(location = 0) in vec2 vertex_attrib;
|
||||||
@@ -93,6 +96,14 @@ uniform sampler2D source; // texunit:0
|
|||||||
|
|
||||||
#endif // !(defined(CUBE_TO_OCTAHEDRAL) || defined(CUBE_TO_PANORAMA))
|
#endif // !(defined(CUBE_TO_OCTAHEDRAL) || defined(CUBE_TO_PANORAMA))
|
||||||
|
|
||||||
|
#ifdef APPLY_LENS_DISTORTION
|
||||||
|
uniform vec2 eye_center;
|
||||||
|
uniform float k1;
|
||||||
|
uniform float k2;
|
||||||
|
uniform float upscale;
|
||||||
|
uniform float aspect_ratio;
|
||||||
|
#endif // APPLY_LENS_DISTORTION
|
||||||
|
|
||||||
layout(location = 0) out vec4 frag_color;
|
layout(location = 0) out vec4 frag_color;
|
||||||
|
|
||||||
// This expects 0-1 range input, outside that range it behaves poorly.
|
// This expects 0-1 range input, outside that range it behaves poorly.
|
||||||
@@ -101,22 +112,69 @@ vec3 srgb_to_linear(vec3 color) {
|
|||||||
return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
|
return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This expects 0-1 range input.
|
||||||
|
vec3 linear_to_srgb(vec3 color) {
|
||||||
|
// Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
|
||||||
|
return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0));
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
#ifdef MODE_SIMPLE_COPY
|
#ifdef MODE_SIMPLE_COPY
|
||||||
|
|
||||||
|
vec2 uv = uv_interp;
|
||||||
|
|
||||||
|
#ifdef APPLY_LENS_DISTORTION
|
||||||
|
uv = uv * 2.0 - 1.0;
|
||||||
|
vec2 offset = uv - eye_center;
|
||||||
|
|
||||||
|
// take aspect ratio into account
|
||||||
|
offset.y /= aspect_ratio;
|
||||||
|
|
||||||
|
// distort
|
||||||
|
vec2 offset_sq = offset * offset;
|
||||||
|
float radius_sq = offset_sq.x + offset_sq.y;
|
||||||
|
float radius_s4 = radius_sq * radius_sq;
|
||||||
|
float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4);
|
||||||
|
offset *= distortion_scale;
|
||||||
|
|
||||||
|
// reapply aspect ratio
|
||||||
|
offset.y *= aspect_ratio;
|
||||||
|
|
||||||
|
// add our eye center back in
|
||||||
|
uv = offset + eye_center;
|
||||||
|
uv /= upscale;
|
||||||
|
|
||||||
|
// and check our color
|
||||||
|
if (uv.x < -1.0 || uv.y < -1.0 || uv.x > 1.0 || uv.y > 1.0) {
|
||||||
|
frag_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
} else {
|
||||||
|
uv = uv * 0.5 + 0.5;
|
||||||
|
#endif // APPLY_LENS_DISTORTION
|
||||||
|
|
||||||
#ifdef USE_TEXTURE_3D
|
#ifdef USE_TEXTURE_3D
|
||||||
vec4 color = textureLod(source_3d, vec3(uv_interp, layer), lod);
|
vec4 color = textureLod(source_3d, vec3(uv, layer), lod);
|
||||||
#elif defined(USE_TEXTURE_2D_ARRAY)
|
#elif defined(USE_TEXTURE_2D_ARRAY)
|
||||||
vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), lod);
|
vec4 color = textureLod(source_2d_array, vec3(uv, layer), lod);
|
||||||
#else
|
#else
|
||||||
vec4 color = texture(source, uv_interp);
|
vec4 color = texture(source, uv);
|
||||||
#endif // USE_TEXTURE_3D
|
#endif // USE_TEXTURE_3D
|
||||||
|
|
||||||
|
#ifdef CONVERT_LINEAR_TO_SRGB
|
||||||
|
// Reading from a *_SRGB texture source will have converted data to linear,
|
||||||
|
// but we should output in sRGB!
|
||||||
|
color.rgb = linear_to_srgb(color.rgb);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MODE_MULTIPLY
|
#ifdef MODE_MULTIPLY
|
||||||
color *= multiply;
|
color *= multiply;
|
||||||
#endif // MODE_MULTIPLY
|
#endif // MODE_MULTIPLY
|
||||||
|
|
||||||
frag_color = color;
|
frag_color = color;
|
||||||
|
|
||||||
|
#ifdef APPLY_LENS_DISTORTION
|
||||||
|
}
|
||||||
|
#endif // APPLY_LENS_DISTORTION
|
||||||
|
|
||||||
#endif // MODE_SIMPLE_COPY
|
#endif // MODE_SIMPLE_COPY
|
||||||
|
|
||||||
#ifdef MODE_SIMPLE_COLOR
|
#ifdef MODE_SIMPLE_COLOR
|
||||||
|
|||||||
Reference in New Issue
Block a user