前言

unity加载烘培贴图是需要加载场景才可以使用,但如果项目只使用一个场景或者有许多关卡地形时,明显通过加载场景来达到更换烘培贴图的这种做法是不妥当的。而terrain地形在有些安卓机上的支持并不是很好,所以有必要把地形转为网格。庆幸的是,网上也有这方面的代码,所以借鉴了网上大神的代码,整合出一套动态加载烘培贴图与地形转网格的方案。
借鉴的网站:
http://www.xuanyusong.com/archives/3807
http://www.cnblogs.com/jietian331/p/5831062.html

一、动态加载烘培贴图。

1、烘培贴图的原理

烘培贴图实际上就是把静态物体上的阴影与光照保存成多张png贴图,并保存每个静态物体对应烘培贴图的编号、裁剪大小与裁剪偏移量。最后,静态物体与关联的裁剪纹理在shader里进行处理。

2、有用的数据

我们知道烘培以后会生成Lightmap Data Asset(5.3之前叫LightmapSnapshot)、贴图、与SkyboxProbe。实际上真正运行的时候只需要贴图以及上面说的每个静态物体对应烘培贴图的编号、裁剪大小与裁剪偏移量。所以,我们只需要把裁剪信息保存起来就可以了。

3、数据保存

我们可以使用文件来保存这些数据,但是有一种更方便的做法,也是本文用到的方法。就是通过挂载脚本,把数据存放在脚本中,在做成预置。这样的做法,就可以把数据完完整整的保存在预置里。

二、Terrain转Mesh

1、实现原理

首先我们要明白,要生成网格需要顶点、三角面,如果有贴图光照还需要uv和发现。明白了这点,我们就可以从这几个方向下手。只要获取到地图的宽高作为行与列,用行与列对应的点作为x与z坐标,再根据此点获取地形高度作为z坐标,就可以生成顶点,再根据顶点来连接三角面。uv坐标也类似,只是把范围缩放到0与1。

2、有用的数据

生成地形网格,我们需要保存顶点数据、瓦片贴图权重、瓦片uv坐标、光照贴图uv坐标、三角面、以及。由于与地形的光照部分直接使用烘培贴图,所以法线可以不用记录。

3、数据保存

之前曾视图使用.obj格式来保存网格数据,但是查看了一下.obj的数据格式,发现其只支持一套uv坐标,不支持多套。所以只能用上面提到的使用脚本预置来保存数据。

三、使用方法

创建一个空物体,添加PrefabLightmapData脚本,并把所有地形相关物体都放在空物体上,成为其子节点。点击Bake/Bake Prefab Lightmaps便可以。生成以后,需要运行一次才会设置材质。有个地方需要注意,由于项目出于效率的考虑,Directional Mode需要设置为Non-Directional。

四、代码

1、PrefabLightmapData.cs

