标题:关于OpenGL的一个小问题。
只看楼主
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
结帖率:100%
已结贴  问题点数:20 回复次数:5 
关于OpenGL的一个小问题。
RT。我准备做一个3D Modeller的程序,读取点线面数据,在窗口复现结构模型。
主要是一些型材(圆管、工字钢等等)、板材。但是有一个小问题,模型生成之后,因为都是一个颜色,重合在一起,无法分别有多少构件,以及边界都在什么位置
有什么方法可以在每个构件的边界上绘制出边线或者轮廓线,可以分辨。比如下图这种


这个是我实验用的代码,绘制了两根圆管,尝试在端部绘制了两条线,但是显示效果不对。
程序代码:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import math

def cross(a, b):
    #原点为O,计算OAB平面的法向
    return [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]]

def cylinder_between(P1, P2, rad):
    v = [P2[0]-P1[0], P2[1]-P1[1], P2[2]-P1[2]]  #P1指向P2的矢量
    height = math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])  #圆柱体长度(高度)
    axis = (1, 0, 0) if math.hypot(v[0], v[1]) < 0.001 else cross(v, (0, 0, 1))  #获得O(原点)、P1和P2的法向,用于旋转
    angle = -math.atan2(math.hypot(v[0], v[1]), v[2])*180/math.pi   #P1指向P2的矢量的旋转角度

    glPushMatrix()
    glTranslate(P1[0], P1[1], P1[2])   # 平移
    glRotate(angle, *axis)    # 旋转
    # glColor(0.5, 1, 0.5)
    # glutWireCylinder(rad, height, 32, 16)
    glColor(0, 0, 1)
    glutSolidCylinder(rad, height, 32, 16)

    # #绘制构件边界线 ----------显示效果不对,
    glColor(1,1,1)
    lineAmount = 50
    glBegin(GL_LINE_LOOP)
    for i in range(0,lineAmount):
        x = rad * math.sin(i * 2 * math.pi / lineAmount)
        y = rad * math.cos(i * 2 * math.pi / lineAmount)
        glVertex2f(x, y)
    glEnd()
    glTranslate(P2[0], P2[1], P2[2])  # 平移
    glBegin(GL_LINE_LOOP)
    for i in range(0,lineAmount):
        x = rad * math.sin(i * 2 * math.pi / lineAmount)
        y = rad * math.cos(i * 2 * math.pi / lineAmount)
        glVertex2f(x, y)
    glEnd()

    glPopMatrix()

def draw():

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, wnd_w/wnd_h, 0.1, 10)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    # 视点设置,可以按照坐标系定义来理解:相机位于坐标原点, X正轴指向视线方向,Z轴为视角向上的方向
    gluLookAt(2, 2, 2,      # 视点(相机)在世界坐标的位置,即坐标原点
              -0.2, -0.5, 0.7,       # 视向点, 即 X正轴某点
              0, 0, 1)       # 视点(相机)向上的点,Z轴正向某点

    glClearColor(0.5, 0.5, 0.5, 1.0)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    # glEnable(GL_DEPTH_TEST)
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) # causes wire frame
    # GL_FILL --------- 填充模式
    # GL_LINE --------- 线框模式
    # GL_POINT --------- 点模式
    # glColor(1, 1, 0.5)
    cylinder_between([0.2, 0.4, -0.5], [-0.2, -0.4, 0.5], 0.3)

    # glColor(0.5, 1, 0.5)
    cylinder_between([-0.2, -0.4, 0.5], [-0.6, -1.2, 2.0], 0.3)

    glutSwapBuffers()
    glutPostRedisplay()

