找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

查看: 146|回复: 8

[其他] 解决Lightmap在PC上与ios和Android上表现不同的问题

[复制链接]

该用户从未签到

39

主题

52

帖子

56

积分

LV.2

Rank: 2

积分
56
QQ
发表于 2016-9-22 15:26:26 | 显示全部楼层 |阅读模式
1、  问题描述
相信很多人碰到过Lightmap的一些问题:
烘培好Lightmap之后,在PC上看起来相当给力,而打包成ios或android之后,就傻眼了,Lightmap往往就出现了改变,例如灯光曝光度不够、光照颜色偏冷色调、有时候甚至黄色光也能变成绿色光等等。
2、造成Lightmap在PC、ios和android上表现不同的原因。
在u3d里,Lightmap的格式是.exr(openEXR),exr格式的储存方式是使用4*16Bit RGBA来储存数据的,即是说,它使用四个通道分别为RGB和alpha,每个通道占16位储存空间,每个像素占48位储存空间来储存数据。所以EXR格式的图片颜色值域范围就达到了[-65504,65504],远大于8bit(颜色值域[0,255],用浮点数表示就是[0,1])格式所能储存的数值范围。
但是EXR格式的Lightmap打包成 android或ios之后,就变成LDR格式(可能是单通道8bit)的了,这就丢失的很多光照信息。例如在PC上烘培出的灯光亮度值是2000,转变成LDR格式后,亮度值就变成了255,这就是为什么打包成android或ios后灯光曝光度不够、光照颜色偏冷色调的原因。
3、 解决方法。
HDR有几种比较常见的编码格式,这里用的编码格式是LogLuv,就是将RGBA_FP32bit(每个通道32bit或16bit)的数据编码到RGBA32(每个通道8bit)的图片中。LogLuv算法几乎能100%还原unity切换平台后导致Lightmap丢掉的精度信息,算法如下:
  1. //FP32(RGB) to LogLUV
  2.    fixed4 EncodeLogLuv(fixed3 vRGB)
  3.    {
  4.        fixed3x3 M = fixed3x3(
  5.            0.2209, 0.3390, 0.4184,
  6.            0.1138, 0.6780, 0.7319,
  7.            0.0102, 0.1130, 0.2969 );
  8.        fixed4 vResult;
  9.        fixed3 Xp_Y_XYZp = mul(vRGB,
  10. M);
  11.        Xp_Y_XYZp = max(Xp_Y_XYZp,
  12. fixed3(1e-6, 1e-6, 1e-6));
  13.        vResult.xy = Xp_Y_XYZp.xy /
  14. Xp_Y_XYZp.z;
  15.        fixed Le = 2 *
  16. log2(Xp_Y_XYZp.y) + 127;
  17.        vResult.w = frac(Le);
  18.        vResult.z = (Le -
  19. (floor(vResult.w*255.0f)) / 255.0f) / 255.0f;
  20.        return vResult;

  21. }
  22. //LogLuv to FP32(RGB)
  23.    fixed3 DecodeLogLuv(in fixed4 vLogLuv)
  24.    {
  25.        fixed3x3 InverseM = fixed3x3(
  26.           6.0014, -2.7008, -1.7996,
  27.           -1.3320, 3.1029, -5.7721,
  28.           0.3008, -1.0882, 5.6268 );
  29.        fixed Le = vLogLuv.z * 255 +
  30. vLogLuv.w;
  31.        fixed3 Xp_Y_XYZp;
  32.        Xp_Y_XYZp.y = exp2((Le - 127)
  33. / 2);
  34.        Xp_Y_XYZp.z = Xp_Y_XYZp.y /
  35. vLogLuv.y;
  36.        Xp_Y_XYZp.x = vLogLuv.x *
  37. Xp_Y_XYZp.z;
  38.        fixed3 vRGB = mul(Xp_Y_XYZp,
  39. InverseM);

  40. return max(vRGB, 0);
  41. }
复制代码


4、 实现步骤
1、 在PC平台烘培好光照贴图Lightmap_PC(.exr格式)。
2、 通过Lightmap_PC生成新的光照贴图Lightmap_LogLuv(.png格式,RGBA32bit,单通道是8bit)。生成过程就用上面提到的LogLuv算法进行编码。这里用GPU来进行生成,有类似GPGPU的思想。如下:

  1. //用LogLuv算法生成的Lightmap输出到temp上,然后就将temp保存到一张.png格式的图片。
  2.        public bool SaveRenderTextureToPNG(Texture inputTex,Shader outputShader, string contents, string pngName)
  3. {
  4.              RenderTexture temp = RenderTexture.GetTemporARy(inputTex.width, inputTex.height, 0, RenderTextureFormat.ARGB32);
  5.              Material mat = new Material(outputShader);
  6.              Graphics.Blit(inputTex, temp, mat);
  7.              bool ret = SaveRenderTextureToPNG(temp, contents,pngName);
  8.              RenderTexture.ReleaseTemporary(temp);
  9.              return ret;

  10.        }
  11.         
  12. //将RenderTexture保存成一张png图片
  13.          public bool SaveRenderTextureToPNG(RenderTexture rt,string contents, string pngName)
  14.          {
  15.               RenderTexture prev = RenderTexture.active;
  16.               RenderTexture.active = rt;
  17.               Texture2D png = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
  18.               png.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
  19.               byte[] bytes = png.EncodeToPNG();
  20.               if (!Directory.Exists(contents))
  21.                    Directory.CreateDirectory(contents);
  22.               FileStream file = File.Open(contents + "/" + pngName + ".png", FileMode.Create);
  23.               BinaryWriter writer = new BinaryWriter(file);
  24.               writer.Write(bytes);
  25.               file.Close();
  26.               Texture2D.DestroyImmediate(png);
  27.               png = null;
  28.               RenderTexture.active = prev;
  29.               return true;

  30.          }
复制代码


3、 用新生成的光照贴图Lightmap_LogLuv替换原来的光照贴图Lightmap_PC。因为Lightmap_PC在切换android或ios会自动将Lightmap_PC压缩为LDR格式,这就丢失了精度。

5、编写生成工具
我已经写好了一个简单的工具,可以将当前的场景下所有用Diffuse Shader的模型自动替换成新的Shader,改新的Shader将不再使用Unity原来.EXR格式的光照贴图,而是使用新生成的光照贴图。

解决Lightmap在PC上与ios和Android上表现不同的问题

解决Lightmap在PC上与ios和Android上表现不同的问题

将会在” Assets/Data/Lightmap/当前场景名字”目录下生成对应的光照贴图,如下

解决Lightmap在PC上与ios和Android上表现不同的问题

解决Lightmap在PC上与ios和Android上表现不同的问题

解决Lightmap在PC上与ios和Android上表现不同的问题

解决Lightmap在PC上与ios和Android上表现不同的问题

将当前的场景下所有用Diffuse Shader的模型自动替换成新的Shader,如下

解决Lightmap在PC上与ios和Android上表现不同的问题

解决Lightmap在PC上与ios和Android上表现不同的问题

代码链接:
链接:
游客,如果您要查看本帖隐藏内容请回复



该用户从未签到

0

主题

5

帖子

0

积分

LV.1

Rank: 1

积分
0
QQ
发表于 2016-9-22 15:41:02 | 显示全部楼层
增强现实希望发展越来越好

该用户从未签到

0

主题

5

帖子

0

积分

LV.1

Rank: 1

积分
0
发表于 2016-9-22 15:41:11 | 显示全部楼层
嗯,很不错的样子!!

该用户从未签到

2

主题

17

帖子

8

积分

LV.1

Rank: 1

积分
8
QQ
发表于 2016-9-22 20:36:18 | 显示全部楼层
看帖怎么能不会呢??

该用户从未签到

1

主题

18

帖子

5

积分

LV.1

Rank: 1

积分
5
QQ
发表于 2016-9-23 08:45:49 | 显示全部楼层
楼主写的很不错,关于AR的知识受教了

该用户从未签到

0

主题

15

帖子

0

积分

LV.1

Rank: 1

积分
0
QQ
发表于 2016-9-23 09:11:37 | 显示全部楼层
楼主辛苦了,帮楼主顶起来

该用户从未签到

2

主题

12

帖子

6

积分

LV.1

Rank: 1

积分
6
QQ
发表于 2017-11-10 09:14:12 | 显示全部楼层
竟然还有零回复,给我消失

该用户从未签到

7

主题

18

帖子

21

积分

LV.1

Rank: 1

积分
21
QQ
发表于 2017-11-30 03:57:29 | 显示全部楼层
想了解下AR增强现实的相关内容来看看

该用户从未签到

4

主题

22

帖子

12

积分

LV.1

Rank: 1

积分
12
发表于 7 天前 | 显示全部楼层
楼主辛苦了。。回帖是一种美德
您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

关闭

站长推荐上一条 /1 下一条

快速回复 返回顶部 返回列表