#if UNITY_EDITOR
using UnityEditor;
using System.IO;
#endif
using UnityEngine;
using System.Collections.Generic;
[DisallowMultipleComponent, ExecuteInEditMode]
public class PrefabLightmapData : MonoBehaviour
{[System.Serializable]struct RendererInfo{public Renderer renderer;public int lightmapIndex;public Vector4 lightmapOffsetScale;}[System.Serializable]struct TerrainInfo{public int lightmapIndex;public Vector4 lightmapOffsetScale;}[System.Serializable]public struct FogInfo{public bool fog;public FogMode fogMode;public Color fogColor;public float fogStartDistance;public float fogEndDistance;public float fogDensity;} [SerializeField]TerrainInfo[] m_TerrainInfo;[SerializeField]RendererInfo[] m_RendererInfo;[SerializeField]Texture2D[] m_Lightmaps;[SerializeField]Texture2D[] m_Lightmaps2;[SerializeField]FogInfo m_FogInfo; const string LIGHTMAP_RESOURCE_PATH = "Assets/Resources/Lightmaps/";[System.Serializable]struct Texture2D_Remap{public int originalLightmapIndex;public Texture2D originalLightmap;public Texture2D lightmap0;public Texture2D lightmap1;}static List<Texture2D_Remap> sceneLightmaps = new List<Texture2D_Remap>();void Awake(){ApplyLightmaps(m_RendererInfo, m_TerrainInfo, m_Lightmaps, m_Lightmaps2,m_FogInfo);for (int i = 0; i < m_TerrainInfo.Length; i++){var info = m_TerrainInfo[i];TerrainToMeshData terrianMeshData = GetComponentInChildren<TerrainToMeshData>();if (terrianMeshData)terrianMeshData.setMaterial(info.lightmapIndex);}}static void ApplyLightmaps(RendererInfo[] rendererInfo, TerrainInfo[] terrainInfo, Texture2D[] lightmaps, Texture2D[] lightmaps2, FogInfo fogInfo){for (int i = 0; i < rendererInfo.Length; i++){var info = rendererInfo[i];info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;info.renderer.lightmapIndex = info.lightmapIndex;}LightmapData[] combinedLightmaps2 = new LightmapData[lightmaps.Length];for (int i = 0; i < lightmaps.Length; i++){combinedLightmaps2[i] = new LightmapData();combinedLightmaps2[i].lightmapFar = lightmaps[i];combinedLightmaps2[i].lightmapNear = lightmaps2[i];}LightmapSettings.lightmaps = combinedLightmaps2;RenderSettings.fog = fogInfo.fog;RenderSettings.fogMode = fogInfo.fogMode;RenderSettings.fogColor = fogInfo.fogColor;RenderSettings.fogStartDistance = fogInfo.fogStartDistance;RenderSettings.fogEndDistance = fogInfo.fogEndDistance;RenderSettings.fogDensity = fogInfo.fogDensity;LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional;//bool existsAlready = false;//int counter = 0;//int[] lightmapArrayOffsetIndex;//if (rendererInfo == null || rendererInfo.Length == 0)//    return;//LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional;//var settingslightmaps = LightmapSettings.lightmaps;//var combinedLightmaps = new List<LightmapData>();//lightmapArrayOffsetIndex = new int[lightmaps.Length];//for (int i = 0; i < lightmaps.Length; i++)//{//    existsAlready = false;//    for (int j = 0; j < settingslightmaps.Length; j++)//    {//        if (lightmaps[i] == settingslightmaps[j].lightmapFar)//        {//            lightmapArrayOffsetIndex[i] = j;//            existsAlready = true;//        }//    }//    if (!existsAlready)//    {//        lightmapArrayOffsetIndex[i] = counter + settingslightmaps.Length;//        var newLightmapData = new LightmapData();//        newLightmapData.lightmapFar = lightmaps[i];//        newLightmapData.lightmapNear = lightmaps2[i];//        combinedLightmaps.Add(newLightmapData);//        ++counter;//    }//}//var combinedLightmaps2 = new LightmapData[settingslightmaps.Length + counter];//settingslightmaps.CopyTo(combinedLightmaps2, 0);//if (counter > 0)//{//    for (int i = 0; i < combinedLightmaps.Count; i++)//    {//        combinedLightmaps2[i + settingslightmaps.Length] = new LightmapData();//        combinedLightmaps2[i + settingslightmaps.Length].lightmapFar = combinedLightmaps[i].lightmapFar;//        combinedLightmaps2[i + settingslightmaps.Length].lightmapNear = combinedLightmaps[i].lightmapNear;//    }//}//ApplyRendererInfo(rendererInfo, lightmapArrayOffsetIndex);//LightmapSettings.lightmaps = combinedLightmaps2;}static void ApplyRendererInfo(RendererInfo[] infos, int[] arrayOffsetIndex){for (int i = 0; i < infos.Length; i++){var info = infos[i];info.renderer.lightmapIndex = arrayOffsetIndex[info.lightmapIndex];info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;}}#if UNITY_EDITOR[MenuItem("Bake/Update Scene with Prefab Lightmaps")]static void UpdateLightmaps(){PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();foreach (var instance in prefabs){ApplyLightmaps(instance.m_RendererInfo, instance.m_TerrainInfo, instance.m_Lightmaps, instance.m_Lightmaps2, instance.m_FogInfo);}Debug.Log("Prefab lightmaps updated");}[MenuItem("Bake/Bake Prefab Lightmaps")]static void GenerateLightmapInfo(){Debug.ClearDeveloperConsole();if (Lightmapping.giWorkflowMode != Lightmapping.GIWorkflowMode.OnDemand){Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");return;}Lightmapping.Bake();string lightMapPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), LIGHTMAP_RESOURCE_PATH);if (!Directory.Exists(lightMapPath))Directory.CreateDirectory(lightMapPath);sceneLightmaps = new List<Texture2D_Remap>();//var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();var sceneName = Path.GetFileNameWithoutExtension(EditorApplication.currentScene);var resourcePath = LIGHTMAP_RESOURCE_PATH + sceneName;var scenePath = System.IO.Path.GetDirectoryName(EditorApplication.currentScene) + "/" + sceneName + "/";PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();foreach (var instance in prefabs){var gameObject = instance.gameObject;var rendererInfos = new List<RendererInfo>();var terrainInfo = new List<TerrainInfo>();var lightmaps = new List<Texture2D>();var lightmaps2 = new List<Texture2D>();GenerateLightmapInfo(scenePath, resourcePath, gameObject, rendererInfos, terrainInfo, lightmaps, lightmaps2);instance.m_RendererInfo = rendererInfos.ToArray();instance.m_Lightmaps = lightmaps.ToArray();instance.m_Lightmaps2 = lightmaps2.ToArray();instance.m_TerrainInfo = terrainInfo.ToArray();instance.m_FogInfo = new FogInfo();instance.m_FogInfo.fog = RenderSettings.fog;instance.m_FogInfo.fogMode = RenderSettings.fogMode;instance.m_FogInfo.fogColor = RenderSettings.fogColor;instance.m_FogInfo.fogStartDistance = RenderSettings.fogStartDistance;instance.m_FogInfo.fogEndDistance = RenderSettings.fogEndDistance;var targetPrefab = PrefabUtility.GetPrefabParent(gameObject) as GameObject;if (targetPrefab != null){//PrefabPrefabUtility.ReplacePrefab(gameObject, targetPrefab);}ApplyLightmaps(instance.m_RendererInfo, instance.m_TerrainInfo, instance.m_Lightmaps, instance.m_Lightmaps2, instance.m_FogInfo);}Debug.Log("Update to prefab lightmaps finished");}static void GenerateLightmapInfo(string scenePath, string resourcePath, GameObject root, List<RendererInfo> rendererInfos, List<TerrainInfo> terrainInfo, List<Texture2D> lightmaps, List<Texture2D> lightmaps2){var renderers = root.GetComponentsInChildren<Renderer>();foreach (Renderer renderer in renderers){if (renderer.lightmapIndex != -1){RendererInfo info = new RendererInfo();info.renderer = renderer;info.lightmapOffsetScale = renderer.lightmapScaleOffset;Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapFar;Texture2D lightmap2 = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapNear;int sceneLightmapIndex = AddLightmap(scenePath, resourcePath, renderer.lightmapIndex, lightmap, lightmap2);info.lightmapIndex = lightmaps.IndexOf(sceneLightmaps[sceneLightmapIndex].lightmap0);if (info.lightmapIndex == -1){info.lightmapIndex = lightmaps.Count;lightmaps.Add(sceneLightmaps[sceneLightmapIndex].lightmap0);lightmaps2.Add(sceneLightmaps[sceneLightmapIndex].lightmap1);}rendererInfos.Add(info);}}Terrain terrain = root.GetComponentInChildren<Terrain>();if (terrain != null){TerrainInfo info = new TerrainInfo();info.lightmapOffsetScale = terrain.lightmapScaleOffset;Texture2D lightmap = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapFar;Texture2D lightmap2 = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapNear;int sceneLightmapIndex = AddLightmap(scenePath, resourcePath, terrain.lightmapIndex, lightmap, lightmap2);info.lightmapIndex = lightmaps.IndexOf(sceneLightmaps[sceneLightmapIndex].lightmap0);if (info.lightmapIndex == -1){info.lightmapIndex = lightmaps.Count;lightmaps.Add(sceneLightmaps[sceneLightmapIndex].lightmap0);lightmaps2.Add(sceneLightmaps[sceneLightmapIndex].lightmap1);}terrainInfo.Add(info);//添加一个game object,挂载一个转换mesh的脚本。GameObject terrainScriptObj = GameObject.CreatePrimitive(PrimitiveType.Cube);GameObject.DestroyImmediate(terrainScriptObj.GetComponent<MeshFilter>());GameObject.DestroyImmediate(terrainScriptObj.GetComponent<MeshRenderer>());GameObject.DestroyImmediate(terrainScriptObj.GetComponent<BoxCollider>());terrainScriptObj.transform.parent = terrain.transform.parent;terrainScriptObj.transform.position = terrain.transform.position;terrainScriptObj.name = "TerrainMesh";TerrainToMeshData terrainToMesh = terrainScriptObj.AddComponent<TerrainToMeshData>();TerrainToMeshData.ConvertTerrianToMesh(terrain.gameObject);GameObject.DestroyImmediate(terrain.gameObject);} }static int AddLightmap(string scenePath, string resourcePath, int originalLightmapIndex, Texture2D lightmap, Texture2D lightmap2){int newIndex = -1;for (int i = 0; i < sceneLightmaps.Count; i++){if (sceneLightmaps[i].originalLightmapIndex == originalLightmapIndex){return i;}}if (newIndex == -1){var lightmap_Remap = new Texture2D_Remap();lightmap_Remap.originalLightmapIndex = originalLightmapIndex;lightmap_Remap.originalLightmap = lightmap;var filename = scenePath + "Lightmap-" + originalLightmapIndex;lightmap_Remap.lightmap0 = GetLightmapAsset(filename + "_comp_light.exr", resourcePath + "_light", originalLightmapIndex, lightmap);if (lightmap2 != null){lightmap_Remap.lightmap1 = GetLightmapAsset(filename + "_comp_dir.exr", resourcePath + "_dir", originalLightmapIndex, lightmap2);}sceneLightmaps.Add(lightmap_Remap);newIndex = sceneLightmaps.Count - 1;}return newIndex;}static Texture2D GetLightmapAsset(string filename, string resourcePath, int originalLightmapIndex, Texture2D lightmap){//AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);//var importer = AssetImporter.GetAtPath(filename) as TextureImporter;//importer.isReadable = true;//AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);//var assetLightmap = AssetDatabase.LoadAssetAtPath<Texture2D>(filename);//var assetPath = resourcePath + "-" + originalLightmapIndex + ".asset";//var newLightmap = Instantiate<Texture2D>(assetLightmap);//AssetDatabase.CreateAsset(newLightmap, assetPath);//newLightmap = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);//importer.isReadable = false;//AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);var assetPath = resourcePath + "-" + originalLightmapIndex + ".exr";AssetDatabase.CopyAsset(filename, assetPath);AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;importer.isReadable = true;AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);var assetLightmap = AssetDatabase.LoadAssetAtPath<Texture2D>(assetPath);importer.isReadable = false;AssetDatabase.ImportAsset(filename, ImportAssetOptions.ForceUpdate);return assetLightmap;}
#endif}

2、TerrainToMeshData.cs

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
[DisallowMultipleComponent, ExecuteInEditMode]
public class TerrainToMeshData : MonoBehaviour
{[SerializeField]Vector3[] m_Vertices;[SerializeField]Vector3[] m_Normals;    //法线可以不用,因为直接用烘培贴图。[SerializeField]Vector2[] m_Uvs;[SerializeField]Vector2[] m_Uv2s;[SerializeField]Vector4[] m_AlphasWeight;[SerializeField]int[] m_Triangles;[SerializeField]Texture2D[] m_Texture;void Start(){MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();MeshRenderer meshRender = gameObject.GetComponent<MeshRenderer>();if (meshFilter == null)meshFilter = gameObject.AddComponent<MeshFilter>();if (meshRender == null)meshRender = gameObject.AddComponent<MeshRenderer>();Mesh mesh = new Mesh();mesh.vertices = m_Vertices;mesh.uv = m_Uvs;mesh.uv2 = m_Uv2s;mesh.triangles = m_Triangles;mesh.tangents = m_AlphasWeight;//mesh.normals = m_Normals;mesh.Optimize();meshFilter.sharedMesh = mesh;}public void setMaterial(int lightMapIndex){MeshRenderer meshRender = gameObject.GetComponent<MeshRenderer>();if (meshRender == null)meshRender = gameObject.AddComponent<MeshRenderer>();var mat = new Material(Shader.Find("shader/Transparent/TerrainDiffuseLightMap"));for (int i = 0; i < m_Texture.Length; i++){//目前只支持4张贴图最多if (i > 4)break;mat.SetTexture("_Texture" + i, m_Texture[i]);}mat.SetTexture("_LightMap", LightmapSettings.lightmaps[lightMapIndex].lightmapFar);meshRender.material = mat;}public static void ConvertTerrianToMesh(GameObject _terrainObj = null){TerrainToMesh(_terrainObj);}private static void TerrainToMesh(GameObject _terrainObj){var terrainObj = _terrainObj;if (terrainObj == null){Debug.Log("terrainObj == null");}var terrain = terrainObj.GetComponent<Terrain>();if (terrain == null){Debug.Log("terrain == null");return;}var terrainData = terrain.terrainData;if (terrainData == null){Debug.Log("terrainData == null");return;}//将顶点数稀释 vertexCountScale*vertexCountScale 倍int vertexCountScale = 1;int w = terrainData.heightmapWidth;int h = terrainData.heightmapHeight;Vector3 size = terrainData.size;float[, ,] alphaMapData = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);Vector3 meshScale = new Vector3(size.x / (w - 1f) * vertexCountScale, 1, size.z / (h - 1f) * vertexCountScale);//此处有问题,若每个图片大小不一,则出问题。日后改善Vector2 uvScale = new Vector2(1f / (w - 1f), 1f / (h - 1f)) * vertexCountScale * (size.x / terrainData.splatPrototypes[0].tileSize.x);Vector2 uv2Scale = new Vector2(1f / (w - 1f), 1f / (h - 1f));w = (w - 1) / vertexCountScale + 1;h = (h - 1) / vertexCountScale + 1;Vector3[] vertices = new Vector3[w * h];Vector2[] uvs = new Vector2[w * h];Vector2[] uv2s = new Vector2[w * h];// 只支持4张图片,每个顶点每个图片所占比重Vector4[] alphasWeight = new Vector4[w * h];Vector3[] normals = new Vector3[w * h];for (int i = 0; i < w; i++){for (int j = 0; j < h; j++){int index = j * w + i;float z = terrainData.GetHeight(i * vertexCountScale, j * vertexCountScale);vertices[index] = Vector3.Scale(new Vector3(i, z, j), meshScale);uvs[index] = Vector2.Scale(new Vector2(i, j), uvScale);uv2s[index] = Vector2.Scale(new Vector2(i, j), uv2Scale);// alpha mapint i2 = (int)(i * terrainData.alphamapWidth / (w - 1f));int j2 = (int)(j * terrainData.alphamapHeight / (h - 1f));i2 = Mathf.Min(terrainData.alphamapWidth - 1, i2);j2 = Mathf.Min(terrainData.alphamapHeight - 1, j2);var alpha0 = alphaMapData[j2, i2, 0];var alpha1 = alphaMapData[j2, i2, 1];var alpha2 = alphaMapData[j2, i2, 2];var alpha3 = 0f;if (terrainData.splatPrototypes.Length > 3)alpha3 = alphaMapData[j2, i2, 3];alphasWeight[index] = new Vector4(alpha0, alpha1, alpha2, alpha3);}}/** 三角形*     b       c*      ********      *   * **      * *   **      ********     a       d*/int[] triangles = new int[(w - 1) * (h - 1) * 6];int triangleIndex = 0;for (int i = 0; i < w - 1; i++){for (int j = 0; j < h - 1; j++){int a = j * w + i;int b = (j + 1) * w + i;int c = (j + 1) * w + i + 1;int d = j * w + i + 1;triangles[triangleIndex++] = a;triangles[triangleIndex++] = b;triangles[triangleIndex++] = c;triangles[triangleIndex++] = a;triangles[triangleIndex++] = c;triangles[triangleIndex++] = d;//计算法线//var side1 = vertices[b] - vertices[a];//var side2 = vertices[c] - vertices[a];//var perp = Vector3.Cross(side1, side2);//perp /= perp.magnitude;//normals[a] = perp;}}Mesh mesh = new Mesh();mesh.vertices = vertices;mesh.uv = uvs;mesh.triangles = triangles;//这里用切线来记录,但是跟切线毛关系都没,只是为了传给shadermesh.tangents = alphasWeight;mesh.normals = normals;mesh.RecalculateNormals();mesh.Optimize();TerrainToMeshData[] prefabs = FindObjectsOfType<TerrainToMeshData>();prefabs[0].m_AlphasWeight = alphasWeight;prefabs[0].m_Texture = new Texture2D[terrainData.splatPrototypes.Length];//prefabs[0].m_Normals = mesh.normals;prefabs[0].m_Uvs = uvs;prefabs[0].m_Uv2s = uv2s;prefabs[0].m_Vertices = vertices;prefabs[0].m_Triangles = triangles;prefabs[0].transform.parent = terrainObj.transform.parent;prefabs[0].transform.position = terrainObj.transform.position;prefabs[0].gameObject.layer = terrainObj.layer;for (int i = 0; i < terrainData.splatPrototypes.Length; i++){prefabs[0].m_Texture[i] = terrainData.splatPrototypes[i].texture;}}
}

3、TerrainDiffuseLightMap.shader

// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'Shader "shader/Transparent/TerrainDiffuseLightMap" {Properties{_Texture0 ("Texture 1", 2D) = "white" {}_Texture1 ("Texture 2", 2D) = "white" {}_Texture2 ("Texture 3", 2D) = "white" {}_Texture3 ("Texture 4", 2D) = "white" {}_LightMap ("Lightmap (RGB)", 2D) = "white" {}}SubShader{Tags {"RenderType"="Opaque"}LOD 200Pass{CGPROGRAM#pragma vertex Vert#pragma fragment Frag#include "UnityCG.cginc"sampler2D _Texture0;sampler2D _Texture1;sampler2D _Texture2;sampler2D _Texture3;sampler2D _LightMap;float4 _LightMap_ST;float4 _Texture0_ST;float4 _Texture1_ST;float4 _Texture2_ST;float4 _Texture3_ST;struct VertexData{float4 Pos : POSITION;float4 Tangent : TANGENT;float2 uv : TEXCOORD0;float2 uv2 : TEXCOORD1;};struct V2F{float4 Pos : SV_POSITION;float4 color : COLOR;float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1;};V2F Vert(VertexData v){V2F o;o.Pos = mul(UNITY_MATRIX_MVP, v.Pos);o.color = v.Tangent;o.uv = v.uv;o.uv2 = v.uv2;return o;}float4 Frag(V2F i) : COLOR{float4 t0 = tex2D(_Texture0, TRANSFORM_TEX(i.uv, _Texture0));float4 t1 = tex2D(_Texture1, TRANSFORM_TEX(i.uv, _Texture1));float4 t2 = tex2D(_Texture2, TRANSFORM_TEX(i.uv, _Texture2));float4 t3 = tex2D(_Texture3, TRANSFORM_TEX(i.uv, _Texture3));fixed4 texcolor = t0 * i.color.x + t1 * i.color.y + t2 * i.color.z + t3 * i.color.w;UNITY_OPAQUE_ALPHA(texcolor.a);texcolor.rgb *= DecodeLightmap(tex2D(_LightMap, TRANSFORM_TEX(i.uv2, _LightMap)));  return texcolor;}ENDCG}} FallBack "Diffuse"
}

动态加载烘培贴图与Terrain转mesh相关推荐

