码迷,mamicode.com
首页 > 其他好文 > 详细

cocos2dx spine之二 :spine变色

时间:2016-07-14 02:14:22      阅读:803      评论:0      收藏:0      [点我收藏+]

标签:

cocos2dx版本为3.10

1.具体原理和代码可以参考博文《利用shader改变图片色相Hue》,下面的代码根据该博文进行整理优化。

基本原理就是将RGB值转换为HSL值后加上输入的HSL值,再转换为RGB值。

 

2.spine变色的思路有三种:

①spine::SkeletonAnimation调用shader

②读取spine对应的atlas文件,分析该文件得到所需的png图片,将该图片读入内存,修改内存中像素颜色,然后生成texture赋值给spine中的spAtlas->pages->rendererObject

③读取spine对应的atlas文件,分析该文件得到所需的png图片,将该图片读入内存,修改内存中像素颜色,保存为新的png图片;读取atlas文件,修改里面png名字为新png图片名字,保存为新的atlas文件;spine创建时使用新的png图片和新的atlas文件;

以上三种方法都可行,但在实现过程中我选择使用了第③种方法;

第①种方法简单易用,但是打包到一些低端的android手机时发现掉帧很厉害,所以才会有第②和第③种方法。

第②种方法经过测试也是可行的,但是破坏了spine的正常创建流程,导致对源码的修改过于复杂容易导致各种问题。

第③种方法独立在正常创建spine流程之前,更稳当可控。

 

3.根据资料色相H值的范围在[0,360],饱和度S值的范围在[0,1],明度L值的范围在[0,1];在PhotoShop中(快捷键ctrl+u)可调值范围为色相H[-180,180],饱和度A[-100,100],明度I[-100,100];

所以在代码中,H值不进行转换,S值和L值都除以100;在实际测试过程中发现,PS调试出来的效果和程序得到的效果在S/L不为0的情况下还是有区别的,具体原因不懂,估计可能是算法不一致吧。

 

4.第①种方法shader

①shader代码

 1 #ifdef GL_ES
 2         precision mediump float;
 3 #endif
 4         varying vec2 v_texCoord;
 5         uniform float u_dH;
 6         uniform float u_dS;
 7         uniform float u_dL;
 8         void main() { 
 9             vec4 texColor = texture2D(CC_Texture0, v_texCoord); 
10             float r = texColor.r; 
11             float g = texColor.g; 
12             float b = texColor.b; 
13             float a = texColor.a; 
14             //convert rgb to hsl 
15             float h; 
16             float s; 
17             float l; 
18             { 
19                 float max = max(max(r, g), b); 
20                 float min = min(min(r, g), b); 
21                 //----h 
22                 if (max == min){ 
23                     h = 0.0; 
24                 } 
25                 else if (max == r&&g >= b){ 
26                     h = 60.0*(g - b) / (max - min) + 0.0; 
27                 } 
28                 else if (max == r&&g < b){ 
29                     h = 60.0*(g - b) / (max - min) + 360.0; 
30                 } 
31                 else if (max == g){ 
32                     h = 60.0*(b - r) / (max - min) + 120.0; 
33                 } 
34                 else if (max == b){ 
35                     h = 60.0*(r - g) / (max - min) + 240.0; 
36                 } 
37                 //----l 
38                 l = 0.5*(max + min); 
39                 //----s 
40                 if (l == 0.0 || max == min){ 
41                     s = 0.0; 
42                 } 
43                 else if (0.0 <= l&&l <= 0.5){ 
44                     s = (max - min) / (2.0*l); 
45                 } 
46                 else if (l > 0.5){ 
47                     s = (max - min) / (2.0 - 2.0*l); 
48                 } 
49             } 
50             //(h,s,l)+(dH,dS,dL) -> (h,s,l) 
51             h = h + u_dH; 
52             s = min(1.0, max(0.0, s + u_dS)); 
53             l = l + u_dL; 
54             //convert (h,s,l) to rgb and got final color 
55             vec4 finalColor; 
56             { 
57                 float q; 
58                 if (l < 0.5){ 
59                     q = l*(1.0 + s); 
60                 } 
61                 else if (l >= 0.5){ 
62                     q = l + s - l*s; 
63                 } 
64                 float p = 2.0*l - q; 
65                 float hk = h / 360.0; 
66                 
67                 float t[3]; 
68                 t[0] = hk + 1.0 / 3.0; 
69                 t[1] = hk; 
70                 t[2] = hk - 1.0 / 3.0;  
71                 
72                 float c[3]; 
73                 for (int i = 0; i < 3; i++){ 
74                     if (t[i] < 0.0)t[i] += 1.0; 
75                     if (t[i] > 1.0)t[i] -= 1.0; 
76                     
77                     if (t[i] < 1.0 / 6.0){ 
78                         c[i] = p + ((q - p)*6.0*t[i]); 
79                     } 
80                     else if (1.0 / 6.0 <= t[i] && t[i] < 0.5){ 
81                         c[i] = q; 
82                     } 
83                     else if (0.5 <= t[i] && t[i] < 2.0 / 3.0){ 
84                         c[i] = p + ((q - p)*6.0*(2.0 / 3.0 - t[i])); 
85                     } 
86                     else{ 
87                         c[i] = p; 
88                     }
89                 } 
90                 finalColor = vec4(c[0], c[1], c[2], a); 
91             } 
92             finalColor += vec4(u_dL, u_dL, u_dL, 0.0); 
93             gl_FragColor = finalColor; 
94         }

