Tôi đang làm việc trên một công cụ kết xuất nhỏ cho một dự án cá nhân và tôi gặp vấn đề với phần ánh xạ kết cấu của nó.
Nó dường như làm việc cho một số trường hợp, nhưng không phải cho những người khác. Ví dụ: khi một trong các đỉnh nằm phía sau máy ảnh, kết cấu sẽ bị kéo dài.
Tôi đoán rằng nó có một cái gì đó để làm với ánh xạ kết cấu không chính xác. Tôi đã thử nhiều thay đổi chủ yếu liên quan đến khoảng cách z đến máy ảnh, nhưng tôi không thể tìm thấy bất kỳ sửa chữa nhanh nào cho mã của mình.
Đây là mã của tôi để chiếu phối cảnh:
public double[] project(double x, double y, double z) {
double tx = x - camera.x;
double ty = z - camera.z;
double tz = y - camera.y;
double cx = Math.cos(camera.pitch);
double cy = Math.cos(camera.yaw);
double cz = Math.cos(camera.roll);
double sx = Math.sin(camera.pitch);
double sy = Math.sin(camera.yaw);
double sz = Math.sin(camera.roll);
double dx = cy * (sz * ty + cz * tx) - sy * tz;
double dy = sx * (cy * tz + sy * (sz * ty + cz * tx)) + cx * (cz * ty - sz * tx);
double dz = cx * (cy * tz + sy * (sz * ty + cz * tx)) - sx * (cz * ty - sz * tx);
double ez = 1.0 / Math.tan(FOV / 2.0);
double bx = ez / dz * dx;
double by = ez / dz * dy;
if (dz < 0.0) {
bx = -bx;
by = -by;
}
int px = (int) (width + bx * height) / 2;
int py = (int) (height + by * height) / 2;
return new double[] { px, py, dz };
}
và ở đây mã của tôi cho ánh xạ kết cấu:
public double[] map(double x, double y, double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3) {
double A = (x0 - x) * (y0 - y2) - (y0 - y) * (x0 - x2);
double B = ((x0 - x) * (y1 - y3) - (y0 - y) * (x1 - x3) + (x1 - x) * (y0 - y2) - (y1 - y) * (x0 - x2)) / 2.0;
double C = (x1 - x) * (y1 - y3) - (y1 - y) * (x1 - x3);
double det = A - 2.0 * B + C;
double u;
if (det == 0.0) {
u = A / (A - C);
if (Double.isNaN(u) || u < 0.0 || u > 1.0)
return null;
} else {
double u1 = ((A - B) + Math.sqrt(B * B - A * C)) / det;
boolean u1valid = !Double.isNaN(u1) && u1 >= 0.0 && 1.0 >= u1;
double u2 = ((A - B) - Math.sqrt(B * B - A * C)) / det;
boolean u2valid = !Double.isNaN(u2) && u2 >= 0.0 && 1.0 >= u2;
if (u1valid && u2valid)
u = u1 < u2 ? u2 : u1;
else if (u1valid)
u = u1;
else if (u2valid)
u = u2;
else
return null;
}
double v1 = ((1.0 - u) * (x0 - x) + u * (x1 - x)) / ((1.0 - u) * (x0 - x2) + u * (x1 - x3));
boolean v1valid = !Double.isNaN(v1) && v1 >= 0.0 && 1.0 >= v1;
double v2 = ((1.0 - u) * (y0 - y) + u * (y1 - y)) / ((1.0 - u) * (y0 - y2) + u * (y1 - y3));
boolean v2valid = !Double.isNaN(v2) && v2 >= 0.0 && 1.0 >= v2;
double v;
if (v1valid && v2valid)
v = v1 < v2 ? v2 : v1;
else if (v1valid)
v = v1;
else if (v2valid)
v = v2;
else
return null;
return new double[] { u, v };
}
và đây là mã bản vẽ quad của tôi:
public void renderFace(Screen screen, int x0, int y0, int z0, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
boolean render = true;
double[] p0 = screen.project(x0, y0, z0);
int px0 = (int) p0[0], py0 = (int) p0[1];
render |= p0[2] >= ZCLIP && px0 >= 0 && px0 < screen.width && py0 >= 0 && py0 < screen.height;
double[] p1 = screen.project(x1, y1, z1);
int px1 = (int) p1[0], py1 = (int) p1[1];
render |= p1[2] >= ZCLIP && px1 >= 0 && px1 < screen.width && py1 >= 0 && py1 < screen.height;
double[] p2 = screen.project(x2, y2, z2);
int px2 = (int) p2[0], py2 = (int) p2[1];
render |= p2[2] >= ZCLIP && px2 >= 0 && px2 < screen.width && py2 >= 0 && py2 < screen.height;
double[] p3 = screen.project(x3, y3, z3);
int px3 = (int) p3[0], py3 = (int) p3[1];
render |= p3[2] >= ZCLIP && px3 >= 0 && px3 < screen.width && py3 >= 0 && py3 < screen.height;
if (!render)
return;
int minX = Math.min(Math.min(px0, px1), Math.min(px2, px3));
if (minX < 0)
minX = 0;
if (minX > screen.width)
minX = screen.width;
int minY = Math.min(Math.min(py0, py1), Math.min(py2, py3));
if (minY < 0)
minY = 0;
if (minY > screen.height)
minY = screen.height;
int maxX = Math.max(Math.max(px0, px1), Math.max(px2, px3));
if (maxX < 0)
maxX = 0;
if (maxX > screen.width)
maxX = screen.width;
int maxY = Math.max(Math.max(py0, py1), Math.max(py2, py3));
if (maxY < 0)
maxY = 0;
if (maxY > screen.height)
maxY = screen.height;
if (minX == maxX || minY == maxY)
return;
for (int py = minY; py < maxY; ++py)
for (int px = minX; px < maxX; ++px) {
double[] uv = screen.map(px + 0.5, py + 0.5, px0, py0, px1, py1, px2, py2, px3, py3);
if (uv == null)
continue;
double u = uv[0], v = uv[1];
double pz = (1 - u) * ((1 - v) * p0[2] + v * p2[2]) + u * ((1 - v) * p1[2] + v * p3[2]);
if (pz < ZCLIP)
continue;
int texX = 15 - Math.min(15, (int) (16 * u));
int texY = 15 - Math.min(15, (int) (16 * v));
screen.setPixel(px, py, pz, Art.WALLS.getPixel(texX, texY) * BRICKS);
}
}
Bất cứ ai có thể chỉ ra những gì tôi đang làm sai? Tôi không có nhiều kinh nghiệm vì đây là lần đầu tiên tôi thử triển khai một công cụ trò chơi.
Cảm ơn bạn cho bất kỳ cái nhìn sâu sắc.