Shader (CMS)

From The Official Visionaire Studio: Adventure Game Engine Wiki
Revision as of 20:52, 17 August 2014 by AFRLme (talk)
Name Type By
Shader Toolkit Definition SimonS

This script offers some easy functions to use shader power. It ranges from blur, noise, saturation, contrast, lightness, colorize to some simple camera controls.

Instructions

1. Add the main script to the Visionaire Studio Script Editor & set the script as a definition script.
2. Call the functions you need.

Examples

shaderZoomCharacter("", 1.2, 3000, easeBackOut) -- Zoom 1.2x on current character in 3s with one bounce
shaderZoomObject(getObject("Objects[pole]"), 1.4, 3000, easeBounceOut)
shaderFollowCharacter("Heinz", 2, 3000) -- Follow character Heinz with a slow camera
shaderViewport(2, 300, 200, 1.41, 3000, easeBounceInOut) -- advanced zooming with rotating

shaderNoise(1, -0.1, 3000) -- activate noise in 3s with a soft black grain
shaderBlur(1, 3000) -- activate blur in 3s
shaderSaturation(0, 3000) -- desaturate image in 3s
shaderLightness(-0.5, 3000) -- darken image in 3s
shaderContrast(2, 3000) -- double contrast
shaderHue(0.5, 2000) -- turn hue wheel, red->green
shaderColorize(0, 1, 3000) -- colorize with red

Reset Values

shaderViewport(1, 0, 0, 0, 1000, easeQuintOut)
shaderStopFollow(easeQuintOut) -- Stop following character & reset viewport

shaderNoise(0, 0, 3000)
shaderBlur(0, 3000)
shaderSaturation(1, 3000)
shaderLightness(0, 3000)
shaderContrast(1, 3000)
shaderHue(0, 3000)
shaderColorize(0, 0, 3000)

Main Script

--
-- Shader Toolkit Hue, Saturation, Luminance, Blur, Noise, Camera Control
-- (c) 2014 Simon Scheckel, Visionaire Studio Engine - with edits by AFRLme
-- Version 0.71 [updated: 17/08/2014]
--
-- Matrix functions from https://github.com/davidm/lua-matrix/blob/master/lua/matrix.lua
-- Developers:    Michael Lutz (chillcode) - original author    David Manura http://lua-users.org/wiki/DavidManura
--
-- Usage:
--
-- all factors like zoom, scale are normally 1 to have no change
-- delay in ms
-- hue in 0-1 (0 = red, 0.5 = cyan, 1 = red again)
--
-- easing functions: Back, Bounce, Circ, Cubic, Elastic, Linear, None, Quad, Quint, Sine, all In/Out/InOut
-- examples: easeBackOut, easeLinearIn, easeElasticInOut etc
-- More information about that: http://easings.net
--
-- shaderZoomCharacter(name, c_scale, delay, easing)
-- shaderZoomObject(object, c_scale, delay, easing)
-- shaderFollowCharacter(name, c_scale, delay)
-- shaderStopFollow()
-- shaderViewport(zoom, x, y, rotation, delay, easing) rotation in 0-2Pi (full turn)
-- shaderPan(offset, delay, easing, axis)
-- shaderRotate(degree, delay, easing) -- degree values 0 to 359 (automatically converts value to Pi)
-- shaderZoom(zoom, delay, easing)
-- on: 1 = on, 0 = off
--
-- shaderNoise(on, strength, delay) -- strength * noise + color, so strength < 0 creates black noise and > 0 white
-- shaderBlur(strength, delay) -- strength 0.8 to 2 recommended, programmed for 1
-- shaderSaturation(factor, delay)
-- shaderLightness(offset, delay)
-- shaderContrast(contrast, delay)
-- shaderHue(target, delay)
-- shaderColorize(hue, strength, delay)
--
-- shaderActivate()
-- shaderDeactivate()
--
-- Read no further if the word matrix multiplication frightens you
--

local matrix = {_TYPE='module', _NAME='matrix', _VERSION='0.2.11.20120416'}
local matrix_meta = {}

function matrix:new( rows, columns, value )
        if type( rows ) == "table" then
                if type(rows[1]) ~= "table" then
                        return setmetatable( {{rows[1]},{rows[2]},{rows[3]}},matrix_meta )
                end
                return setmetatable( rows,matrix_meta )
        end
        local mtx = {}
        local value = value or 0
        if columns == "I" then
                for i = 1,rows do
                        mtx[i] = {}
                        for j = 1,rows do
                                if i == j then
                                        mtx[i][j] = 1
                                else
                                        mtx[i][j] = 0
                                end
                        end
                end
        else
                for i = 1,rows do
                        mtx[i] = {}
                        for j = 1,columns do
                                mtx[i][j] = value
                        end
                end
        end
        return setmetatable( mtx,matrix_meta )
end

function matrix.mul( m1, m2 )
        local mtx = {}
        for i = 1,#m1 do
                mtx[i] = {}
                for j = 1,#m2[1] do
                        local num = m1[i][1] * m2[1][j]
                        for n  = 2,#m1[1] do
                                num = num + m1[i][n] * m2[n][j]
                        end
                        mtx[i][j] = num
                end
        end
        return setmetatable( mtx, matrix_meta )
end

setmetatable( matrix, { __call = function( ... ) return matrix.new( ... ) end } )

-- End of matrix functions

function matrix.tofloat( m1 )
        local mtx = {}
        local pos = 1
        for i = 1,#m1 do
                for j = 1,#m1[1] do
                        mtx[pos] = m1[i][j]
                        pos=pos+1
                end
        end
        return mtx
end

