I've to build a tubular structure out of branches. Each branch has a starting position, an end position, a starting direction and an end direction. With this 4 elements I want to draw cylinders connected to each other. Unfortunately, I can not use ofNode like I did here https://forum.openframeworks.cc/t/how-to-draw-a-cylinder-starting-from-2-ofnode/22323 because it turned out to be too slow.
My current problem is to draw a single cylinder, what I would like to have is this:
![]()
Where A is startingPos
and B is endingPos
. B-A is the startingDir
and C - B is the the endDir
. C is the lookingAt
point that the top face should look.
What I'm obtaining now, is this:
As you see, the rotation of the top face happens on an axis that is not what it should be.
To rotate the top face, I use:
the formula:
angle = acos(v1 dot v2)
axis = norm(v1 cross v2)
Therefore:
auto angle = acos(glm::dot(glm::normalize(startDir), glm::normalize(endDir)));
auto axis = glm::normalize(glm::cross(startDir, endDir));
glm::mat4x4 rotMat = glm::axisAngleMatrix(axis, angle);
This is the whole code that I'm using to draw this scene:
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
//light.enable();
glm::vec3 startPos = glm::vec3(0.0f,0.0f, 0.0f);
glm::vec3 endPos = glm::vec3(0.0f, 40.0f, 0.0f);
lookingAt = glm::vec3(40.0f, 75.0f, 0.0f);
glm::vec3 startDir = glm::normalize(endPos - startPos);
glm::vec3 endDir = glm::normalize(lookingAt - endPos);
createTube(startPos, endPos, startDir, endDir, this->mesh);
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
ofEnableDepthTest();
cam.begin();
ofSetColor(0,0,0,100);
mesh.drawWireframe();
auto n = mesh.getNormals();
auto v = mesh.getVertices();
float normalLength = 20.;
ofSetColor(255,0,0,70);
for(unsigned int i=0; i < n.size() ;i++){
ofDrawLine(.98*v[i].x,.98*v[i].y,.98*v[i].z,
.98*v[i].x+n[i].x*normalLength*.2,.98*v[i].y+n[i].y*normalLength*.2,.98*v[i].z+n[i].z*normalLength*.2);
}
ofDrawSphere(lookingAt.x, lookingAt.y, lookingAt.z, 3);
cam.end();
ofDisableDepthTest();
}
void ofApp::createTube(glm::vec3 startPos, glm::vec3 endPos, glm::vec3 startDir, glm::vec3 endDir, ofMesh& mesh){
bool cap = false;
int resolution = 6;
int textureRepeat = 1;
float length = glm::distance(startPos, endPos);
const int radius = 8;
const int scaledRadius = 8;//for now, do not scale the branches;
auto angle = acos(glm::dot(glm::normalize(startDir), glm::normalize(endDir)));
auto axis = glm::normalize(glm::cross(startDir, endDir));
glm::mat4x4 rotMat = glm::axisAngleMatrix(axis, angle);
// Cylinder body
int first = mesh.getNumVertices();
for (int i = 0; i <= resolution; i++) {
// if it is the last face, close it where the first face
// was started
if (i == resolution) {
mesh.addIndex(first+(i*2));
mesh.addIndex(first);
mesh.addIndex(first+1);
mesh.addIndex(first+1);
mesh.addIndex(first+(i*2)+1);
mesh.addIndex(first+(i*2));
} else {
mesh.addIndex(first+(i*2));
mesh.addIndex(first+(i*2)+2);
mesh.addIndex(first+(i*2)+3);
mesh.addIndex(first+(i*2)+3);
mesh.addIndex(first+(i*2)+1);
mesh.addIndex(first+(i*2));
}
}
for (int i = 0; i <= resolution; i++) {
//calculate x and y component
float theta = 2.0f * 3.1415926f * float(i) / float(resolution);
float x = radius * cosf(theta);
float z = radius * sinf(theta);
glm::vec3 offset = glm::vec3(x, startPos.y, z);
glm::vec3 circleBottom = startPos + offset;
glm::vec3 direction = glm::normalize(circleBottom);
glm::vec3 circleTop = glm::vec3(rotMat * glm::vec4((endPos + offset),0.0));
glm::vec3 directionTop = endDir;
// bottom
//botton and top vertices share the same normal
glm::vec3 normal = glm::normalize(circleBottom-startPos);
mesh.addVertex(circleBottom);
mesh.addNormal(normal);
//top
mesh.addVertex(circleTop);
mesh.addNormal(normal);
}
}
Does anyone have some suggestion?