#java #math #3d #geometry #rendering
#java #математика #3D #геометрия #рендеринг
Вопрос:
Я настроил простой 3D-рендерер на Java, который управляет проецированием 3D-куба на заданную 2D-панель. Теперь я на том этапе, когда я хотел бы повернуть этот куб, чтобы продемонстрировать 3D. Однако, как только я добавляю к нему поворот, углы, которые образуют треугольники, больше не «синхронизируются», и в итоге получаются странные перекрывающиеся вершины.
Это визуализируется с использованием только двух вершин, чтобы четко показать проблему. Я не уверен, как это исправить.
Пока это мой код.
meshCube = new mesh();
proj.m[0][0]= fAspectRatio *fFovRad;
proj.m[1][1]= fFovRad;
proj.m[2][2]= fFar / (fFar-fNear);
proj.m[3][2]=(-fFar*fNear)/(fFar-fNear);
proj.m[2][3]=1.0f;
proj.m[3][3] = 0.0f;
// SOUTH
meshCube.tris.add(new triangle(new vector(0.0f,0.0f,0.0f), new vector(0.0f,1.0f,0.0f), new vector(1.0f,1.0f,0.0f)));
meshCube.tris.add(new triangle(new vector(0.0f,0.0f,0.0f), new vector(1.0f,1.0f,0.0f), new vector(1.0f,0.0f,0.0f)));
// EAST
meshCube.tris.add(new triangle(new vector(1.0f,0.0f,0.0f), new vector(1.0f,1.0f,0.0f), new vector(1.0f,1.0f,1.0f)));
meshCube.tris.add(new triangle(new vector(1.0f,0.0f,0.0f), new vector(1.0f,1.0f,1.0f), new vector(1.0f,0.0f,1.0f)));
/*
// NORTH
meshCube.tris.add(new triangle(new vector(1.0f,0.0f,1.0f), new vector(1.0f,1.0f,1.0f), new vector(0.0f,1.0f,1.0f)));
meshCube.tris.add(new triangle(new vector(1.0f,0.0f,1.0f), new vector(0.0f,1.0f,1.0f), new vector(0.0f,0.0f,1.0f)));
// WEST
meshCube.tris.add(new triangle(new vector(0.0f,0.0f,1.0f), new vector(0.0f,1.0f,1.0f), new vector(0.0f,1.0f,0.0f)));
meshCube.tris.add(new triangle(new vector(0.0f,0.0f,1.0f), new vector(0.0f,1.0f,0.0f), new vector(0.0f,0.0f,0.0f)));
// TOP
meshCube.tris.add(new triangle(new vector(0.0f,1.0f,0.0f), new vector(0.0f,1.0f,1.0f), new vector(1.0f,1.0f,1.0f)));
meshCube.tris.add(new triangle(new vector(0.0f,1.0f,0.0f), new vector(1.0f,1.0f,1.0f), new vector(1.0f,1.0f,0.0f)));
// BOTTOM
meshCube.tris.add(new triangle(new vector(1.0f,0.0f,1.0f), new vector(0.0f,0.0f,1.0f), new vector(0.0f,0.0f,0.0f)));
meshCube.tris.add(new triangle(new vector(1.0f,0.0f,1.0f), new vector(0.0f,0.0f,0.0f), new vector(1.0f,0.0f,0.0f)));*/
JPanel renderPanel = new JPanel() {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.WHITE);
for (triangle t : meshCube.tris) {
triangle triRotatedZ = new triangle(t.p[0],t.p[1],t.p[2]);
long finish = System.nanoTime();
long timeElapsed = finish - start;
fTheta = 0.1f * 1.0f; //This should really be fTheta = 1.0f * timeElapsed; but doesn't seem to work that way.
System.out.println(fTheta);
mat4x4 matRotZ = new mat4x4();
mat4x4 matRotX = new mat4x4();
matRotZ.m[0][0] = (float)Math.cos(fTheta);
matRotZ.m[0][1] = (float)Math.sin(fTheta);
matRotZ.m[1][0] = (float)-Math.sin(fTheta);
matRotZ.m[1][1] = (float)Math.cos(fTheta);
matRotZ.m[2][2] = 1;
matRotZ.m[3][3] = 1;
matRotX.m[0][0] = 1;
matRotX.m[1][1] = (float)Math.cos((fTheta*0.5f));
matRotX.m[1][2] = (float)Math.sin((fTheta*0.5f));
matRotX.m[2][1] = (float)-Math.sin((fTheta*0.5f));
matRotX.m[2][2] = (float)Math.cos((fTheta*0.5f));
matRotX.m[3][3] = 1;
triRotatedZ.p[0] = multiplyMatrixVector(t.p[0],matRotZ);
triRotatedZ.p[1] = multiplyMatrixVector(t.p[1],matRotZ);
triRotatedZ.p[2] = multiplyMatrixVector(t.p[2],matRotZ);
triangle triRotatedZX = new triangle(triRotatedZ.p[0],triRotatedZ.p[1],triRotatedZ.p[2]);
triRotatedZX.p[0] = multiplyMatrixVector(triRotatedZ.p[0],matRotX);
triRotatedZX.p[1] = multiplyMatrixVector(triRotatedZ.p[1],matRotX);
triRotatedZX.p[2] = multiplyMatrixVector(triRotatedZ.p[2],matRotX);
triangle triTranslated = new triangle(triRotatedZX.p[0],triRotatedZX.p[1],triRotatedZX.p[2]);
triTranslated.p[0].z = triRotatedZX.p[0].z 3.0f;
triTranslated.p[1].z = triRotatedZX.p[1].z 3.0f;
triTranslated.p[2].z = triRotatedZX.p[2].z 3.0f;
triangle triProjected = new triangle(triTranslated.p[0],triTranslated.p[1],triTranslated.p[2]);
triProjected.p[0] = multiplyMatrixVector(triTranslated.p[0],proj);
triProjected.p[1] = multiplyMatrixVector(triTranslated.p[1],proj);
triProjected.p[2] = multiplyMatrixVector(triTranslated.p[2],proj);
// Scale into view
triProjected.p[0].x = 1.0f;
triProjected.p[0].y = 1.0f;
triProjected.p[1].x = 1.0f;
triProjected.p[1].y = 1.0f;
triProjected.p[2].x = 1.0f;
triProjected.p[2].y = 1.0f;
triProjected.p[0].x *= 0.5f * 500.0f;
triProjected.p[0].y *= 0.5f * 500.0f;
triProjected.p[1].x *= 0.5f * 500.0f;
triProjected.p[1].y *= 0.5f * 500.0f;
triProjected.p[2].x *= 0.5f * 500.0f;
triProjected.p[2].y *= 0.5f * 500.0f;
Path2D path = new Path2D.Double();
path.moveTo(triProjected.p[0].x, triProjected.p[0].y);
path.lineTo(triProjected.p[1].x, triProjected.p[1].y);
path.lineTo(triProjected.p[2].x, triProjected.p[2].y);
path.closePath();
g2.draw(path);
}
}
};
Код для умножения матриц:
public static vector multiplyMatrixVector(vector in, mat4x4 m){
vector out = new vector(0,0,0);
out.x = in.x * m.m[0][0] in.y * m.m[1][0] in.z * m.m[2][0] m.m[3][0];
out.y = in.x * m.m[0][1] in.y * m.m[1][1] in.z * m.m[2][1] m.m[3][1];
out.z = in.x * m.m[0][2] in.y * m.m[1][2] in.z * m.m[2][2] m.m[3][2];
float w = in.x * m.m[0][3] in.y * m.m[1][3] in.z * m.m[2][3] m.m[3][3];
if(w!=0.0f) {
out.x /= w;
out.y /= w;
out.z /= w;
return out;
}
System.out.println("W is 0.");
return out;
}
Комментарии:
1. Возможно, причина вашей проблемы не в этом, но вы не выполняете решающее разделение перспективы.
2. Я полагаю, что я нахожусь в своей функции multiplyMatrixVector. Я только начинаю с этого, так что, возможно, я ошибаюсь. Я добавил исходное сообщение.
3.
multiplyMatrixVector
должна быть функция общего назначения, которая делает именно то, что описывает ее название, а не что-то дополнительное. Вы должны выполнить разделение перспективы явно после проекции. Кроме того,w!=0.0f
это очень плохая идея из-за числовой неточности.4. @meowgoesthedog Я принял к сведению ваш комментарий для дальнейшей доработки (спасибо!), Однако, этот джентльмен использует точно такую же функцию, и его, кажется, работает просто отлично.
Ответ №1:
for (triangle t : meshCube.tris) {
…
fTheta = 0.1f * 1.0f;
У вас есть новый ракурс камеры для каждого треугольника. Переместите вычисление вашей матрицы за пределы цикла.
Комментарии:
1. Это было именно так. Мой герой <3