def SetupRC():  # 设置灯光和渲染效果的函数,如未使用该函数,绘制出的模型无高亮和阴影,无法体现出立体感
    # Light values and coordinates光照 值与坐标;环境光,漫射光,镜面光,光的坐标,
    ambientLight = [0.4, 0.4, 0.4, 1.0]
    diffuseLight = [0.7, 0.7, 0.7, 1.0]
    specular = [0.9, 0.9, 0.9, 1.0]
    lightPos = [-50.0, 200.0, 200.0, 1.0]
    specref = [0.6, 0.6, 0.6, 1.0]

    glEnable(GL_DEPTH_TEST)  # Hidden surface removal
    glEnable(GL_CULL_FACE)  # Do not calculate inside of solid object
    glFrontFace(GL_CCW)
    glEnable(GL_LIGHTING)

    # Setup light 0
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight)
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight)
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular)

    # Position and turn on the light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos)
    glEnable(GL_LIGHT0)

    # Enable color tracking
    glEnable(GL_COLOR_MATERIAL)

    # Set Material properties to follow glColor values
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

    # All materials hereafter have full specular reflectivity with a moderate shine
    glMaterialfv(GL_FRONT, GL_SPECULAR, specref)
    glMateriali(GL_FRONT, GL_SHININESS, 64)

    glClearColor(0.0, 0.0, 0.0, 1.0)  # 背景黑色

wnd_w, wnd_h = 1000, 1000  # 窗口尺寸
glutInit()          # OpenGL初始化
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)    # 设置显示模式
glutInitWindowSize(wnd_w, wnd_h)            # 设置窗口尺寸
glutInitWindowPosition(0, 0)           # 设置窗口位置(相对于显示器的左上角)
glutCreateWindow("cylinder")        # 创建窗口
# glViewport(0,0,300,300);

glutDisplayFunc(draw)           # 调用绘图函数
SetupRC()               # 设置灯光效果
glutMainLoop()      #进入GLUT事件处理循环,让所有的与“事件”有关的函数调用无限循环。

搜索更多相关主题的帖子: OpenGL rad 绘制 坐标 math 
2021-05-22 15:52
fall_bernana
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:17
帖 子:240
专家分:2086
注 册:2019-8-16
得分:20 
回复 楼主 xiangyue0510
程序代码:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import math

def cross(a, b):
    #原点为O,计算OAB平面的法向
    return [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]]

def cylinder_between(P1, P2, rad):
    v = [P2[0]-P1[0], P2[1]-P1[1], P2[2]-P1[2]]  #P1指向P2的矢量
    height = math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])  #圆柱体长度(高度)
    axis = (1, 0, 0) if math.hypot(v[0], v[1]) < 0.001 else cross(v, (0, 0, 1))  #获得O(原点)、P1和P2的法向,用于旋转
    angle = -math.atan2(math.hypot(v[0], v[1]), v[2])*180/math.pi   #P1指向P2的矢量的旋转角度

    glPushMatrix()
    glTranslate(P1[0], P1[1], P1[2])   # 平移
    glRotate(angle, *axis)    # 旋转---》旋转后的坐标系已经改变,所以你画的第一个边界线没有问题,但是你换到另外一头还是使用之前的坐标系的点,肯定是不对的。你需要算出该点在旋转后的坐标系里的位置
    # glColor(0.5, 1, 0.5)
    # glutWireCylinder(rad, height, 32, 16)
    glColor(0, 0, 1)
    glutSolidCylinder(rad, height, 32, 16)

    # #绘制构件边界线 ----------显示效果不对,
    glColor(1,1,1)
    lineAmount = 50
    glBegin(GL_LINE_LOOP)
    for i in range(0,lineAmount):
        x = rad * math.sin(i * 2 * math.pi / lineAmount)
        y = rad * math.cos(i * 2 * math.pi / lineAmount)
        glVertex2f(x, y)
    glEnd()
    glTranslate(P2[0], P2[1], P2[2])  # 平移
    glBegin(GL_LINE_LOOP)
    for i in range(0,lineAmount):
        x = rad * math.sin(i * 2 * math.pi / lineAmount)
        y = rad * math.cos(i * 2 * math.pi / lineAmount)
        glVertex2f(x, y)
    glEnd()

    glPopMatrix()

