- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
场景
我正在使用 unity c# 重新发明一个类似 google-earth 的项目体验。当用户在全局范围内平移相机时,会从网络异步加载新的图 block 。到目前为止,我能够加载所有 TMS tiles基于它们的 x & y 坐标和缩放级别。目前我正在使用图 block x,y 来尝试找出图 block 应该出现在我的地球“球体”上的什么位置,这变得非常乏味,我认为是因为欧拉角和四元数之间的差异。
Camera.main
的角度来确定应该随时查看哪些图 block (似乎工作正常)问题
仅使用瓷砖的 TMS 坐标 (0,0 - 63,63) 如何计算瓷砖的 xyz“地球”位置及其 xyz 旋转?
额外
Mathf.Sin
和 Mathf.Cos
来计算位置和旋转我已经弄清楚如何使图 block 位置正确。现在我被卡在正确的方 block 旋转上了。
对我帮助最大的代码是关于 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;
在添加@Ruzihm 的计算法线答案之后
添加@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。
请注意,顶点的位置是在着色器中根据纬度/经度分配的,与对象的变换无关。如果您启用了视锥体剔除(默认情况下启用),请确保网格组件(以变换为中心,您可以在场景 View 中看到的线框)在相机中可见,否则 unity 将停止渲染它~效率~。
使用此过程使用瓷砖绘制完整球体的示例:
为了快速演示,创建一个新项目,将其放在相机上,并为其分配一个具有上述着色器的 Material 和一个要平铺的纹理。
它将创建 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;
}
}
关于c# - Unity - 使用从网络加载的 64 多个单独的地球卫星图 block 完全包裹球体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70162448/
我是一名优秀的程序员,十分优秀!