②调用代码

1     auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_vert, shader_content);
2     GLProgramState* glState = GLProgramState::getOrCreateWithGLProgram(glprogram);
3 
4     glState->setUniformFloat("u_dH", h);
5     glState->setUniformFloat("u_dS", s / 100);
6     glState->setUniformFloat("u_dL", l / 100);
7 
8     skeleton_animation->setGLProgramState(glState);

 

5.第③种方法创建新的png文件和atlas文件

①创建新png文件函数

  1 Image* create_new_image_hsl(Image* image, float u_dH, float u_dS, float u_dL){
  2     u_dH = u_dH;
  3     u_dS = u_dS / 100.0f;
  4     u_dL = u_dL / 100.0f;
  5 
  6     bool hasAlpha = image->hasAlpha();
  7     Texture2D::PixelFormat pixelFormat = image->getRenderFormat();
  8     int bit_per_pixel = image->getBitPerPixel(); //每像素多少位
  9     unsigned int length = image->getWidth()*image->getHeight();
 10 
 11     if (hasAlpha){
 12         //只处理了RGBA8888的格式
 13         if (pixelFormat == Texture2D::PixelFormat::RGBA8888){
 14             unsigned int* inPixel32 = (unsigned int*)image->getData();
 15             for (unsigned int i = 0; i < length; ++i, ++inPixel32)
 16             {
 17                 unsigned char cr = (*inPixel32 >> 0) & 0xFF; // R
 18                 unsigned char cg = (*inPixel32 >> 8) & 0xFF; // G
 19                 unsigned char cb = (*inPixel32 >> 16) & 0xFF; // B
 20                 unsigned char ca = (*inPixel32 >> 24) & 0xFF; // A
 21                 //透明图层不做处理
 22                 if (ca){
 23                     float r = cr*1.0f / 0xFF;
 24                     float g = cg*1.0f / 0xFF;
 25                     float b = cb*1.0f / 0xFF;
 26 
 27                     float h = 0;
 28                     float s = 0;
 29                     float l = 0;
 30                     {
 31                         float max = r > g ? r : g;
 32                         max = max > b ? max : b;
 33 
 34                         float min = r < g ? r : g;
 35                         min = min < b ? min : b;
 36 
 37                         //----h
 38                         if (max == min){
 39                             h = 0;
 40                         }
 41                         else if (max == r && g >= b){
 42                             h = 60.0f*(g - b) / (max - min);
 43                         }
 44                         else if (max == r && g < b){
 45                             h = 60.0f*(g - b) / (max - min) + 360.0f;
 46                         }
 47                         else if (max == g){
 48                             h = 60.0f*(b - r) / (max - min) + 120.0f;
 49                         }
 50                         else if (max == b){
 51                             h = 60.0f*(r - g) / (max - min) + 240.0f;
 52                         }
 53                         //----l
 54                         l = 0.5f*(max + min);
 55                         //----s
 56                         if (l == 0 || max == min){
 57                             s = 0;
 58                         }
 59                         else if (0 <= l&&l <= 0.5f){
 60                             s = (max - min) / (2.0f*l);
 61                         }
 62                         else if (l > 0.5f){
 63                             s = (max - min) / (2.0f - 2.0f*l);
 64                         }
 65                     }
 66                     //(h,s,l)+(dH,dS,dL) -> (h,s,l)
 67                     h = h + u_dH;
 68                     s = 0 > s + u_dS ? 0 : s + u_dS;
 69                     s = s < 1.0f ? s : 1.0f;
 70 
 71                     l = l + u_dL;
 72                     //convert (h,s,l) to rgb and got final color
 73 
 74                     //vec4 finalColor;                
 75                     {
 76                         float q;
 77                         if (l < 0.5f){
 78                             q = l*(1.0f + s);
 79                         }
 80                         else if (l >= 0.5f){
 81                             q = l + s - l*s;
 82                         }
 83                         float p = 2.0f*l - q;
 84                         float hk = h / 360.0f;
 85 
 86                         float t[3] = {};
 87                         t[0] = hk + 1.0f / 3.0f;
 88                         t[1] = hk;
 89                         t[2] = hk - 1.0f / 3.0f;
 90 
 91                         float c[3] = {};
 92                         for (int i = 0; i < 3; i++){
 93                             if (t[i] < 0){
 94                                 t[i] += 1.0f;
 95                             }
 96                             if (t[i] > 1.0f){
 97                                 t[i] -= 1.0f;
 98                             }
 99 
100                             if (t[i] < 1.0f / 6.0f){
101                                 c[i] = p + ((q - p)*6.0f*t[i]);
102                             }
103                             else if (1.0f / 6.0f <= t[i] && t[i] < 0.5f){
104                                 c[i] = q;
105                             }
106                             else if (0.5f <= t[i] && t[i] < 2.0f / 3.0f){
107                                 c[i] = p + ((q - p)*6.0f*(2.0f / 3.0f - t[i]));
108                             }
109                             else{
110                                 c[i] = p;
111                             }
112                         }
113                         //finalColor = vec4(c[0], c[1], c[2], a);
114 
115                         r = c[0];
116                         g = c[1];
117                         b = c[2];
118                     }
119 
120                     //finalColor += vec4(u_dL, u_dL, u_dL, 0.0);
121                     r += u_dL;
122                     g += u_dL;
123                     b += u_dL;
124 
125                     if (r > 1.0f) r = 1.0f;
126                     if (g > 1.0f) g = 1.0f;
127                     if (b > 1.0f) b = 1.0f;
128                     if (r < 0) r = 0;
129                     if (g < 0) g = 0;
130                     if (b < 0) b = 0;
131 
132                     unsigned char final_r = r * 0xFF;
133                     unsigned char final_g = g * 0xFF;
134                     unsigned char final_b = b * 0xFF;
135                     unsigned char final_a = ca;
136 
137 
138                     unsigned int val = final_a;
139                     val = val << 8;
140                     val |= final_b;
141                     val = val << 8;
142                     val |= final_g;
143                     val = val << 8;
144                     val |= final_r;
145 
146                     *inPixel32 = val;
147                 }
148             }
149         }
150     }
151 
152     return image;
153 }

 

