OpenGL简单的3D机器人手臂

时间:2015-04-15 22:49:49

标签: c++ opengl

我想用搅拌机制作简单的3D机器人手臂。目前我可以导入obj文件和纹理,旋转,翻译和缩放。

问题: 为了简化,机器人手臂将有3个部分,基部(圆柱体旋转)和两个长方体。我没有旋转cilinder和长方体的问题。但这两个长方体必须连接,我不知道该怎么做。我可以使用简单的正弦和余弦函数来计算第一个旋转的第二个长方体的位置,但我不知道如何测量物体的长度。

第二个问题: 我可以在一个obj文件中导出所有3个对象,然后在openGL中将它们分开吗?

my_solution

3 个答案:

答案 0 :(得分:1)

您还没有回复评论,但我想我还是会发布此代码。我写这个是为了在OpenGL中渲染3D机器人手。我有所有手指和手(由其他人制作)的搅拌机模型文件,我将其单独导出到.obj文件。

最终结果可见here。如您所见,我还添加了使用鼠标更改视点的功能。我通过反复试验方法确定了手指指骨的偏移量,但也许您可以使用Blender找到点之间的偏移,如here所述。我现在无法测试,因为我的工作电脑上没有Blender。

以下代码描述了我实现此目的。我把它分解,以便我可以写一些解释,但按顺序放置所有部分将生成我的完整功能,以绘制一个附加在手上的单个手指。

我的绘图功能以:

开头
double t_x, t_y, t_z;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer
glLoadIdentity();

// Set viewpoint:
gluLookAt(eyex+3.0f, eyey+3.0f, eyez+3.0f, focusx, focusy, focusz, 0, 1, 0);
glPushMatrix();

glRotatef(g_xRotation, 0,1,0); // Rotate with mouse (g_x and g_y are determined elsewhere)
glRotatef(g_yRotation, 1,0,0);

现在我们设置在原点(按照鼠标指示旋转),我们可以从绘制手掌开始。不需要换档(它在原点)。

// DRAW PALM
glColor3f(1.0f, 1.0f, 1.0f); // Use proper color - white
palmHand -> draw();

手掌渲染后,我们移动绘制第一根手指。翻译中的1.87f是通过实验确定的。这里的价值还取决于我从Blender出口商品的质量,但一旦你出口一次,它就不会改变。 (我实际上对我为自己留下的相当自鸣得意的评论感到惊讶 - 这段代码已经有几年了)。指骨只围绕一个轴旋转,旋转值(角度)存储在f_p[]中。

// DRAW FINGER 1
// CONSTANT: Move to first vertex
glTranslatef(0.0f, 0.0f, 1.87f); 

glRotatef(f_p[0].theta, 0, 0, 1); // Do rotation for phalanx 1 with specified angle
glColor3f(16.0f/255.0f, 78.0f/255.0f, 139.0f/255.0f); // Use proper color - blue
phalanx1Hand -> draw(); 

// CONSTANT: Necessary adjustment because of model file offset (nobody's perfect, okay?)
glTranslatef(0.0f, 0.03f, 0.0f);

绘制第二个(中间)指骨遵循与底部指骨相同的过程,除了它围绕不同的轴旋转。

// CONSTANT: Move to second vertex
glTranslatef(1.3f, 0.0f, 0.0f); 

glRotatef(f_p[1].theta, 0, 1, 0); // Do rotation for phalanx 2 with specified angle
phalanx2Hand -> draw();

方阵#2没有额外的偏移量,因为我想当我从Blender输出它时,我正确排列了模型。

// CONSTANT: Rotate to third vertex
glRotatef(-90.0f, 0, 1, 0);

// CONSTANT: Move to third vertex
glTranslatef(2.0f, 0.0f, 0.0f);

glRotatef(f_p[2].theta, 0, 1, 0); // Do rotation for phalanx 3 with specified angle
phalanx3Hand -> draw();

