Javascript THREE.JS-展平测地多面体
我正在开发一个基于六边形瓷砖的行星生成器——想想Civ5地形投影到测地球体上 下图为该形状的上半部分: 我希望将这些单独的六边形和五边形展平成一个平面,尽管是一个不规则的平面,以便在反转变换和重组球体之前,在其上应用标准、正常的地形生成技术 我将生成两个平面,北方和南方,考虑到它本质上不可能展平任何真正的球体 然而,考虑到可以在2d空间中显示六角网格,我认为没有理由不能制作这样的网格——尽管沿五边形有一些变形 在我看来,我的步骤如下Javascript THREE.JS-展平测地多面体,javascript,three.js,3d,geodesic-sphere,Javascript,Three.js,3d,Geodesic Sphere,我正在开发一个基于六边形瓷砖的行星生成器——想想Civ5地形投影到测地球体上 下图为该形状的上半部分: 我希望将这些单独的六边形和五边形展平成一个平面,尽管是一个不规则的平面,以便在反转变换和重组球体之前,在其上应用标准、正常的地形生成技术 我将生成两个平面,北方和南方,考虑到它本质上不可能展平任何真正的球体 然而,考虑到可以在2d空间中显示六角网格,我认为没有理由不能制作这样的网格——尽管沿五边形有一些变形 在我看来,我的步骤如下 生成每个平铺,就像它自己的THREE.Object3D一样,它
# If center-point of tile is ( 0, 0, 0 ) relative to itself
# and
# Vertex with maximum x distance from center is ( x, y, z )
# then
# the x-distance from the center is x, and the y-distance is y, z-distance is z
# therefor
# I will always have two sides, the opposite and the adjacent, of any triangle I'm forming with sed point
#
# Using normal trig, I can calculate the angle
let rotationX = Math.atan( vertex.y / vertex.x )
我只是将该旋转反向应用于object3D(或者我想是内部网格?)
这一直不起作用,我无法形成这样的感觉:我至少遗漏了问题的一个关键部分。如果我在这件事上完全不对劲,我也不会感到惊讶
下一步是适当地间隔瓷砖,使其xz位置类似于2d坐标,而不是3d坐标。这一点我也不知道
我意识到这可能是毫无意义的。我想我可以简单地在球体上执行我的世界构建,但是我很难将我的思想弯曲到第三维度
代码如下
AppAbstract.js-包含场景、摄影机等
class AppAbstract {
constructor( positional, parameters ) {
this.setupScene( parameters );
};
setupScene( parameters ) {
this._scene = new THREE.Scene();
this._camera = new THREE.PerspectiveCamera( 50, 2, 1, 100000 );
this._camera.position.z = 2700;
this._camera.position.y = 0;
this._renderer = new THREE.WebGLRenderer( {
canvas: parameters[ 'canvas' ],
antialias: false,
alpha: true,
} );
this.renderer.setSize( window.innerWidth, window.innerWidth / 2 );
this.renderer.setPixelRatio( window.devicePixelRatio );
this.renderer.sortObjects = false;
window.addEventListener( 'resize', () => {
this.renderer.setSize( window.innerWidth, window.innerWidth / 2 );
}, false );
this.ambientLight = new THREE.AmbientLight( 0xffffff, 1 );
this._scene.add( this.ambientLight );
this._controls = new THREE.OrbitControls( this._camera, this._renderer.domElement );
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.1;
this.controls.rotateSpeed = 0.1;
this.controls.autoRotate = false;
this.controls.autoRotateSpeed = 0.01;
this.controls.zoomSpeed = 0.1;
};
get scene() {
return this._scene;
};
get camera() {
return this._camera;
};
get renderer() {
return this._renderer;
};
get controls() {
return this._controls;
};
};
planetap.js-
class PlanetApp extends AppAbstract {
constructor( positional, parameters ) {
super( positional, parameters );
this.planet = new Planet( this, positional, parameters );
this.scene.add( this.planet );
};
};
Planet.js
class Planet extends THREE.Object3D {
constructor( app, positional, parameters ) {
this.generateMaterials();
this.generateTiles( positional[ 0 ] );
};
generateMaterials() {
this.material = new THREE.MeshBasicMaterial( {
color: 0x6495ED,
} );
this.wireframe = new THREE.MeshBasicMaterial( {
color: 0x000000,
wireframe: true,
} );
};
generateTiles( subdivisions ) {
let hexasphere = new Hexasphere( 1000, subdivisions, 0.99 );
hexasphere.tiles.map( ( tile, index ) => {
this.tiles.push( new Tile( tile, index ) );
this.add( this.tiles[ index ] );
} );
};
}
Tile.js
class Tile extends THREE.Object3D {
constructor( tile, index ) { super();
this.index = index;
this.getCenterPoint( tile );
this.getOrdinalLatitude();
this.generateMaterials();
this.generateGeometry( tile );
this.generateObjects();
};
getCenterPoint( tile ) {
let [ xPositions, yPositions, zPositions ] = [ [], [], [] ];
for ( let index = 0; index < tile.boundary.length; index++ ) {
let vertex = tile.boundary[ index ];
xPositions.push( parseFloat( vertex.x ) );
yPositions.push( parseFloat( vertex.y ) );
zPositions.push( parseFloat( vertex.z ) );
};
let centerX = xPositions.reduce( ( a, b ) => a + b, 0 );
centerX = centerX / xPositions.length;
let centerY = yPositions.reduce( ( a, b ) => a + b, 0 );
centerY = centerY / yPositions.length;
let centerZ = zPositions.reduce( ( a, b ) => a + b, 0 );
centerZ = centerZ / zPositions.length;
this.position.set( centerX, centerY, centerZ );
};
getOrdinalLatitude() {
let boolean = this.position.y >= -10;
let ordinal = ( boolean ) ? 'northern' : 'southern';
this.ordinalLatitude = ordinal;
};
generateMaterials() {
this.material = new THREE.MeshStandardMaterial( {
color: 0x0077be,
} );
this.wireframe = new THREE.MeshStandardMaterial( {
color: 0x000000,
wireframe: true,
} );
};
generateVertices( tile ) {
this.geometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) );
tile.boundary.map( ( point, index ) => {
let xPosition = point.x - this.position.x;
let yPosition = point.y - this.position.y;
let zPosition = point.z - this.position.z;
let vertex = new THREE.Vector3(
xPosition, yPosition, zPosition
);
this.geometry.vertices.push( vertex );
} );
};
generateFaces() {
this.geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
this.geometry.faces.push( new THREE.Face3( 0, 2, 3 ) );
this.geometry.faces.push( new THREE.Face3( 0, 3, 4 ) );
this.geometry.faces.push( new THREE.Face3( 0, 4, 5 ) );
if ( this.geometry.vertices.length == 6 ) {
this.geometry.faces.push( new THREE.Face3( 0, 5, 1 ) );
};
if ( this.geometry.vertices.length == 7 ) {
this.geometry.faces.push( new THREE.Face3( 0, 5, 6 ) );
this.geometry.faces.push( new THREE.Face3( 0, 6, 1 ) );
};
};
generateGeometry( tile ) {
this.geometry = new THREE.Geometry();
this.generateVertices( tile );
this.generateFaces();
};
generateObjects( tile ) {
var mesh = new THREE.Mesh( this.geometry, this.material );
var frame = new THREE.Mesh( this.geometry, this.wireframe );
this.add( mesh ); this.add( frame );
};
normalizeLatitude() {
this.position.set( this.position.x, 0, this.position.z );
};
normalizeXRotation() {
let furthestVertex = this.geometry.vertices.reduce(
( a, b ) => a.x > b.x ? a : b
);
let radians = Math.atan( furthestVertex.z / furthestVertex.x );
this.rotateX( -radians );
};
normalizeYRotation() {
let furthestVertex = this.geometry.vertices.reduce(
( a, b ) => a.y > b.y ? a : b
);
let radians = Math.atan( furthestVertex.z / furthestVertex.y );
this.rotateY( -radians );
};
normalizeZRotation() {
let furthestVertex = this.geometry.vertices.reduce(
( a, b ) => a.z > b.z ? a : b
);
let radians = Math.atan( furthestVertex.z / furthestVertex.x );
this.rotateZ( -radians );
};
normalizeRotation() {
// this.normalizeXRotation();
// this.normalizeYRotation();
// this.normalizeZRotation();
};
};
类平铺扩展了3.Object3D{
构造函数(tile,index){super();
这个指数=指数;
此.getCenterPoint(平铺);
this.getOrdinality();
这个。生成材料();
本发明涉及发电计量学(瓷砖);
这是.generateObject();
};
getCenterPoint(平铺){
设[xPositions,yPositions,zPositions]=[[],[],[];
for(让index=0;indexa+b,0);
centerX=centerX/xPositions.length;
设centerY=yPositions.reduce((a,b)=>a+b,0);
centerY=centerY/y位置.length;
让centerZ=zPositions.reduce((a,b)=>a+b,0);
centerZ=centerZ/zPositions.length;
此.position.set(centerX、centerY、centerZ);
};
GetOrdinality(){
设布尔值=this.position.y>=-10;
设序数=(布尔)?'northern':'southern';
这个。序数=序数;
};
生成材料(){
this.material=新的3.mesh标准材质({
颜色:0x0077be,
} );
this.wireframe=新的三个.MeshStandardMaterial({
颜色:0x000000,
线框:对,
} );
};
发电机(瓷砖){
this.geometry.vertices.push(新的3.Vector3(0,0,0));
tile.boundary.map((点,索引)=>{
设xPosition=point.x—此.position.x;
让yPosition=point.y-这个.position.y;
设zPosition=point.z-此.position.z;
设顶点=新的三个。向量3(
xPosition,yPosition,zPosition
);
这个.geometry.vertex.push(顶点);
} );
};
生成(){
这个.geometry.faces.push(新的三个.Face3(0,1,2));
这个.geometry.faces.push(新的三个.Face3(0,2,3));
这个.geometry.faces.push(新的三个.Face3(0,3,4));
这个.geometry.faces.push(新的三个.Face3(0,4,5));
if(this.geometry.vertices.length==6){
这个.geometry.faces.push(新的三个.Face3(0,5,1));
};
if(this.geometry.vertices.length==7){
这个.geometry.faces.push(新的三个.Face3(0,5,6));
这个.geometry.faces.push(新的三个.Face3(0,6,1));
};
};
发电计量(瓷砖){