module Processing # Shader object. # class Shader # Initialize shader object. # # @param vertSrc [String] vertex shader source # @param fragSrc [String] fragment shader source # def initialize(vertSrc, fragSrc) @shader = Rays::Shader.new fragSrc, vertSrc, ENV__ end # Sets uniform variables. # # @overload set(name, a) # @overload set(name, a, b) # @overload set(name, a, b, c) # @overload set(name, a, b, c, d) # @overload set(name, nums) # @overload set(name, vec) # @overload set(name, vec, ncoords) # @overload set(name, tex) # # @param name [String] uniform variable name # @param a [Numeric] int or float value # @param b [Numeric] int or float value # @param c [Numeric] int or float value # @param d [Numeric] int or float value # @param nums [Array] int or float array # @param vec [Vector] vector # @param ncoords [Integer] number of coordinates, max 4 # @param tex [Image] texture image # def setUniform(name, *args) arg = args.first case when Array === arg @shader.uniform name, *arg when Numeric === arg @shader.uniform name, *args when Vector === arg vec, ncoords = args @shader.uniform name, vec.getInternal__.to_a(ncoords || 3) when arg.respond_to?(:getInternal__) @shader.uniform name, arg.getInternal__ else raise ArgumentError end end alias set setUniform # @private def getInternal__() @shader end # @private ENV__ = { attribute_position: [:vertex, :position], attribute_texcoord: :texCoord, attribute_color: :color, varying_position: :vertPosition, varying_texcoord: :vertTexCoord, varying_color: :vertColor, uniform_position_matrix: [:transform, :transformMatrix], uniform_texcoord_matrix: :texMatrix, uniform_texcoord_min: :texMin, uniform_texcoord_max: :texMax, uniform_texcoord_offset: :texOffset, uniform_texture: [:texMap, :texture] }.freeze # @private def self.createFilter__(*args) case arg = args.shift when Shader arg when :threshold self.new(nil, <<~END).tap {|sh| sh.set :threshold, (args.shift || 0.5)} uniform float threshold; uniform sampler2D texMap; varying vec4 vertTexCoord; varying vec4 vertColor; void main() { vec4 col = texture2D(texMap, vertTexCoord.xy) * vertColor; float gray = col.r * 0.3 + col.g * 0.59 + col.b * 0.11; gl_FragColor = vec4(vec3(gray > threshold ? 1.0 : 0.0), 1.0); } END when :gray self.new nil, <<~END uniform sampler2D texMap; varying vec4 vertTexCoord; varying vec4 vertColor; void main() { vec4 col = texture2D(texMap, vertTexCoord.xy); float gray = col.r * 0.3 + col.g * 0.59 + col.b * 0.11; gl_FragColor = vec4(vec3(gray), 1.0) * vertColor; } END when :invert self.new nil, <<~END uniform sampler2D texMap; varying vec4 vertTexCoord; varying vec4 vertColor; void main() { vec4 col = texture2D(texMap, vertTexCoord.xy); gl_FragColor = vec4(vec3(1.0 - col.rgb), 1.0) * vertColor; } END when :blur self.new(nil, <<~END).tap {|sh| sh.set :radius, (args.shift || 1).to_f} #define PI 3.1415926538 uniform float radius; uniform sampler2D texMap; uniform vec3 texMin; uniform vec3 texMax; uniform vec3 texOffset; varying vec4 vertTexCoord; varying vec4 vertColor; float gaussian(vec2 pos, float sigma) { float s2 = sigma * sigma; return 1.0 / (2.0 * PI * s2) * exp(-(dot(pos, pos) / (2.0 * s2))); } void main() { float sigma = radius * 0.5; vec3 color = vec3(0.0); float total_weight = 0.0; for (float y = -radius; y < radius; y += 1.0) for (float x = -radius; x < radius; x += 1.0) { vec2 offset = vec2(x, y); float weight = gaussian(offset, sigma); vec2 texcoord = vertTexCoord.xy + offset * texOffset.xy; if ( texcoord.x < texMin.x || texMax.x < texcoord.x || texcoord.y < texMin.y || texMax.y < texcoord.y ) continue; color += texture2D(texMap, texcoord).rgb * weight; total_weight += weight; } gl_FragColor = vec4(color / total_weight, 1.0) * vertColor; } END else nil end end end# Shader end# Processing