②分析atlas文件,得到对应的png文件,并生成新png文件和atlas文件

 1 void create_new_png_atlas_hls(const std::string& atlasFile, float u_dH, float u_dS, float u_dL)
 2 {
 3     std::string atlas_file_full_name = FileUtils::getInstance()->fullPathForFilename(atlasFile);
 4     Data data = FileUtils::getInstance()->getDataFromFile(atlas_file_full_name);
 5 
 6     char* bytes = new char[data.getSize()]();
 7     memcpy(bytes, data.getBytes(), data.getSize());
 8 
 9     //遍历得到第一个‘\n‘,则是png名字
10     int start_idx = 0, end_idx = 0;
11     for (int i = 0; i < data.getSize(); ++i){
12         end_idx = i;
13 
14         if (bytes[i] == \n){
15             //判断是否png
16             int len = end_idx - start_idx;
17             if (len > 4 && bytes[end_idx - 4] == . &&
18                 (bytes[end_idx - 3] == p || bytes[end_idx - 3] == P) &&
19                 (bytes[end_idx - 2] == n || bytes[end_idx - 2] == N) &&
20                 (bytes[end_idx - 1] == g || bytes[end_idx - 1] == G)){
21 
22                 //新文件路径
23                 char sz_atlas_path[256] = {};
24                 memcpy(sz_atlas_path, atlas_file_full_name.c_str(), atlas_file_full_name.size() - 6);
25                 std::string new_atlas_path = StringUtils::format("%s_%d_%d_%d.atlas", sz_atlas_path, (int)u_dH, (int)u_dS, (int)u_dL);
26 
27                 //png的名字
28                 char png_name[256] = {};
29                 memcpy(png_name, bytes + start_idx, len - 4);
30                 std::string new_png_name = StringUtils::format("%s_%d_%d_%d.png", png_name, (int)u_dH, (int)u_dS, (int)u_dL);
31 
32                 //根据新名字生成新的atlas文件
33                 unsigned char* new_atlas_content = new unsigned char[data.getSize() + new_png_name.size()]();
34                 int len = 0;
35                 memcpy(new_atlas_content, bytes, start_idx);
36                 len += start_idx;
37                 memcpy(new_atlas_content + len, new_png_name.c_str(), new_png_name.size());
38                 len += new_png_name.size();
39                 if (end_idx < data.getSize()){
40                     memcpy(new_atlas_content + len, bytes + end_idx, data.getSize() - end_idx);
41                 }
42                 len += (data.getSize() - end_idx);
43 
44                 Data data;
45                 data.copy(new_atlas_content, len);
46 
47                 if (!FileUtils::getInstance()->writeDataToFile(data, new_atlas_path)){
48                     cocos2d::log("save file %s error.", new_atlas_path.c_str());
49                 }
50 
51                 data.clear();
52                 delete[]new_atlas_content;
53 
54 
55                 //写入新的图片
56                 std::string png_file_full_name = FileUtils::getInstance()->fullPathForFilename(StringUtils::format("%s.png", png_name));
57                 char sz_png_path[256] = {};
58                 memcpy(sz_png_path, png_file_full_name.c_str(), png_file_full_name.size() - 4);
59                 std::string  new_png_path = StringUtils::format("%s_%d_%d_%d.png", sz_png_path, (int)u_dH, (int)u_dS, (int)u_dL);
60 
61                 Image* image = new Image();
62                 image->initWithImageFile(png_file_full_name);
63 
64                 Image* new_image = create_new_image_hsl(image, u_dH, u_dS, u_dL);
65                 if (!new_image->saveToFile(new_png_path, false)){
66                     cocos2d::log("save file %s error.", new_png_path.c_str());
67                 }
68                 delete image;
69 
70                 break;
71             }
72 
73             start_idx = i + 1;
74         }
75     }
76     delete[]bytes;
77 }

 

cocos2dx spine之二 :spine变色

标签:

原文地址:http://www.cnblogs.com/chevin/p/5668364.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!