def draw():

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, wnd_w/wnd_h, 0.1, 10)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    # 视点设置,可以按照坐标系定义来理解:相机位于坐标原点, X正轴指向视线方向,Z轴为视角向上的方向
    gluLookAt(2, 2, 2,      # 视点(相机)在世界坐标的位置,即坐标原点
              -0.2, -0.5, 0.7,       # 视向点, 即 X正轴某点
              0, 0, 1)       # 视点(相机)向上的点,Z轴正向某点

    glClearColor(0.5, 0.5, 0.5, 1.0)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    # glEnable(GL_DEPTH_TEST)
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) # causes wire frame
    # GL_FILL --------- 填充模式
    # GL_LINE --------- 线框模式
    # GL_POINT --------- 点模式
    # glColor(1, 1, 0.5)
    cylinder_between([0.2, 0.4, -0.5], [-0.2, -0.4, 0.5], 0.3)

    # glColor(0.5, 1, 0.5)
    cylinder_between([-0.2, -0.4, 0.5], [-0.6, -1.2, 2.0], 0.3)

    glutSwapBuffers()
    glutPostRedisplay()

def SetupRC():  # 设置灯光和渲染效果的函数,如未使用该函数,绘制出的模型无高亮和阴影,无法体现出立体感
    # Light values and coordinates光照 值与坐标;环境光,漫射光,镜面光,光的坐标,
    ambientLight = [0.4, 0.4, 0.4, 1.0]
    diffuseLight = [0.7, 0.7, 0.7, 1.0]
    specular = [0.9, 0.9, 0.9, 1.0]
    lightPos = [-50.0, 200.0, 200.0, 1.0]
    specref = [0.6, 0.6, 0.6, 1.0]

    glEnable(GL_DEPTH_TEST)  # Hidden surface removal
    glEnable(GL_CULL_FACE)  # Do not calculate inside of solid object
    glFrontFace(GL_CCW)
    glEnable(GL_LIGHTING)

    # Setup light 0
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight)
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight)
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular)

    # Position and turn on the light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos)
    glEnable(GL_LIGHT0)

    # Enable color tracking
    glEnable(GL_COLOR_MATERIAL)

    # Set Material properties to follow glColor values
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

    # All materials hereafter have full specular reflectivity with a moderate shine
    glMaterialfv(GL_FRONT, GL_SPECULAR, specref)
    glMateriali(GL_FRONT, GL_SHININESS, 64)

    glClearColor(0.0, 0.0, 0.0, 1.0)  # 背景黑色

wnd_w, wnd_h = 1000, 1000  # 窗口尺寸
glutInit()          # OpenGL初始化
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)    # 设置显示模式
glutInitWindowSize(wnd_w, wnd_h)            # 设置窗口尺寸
glutInitWindowPosition(0, 0)           # 设置窗口位置(相对于显示器的左上角)
glutCreateWindow("cylinder")        # 创建窗口
# glViewport(0,0,300,300);

glutDisplayFunc(draw)           # 调用绘图函数
SetupRC()               # 设置灯光效果
glutMainLoop()      #进入GLUT事件处理循环,让所有的与“事件”有关的函数调用无限循环。
2021-05-24 11:53
sssooosss
Rank: 9Rank: 9Rank: 9
等 级:禁止访问
威 望:3
帖 子:664
专家分:1115
注 册:2019-8-27
得分:0 
共同学习
2021-05-27 08:39
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
得分:0 
回复 2楼 fall_bernana
十分感谢。这几天忙其他事情,没看到,回去后我研究一下您的代码。
2021-05-27 17:28
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
得分:0 
回复 2楼 fall_bernana
你的回复让我受益匪浅
刚才已经把代码改好了,坐标转换比较麻烦,所以用笨办法先把坐标还原回去,再平移旋转画第二个点的边界线。
2021-05-29 00:58



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-505807-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.028630 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved