常用图片处理算法shader版

 - by Hector

最近学习了一段时间的gles, 搜了一些photoshop的常见图片处理算法,用shader实现了一下,下面所有效果基于opengles 2.0,利用Cocosd-x 3.0引擎框架测试通过。所有算法在实际使用时,注意优化与改进。

New:后面又加了几种特效,并把刀塔传奇里面的shader也加进去了,代码是在cocos2d-x项目下开了一个branch,写在Test项目里(第一个Test就是)。如果你本地有clone, cocos2d-x的项目,加一个remote,运行即可。

branch地址:https://github.com/myourys/cocos2d-x/tree/mytest

反相(底片效果)

说明:对应ps反相操作,rgb值都取反,比如r = 1-r。效果为黑变白,白变黑。

frame shader:

    vec4 nomalColor = texture2D(CC_Texture0, v_texCoord);
    gl_FragColor = vec4(1.0 - nomalColor.r,1.0 - nomalColor.b,1.0 - nomalColor.g,1.0);

灰图

说明:灰色图片每个颜色点的rgb值是一样的,只有明暗变化,因此,综合rgb的亮度得到灰图的亮度,rgb的亮度因子是前人综合得到。

frame shader:

    vec4 v_orColor = texture2D(CC_Texture0, v_texCoord);
    float gray = dot(v_orColor.rgb, vec3(0.299, 0.587, 0.114));
    gl_FragColor = vec4(gray, gray, gray, v_orColor.a);

黑白照片

说明:黑白照片只有黑白两种颜色,求RGB平均值Avg = (R + G + B) / 3,如果Avg >= 100,则新的颜色值为R=G=B=255;如果Avg < 100,则新的颜色值为R=G=B=0;100是一个经验值,设置为128也可以,可以根据效果来调整。

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;
uniform sampler2D u_texture;

void main()
{
    vec4 color;
    color = texture2D(u_texture, v_texCoord);
    if ((color.r + color.g + color.b)/3.0 > 100.0/255.0) {
        color.rgb = vec3(1);
    }
    else{
        color.rgb = vec3(0);
    }
    gl_FragColor = vec4(color.rgb, 1);
}

浮雕

说明:用当前点的RGB值减去相邻点的RGB值并加上0.5作为新的RGB值。由于图片中相邻点的颜色值是比较接近的,因此这样的算法处理之后,只有颜色的边沿区域,也就是相邻颜色差异较大的部分的结果才会比较明显,而其他平滑区域则值都接近128左右,也就是灰色,这样就具有了浮雕效果。

ps:shader 中的参数可调节,得到更丰富的明暗变化,凹凸变化。

frame shader:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;
uniform sampler2D u_texture;
// image's size
uniform vec2 v_texSize;

void main()
{
    vec2 onePixel = vec2(1.0 / v_texSize.r, 1.0 / v_texSize.g);

    vec4 color;
    color.rgb = vec3(0.5);
    color -= texture2D(u_texture, v_texCoord - onePixel) * 5.0;
    color += texture2D(u_texture, v_texCoord + onePixel) * 5.0;

    color.rgb = vec3((color.r + color.g + color.b) / 3.0);
    gl_FragColor = vec4(color.rgb, 1);
}

平滑图像

说明:每个像素点平均上下左右和几个角的像素值,然后平均。

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;
uniform sampler2D u_texture;
// image's size
uniform vec2 v_texSize;

void main()
{
    vec2 onePixel = vec2(1.0 / v_texSize.r, 1.0 / v_texSize.g);

    vec4 nomalColor = texture2D(u_texture, v_texCoord);
    nomalColor += texture2D(u_texture, v_texCoord + vec2(onePixel.r,0));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(-onePixel.r,0));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(0,onePixel.g));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(0,-onePixel.g));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(onePixel.r,onePixel.g));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(onePixel.r,-onePixel.g));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(-onePixel.r,onePixel.g));
    nomalColor += texture2D(u_texture, v_texCoord + vec2(-onePixel.r,-onePixel.g));

    nomalColor.rgb = vec3(nomalColor.rgb / 9.0);
    gl_FragColor = vec4(nomalColor.rgb, 1);
}

曝光效果

说明:逆转值小于128的R、G、B分量值,产生正片和负片混合的效果。

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;
uniform sampler2D u_texture;

void main()
{
    vec4 color= texture2D(u_texture, v_texCoord);
    if (color.r < 128.0/255.0) {
        color.r = 1.0- color.r;
    }
    if (color.g < 128.0/255.0) {
        color.g = 1.0- color.g;
    }
    if (color.b < 128.0/255.0) {
        color.b = 1.0- color.b;
    }

    gl_FragColor = vec4(color.rgb, 1);
}

霓虹效果

说明:用来描绘图像的轮廓,勾画颜色变化的边缘,加强其过度效果,产生轮廓发光的效果。计算方式是将原图像当前像素的R、G、B分量与其右方和下方像素做梯度运算(差的平方和的平方根)。

frame shader:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;
uniform sampler2D u_texture;
// image's size
uniform vec2 v_texSize;