  1. ECharts动态加载数据绘制折线图

    Echarts动态加载数据绘制折线图 ECharts 引入ECharts 步骤 连接数据接口,动态加载图表 动态加载数据,整体代码 折线图绘制 总结 绘制多个图表的方法 ECharts 纯Javasc ...

  2. Echarts动态加载多条折线图

    背景:动态加载多条折线图,折线图条数不确定 页面效果: 页面代码 //气象数据function serchQx(beginTime, endTime, str, parameter) {$(" ...

  3. Echarts使用及动态加载图表数据 折线图X轴数据动态加载

    Echarts简介 echarts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,来自百度...我想应该够简洁了 使用Echarts 目前,就官网的文 ...

  4. Vuforia动态加载识别图

    1.首先新建一个脚本命名为"VuforiaDefine" 用来管理模块的的一些公共定义 2.我们将识别图数据放到 persistentDataPath 目录里面 using Uni ...

  5. HelloChart框架动态加载数据

    HelloChart框架动态加载数据 之前使用MPAndroidChart做过一个动态加载数据的折线统计图,完成如下功能: 一个动态加载数据的图表,首次进入加载20条,并且视图显示在最右边,然后滑动到 ...

  6. ceisum 加载geojson,使用 Cesium 动态加载 GeoJSON 数据

