diff --git a/src/core/shaders/webgl/LinearGradient.ts b/src/core/shaders/webgl/LinearGradient.ts index 39075c1e..f234df08 100644 --- a/src/core/shaders/webgl/LinearGradient.ts +++ b/src/core/shaders/webgl/LinearGradient.ts @@ -49,6 +49,8 @@ export const LinearGradient: WebGlShaderType = { # endif #define PI 3.14159265359 + #define MAX_STOPS ${props.colors.length} + #define LAST_STOP ${props.colors.length - 1} uniform float u_alpha; uniform vec2 u_dimensions; @@ -56,8 +58,8 @@ export const LinearGradient: WebGlShaderType = { uniform sampler2D u_texture; uniform float u_angle; - uniform float u_stops[${props.stops.length}]; - uniform vec4 u_colors[${props.colors.length}]; + uniform float u_stops[MAX_STOPS]; + uniform vec4 u_colors[MAX_STOPS]; varying vec4 v_color; varying vec2 v_textureCoords; @@ -66,6 +68,27 @@ export const LinearGradient: WebGlShaderType = { return d * vec2(cos(angle), sin(angle)) + (u_dimensions * 0.5); } + vec4 getGradientColor(float dist) { + dist = clamp(dist, 0.0, 1.0); + + if(dist <= u_stops[0]) { + return u_colors[0]; + } + + if(dist >= u_stops[LAST_STOP]) { + return u_colors[LAST_STOP]; + } + + for(int i = 0; i < LAST_STOP; i++) { + float left = u_stops[i]; + float right = u_stops[i + 1]; + if(dist >= left && dist <= right) { + float lDist = smoothstep(left, right, dist); + return mix(u_colors[i], u_colors[i + 1], lDist); + } + } + } + void main() { vec4 color = texture2D(u_texture, v_textureCoords) * v_color; float a = u_angle; @@ -74,7 +97,7 @@ export const LinearGradient: WebGlShaderType = { vec2 t = calcPoint(lineDist * 0.5, a + PI); vec2 gradVec = t - f; float dist = dot(v_textureCoords.xy * u_dimensions - f, gradVec) / dot(gradVec, gradVec); - ${genGradientColors(props.stops.length)} + vec4 colorOut = getGradientColor(dist); gl_FragColor = mix(color, colorOut, clamp(colorOut.a, 0.0, 1.0)); } `; diff --git a/src/core/shaders/webgl/RadialGradient.ts b/src/core/shaders/webgl/RadialGradient.ts index bd23210a..e1810f87 100644 --- a/src/core/shaders/webgl/RadialGradient.ts +++ b/src/core/shaders/webgl/RadialGradient.ts @@ -21,9 +21,8 @@ import { RadialGradientTemplate, type RadialGradientProps, } from '../templates/RadialGradientTemplate.js'; -import { genGradientColors } from '../../renderers/webgl/internal/ShaderUtils.js'; -import type { WebGlRenderer } from '../../renderers/webgl/WebGlRenderer.js'; import type { WebGlShaderType } from '../../renderers/webgl/WebGlShaderNode.js'; +import type { WebGlRenderer } from '../../renderers/webgl/WebGlRenderer.js'; export const RadialGradient: WebGlShaderType = { props: RadialGradientTemplate.props, @@ -48,38 +47,61 @@ export const RadialGradient: WebGlShaderType = { }, fragment(renderer: WebGlRenderer, props: RadialGradientProps) { return ` - # ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; - # else - precision mediump float; - # endif + # ifdef GL_FRAGMENT_PRECISION_HIGH + precision highp float; + # else + precision mediump float; + # endif - #define PI 3.14159265359 + #define MAX_STOPS ${props.colors.length} + #define LAST_STOP ${props.colors.length - 1} - uniform float u_alpha; - uniform vec2 u_dimensions; + uniform float u_alpha; + uniform vec2 u_dimensions; - uniform sampler2D u_texture; + uniform sampler2D u_texture; - uniform vec2 u_projection; - uniform vec2 u_size; - uniform float u_stops[${props.stops.length}]; - uniform vec4 u_colors[${props.colors.length}]; + uniform vec2 u_projection; + uniform vec2 u_size; + uniform float u_stops[MAX_STOPS]; + uniform vec4 u_colors[MAX_STOPS]; - varying vec4 v_color; - varying vec2 v_textureCoords; + varying vec4 v_color; + varying vec2 v_textureCoords; - vec2 calcPoint(float d, float angle) { - return d * vec2(cos(angle), sin(angle)) + (u_dimensions * 0.5); - } + vec2 calcPoint(float d, float angle) { + return d * vec2(cos(angle), sin(angle)) + (u_dimensions * 0.5); + } - void main() { - vec4 color = texture2D(u_texture, v_textureCoords) * v_color; - vec2 point = v_textureCoords.xy * u_dimensions; - float dist = length((point - u_projection) / u_size); - ${genGradientColors(props.stops.length)} - gl_FragColor = mix(color, colorOut, clamp(colorOut.a, 0.0, 1.0)); - } - `; + vec4 getGradientColor(float dist) { + dist = clamp(dist, 0.0, 1.0); + + if(dist <= u_stops[0]) { + return u_colors[0]; + } + + if(dist >= u_stops[LAST_STOP]) { + return u_colors[LAST_STOP]; + } + + for(int i = 0; i < LAST_STOP; i++) { + float left = u_stops[i]; + float right = u_stops[i + 1]; + if(dist >= left && dist <= right) { + float lDist = smoothstep(left, right, dist); + return mix(u_colors[i], u_colors[i + 1], lDist); + } + } + } + + void main() { + vec4 color = texture2D(u_texture, v_textureCoords) * v_color; + vec2 point = v_textureCoords.xy * u_dimensions; + float dist = length((point - u_projection) / u_size); + + vec4 colorOut = getGradientColor(dist); + gl_FragColor = mix(color, colorOut, clamp(colorOut.a, 0.0, 1.0)); + } + `; }, }; diff --git a/visual-regression/certified-snapshots/chromium-ci/shader-linear-gradient-1.png b/visual-regression/certified-snapshots/chromium-ci/shader-linear-gradient-1.png index e8b18f88..61c3e7cb 100644 Binary files a/visual-regression/certified-snapshots/chromium-ci/shader-linear-gradient-1.png and b/visual-regression/certified-snapshots/chromium-ci/shader-linear-gradient-1.png differ diff --git a/visual-regression/certified-snapshots/chromium-ci/shader-radial-gradient-1.png b/visual-regression/certified-snapshots/chromium-ci/shader-radial-gradient-1.png index c759843d..adb55191 100644 Binary files a/visual-regression/certified-snapshots/chromium-ci/shader-radial-gradient-1.png and b/visual-regression/certified-snapshots/chromium-ci/shader-radial-gradient-1.png differ