void main()
{
    vec2 onePixel = vec2(1.0 / v_texSize.r, 1.0 / v_texSize.g);

    vec4 color = texture2D(u_texture, v_texCoord);
    vec4 colorRight = texture2D(u_texture, v_texCoord + vec2(0,onePixel.t));
    vec4 colorBottom = texture2D(u_texture, v_texCoord + vec2(onePixel.s,0));

    color.r = 3.0* sqrt( (color.r - colorRight.r) * (color.r - colorRight.r) + (color.r - colorBottom.r) * (color.r - colorBottom.r) );
    color.g = 3.0* sqrt( (color.g - colorRight.g) * (color.g - colorRight.g) + (color.g - colorBottom.g) * (color.g - colorBottom.g) );
    color.b = 3.0* sqrt( (color.b - colorRight.b) * (color.b - colorRight.b) + (color.b - colorBottom.b) * (color.b - colorBottom.b) );

    color.r >1.0 ? 1.0 : color.r;
    color.g >1.0 ? 1.0 : color.g;
    color.b >1.0 ? 1.0 : color.b;
    gl_FragColor = vec4(color.rgb, 1);
}

 

利用智能指针将非cocos2d-x对象转化为cocos2d-x对象

 - by Hector

先看代码

 

template <class T>
class WRef:public Ref
{
public:
    WRef(T* p):_p(p){};
    virtual ~WRef(){delete _p;};
    
    static WRef* Create(T* p){
        WRef* pRet = new WRef(p);
        if (pRet)
        {
            pRet->autorelease();
            return pRet;
        }
        else
        {
            delete pRet;
            pRet = NULL;
            return NULL;
        }
    };
    
    inline T* operator->() const throw() {return _p;}
    inline T* get(){return _p;};
protected:
    T* _p;
};

cocos2d-x对象都是继承自Ref这个类,拥有引用计数,并可以由自动释放池自动释放,如果非cocos2d-x类,比如你自己写的一些类,STL容器等想将其生命周期绑定到某个Node上,就没法实现了。

还有一个重要的作用是cocos的一些回调参数必须继承自Ref,想传入非Ref参数就没办法了。

利用智能指针的思想,将非cocos2d-x类封装到Ref里面,使用起来也比较简单。
比如:

//创建:
btns =new std::vector<Widget*>;
            _wgt->setUserObject(WRef<std::vector<Widget*>>::Create(btns));
//使用
auto btns = ((WRef<std::vector<Widget*>>*)_wgtPapers->getUserObject())->get();

游戏资源的脚本处理与Cocostudio二次拼图

 - by Hector

目前已通过脚本实现游戏多版本资源处理,图片自动拼图加密,资源筛选同步,Icon,Spash,音效更新替换等等,总之只需一个脚本就可以处理所有有关资源的事情。

1.Cocostudio二次拼图与加密

看下代码不难发现cocos2d-x的所有图片资源都存在Texture内存里面,framespritecache存储了plist对应的小图资源,所有plist图片包括cocostudio最终都是通过SpriteFrameCachegetSpriteFrameByName函数得到。

Cocostudio的导出文件ExportJson中存储了所用到的plist文件路径,在加载ExportJson时,首先加载Plist资源。所以我们只要保证在cocostudio加载Plist之前将Plist手动加载好Cocostudio就可以通过SpriteFrameCache找到了,至于拼图与加密直接用TexturePacker加密和拼图了。而原来ExportJson中的Plist文件路径,你可以随便换个 已有的plist路径就可以了。

2.自动拼图

TexturePacker是一个非常好的拼图工具,选择好需要拼图的目录、格式、全局加密密码后,会生成一个tps配置文件,TexturePacker有个命令行工具TexturePacker Command Tools,安装好之后就可以运行TexturePacker xxx.tps就可以自动拼图了。

3.搜索ExportJson文件并处理

利用find -exec cp 组合命令可以搜索设计目录下所有的ExportJson文件并拷贝出来,然后用find -exec sed 组合命令可以将ExportJson文件中Plist文件进行改名(原因见第一条内容)。

4.拼图的特殊处理

可能cocostudio有些特殊图片需要删掉(如PS生成文件也会拼图需要删掉,psd,psd.png),可以用find -exec rm删掉,或者rsync --delete同步时筛选出来。

可能一些特殊版本不需要某些资源,或者要将资源改名,可以用find -exec awk sed组合命令改名。

5.资源与游戏资源目录同步

可以用rsync与游戏资源目录进行同步,包括音效,多语言文件,Icon,Splash等等,适当加一些排除,覆盖的参数。 如果是挑选的个别资源直接cp强制覆盖也可。

6.适当为脚本添加参数

如果游戏有多个版本,为脚本添加参数,可以根据条件方便的筛选资源,特殊处理,特殊拼图等等。

五分钟让C++支持内存加密

 - by Hector

五分钟让C++支持内存加密

支持Cocos2d-x,防八门神器

内存破解无非就是通过各种方法定位到数据存到内存的位置,然后修改内存,主要方式是正常通过多次修改数据,多次筛选来定位内存地址。

所以我们保证内存里面存的是加工过的数据,并能正常存取就行了。假如我们有个数据A需要加密,我们产生一个0~0xFF的随机数R,存取时我们对A的每个字节和R进行异或操作,解密时对每个字节再进行一次异或就可以得到原来的数据了。
因此我们定一个数据结构,保存的是加密后的A和随机数R。

为了方便程序使用,我们可以定义一个模板类,然后重载其常用的运算符,这样原有的程序只需要将数据类型(int,float,double)改为加密的数据类型就可以了。

如果你觉得还不安全,你可以定期修改下内存位置。。。。