    前言 需求是这样的,我需要在地图中显示 08 年到现在的地震情况,地震都是发生在具体的时间点的,那么问题就来了,如何实现地震情况按照时间动态渲染而不是一次全部加载出来. 一. 方案分析 这里面牵扯到两 ...

  7. python 爬虫 快看漫画整站爬取(解决动态加载漫画图片地址、漫画图片合成长图、图片文件排序等问题)

    运行结果: 这个是爬取的目标 爬取之后建立文件夹,合成长图之后删除文件夹 这里仅仅做几组演示, 由于合成的图片有单列长度限制,所有拆分成两列 开始: 首先打开网站,找到某个漫画,发现点鼠标右键不可以, ...

  8. echart自定义动画_ECharts使用—折线图动态加载

    最近需求中用到折线图,单线条,多线交错,之前是散点图,用的是另一个 amcharts.js,这个文档也能找的到,回归早本次重点:ECharts 一.首先引入echarts.common.min.js文 ...

  9. 【Unity】光照贴图动态加载

    一般情况下对场景进行烘焙后,其实不用关心光照贴图的加载问题,Unity会自动帮我们处理好的,比如这个测试场景,烘焙结束后,关掉烘焙灯光,运行,直接运行得到的效果就是预期这样,没有写任何代码,光照贴图就 ...

最新文章

