Zwq— 2021-04-07 10:45 采纳率: 100%
浏览 294
已结题

C#如何用线程来控制三维点云图的动态绘制?

使用SharpGL三位点云图的绘制时,一般是将所有的数据处理好然后通过OpenGLDraw整体绘制出来。

我现在想要用线程来控制点云图的绘制,同时要是动态的。我试过用OpenGLDraw来动态绘制,将z轴数据固定加1,第一次画一个点,然后擦除,第二次两个点,擦除,这样循环直到绘制完成。

这个方法是可以的,然后我又试了用线程代替OpenGLDraw,将每次绘制擦除的代码放到一个while循环内,但是结果有问题,OpenGLControl控件上没有显示点。

请问能否给我提供一个思路,或者在我的思路上帮我解答一下问题。

以下是我线程上挂的方法代码。

private void DynamicShow()
        {
            for (int i = 0; i < xds; i++)//xds为总点数
            {
                dynamicZ.Add(maxz[i] + i);//准备Z轴数据
            }

            while (openFileReadyFlag)
            {
                gl.LoadIdentity();//重置当前指定的矩阵为单位矩阵
                gl.Translate(_ZBx, _ZBy, _ZBz);//平移函数,参数为XYZ方向上的平移大小;最后一个参数为距离屏幕距离;

                gl.Rotate(_x, 1.0f, 0.0f, 0.0f);//绕x轴旋转_x度,_x为正表示逆时针
                gl.Rotate(_y, 0.0f, 1.0f, 0.0f);
                gl.Rotate(_z, 0.0f, 0.0f, 1.0f);

                gl.Begin(_model);
                gl.Color(1.0f, 1.0f, 0.0f);

                gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
                for (int i = 0; i < max; i++)//用max来控制使每次绘制比上一次多一个点
                {
                    gl.Vertex((maxx[i] - _ZBxT) / _ZBv, (maxy[i] - _ZByT) / _ZBv, maxz[i] / _ZBzT);//数组为点云坐标数组,其他为坐标换算参数
                }
                max++;
                Thread.Sleep(2);

                gl.End();
                if (max == xds)
                {
                    break;
                }
            }
        }
  • 写回答

1条回答 默认 最新

  • asgpt 2023-02-24 18:58
    关注

    你的方法是通过循环不断地在OpenGL中添加和删除点来动态绘制点云图的。然而,这种方式可能会在每次迭代中花费较长的时间,因为你需要在绘图上下文中进行许多操作,包括重置矩阵、平移、旋转、清除颜色缓冲区和绘制点。

    在这种情况下,使用线程可以提高绘制速度,但是你的线程函数中的操作似乎也是一个死循环,只会导致OpenGL控件一直处于绘图状态。此外,你的线程函数似乎没有使用OpenGL的双缓冲技术,这可能会导致绘图不连贯或闪烁。

    下面是一种更有效的方法来实现动态绘制点云图:

    • 在主线程中创建一个点云对象,例如使用OpenGL的顶点缓冲区(VBO)或者顶点数组(VAO)。
    • 在后台线程中更新点云对象。你可以使用C#的Task或者Thread类来实现后台线程,这里我们使用Task作为示例。
    • 在主线程中调用OpenGL绘图函数,例如glDrawArrays或glDrawElements,以使用更新后的点云对象渲染场景。

    以下是使用Task来实现动态绘制点云图的代码示例:

    private void InitScene()
    {
        // 初始化点云对象,例如使用VBO或者VAO
        // 这里使用VBO作为示例
        float[] points = new float[xds * 3]; // 每个点包含x、y、z三个分量
        // 将x、y、z坐标按顺序存入points数组
        // ...
        int vbo;
        gl.GenBuffers(1, out vbo);
        gl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, vbo);
        gl.BufferData(OpenGL.GL_ARRAY_BUFFER, points.Length * sizeof(float), points, OpenGL.GL_STATIC_DRAW);
        gl.VertexPointer(3, OpenGL.GL_FLOAT, 0, IntPtr.Zero);
        gl.EnableClientState(OpenGL.GL_VERTEX_ARRAY);
    }
    
    private void StartDrawing()
    {
        Task.Run(() =>
        {
            int max = 0;
            while (openFileReadyFlag)
            {
                float[] dynamicZ = new float[xds];
                for (int i = 0; i < xds; i++)
                {
                    dynamicZ[i] = maxz[i] + i;
                }
                // 将dynamicZ数组的值更新到点云对象中的z坐标上
                // ...
    
                max++; // 增加每次绘制的点数
    
                Thread.Sleep(2);
                if (max >= xds) break;
            }
        });
    }
    
    private void DrawScene()
    {
        gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
    
        gl.DrawArrays(_model, 0, max); // 渲染点云对象中的前max个点
    
        gl.Flush();
    }
    
    
    

    注意,在使用OpenGL绘图函数之前,需要确保已经初始化了点

    • OpenGL 帧缓冲区的清除
      在每次绘图时,需要清除帧缓冲区,以避免之前的绘制影响到当前的绘制。您在代码中使用了 gl.Clear() 函数来清除帧缓冲区,但是该函数的位置不太合适,应该将其放在循环外面,只执行一次,如下所示:
    
    gl.LoadIdentity();//重置当前指定的矩阵为单位矩阵
    gl.Translate(_ZBx, _ZBy, _ZBz);//平移函数,参数为XYZ方向上的平移大小;最后一个参数为距离屏幕距离;
    gl.Rotate(_x, 1.0f, 0.0f, 0.0f);//绕x轴旋转_x度,_x为正表示逆时针
    gl.Rotate(_y, 0.0f, 1.0f, 0.0f);
    gl.Rotate(_z, 0.0f, 0.0f, 1.0f);
    gl.Begin(_model);
    gl.Color(1.0f, 1.0f, 0.0f);
    
    gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); // 在循环外清除帧缓冲区
    while (openFileReadyFlag)
    {
        for (int i = 0; i < max; i++)//用max来控制使每次绘制比上一次多一个点
        {
            gl.Vertex((maxx[i] - _ZBxT) / _ZBv, (maxy[i] - _ZByT) / _ZBv, maxz[i] / _ZBzT);//数组为点云坐标数组,其他为坐标换算参数
        }
        max++;
        Thread.Sleep(2);
    
        gl.End();
        if (max == xds)
        {
            break;
        }
    }
    
    
    • 顶点坐标的范围
      您在绘制时使用了 gl.Vertex() 函数来指定顶点坐标,但是坐标值可能超出了 OpenGL 视口的范围,导致无法显示。您可以尝试调整坐标值的范围,或者调整 OpenGL 视口的大小来解决该问题。
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 6月9日
  • 已采纳回答 6月1日

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog