1. 程式人生 > >cocos2dx中用shader實現折射效果

cocos2dx中用shader實現折射效果

eight endif cocos 計算模型 for fragment ade ima 2dx

目的:給定任意法線貼圖,實現折射效果

主要技術:RenderTarget,glsl

提取出一個可供使用的Sprite派生類

計算模型如下:

技術分享

黑色部分為玻璃切線,紅色部分為場景。綠色線為垂直於場景的視線及其延長線,紅色為法線。我們求折射光,等於在給定的OB,法線向量下,求取視線經過折射後與場景的交點和視線延長線和場景交點的偏移量。求出偏移量以後,就能非常方便的利用texture2D函數采樣rendertexture,得到顏色。

假設法線向量為a,則我們容易得到x, y方向的偏移為:

deltaX = a.x * OB / a.z

deltaY = a.y * OB / a.z

由於進入fragment shader的坐標系是ndc坐標系,外部需要給shader屏幕尺寸width, height,從而得到:

deltaX(ndc) = a.x * OB / (a.z * width)

deltaY(ndc) = a.y * OB / (a.z * height)

接下來就非常簡單

gl_FragColor = texture2D(renderTarget, worldUV + deltaXY(ndc))

得到worldUV的方法:

在vertex shader中:

worldUV = MVP * position

worldUV = worldUV / worldUV.w //這個很重要,必須除了w才能得到ndc坐標,否則結果不對

worldUV = vec2((worldUV.x + 1.) * 0.5, (1. - worldUV.y) * 0.5)

所有shader代碼:

attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
#ifdef GL_ES
varying mediump vec2 v_texCoord;
varying mediump vec2 v_worldTexCoord;
varying mediump vec4 v_fragmentColor;
#else
varying vec2 v_texCoord;
varying vec2 v_worldTexCoord;
varying vec4 v_fragmentColor;
#endif

void main()
{
    gl_Position = CC_PMatrix * a_position;
    v_texCoord = a_texCoord;
    v_fragmentColor = a_color;
    v_worldTexCoord = gl_Position.xy / gl_Position.w;
    v_worldTexCoord = vec2((v_worldTexCoord.x + 1.) * 0.5, (1. - v_worldTexCoord.y) * 0.5);
}


#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
uniform vec2 u_screenExtent;
uniform sampler2D sceneTexture;
uniform vec3 u_rgbRatio;
uniform float u_height;
varying vec2 v_texCoord;
varying vec2 v_worldTexCoord;

void main()
{
    vec2 worldTex = vec2(v_worldTexCoord.x, 1. - v_worldTexCoord.y);
    vec4 normal = texture2D(CC_Texture0, v_texCoord) * 2. - vec4(1., 1., 1., 0);
    vec2 bias = vec2(u_height * normal.x / (normal.z * u_screenExtent.x), u_height * normal.y / (normal.z * u_screenExtent.y));
    vec4 frag = vec4(0.,0.,0.,0.);
    frag.r = texture2D(sceneTexture, worldTex + bias * u_rgbRatio.r).r;
    frag.g = texture2D(sceneTexture, worldTex + bias * u_rgbRatio.g).g;
    frag.b = texture2D(sceneTexture, worldTex + bias * u_rgbRatio.b).b;
    gl_FragColor = frag;
    gl_FragColor.a = 1.;
}

貼一個效果圖:

技術分享

cocos2dx中用shader實現折射效果