如何用图像绘制等距平面? [复制]
Posted
技术标签:
【中文标题】如何用图像绘制等距平面? [复制]【英文标题】:How to draw an isometric plane with images? [duplicate] 【发布时间】:2016-07-30 02:23:00 【问题描述】:我想创建等轴测图。地图存在等距矩形,如图:
我想将每个矩形表示为具有宽度和高度的二维矩形。 因此,例如,当您在编辑器中创建地图时,您可以绘制 2d 矩形,并且此创建可以转换为等距平面。 等轴测平面的宽度是从北到东南(从菱形顶部到右侧。) 高度是从北到西南。 (从上到左)
现在我有两个问题。
第一个问题
我正在画布上绘制这张等距地图,我正在使用屏幕外画布分别绘制每个平面。我想计算屏幕外画布的 2d 宽度和高度。我用这个数学来做到这一点:
var canvasWidth = Math.cos(30) * planeWidth + Math.cos(30) * planeHeight;
var canvasHeight = Math.sin(30) * planeWidth + Math.cos(30) * planeHeight;
// still remember that planeWidth and planeHeight are isometric, so oblique sides
但这并没有为我提供合适的画布尺寸。 我想知道的另一件事是用像素计算斜边是否明智。
第二个问题 我想为飞机使用“纹理”图像。所以,我有这样的图像:
我的想法是存储每个图像的斜边,例如平面的宽度和高度。 当我想用特定图像绘制平面时,我可以重复该图像。
主要目标是创建具有像素精确给定宽度和高度的等距平面。并且飞机应该具有图像作为纹理。这些图像已经是等距的,因此可以像等距瓷砖一样重复和剪裁。
我的问题: 1. 我想知道使用斜边作为宽度和高度是否明智,无论如何还是想办法继续使用 2d 尺寸不是更好吗?
在离屏画布上创建一个二维矩形,并用非等距纹理图像填充它们,然后变换该画布,这不是更聪明吗?
如果我使用斜边来表示我的平面和图像的宽度/高度,那么这些长度是真正的长度吗?它就像一个线性函数:它只是像素。每 2 个水平,1 个垂直。一个奇数表示水平,不会给出一个整数表示垂直。 (而且我认为这会给我以后带来不必要的麻烦)。
【问题讨论】:
地图是2D 2.5D 还是3D?你考虑过使用精灵吗?看看***.com/a/36454198/2521214。也不要使用sin, cos
,它们可以将舍入误差添加到最终像素输出(保持 x 不变,并将 y 除以 2)。一个好主意是将单元格/平铺/精灵大小限制为可被 2 或 4 整除以避免舍入问题。
对“重复”问题的回答没有回答这个问题,因为它没有按照这个问题的要求给出准确的等距投影(即 1 到 0.5 像素比)。跨度>
【参考方案1】:
要绘制等距平面,请使用变换矩阵设置 x 和 y 轴。
假设 x 轴沿向量 (1,0.5),y 轴沿向量 (-1,0.5),原点仍位于左上角。
这样定义的。
var xAxis =
x : 1,
y : 0.5,
var yAxis =
x : -1,
y : 0.5,
var origin =
x : 0,
y : 0,
要设置转换,只需使用
ctx.setTransform(xAxis.x, xAxis.y, yAxis.x, yAxis.y, origin.x, origin.y);
现在所有的渲染都在那个等距平面上。
您可以将轴设置为您希望的任何等距投影。我使用的那个会增加一个像素的面积。这一切都取决于 x 和 y 轴的长度和相对方向。
更新
只是出于兴趣。
由于许多等轴测投影倾向于改变每个像素的总面积,因此我包含了一个简单的计算,无论使用何种投影,都会对像素面积进行归一化。 (对于我给出的投影,它恰好是 2 的平方根的 1)
使用xAxis
和yAxis
计算该投影的像素面积
var area = (xAxis.x * ( xAxis.y + yAxis.y ) + ( xAxis.x + yAxis.x ) * yAxis.y) - (xAxis.y * ( xAxis.x + yAxis.x ) + ( xAxis.y + yAxis.y ) * yAxis.x)
面积平方根上的那个就是所需的比例
var scaleBy = 1 / Math.sqrt(area);
您可以像这样直接将其应用于轴...
xAxis.x *= scaleBy;
xAxis.y *= scaleBy;
yAxis.x *= scaleBy;
yAxis.y *= scaleBy;
ctx.setTransform(xAxis.x, xAxis.y, yAxis.x, yAxis.y, origin.x, origin.y);
或在设置转换后通过ctx.scale
应用它
ctx.setTransform(xAxis.x, xAxis.y, yAxis.x, yAxis.y, origin.x, origin.y);
ctx.scale(scaleBy, scaleBy);
示例
演示展示了这种方法的简单应用(没有像素归一化)。
var canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.position = "absolute";
canvas.style.left = "0px";
canvas.style.top = "0px";
document.body.appendChild(canvas);
function demo()
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
ctx.font = "80px arial black";
ctx.lineWidth = 8;
ctx.lineJoin = "round"
ctx.strokeStyle = "green";
ctx.fillStyle = "#aF6";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// the axis and origin
var xAxis = x : 1, y: 0.5;
var yAxis = x : -1, y: 0.5;
var origin = x : 0, y : 0;
// cludge factor dividing by two to fit the display area
ctx.setTransform(xAxis.x / 2, xAxis.y / 2, yAxis.x / 2, yAxis.y / 2, origin.x, origin.y);
// draw big text
ctx.strokeText("Isometric",ctx.canvas.width/2,0);
ctx.fillText("Isometric",ctx.canvas.width/2,0);
// half size text
ctx.font = "40px arial black";
ctx.lineWidth = "4";
ctx.strokeText("projection",ctx.canvas.width/2,60);
ctx.fillText("projection",ctx.canvas.width/2,60);
// tiny text
ctx.font = "16px arial black";
ctx.lineWidth = "3";
ctx.strokeText("using 2D context transformation",ctx.canvas.width/2,100);
ctx.fillText("using 2D context transformation",ctx.canvas.width/2,100);
// add an image to demonstrate that the project will be applied to
// anything that is rendered.
var image = new Image();
image.src = "https://i.stack.imgur.com/C7qq2.png?s=328&g=1";
image.addEventListener("load",function()
ctx.drawImage(this,ctx.canvas.width-this.width,-this.height * 1.2);
);
demo();
window.addEventListener("resize",demo);
【讨论】:
以上是关于如何用图像绘制等距平面? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何用android studio替换所有屏幕尺寸图像的可绘制图像?
急!!如何用matlab导入asc和stl格式的点云数据,并绘制图像?