Това е малко сложно, но се свежда до доста прост проблем, надявам се. И така, ето как става: използвам Unity, за да генерирам обект на карта на игра по време на изпълнение от bsp файл, който има цял куп върхове, лица, uvs, препратки към текстури и т.н. Създадените мрежи излизат точно както трябва да бъдат и всички текстури излизат добре. Има обаче един проблем, има толкова много мрежи, създадени с толкова много материали, което води до много извиквания за изтегляне, което прави програмата бавна. Така че потърсих начин да намаля повикванията за теглене и намерих решение. Комбинирайте всички мрежи в една голяма мрежа и създайте текстурен атлас, като комбинирате всички използвани текстури. Комбинирането на мрежите работи добре и комбинирането на текстурите също излиза страхотно. Тогава се сблъсках с проблема с uv картографирането. Така че намерих решение от бялата книга на NVidia за създаване на персонализиран шейдър, който използва функцията tex2d, за да интерполира текселите от текстурата, използвайки uv позициите с техните производни. Мисля, че това щеше да свърши работа, но моите мрежи имат наистина странни триъгълници и мисля, че съсипват това решение. В изображенията по-долу можете да видите разликата, когато мрежите са комбинирани и когато са отделни:
Комбинирани мрежи с променени UV и персонализиран шейдър
Това е кодът, който използвам в шейдъра, за да задам цвета на модела:
o.Albedo = tex2D (_MainTex, IN.uv2_BlendTex, ddx(IN.uv_MainTex), ddy(IN.uv_MainTex)).rgb;
Както можете да видите, добавих втори UV, който е версията без плочки на оригиналния UV. Правя това, като използвам функцията frac(), но в C# кода, а не в шейдъра. Тъй като текстурите могат да бъдат с различни размери, трябваше да изчисля UV, преди да стигна до шейдъра, защото имам достъп до размерите на текстурата по това време.
Ето кода, който използвах за изчисляване на 2 UV:
Rect surfaceTextureRect = uvReMappers[textureIndex];
Mesh surfaceMesh = allFaces[i].mesh;
Vector2[] atlasTiledUVs = new Vector2[surfaceMesh.uv.Length];
Vector2[] atlasClampedUVs = new Vector2[surfaceMesh.uv.Length];
for (int j = 0; j < atlasClampedUVs.Length; j++)
{
Vector2 clampedUV = new Vector2((surfaceMesh.uv[j].x - Mathf.Floor(surfaceMesh.uv[j].x)), (surfaceMesh.uv[j].y - Mathf.Floor(surfaceMesh.uv[j].y)));
float atlasClampedX = (clampedUV.x * surfaceTextureRect.width) + surfaceTextureRect.x;
float atlasClampedY = (clampedUV.y * surfaceTextureRect.height) + surfaceTextureRect.y;
atlasTiledUVs[j] = new Vector2((surfaceMesh.uv[j].x * surfaceTextureRect.width) + surfaceTextureRect.x, (surfaceMesh.uv[j].y * surfaceTextureRect.height) + surfaceTextureRect.y);
atlasClampedUVs[j] = new Vector2(atlasClampedX, atlasClampedY);
if (i < 10) { Debug.Log(i + " Original: " + surfaceMesh.uv[j] + " ClampedUV: " + clampedUV); }
}
surfaceMesh.uv = atlasTiledUVs;
surfaceMesh.uv2 = atlasClampedUVs;
Масивът uvReMappers е масив от Rect, създаден при използване на функцията Texture2D PackTextures().
Съжалявам, че отнех толкова време, но ето го въпросът ми: Защо текстурите излизат изкривени. Дали защото начинът, по който мрежите са триъгълни, или е заради начина, по който написах персонализирания шейдър. И накрая как мога да го поправя.
Благодаря ви за отделеното време. Съжалявам, че пиша толкова много, но никога досега не съм публикувал въпрос. Винаги намирам отговори на почти всичките си проблеми онлайн, но от дни търся как да разреша този проблем. Чувствам, че може да е твърде конкретно, за да мога да намеря отговор. Надявам се да съм дал достатъчно информация.