无UV贴图技术
星球算法吧
全部回复
仅看楼主
level 5
KnIfER 楼主
大星球生成,首先有三大问题。
其一,网格生成算法。其二,碰撞如何解决。其三,材质的处理方法。
在现在我的尝试中,网格由典型的正二十面体-三角形细分法生成。将正二十面体投射到一个单位球体上面,也就是有人说的Icosphere(发明这个单词肯定是因为原来的Icosahedron太拗口了!)。初期尝试使用ProceduralMesh,发现影响帧率的主要是碰撞烘焙。把异步碰撞打开就可以了,流畅的很,可以生成更多三角形。
所以使用ProceduralMesh直接免去了更加深入的底层研究,哈哈哈。
材质么,不就是各种贴图么。大概也有人全部使用实时随机算法控制,但我认为那是没有灵魂的。
我的思路如下:
材质用数个tile+alpha遮罩的组合实现,tile又可分近、远大小不同的tile以在各个高度提供细节。同一张tile又可染上不同颜色,比如土壤tile,偏青色用于平原土壤,偏深绿色则用于森林土壤。
为了使材质与地形相符合,必须:使用高度图控制单位球体的形状,并使用与之相对应的图层遮罩控制各个tile的混合。
2019年01月30日 03点01分 1
level 5
KnIfER 楼主
一颗星球用一张大图控制材质,可能会存在分辨率不够的问题,不过暂时没得选择,就这样下去吧,相信会解决的。
具体的贴图方法:
采用等距圆柱投影(Equidistant Cylindrical Projection )将单位球体上的(x、y、z)投射为(u、v)。
公式代码如下:
float M_PI = PI;
float u = 0.5 + (atan2(n.y,n.x))/(2*M_PI);
float v = 0.5 - asin(n.z)/M_PI;
return float2(u,v);
简单高效,两级的拉伸也比较小。
材质在GPU端使用上述公式取样、混合,
而地形也使用同样的公式在Cpp代码中在CPU端对高度图采样。
(List of map projections --wikipedia)
(Equirectangular projection --wikipedia)
2019年01月30日 03点01分 2
level 5
KnIfER 楼主
2019年01月30日 03点01分 5
level 5
KnIfER 楼主
8k地球贴图:
Natural Earth III – Texture Maps -- shadedrelief网
上图我只用了2048 * 1024的
2019年01月30日 03点01分 6
level 5
KnIfER 楼主
//const FColor* data = static_cast<const FColor*>(Heightmap->PlatformData->Mips[0].BulkData.LockReadOnly());
//Heightmap->PlatformData->Mips[0].BulkData.Unlock();
md吞我帖子。高度图由于要在cpp中访问所以不要设置压缩,不要生成mipmap,否则会出现访问错误而导致引擎崩溃。
float APLOD20World::UVMapping(FVector n, const FColor* data) {
if (Heightmap) {
double u = 0.5 + (atan2(n.Y, n.X)) / (2 * M_PI);
double v = 0.5 - asin(n.Z) / M_PI;
u = FMath::Clamp(u, 0.0, 1.0);
v = FMath::Clamp(v, 0.0, 1.0);
u = u * Heightmap->GetSizeX();
v = v * Heightmap->GetSizeY();
int baseY = FMath::FloorToInt(v), baseX = FMath::FloorToInt(u);
float blendY = FMath::Frac(v);
float blendX = FMath::Frac(u);
FColor PixelColorA = data[baseY* Heightmap->GetSizeX() + baseX];
FColor PixelColorB = blendX > 0?data[baseY* Heightmap->GetSizeX() + baseX+1]: PixelColorA;
FColor PixelColorC = blendY > 0?data[(baseY+1)* Heightmap->GetSizeX() + baseX]: PixelColorA;
FColor PixelColorD = blendX > 0 && blendY>0? data[(baseY+1)* Heightmap->GetSizeX() + baseX+1] : PixelColorC;
float heightA,heightB;
heightA = PixelColorA.R * (1 - blendX) + blendX * PixelColorB.R;
heightB = PixelColorC.R * (1 - blendX) + blendX * PixelColorD.R;
return (heightA*(1- blendY)+ heightB* blendY - 128.0)/128.0;
}
return 0.f;
}
2019年01月30日 04点01分 7
level 1
看到知乎上有人用立方体映射成一个球体, 这是为什么呢? 要生成星球第一步是生成网格
2019年12月25日 11点12分 8
1