解决Lightmap在PC上与ios和Android上表现不同的问题
porry20009
porry20009 10415 270
精华热门加亮 Shader 着色器 2016-03-04 21:20
LightmapPC上与androidios的区别以及解决方法

1、  问题描述
相信很多人碰到过Lightmap的一些问题:
烘培好Lightmap之后,在PC上看起来相当给力,而打包成iosandroid之后,就傻眼了,Lightmap往往就出现了改变,例如灯光曝光度不够、光照颜色偏冷色调、有时候甚至黄色光也能变成绿色光等等。
2、造成LightmapPCiosandroid上表现不同的原因
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丢掉的精度信息,算法如下:
   //FP32(RGB) to LogLUV
   fixed4 EncodeLogLuv(fixed3 vRGB)
   {
       fixed3x3 M = fixed3x3(
           0.2209, 0.3390, 0.4184,
           0.1138, 0.6780, 0.7319,
           0.0102, 0.1130, 0.2969 );
       fixed4 vResult;
       fixed3 Xp_Y_XYZp = mul(vRGB,
M);
       Xp_Y_XYZp = max(Xp_Y_XYZp,
fixed3(1e-6, 1e-6, 1e-6));
       vResult.xy = Xp_Y_XYZp.xy /
Xp_Y_XYZp.z;
       fixed Le = 2 *
log2(Xp_Y_XYZp.y) + 127;
       vResult.w = frac(Le);
       vResult.z = (Le -
(floor(vResult.w*255.0f)) / 255.0f) / 255.0f;
       return vResult;

}
//LogLuv to FP32(RGB)
   fixed3 DecodeLogLuv(in fixed4 vLogLuv)
   {
       fixed3x3 InverseM = fixed3x3(
          6.0014, -2.7008, -1.7996,
          -1.3320, 3.1029, -5.7721,
          0.3008, -1.0882, 5.6268 );
       fixed Le = vLogLuv.z * 255 +
vLogLuv.w;
       fixed3 Xp_Y_XYZp;
       Xp_Y_XYZp.y = exp2((Le - 127)
/ 2);
       Xp_Y_XYZp.z = Xp_Y_XYZp.y /
vLogLuv.y;
       Xp_Y_XYZp.x = vLogLuv.x *
Xp_Y_XYZp.z;
       fixed3 vRGB = mul(Xp_Y_XYZp,
InverseM);

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

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

       }
       
//
RenderTexture保存成一张png图片
         public bool SaveRenderTextureToPNG(RenderTexture rt,string contents, string pngName)
         {
              RenderTexture prev = RenderTexture.active;
              RenderTexture.active = rt;
              Texture2D png = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
              png.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
              byte[] bytes = png.EncodeToPNG();
              if (!Directory.Exists(contents))
                   Directory.CreateDirectory(contents);
              FileStream file = File.Open(contents + "/" + pngName + ".png", FileMode.Create);
              BinaryWriter writer = new BinaryWriter(file);
              writer.Write(bytes);
              file.Close();
              Texture2D.DestroyImmediate(png);
              png = null;
              RenderTexture.active = prev;
              return true;

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

5、编写生成工具

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

图片:1.jpg



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

图片:LogLuvLightmap.png



图片:2.jpg



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

图片:新替换的Shader.png


本部分内容设定了隐藏,需要回复后才能看到
5条评分, 鲜花+512 威望+10
  • 鲜花+1
    谢谢分享
  • 鲜花+1
    好思路,谢谢分享
  • 威望+10
    很赞的工具
  • 鲜花+10
    很赞的工具
  • 鲜花500
    这篇文章好,解决常见烘焙问题。
分享:
游客
要评论请先登录 或者 注册
270条回应 只看楼主 最新
yxriyin 师者 2016-03-05 13:43 1楼
挺好的 是5.0以后的版本才有这个问题吗 以前用unity4 没怎么注意这个问题
yxriyin 师者 2016-03-05 13:50 2楼
这个是unity中国区的“专家”对这个问题的答复:
另外还有朋友曾经咨询:项目的场景在手机上的烘焙效果与Editor中看到的实时灯光的差异非常的大,已经远远比上面对比图中的差别要大了。

如果大家也有这样的问题,那么请注意:不同的屏幕对于同一种颜色的表现都会有或多或少的差别,要对比手机与电脑上看到的颜色差别不能直接进行对比,而应该让两个效果在同一个屏幕中对比。一个简单的办法是在手机中截屏然后传到电脑中进行对比。感兴趣的同学可以尝试,保证你一定会为手机与电脑屏幕的颜色解析差异感到惊讶。

楼主可以打他们的脸了
zs131420 学徒 2016-03-05 14:01 3楼
taihaole``
水木黑 新手 2016-03-05 15:37 4楼
感谢楼主  帮了我大忙
qq32026 学徒 2016-03-06 02:39 5楼
fafewfewffw
电影院吃苹果 学徒 2016-03-06 23:38 6楼
感谢楼主的分享
lrdlcl 学徒 2016-03-07 06:31 7楼
谢谢分享,真心不错
215550300 学徒 2016-03-07 09:27 8楼
学习
                                 学习
                 学习
                 学习
                 学习
leonbeyond007 学徒 2016-03-07 09:48 9楼
感谢楼主  帮了我大忙
1 2 3 4 ...28
返回顶部