Мне дано два GLKVector3
, представляющие начальную и конечную точки цилиндра. Используя эти точки и радиус, мне нужно построить и сделать цилиндр. Я могу построить цилиндр с правильным расстоянием между точками, но в фиксированном направлении (в настоящее время всегда в направлении y (0, 1, 0) вверх). Я не уверен, какие вычисления мне нужно сделать, чтобы заставить цилиндр на правильной плоскости между двумя точками, чтобы линия проходила через две конечные точки. Я думаю, что есть какие-то вычисления, которые я могу применить, когда создаю свои данные вершин с вектором направления или углом, который создаст цилиндр, указывающий на правильное направление. Кто-нибудь имеет алгоритм или знает об одном, который поможет?
Используя OpenGL ES 2.0 с iOS, как я рисую цилиндр между двумя точками?
Ответ 1
Отметьте эту удивительную статью ; он датируется, но после адаптации алгоритма он работает как шарм. Один совет, OpenGL ES 2.0 поддерживает только треугольники, поэтому вместо использования GL_QUAD_STRIP, как это делает метод, вместо этого используйте GL_TRIANGLE_STRIP, и результат будет идентичным. Сайт также содержит кучу другой полезной информации о геометрии OpenGL.
См. приведенный ниже код для решения. Self представляет сетку и содержит вершины, индексы и т.д.
- (instancetype)initWithOriginRadius:(CGFloat)originRadius
atOriginPoint:(GLKVector3)originPoint
andEndRadius:(CGFloat)endRadius
atEndPoint:(GLKVector3)endPoint
withPrecision:(NSInteger)precision
andColor:(GLKVector4)color
{
self = [super init];
if (self) {
// normal pointing from origin point to end point
GLKVector3 normal = GLKVector3Make(originPoint.x - endPoint.x,
originPoint.y - endPoint.y,
originPoint.z - endPoint.z);
// create two perpendicular vectors - perp and q
GLKVector3 perp = normal;
if (normal.x == 0 && normal.z == 0) {
perp.x += 1;
} else {
perp.y += 1;
}
// cross product
GLKVector3 q = GLKVector3CrossProduct(perp, normal);
perp = GLKVector3CrossProduct(normal, q);
// normalize vectors
perp = GLKVector3Normalize(perp);
q = GLKVector3Normalize(q);
// calculate vertices
CGFloat twoPi = 2 * PI;
NSInteger index = 0;
for (NSInteger i = 0; i < precision + 1; i++) {
CGFloat theta = ((CGFloat) i) / precision * twoPi; // go around circle and get points
// normals
normal.x = cosf(theta) * perp.x + sinf(theta) * q.x;
normal.y = cosf(theta) * perp.y + sinf(theta) * q.y;
normal.z = cosf(theta) * perp.z + sinf(theta) * q.z;
AGLKMeshVertex meshVertex;
AGLKMeshVertexDynamic colorVertex;
// top vertex
meshVertex.position.x = endPoint.x + endRadius * normal.x;
meshVertex.position.y = endPoint.y + endRadius * normal.y;
meshVertex.position.z = endPoint.z + endRadius * normal.z;
meshVertex.normal = normal;
meshVertex.originalColor = color;
// append vertex
[self appendVertex:meshVertex];
// append color vertex
colorVertex.colors = color;
[self appendColorVertex:colorVertex];
// append index
[self appendIndex:index++];
// bottom vertex
meshVertex.position.x = originPoint.x + originRadius * normal.x;
meshVertex.position.y = originPoint.y + originRadius * normal.y;
meshVertex.position.z = originPoint.z + originRadius * normal.z;
meshVertex.normal = normal;
meshVertex.originalColor = color;
// append vertex
[self appendVertex:meshVertex];
// append color vertex
[self appendColorVertex:colorVertex];
// append index
[self appendIndex:index++];
}
// draw command
[self appendCommand:GL_TRIANGLE_STRIP firstIndex:0 numberOfIndices:self.numberOfIndices materialName:@""];
}
return self;
}
Ответ 2
Вы рисуете более одного из этих цилиндров? Или когда-либо рисовать его в другом положении? Если это так, использование алгоритма из удивительной статьи - это не очень-то замечательная идея. Каждый раз, когда вы загружаете данные геометрии на GPU, вы несете затраты на производительность.
Лучший подход состоит в том, чтобы вычислить геометрию для одного базового цилиндра один раз, скажем, один с единичным радиусом и высотой - и материал, который данные вершин в VBO. Затем, когда вы рисуете, используйте матрицу преобразования модели в мир для масштабирования (независимо от радиуса и длины, если необходимо) и вращайте цилиндр на место. Таким образом, единственные новые данные, которые отправляются на GPU с каждым вызовом вызова, представляют собой матрицу 4x4 вместо всех данных вершин для любого полигонала цилиндра, который вы рисуете.