博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解决Lightmap在PC上与ios和Android上表现不同的问题
阅读量:6721 次
发布时间:2019-06-25

本文共 3252 字,大约阅读时间需要 10 分钟。

Lightmap在PC上与android和ios的区别以及解决方法

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丢掉的精度信息,算法如下:

//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在切换android或ios会自动将Lightmap_PC压缩为LDR格式,这就丢失了精度。

本文转自jiahuafu博客园博客,原文链接如需转载请自行联系原作者

jiahuafu

你可能感兴趣的文章
python datatime日期和时间值模块
查看>>
VMware 虚拟化编程(14) — VDDK 的高级传输模式详解
查看>>
讨论java中调用函数,形参的传递是值传递还是引用传递的问题
查看>>
HDFS 常用命令行:
查看>>
命名空间在扩展方法中的妙用
查看>>
企业生产环境集群稳定性-HA就行吗?
查看>>
jQuery扩展
查看>>
二叉搜索树与双向链表
查看>>
(2016-09-01)SQL批量生成随机字符串
查看>>
Can you find it?
查看>>
mysql配置文件
查看>>
解决应用服务器变为集群后的Session问题
查看>>
【BZOJ】2406 矩阵
查看>>
Tcl internal variables
查看>>
springcloud文章推荐
查看>>
java分享第十四天(TestNG Assert详解)
查看>>
一个JNI的helloworld小demo
查看>>
网络编程总结
查看>>
NIC Bonding: 2 nic port as 1 interface
查看>>
动态代理--jdk和cglib
查看>>