我以前做了几个实验,以找到绘制大规模六边形网格的最佳方法。
我尝试使用three.line
、three.linesegments
绘制hexes。它在小网格中工作得很好,但如果我在一个网格中有超过1000+的单元格,fps就开始很难下降。
所以我想出了这个想法,将纹理(包含六边形网格模式)应用到一个简单的平面上。我只需要设置纹理的repeat()
函数来指定垂直和水平执行多少次重复。
window.onload = function() {
var renderer, camera, scene, controls, all_loaded = false, controls, tiles = {};
var imgDataURI = "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAGgAAABaCAYAAABUrhMHAAAFhklEQVR4Xu2dT2gcdRTH34tpLS2Ipx70VkFRmpLZnlRSK+6MIkIqmIvFYnfWqgc9FBQFq2C9WKHoyT/spFKplwgmIKI7q9YG9ZSdpSmWCvamh55ESaltuk9+kU12k2x2fr/f/N5OlrenkJ3ve2++n9mZ3/x+O28x9L0fojh5GAbg9VxQ+L5JhIOyP+Wg8BYKoPwemQIov2yWKhNAAojXAbkG8fqtnU0AaVvGKxBAvH5rZxNA2pbxCgQQr9/a2QSQtmW8AgHE67d2NgGkbRmvQADx+q2dbSABlQLv4mQ1uVfbjRwKyn7hVwKCKE7uy2F52iWFgTeNYeD9A0RXbtx6dd/pr377QztKDgSlB++5A7fvmEWgnaocArxCVxfGJn+69GcOytMu4dATd9+55d/t5wBxJyp16HsfAeIRbNJ3lVria0fsoyD0C98CkI8AH1fi5EVVStn3PiSA5wEwjuL6o30sTzt1uejFNISPANEnUZy8sASo9Qr90VlAfACaeDKq1V/Rjs4oKBcLJ2AIjhI1f4nixth6qdX+IA7dD004WanVX2UsTztVWCy8B0N0FIh+bt+fDkAq6qGx3Xu2btvyNQHsAKTDUbUxrZ3NoaBcHB0nxE8RYIHw5mNR9fyFjdKFwZ7dSLd8o/YHiZ6t1BozDsvTDh0GoweQ8BQALFy/duPx07MXzrcHWQOo9eaRwHv5JuG7QHT598Vk79mzcE07e4aCiQnYettfXgKAuwCar0Vx4wOd8KXAewkJTwDQ5b9vT7ypKbiuo8962/37Ydtdw94cIO5Car5eqTXeXy9HV0DLp73AO4OETwPSTKWaHMi60DTxwmLhS0AaR8Azlbj+TBpNt23KfuEzAjoIhDNRrf6kTSxTbTnwpoFwnJA+j6rJwY3i9ATUEpcCbw4JRwjo+GScHDctTkcXFr03EPFNQJqvVJO9Otpe25YDbw7U/hC9HdWSd3ptn8X7Jd87hoDHCGl+MuX+pAakCjzsjzw0hMNT6u8mLU6ciud/zKLw1THCYGQfwPAX//9/8amoOn9uM+ex8U0L0PKnyeBISGtwP45sl59U2zOPEaCW2Trn0l6A8nBtyPJaF2Z07bYCpExPOxrpBihvoyvb0WLWo19rQCujvY3H82uvM/m+P9G933J1/5gZoGVQXe6I2wFtpjv8tDMWrmZgMge0fH1aNaek/r+Z58jWm/PjmMN0BkgB6ZiVpc0/y9w+a07KOYZVAKeAVkZ7hYtERIOyTqPWnZpIyLGOxgJo0FY6OfdHAPW6QVvnfQFkYBqnRABxum2QSwAZmMYpEUCcbhvkEkAGpnFKBBCn2wa5BJCBaZwSAcTptkEuAWRgGqdEAHG6bZBLABmYxikRQJxuG+QSQAamcUoEEKfbBrkEkIFpnBIBxOm2QS4BZGAap0QAcbptkEsAGZjGKRFAnG4b5BJABqZxSgQQp9sGuQSQgWmcEgHE6bZBLgFkYBqnRABxum2Qa+AAlQP58rzBcbAkcfrdbHn8xBTLis4ZoNVNgVRKeYBLH1jmgLo1BWovTR6BTA8qM0C9mgKtLinvTY4G5iFieQy/89DL1WP40sii+6mqr40sTJoCpT3rSiuYTqe0rkE2TYHSAlLbSTMlg2G2bVMgHUCtbV02OerHJ9XkzNPzE5TVudQE0Aooaei3xr+sRyM2gJTWtslR3po2pR39SlNZ2yPHUt/r/lHaMlsanJV8w7bMHE2BstqRNTMSg97YXH4awNWhYx63YxVAflzD3EjXSrWOJj8V7dpli/hq5VYAWRjoWiqAXDtsGV8AWRroWi6AXDtsGV8AWRroWi6AXDtsGV8AWRroWi6AXDtsGV8AWRroWi6AXDtsGV8AWRroWi6AXDtsGV8AWRroWq4A/QeCYJEAFo/atwAAAABJRU5ErkJggg=="
function initRenderer(){
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.setClearColor(0x264d73, 1);
}
function initScene(){
scene = new THREE.Scene();
//scene.fog = new THREE.Fog( 0x264d73, 500, 900 )
}
function initCamera(){
camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 1, 10000 );
camera.position.set( 0.0, 211 ,40 );
camera.lookAt(scene.position);
scene.add(camera);
controls = new THREE.OrbitControls( camera );
}
function initLights(){
var aLight = new THREE.AmbientLight(0xD0D0D0, 0.5);
scene.add(aLight);
}
////// Initializers ////////////////////////
var Cell = function( q, r, s ){
this.q = q;
this.r = r;
this.s = s;
this.h = 0;
this._hashID = this.q+"."+this.r+"."+this.s;
};
Cell.prototype.constructor = Cell;
function cellToPixel ( layout, cell ){ //// point ///
var M = layout.orientation;
var v = new THREE.Vector3();
v.x = ( M.f0 * cell.q + M.f1 * cell.r ) * layout.size;
v.y = cell.h ;
v.z = ( M.f2 * cell.q + M.f3 * cell.r ) * layout.size;
return v;
};
var Tile = function( coords, layout ){
this.cell = new Cell( coords[0], coords[1], coords[2] );
this.pos = cellToPixel( layout, this.cell );
};
Tile.prototype.constructor = Tile;
function generateGrid( grid_size, cell_size , origin ){
//// set layout type ( pointy ) ///
var layout = {
orientation: {
//// forward matrix ////
f0: Math.sqrt(3.0),
f1: Math.sqrt(3.0) / 2.0,
f2: 0.0,
f3: 3.0 / 2.0,
/// reverse matrix ////
b0: Math.sqrt(3.0) / 3.0,
b1: -1.0 / 3.0,
b2: 0.0,
b3: 2.0 / 3.0,
start_angle: 0.5
},
size: cell_size,
origin: origin
}
///generate tiles ///
var r1, r2, t, q, r;
for ( q = -grid_size; q <= grid_size; q++ ) {
r1 = Math.max(-grid_size, -q - grid_size);
r2 = Math.min(grid_size, -q + grid_size);
for ( r = r1; r <= r2; r++ ) {
t = new Tile( [ q, r, -q-r ] , layout );
tiles[ t.cell._hashID ] = t;
}
}
/// hex-corners ///
var hex_corners = [], offset_x , offset_y, angle = 0;
for (var i = 0; i < 6; i++) {
angle = 2.0 * Math.PI * ( i + layout.orientation.start_angle ) / 6;
offset_x = layout.size * Math.cos( angle );
offset_y = layout.size * Math.sin( angle );
hex_corners.push( [parseFloat( offset_x.toFixed()) , parseFloat(offset_y.toFixed())] );
}
//// hex corner points ///
var points_Geo = new THREE.Geometry();
for( var t in tiles ){
for( var c = 0, c_l = hex_corners.length; c < c_l; c++ ){
points_Geo.vertices.push( new THREE.Vector3( tiles[t].pos.x + hex_corners[c][0],0, tiles[t].pos.z + hex_corners[c][1] ) );
}
}
points_Geo.mergeVertices();
var points_Mat = new THREE.PointsMaterial( { size: 3, color: 0xFFFFFF, sizeAttenuation: true, transparent: true, opacity: 1 } );
var points_Mesh = new THREE.Points( points_Geo, points_Mat );
scene.add( points_Mesh )
}
function add_plane(){
var plane, material, image = new Image(), texture = new THREE.Texture();
image.onload = function(){
texture.image = image;
texture.needsUpdate = true;
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.anisotropy = 16;
texture.repeat.set( 9.587, 11 );
console.log(texture)
material = new THREE.MeshLambertMaterial({transparent: true, emissive:0xb3cce6, color: 0xFFFFFF, opacity: 0.7, map : texture });
plane = new THREE.Mesh(new THREE.PlaneGeometry( 500, 500 ), material);
plane.rotateX( -(Math.PI/2) )
plane.position.set( -11.1,-0.1,0)
scene.add(plane);
camera.lookAt( plane );
all_loaded = true;
};
image.src = imgDataURI;
}
///// Mouse events ////////
///// Main /////////
function main(){
initRenderer(window.innerWidth, window.innerHeight );
initScene();
initCamera(window.innerWidth, window.innerHeight );
initLights();
add_plane();
generateGrid( 8, 15, {x:0, y:0, z: 0});
animate();
}
function animate(){
window.requestAnimationFrame( animate );
//if( all_loaded ){
render_all();
//}
controls.update()
}
function render_all(){
renderer.render(scene, camera);
}
main();
}
body , canvas{
width: 100%;
height: 100%;
margin:0;
padding:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/threejs/r76/three.min.js"></script>
<script src="https://dl.dropboxusercontent.com/u/3587259/Code/Threejs/OrbitControls.js"></script>
您面临的问题是由于舍入错误。计算在哪里绘制六边形的代码通常是从一个开始的偏移量开始的。借用代码形式计算随机生成的6个顶点的六边形,我可以给你提供控制台输出它是如何计算的。
由于这是动态计算的,存在舍入错误,浏览器必须指示显示器在某个地方绘制它,显示器将它交给显卡,显卡决定哪个像素将实际绘制线条。
js lang-js prettyprint-override">var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// draw your original hexagon
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(30,-50);
ctx.lineTo(83,-50);
ctx.lineTo(113,0);
ctx.lineTo(83,50);
ctx.lineTo(30,50);
ctx.closePath();
ctx.lineWidth=3;
ctx.stroke();
// same hexagon using drawHexagon()
ctx.strokeStyle='red';
ctx.lineWidth=1;
drawHexagon(0,0,113/2);
function drawHexagon(leftX,middleY,radius){
var centerX=leftX+radius;
var centerY=middleY;
ctx.beginPath();
ctx.moveTo (centerX+radius*Math.cos(0), centerY+radius*Math.sin(0));
for (var i=1; i<=6;i++) {
console.log("FLoaty coordinates, not absolute pixel: "+(centerX+radius*Math.cos(i*2*Math.PI/6)));
ctx.lineTo(centerX+radius*Math.cos(i*2*Math.PI/6), centerY+radius*Math.sin(i*2*Math.PI/6));
}
ctx.closePath();
ctx.stroke();
}
drawHexagon(0,100,113/2);
drawHexagon(0,200,113/2);
body{ background-color: ivory; padding:10px; }
canvas{border:1px solid red;}
<h4>Fn() to draw hexagon with specified radius and left-midpoint.</h4>
<canvas id="canvas" width=300 height=300></canvas>
我似乎在绘制正确的十六进制网格时遇到了一点麻烦: 正如您所看到的,六边形只是稍微不对齐,尽管我相信我的数学是正确的(其中一些可以通过http://www.redblobgames.com/grids/hexagons/进行验证)。 我的绘制方法是从左上六边形(第一行的第一个瓷砖)开始,绘制那一行瓷砖。然后对于下一行,有一个负X偏移量和正Y偏移量等,直到它到达中间行,在中间行X偏移量增加,直到0:
我正在绘制一个纹理四边形,但使用的纹理是以前绑定的纹理,即使我试图绑定一个新纹理。 在GuiHandler中创建纹理。Java语言 渲染代码 有人知道为什么使用先前绑定的纹理而不是正确的纹理吗?P、 我正在使用LWJGL
这更多的是一个方法问题,而不仅仅是技术问题。 我有一个生成的球体,分解成六边形作为一个网格。每一个六边形瓷砖都是一种不同的地形,例如,山,丘陵,海洋,飞机等。我想在3D中把每一种地形类型画成几个网格的集合,代表一种相应的地形类型。 现在最大的问题是如何在运行时将地形网格调整到每个六边形面,这取决于地形类型,在运行时地形类型也会发生变化,例如,地形变形。同时,考虑到六边形并不是完全正则或相等的。 缩
问题内容: 我在本教程中使用了六边形代码,并创建了一个createHex类(我应该发布代码吗?)。链接的网页已使用以下代码通过createHex中的数学运算实际绘制六边形: 我遇到的问题是Android没有包含所有必需方法的Graphics类。我在android文档上做了大约一个半小时的钓鱼,而我发现最接近的东西是Path类,但是它没有我需要的方法。我想在顶部的链接文章中使用六边形代码,但找不到等
我试图旋转纹理时,我画他们。我认为这样做比在Paint.NET中旋转图像90度并将它们保存在不同的文件中更有意义。我查看了api文档中spritebatch绘图参数,但我就是不明白。有一堆参数,比如srcX、srcY、originX等等。我也想知道如何做同样的纹理区域。以下是api文档页面的链接:http://libgdx.badlogicgames.com/nightlies/docs/api/