Unity - completely wrap sphere with 64+ individual earth-satellite tiles loaded from web(Unity-使用从Web加载的64+个单独的地球卫星瓷砖完全包裹球体)
问题描述
场景
我正在使用unity c#将类似Google-Earth的体验重新发明为一个项目。当用户在全球范围内摇摄相机时,从网络异步加载新的瓷砖。到目前为止,我可以根据TMS tiles的x&;y坐标和缩放级别加载所有的TMS tiles。目前,我正在使用瓷砖x,y来尝试计算瓷砖应该出现在我的地球上的哪个位置&球面&我想是因为欧拉角和四元数之间的不同,它变得相当单调乏味。
- 我正在使用
Camera.main
的角度来确定应该随时查看哪些磁贴(看起来工作正常) - 我必须加载/卸载分片以进行内存管理,因为级别10可以接收超过1,000,512x512个分片
- 我正在尝试将下载的磁贴的x,y坐标(2D)转换为3D位置旋转(&A;P;R)
问题
仅使用我的磁贴的TMS坐标(0,0-63,63),我如何计算磁贴的xyz地球位置及其xyz旋转?
额外
- 在所附屏幕截图中,我处于缩放级别4(64个平铺)
- y轴0是地球的底部,y轴15是顶部
- 到目前为止,我主要使用
Mathf.Sin
和Mathf.Cos
来计算位置和旋转
**编辑**
我已经想好怎么把瓷砖的位置弄对了。现在我卡在瓷砖的正确旋转上了。
通过有关generating a sphere in python的问题找到对我帮助最大的代码。
我将代码修改为如下所示:
// convenience helpers @jkr
float ti = tilesInfo["tilesXY"]; // basically the amount of tiles across either axis @jkr
float ti2 = ti / 2;
float pi = Mathf.PI;
float pi2 = pi / 2;
float pipi = pi * 2;
// position for 3d tiles @jkr
float phi = keyY / ti * pi;
float theta = keyX / ti * pipi;
x = Mathf.Sin(phi) * Mathf.Cos(theta) * ER;
y = Mathf.Sin(phi) * Mathf.Sin(theta) * ER;
z = Mathf.Cos(phi) * ER;
**编辑2**
添加@Ruzihm的答案计算法线后
**编辑3**
添加@Ruzihm的着色器之后。我继续做了一些调整,让事情变得更合适,还有很长的路要走,但至少这是一个很大的进步。
推荐答案
如果您为每个顶点指定纬度和经度,并指定球体中心和半径,则可以让着色器指定它们的位置和方向,而不是在C#中定位和定向平面:
Shader "Custom/SquareBender" {
Properties{
_MainTex("Tex", 2D) = "" {}
_SphereCenter("SphereCenter", Vector) = (0, 0, 0, 1)
_SphereRadius("SphereRadius", Float) = 5
}
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float2 uv : TEXCOORD0;
float2 lonLat : TEXCOORD1;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 norm : NORMAL;
float2 uv : TEXCOORD0;
};
float4 _SphereCenter;
float _SphereRadius;
v2f vert(appdata v)
{
v2f o;
float lon = v.lonLat.x;
float lat = v.lonLat.y;
fixed4 posOffsetWorld = fixed4(
_SphereRadius*cos(lat)*cos(lon),
_SphereRadius*sin(lat),
_SphereRadius*cos(lat)*sin(lon), 0);
float4 posObj = mul(unity_WorldToObject,
posOffsetWorld + _SphereCenter);
o.pos = UnityObjectToClipPos(posObj);
o.uv = v.uv;
o.norm = mul(unity_WorldToObject, posOffsetWorld);
return o;
}
sampler2D _MainTex;
float4 frag(v2f IN) : COLOR
{
fixed4 col = tex2D(_MainTex, IN.uv);
return col;
}
ENDCG
}
}
FallBack "VertexLit"
}
您可以将数据分配给顶点,如下所示:
// tileIndex is column/row/zoom of current tile
// uv is relative postion within tile
// (0,0) for bottom left, (1,1) top right
Vector2 GetLonLatOfVertex(Vector3Int tileIndex, Vector2 uv)
{
float lon, lat;
// Use tileIndex and uv to calculate lon, lat (in RADIANS)
// Exactly how you could do this depends on your tiling API...
return new Vector2(lon, lat);
}
// Call after plane mesh is created, and any additional vertices/uvs are set
// tileIndex is column/row/zoom of current tile
void SetUpTileLonLats(Mesh mesh, Vector3Int tileIndex)
{
Vector2[] uvs = mesh.uv;
Vector2[] lonLats= new Vector2[uvs.Length];
for (int i = 0; i < lonLats.Length; i++)
{
lonLats[i] = GetLonLatOfVertex(tileIndex, uvs[i]);
}
mesh.uv2 = lonLats;
}
平面的顶点越多,球体就会出现圆化,尽管这会导致瓷砖上的纹理发生更多扭曲。取舍取决于您。只需确保如果您按程序添加更多顶点/三角形,则为它们指定适当的UV即可。
请注意,顶点的位置是根据经度/经度在着色器中指定的,与对象的变换无关。如果启用了平锥剔除(默认情况下处于启用状态),请确保网格组件(位于变换的中心,您可以在场景视图中看到的是线框)在相机中可见,否则为了提高效率,unity将停止渲染它。使用此过程使用瓷砖绘制完整球体的示例:
若要快速演示,请创建一个新项目,将其放在相机上,并为其指定具有上述着色器的材质和要平铺的纹理。
它将创建16个具有相同图像的平面,每个平面包含45度纬度和90度经度,并将它们包裹在一个球体周围。为每个平面分配不同的图像留给读者作为练习。public class test : MonoBehaviour
{
[SerializeField] Material mat;
private void Start()
{
for (int i = 0 ; i < 16 ; i++)
{
int lonIndex = i % 4; // 0, 1, ..., 2, 3
int latIndex = i / 4 - 2; // -2, -2, ..., 1, 1
GameObject plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
plane.GetComponent<MeshRenderer>().material = mat;
Vector3Int index = new Vector3Int(lonIndex, latIndex, 0);
SetUpTileLonLats(plane.GetComponent<MeshFilter>().mesh, index);
}
}
Vector2 GetLonLatOfVertex(Vector3Int tileIndex, Vector2 uv)
{
// Reminder: tileIndex goes from (0,-2) to (3,1)
// Needs to go from (0, -.5pi) to (2pi, .5pi) depending on uv & index
float lon = (tileIndex.x + uv.x) * 0.5f * Mathf.PI;
float lat = (tileIndex.y + uv.y) * 0.25f * Mathf.PI;
return new Vector2(lon, lat);
}
void SetUpTileLonLats(Mesh mesh, Vector3Int tileIndex)
{
Vector2[] uvs = mesh.uv;
Vector2[] lonLats = new Vector2[uvs.Length];
for (int i = 0; i < lonLats.Length; i++)
{
lonLats[i] = GetLonLatOfVertex(tileIndex, uvs[i]);
}
mesh.uv2 = lonLats;
}
}
这篇关于Unity-使用从Web加载的64+个单独的地球卫星瓷砖完全包裹球体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:Unity-使用从Web加载的64+个单独的地球卫星瓷砖完全包裹球体
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
- 如何用自己压缩一个 IEnumerable 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04
- C# 中多线程网络服务器的模式 2022-01-01
- 输入按键事件处理程序 2022-01-01
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01