shader = {_temporary_=0, num = shaderCompile([[#ifdef GL_ES
precision lowp float;
precision lowp int;
#endif
varying vec2 texcoord;
uniform mat4 mvp_mat;
uniform mat4 cam_mat;
attribute vec2 position;
attribute vec2 uv;
uniform int pass;
void main ()
{
  if(pass==0)
  gl_Position = mvp_mat * (cam_mat * vec4(position.x,position.y,0.0,1.0));
else
gl_Position = mvp_mat * vec4(position.x,position.y,0.0,1.0);
  texcoord = uv;
}]],[[#ifdef GL_ES
precision highp float;
precision lowp  int;
#endif

uniform sampler2D composite;
uniform int pass;
uniform float noise;
uniform float noiseFactor;
uniform float iTime;
uniform vec4 weights;
uniform vec4 shader_coeff;
varying vec2 texcoord;

void identity() {
        gl_FragColor = texture2D(composite, texcoord.st);
}

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

void blurFast(){
        vec4 sum = vec4(0.0);
        float blurSize=1.0/2048.0*(4.0-float(pass));
        sum += texture2D(composite, vec2(texcoord.x - blurSize, texcoord.y - blurSize)) * weights[0];
        sum += texture2D(composite, vec2(texcoord.x - blurSize, texcoord.y + blurSize)) * weights[0];
        sum += texture2D(composite, vec2(texcoord.x, texcoord.y)) * weights[1];
        sum += texture2D(composite, vec2(texcoord.x + blurSize, texcoord.y - blurSize)) * weights[0];
        sum += texture2D(composite, vec2(texcoord.x + blurSize, texcoord.y + blurSize)) * weights[0];
        gl_FragColor = sum;
}

vec3 rgb2hsv(vec3 c)
{
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
 
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void sat()
{
    vec4 textureColor = texture2D(composite, texcoord.st);
    vec3 fragRGB = textureColor.rgb;
    vec3 fragHSV = rgb2hsv(fragRGB);
    fragHSV.x += shader_coeff[0];
    fragHSV.y *= shader_coeff[1];
    fragHSV.z = (fragHSV.z - 0.5)*shader_coeff[2]+0.5+shader_coeff[3];
    fragRGB = hsv2rgb(fragHSV);
    fragHSV.x = weights[3];
    vec3 fragRGBC = hsv2rgb(fragHSV);
    vec4 color = vec4(mix(fragRGB, fragRGBC, weights[2]), textureColor.w);
    if(noise==1.0)
                color+= noiseFactor*rand(texcoord.xy+vec2(iTime*2.0,0.0));
    gl_FragColor=color;
}
void main()
{    
if(pass==0)  
        sat();
else if(pass!=5)
        blurFast();
else
        identity();
}]])}
shader_coeff0=0
shader_coeff1=1
shader_coeff2=1
shader_coeff3=0
shader_mweight=1
shader_weight=0
shader_downsize=1
shader_colorize=0
shader_color=0
shader_iTime = 0
shader_noise=0
shader_noiseStrength=0
shader_passes=2

shader_rotate=0.0
shader_scale = 1.0
shader_offsetx = 0.0
shader_offsety = 0.0
shader_noise = 0.0
shader_follow = {on=0, name="", c_scale=1, easing = easeQuintOut, delay = 0}

c_res=game:getPoint(VGameWindowResolution)

shaderSetOptions("active",shader.num)
shaderSetOptions("downsize",1)
shaderSetOptions("passes",2)
shaderUniform("weights",{shader_weight,shader_mweight,shader_colorize,shader_color})
shaderUniform("shader_coeff",{shader_coeff0,shader_coeff1,shader_coeff2,shader_coeff3})

-- * function that stops following specified character & resets camera back to default * --
function shaderStopFollow(easing)
 shader_follow.on = 0
 shaderViewport(1, 0, 0, 0, shader_follow.delay, easing)
 unregisterEventHandler("mainLoop", "followCharacter")
end

-- * function that smoothly follows specified character * --
function shaderFollowCharacter(name, c_scale, delay)
 if name == "" then name = game:getLink(VGameCurrentCharacter):getName() end
 if shader_follow.on == 0 then registerEventHandler("mainLoop", "followCharacter") end
 shader_follow.on = 1
 shader_follow.name = name
 shader_follow.c_scale = c_scale
 shader_follow.delay = delay
end

function shaderZoomCharacter(name, c_scale, delay, easing)
        local c_position={}
        if(name=="")then
                c_position=game:getLink(VGameCurrentCharacter):getPoint(VCharacterPosition)
        else
                c_position=getObject("Characters["..name.."]"):getPoint(VCharacterPosition)
        end
        local c_scroll=game:getPoint(VGameScrollPosition)
        c_position.x=c_position.x-c_scroll.x
        c_position.y=c_position.y-c_scroll.y
        c_position.x=c_position.x-(c_res.x/c_scale/2)
        c_position.y=c_position.y-(c_res.y/c_scale/1.2)
        shaderViewport(c_scale, c_position.x, c_position.y, 0, delay, easing)
end

function shaderZoomObject(object, c_scale, delay, easing)
        local c_position={}
        c_position=object:getPoint(VObjectPosition)
        local c_scroll=game:getPoint(VGameScrollPosition)
        c_position.x=c_position.x-c_scroll.x
        c_position.y=c_position.y-c_scroll.y
        c_position.x=c_position.x-(c_res.x/c_scale/2)
        c_position.y=c_position.y-(c_res.y/c_scale/1.2)
        shaderViewport(c_scale, c_position.x, c_position.y, 0, delay, easing)
end

function shaderNoise(on, strength,delay)
        shaderUniform("noise",on)
        startTween("shader_noiseStrength", shader_noiseStrength, strength, delay,easeLinearInOut)
        shader_noise=on
end

-- * function that blurs the screen * --
function shaderBlur(strength, delay)
        if strength > 0 then
                startTween("shader_mweight",shader_mweight,0.4/strength/strength, delay,easeBackInOut)
                startTween("shader_weight", shader_weight, 0.15*strength, delay,easeBackInOut)
                startTween("shader_downsize", shader_downsize, 4*strength, delay, easeLinearInOut)
                if strength > 1.4 then shaderLightness( -(strength / 100 * strength * 4), delay) else shaderLightness(0, delay) end
                shader_passes=6
        else
                startTween("shader_mweight",shader_mweight,1, delay,easeBackInOut)
                startTween("shader_weight", shader_weight, 0, delay,easeBackInOut)
                startTween("shader_downsize", shader_downsize, 1, delay, easeLinearInOut)
                startTween("shader_passes", shader_passes, 2, delay, easeNoneInOut)
                shaderLightness(0, delay)
        end
end

function shaderSaturation(factor, delay)
        startTween("shader_coeff1",shader_coeff1,factor,delay,easeLinearInOut)
end

function shaderLightness(offset, delay)
        startTween("shader_coeff3",shader_coeff3,offset,delay,easeLinearInOut)
end

function shaderContrast(contrast, delay)
        startTween("shader_coeff2",shader_coeff2,contrast,delay,easeLinearInOut)
end

function shaderHue(target, delay)
        startTween("shader_coeff0",shader_coeff0,target,delay,easeLinearInOut)
end

function shaderColorize(hue, strength, delay)
        startTween("shader_colorize",shader_colorize,strength,delay,easeLinearIn)
        shader_color=hue
end

function shaderViewport(zoom, x, y, rotation, delay, easing)
        startTween("shader_offsetx", shader_offsetx, x, delay,easing)
        startTween("shader_offsety", shader_offsety, y, delay,easing)
        startTween("shader_scale", shader_scale, zoom, delay,easing)    
        startTween("shader_rotate", shader_rotate, rotation, delay,easing)      
end

-- * allows you to pan the camera left or right * --
function shaderPan(offset, delay, easing, axis)
 if axis then startTween("shader_offsety", shader_offsety, offset, delay, easing) else startTween("shader_offsetx", shader_offsetx, offset, delay,easing) end
end

-- * allows you to zoom the camera in or out * --
function shaderZoom(zoom, delay, easing)
 startTween("shader_scale", shader_scale, zoom, delay, easing)
end

-- * allows you to rotate the screen (w/ degree instead of pi) * --
function shaderRotate(degree, delay, easing)
 degree = (degree / 360 * 2 * 3.14) -- convert degree to pi
 startTween("shader_rotate", shader_rotate, degree, delay, easing)
end

-- * function that follows character; only active when loop enabled * --
function followCharacter()
 --if shader_follow.on == 1 then
  shaderZoomCharacter(shader_follow.name, shader_follow.c_scale, shader_follow.delay, shader_follow.easing)
 --end
end

function shaderActivate()
        shaderSetOptions("active",shader.num)
end

function shaderDeactivate()
        shaderSetOptions("active",0)
end

function shaderMain()
    shader_iTime=shader_iTime+0.0166
    if(shader_iTime>1)then
                shader_iTime=0
    end
        shaderUniform("iTime",shader_iTime*0.1)
        shaderUniform("noiseFactor",shader_noiseStrength)
        shaderUniform("weights",{shader_weight,shader_mweight,shader_colorize,shader_color})
        shaderUniform("shader_coeff",{shader_coeff0,shader_coeff1,shader_coeff2,shader_coeff3})
        shaderSetOptions("downsize",shader_downsize)
        shaderSetOptions("passes",shader_passes)

        local rot = matrix{{math.cos(shader_rotate),math.sin(shader_rotate),0,0},{-math.sin(shader_rotate),math.cos(shader_rotate),0,0},{0,0,1,0},{0,0,0,1}}
        local scale = matrix{{shader_scale,0,0,0},{0,shader_scale,0,0},{0,0,1,0},{0,0,0,1}}
        local translate = matrix{{1,0,0,0},{0,1,0,0},{0,0,1,0},{-c_res.x/2,-c_res.y/2,0,1}}
        local translate2 = matrix{{1,0,0,0},{0,1,0,0},{0,0,1,0},{c_res.x/2,c_res.y/2,0,1}}
        local translate3 = matrix{{1,0,0,0},{0,1,0,0},{0,0,1,0},{-shader_offsetx/shader_downsize,-shader_offsety/shader_downsize,0,1}}
        shaderUniform("cam_mat",matrix.tofloat(matrix.mul(matrix.mul(matrix.mul(matrix.mul(translate,rot),translate2),translate3),scale)))
end
registerEventHandler("mainLoop", "shaderMain")
shaderMain()