完成绘制单个手指。现在我们将所有的旋转和翻译反转回到起始位置(因为有很多旋转方式,你必须确保你保持订单一致,否则你将会在其他地方结束,手指将会到处都是。

// CONSTANT: Return to origin
// Undo rotations and translations in proper order
glRotatef((-1.0f*f_p[2].theta), 0, 1, 0); // Phalanx 3 rotation
glTranslatef(-2.0f, 0.0f, 0.0f); // Phalanx 3 translation
glRotatef(90.0f, 0, 1, 0); // Rotation to Phalanx 3
glRotatef((-1.0f*f_p[1].theta), 0, 1, 0); // Phalanx 2
glTranslatef(-1.3f, -0.03f, 0.0f); // Phalanx 2 translation and adjustment
glRotatef((-1.0f*f_p[0].theta), 0, 0, 1); // Rotation to Phalanx 1
glTranslatef(0.0f, 0.0f, -1.87f); // Phalanx 1 translation

最后,由于我的模型一侧有两个手指,另一侧有一个手指,我必须在绘制另外两个手指之前旋转:

// CONSTANT: Keep parts right side up
glRotatef(90.0f, 0, 0, 1);

此时我会对指针2和3执行相同的处理(基本上是从// DRAW FINGER 1注释开始的代码)。您可能不需要这样做,因为我认为您的模型没有所有这些额外部分。此时,您可以将所有旋转/翻译放回原点,然后完成:

glPopMatrix();

并返回之前正在做的任何事情(等待用户输入等)。

我使用的draw()函数是使用从.obj文件中提取的数据绘制三角形的标准函数。

答案 1 :(得分:0)

你是否考虑像操纵人类的手臂一样操纵物体?这样,对象都是链接的,不会失去同步。然后动画可以作为一个整体应用于钻机。减少计算量,对您来说更容易。

示例(本网站的其他页面也很有用): http://www.blender.org/api/htmlI/x7613.html http://www.blender.org/api/htmlI/x7891.html

参考: http://wiki.blender.org/index.php/Doc:2.6/Manual/Rigging

答案 2 :(得分:0)

要了解有关解决方案的更多信息,请参阅denavit hartenberg notation

我的解决方案很简单。我有类运动链,我存储了一个位置,所有模型的方向的矢量。我使用for循环遍历此类中的所有元素,并将每个元素的位置和旋转相乘。

假设我们有3个元素 此链中最后一个元素的位置将是(伪代码):

currentElementposition * currentElementorientation 

第二个元素的位置:

(currentElementPosition*currentElementorientation)*positionOfPreviousElement

第一个元素的位置:

(currentElementPosition*currentElementorientation)*positionOfPreviousElement

后来的对象被缩放。

移动和旋转是4x4矩阵

glm::mat4 rotate;
glm::mat4 move;

我使用的功能:

void Model::moveModel(std::vector<glm::vec3> & positions, std::vector<glm::vec3> & orienations, int id)
{
    try
    {
        if (positions.size() != orienations.size()) throw "Size of positions vector should be equal to orienations vector";

        glm::mat4 objPosition;

        for (int i = id ; i >= 0  ; --i)
        {
            rotate = glm::eulerAngleYXZ(orienations[i].y, orienations[i].x, orienations[i].z);
            move = glm::translate(glm::mat4(), positions[i]);
            objPosition = (move * rotate) * objPosition;
        }

        objScale = scale(glm::mat4(), objSize); // scaling object
        objPosition = objPosition * objScale;

        glUniformMatrix4fv(objPositionID, 1, GL_FALSE, &objPosition[0][0]);
        glUniformMatrix4fv(perspectiveGL, 1, GL_FALSE, &perspective[0][0]);
        glUniformMatrix4fv(lookAtGL, 1, GL_FALSE, &lookAt[0][0]);
        glUniform3f(lightPositionGL, lightPosition.x, lightPosition.y, lightPosition.z); // przesłanie 3 liczb float
    }
    catch(char const * errorMsg)
    {
        std::cout << errorMsg << std::endl;
    }
}