  1. numpy使用np.argmax函数获取一维数组中最大值所在的索引(index of largest value in numpy array with np.argmax)
  2. redis的key和value限制
  3. 危!我用python克隆了女朋友的声音!
  4. linux 设备节点 驱动,【Linux驱动】自动创建设备节点
  5. 用html写出生日蛋糕,纯HTML5+CSS3制作生日蛋糕代码
  6. dataframe去重复 python_python – 在DataFrame中组合重复的列
  7. 物联网时代AMD迎来最强发展契机
  8. 深度学习实践指南(四)—— 一个典型的深度学习的实践流程
  9. JSbridge原理与实现简析
  10. https数据传输协议(安全套接字层超文本传输协议)
  11. 完美商业计划书全攻略
  12. OPPO系统推送SDK集成踩坑思路
  13. Xfire+WebService “Discarding unexpected response: HTTP/1.1 100 Continue”错误解决
  14. 无法连接wifi Wifi 6 mt7921 wireless lan card无法启用
  15. python-图片上添加字符
  16. foxmail收件箱按照每个人进行划分
  17. 数据结构与算法——左程云08
  18. python中 pip不慎卸载了,重新安装方法
  19. 【市场观点学习】【转载】市场细分
  20. 三相逆变器双pi控制器参数如何调节_电工学习笔记 - 比例谐振控制器- PR controller...

热门文章

  1. Python制作的赛车小游戏源代码,逆行飙车
  2. mysql 循环_MySQL实现for循环逐个遍历
  3. 2022年混过的那些SAP项目
  4. uboot移植到IMX6ULL平台详细过程
  5. Oracle表空间清理
  6. Python 面试实训 100 题,哪道难住了你?
  7. 学计算机的学后感,关于大学生计算机学习心得体会(精选4篇)
  8. 《关于移动游戏出版服务管理的通知》 原文
  9. 使用ESP8266信标垃圾邮件发送者来跟踪智能手机用户
  10. pip安装pytorch出现报错MemoryError