使用opengl和列表的C#线程问题! [英] C# thread problems with opengl and lists!

查看:81
本文介绍了使用opengl和列表的C#线程问题!的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我已经有这个问题了一段时间了,我希望你们有一个解决方案。我正在尝试通过一个线程创建块,然后将块添加到我的主类中的列表中,在那里我绘制块。但是在尝试设置包含多维数据集顶点的VBO时失败了,我得到了这个异常:'System.AccessViolationException'。



这是我的立方体代码:

 公共多维数据集(Vector3 pos, float 维度)
{
position = pos;
dimensions = dimension;

float cubePos = dimension;
cube = new VBO( new Vector3 [] {
new Vector3(cubePos,cubePos,-cubePos), new Vector3(-cubePos,cubePos,-cubePos), new Vector3(-cubePos,cubePos,cubePos), new Vector3(cubePos,cubePos,cubePos),
new Vector3(cubePos,-cubePos,cubePos), new Vector3(-cubePos,-cubePos,cubePos) , new Vector3(-cubePos,-cubePos,-cubePos), new Vector3(cubePos,-cubePos, -cubePos),
new Vector3(cubePos,cubePos,cubePos), new Vector3( - cubePos,cubePos,cubePos), new Vector3(-cubePos,-cubePos,cubePos), new Vector3(cubePos,-cubePos,cubePos),
new Vector3(cubePos,-cubePos,-cubePos), new Vector3(-cubePos,-cubePos,-cubePos), new Vector3(-cubePos,cubePos,-cubePos) , new Vector3(cubePos,cubePos,-cubePos),
new Vector3(-cubePos, cubePos,cubePos), new Vector3(-cubePos,cubePos,-cubePos), new Vector3(-cubePos ,-cubePos,-cubePos), new Vector3(-cubePos,-cubePos,cubePos),
new Vector3(cubePos,cubePos,-cubePos), new Vector3(cubePos,cubePos,cubePos), new Vector3(cubePos,-cubePos,cubePos), new Vector3(cubePos,-cubePos,-cubePos)});

color = new VBO( new Vector3 [] {
new Vector3( 1 1 ,< span class =code-digit> 1 ), new Vector3( 1 ,< span class =code-digit> 1 , 1 ), new Vector3(< span class =code-digit> 1 , 1 1 ), new Vector3( 1 1 1 ),
new Vector3( 1 1 1 ), new Vector3 ( 1 1 1 ), new Vector3( 1 1 1 ), new Vector3( 1 1 1 ),
new Vector3( 1 1 1 ), new Vector3( 1 1 1 ), new Vector3( 1 1 1 ), new Vector3( 1 1 1 ),
new Vector3( 1 1 1 ), new Vector3( 1 1 1 ), new Vector3( 1 1 1 ), new Vector3( 1 1 1 ),
new Vector3( 1 ,< span class =code-digit> 1 , 1 ), new Vector3(< span class =code-digit> 1 , 1 1 ), new Vector3( 1 1 , 1 ), new Vector3(< span class =code-digit> 1 , 1 1 ),
new Vector3( 1 1 1 ), new Vector3( 1 1 1 ), new Vector3 ( 1 1 1 ), new Vector3( 1 1 ,< span class =code-digit> 1 ),});

elements = new VBO( new int [] { 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 },BufferTarget.Element ArrayBuffer);
}





这是我在班级的代码:

< pre lang =c#> 使用系统;
使用 System.Threading;
使用 System.Windows.Forms;
使用 System.Collections.Generic;
使用 OpenGL;
使用 Tao.FreeGlut;
使用 System.Collections.Concurrent;

命名空间 OpenGLTutorial1
{
public class Game1:游戏
{
private 块块;
私人相机相机;
private bool left = false ,forward = false ,back = false ,right = false ,up = false ;

// private List chunks = new List();
private ConcurrentBag chunks = new ConcurrentBag();
private Thread chunkThread;

private Vector3 nextChunk;
public 覆盖 void LoadContent ()
{
camera = new 相机( new Vector3( 0 50 0 ),Quaternion.Identity) ;
camera.SetDirection( new Vector3( 0 0 ,-1));
// cube1 = new Cube(Vector3.Zero,1,dirt.jpg);
Program.SetCursor(Glut.GLUT_CURSOR_NONE);

Global.Manager.LoadBlocks( Blocks.xml);

block = Global.Manager.NewBlock( new Vector3( 0 ,< span class =code-digit> 0 , 0 ), 0 );

chunks.Add( new Chunk(Vector3.Zero, 8 )) ;
chunkThread = new 线程(CreateChunk);
// chunkThread.SetApartmentState(ApartmentState.STA);
chunkThread.Start ();

nextChunk = new Vector3(startChunk.X,startChunk.Y,startChunk.Z);

Program.SetViewMatrix(camera.ViewMatrix);
base .LoadContent();
}
私有 静态 float add = 0 ;
私有 静态 int 速度= 5 ;
public 覆盖 void 更新( float deltaTime)
{
Program.SetViewMatrix(camera.ViewMatrix);

if (back)camera.MoveRelativeXZ(Vector3.UnitZ * deltaTime * speed);
if (forward)camera.MoveRelativeXZ(-Vector3.UnitZ * deltaTime * speed);
if (左)camera.MoveRelativeXZ(-Vector3.UnitX * deltaTime * speed);
if (右)camera.MoveRelativeXZ(Vector3.UnitX * deltaTime * speed);
if (up)camera.Move( new Vector3( 0 ,deltaTime * 2 .5f, 0 ));

/ * add + = deltaTime * 100;
if(add> = 20)
{
CreateChunk();
add = 0;
} * /

base .Update(deltaTime);
}
public 覆盖 void 绘制(参考 ShaderProgram程序)
{
block.Draw( ref program);
foreach var item in 块)
{
块块=(块)项;
chunk.Draw( ref program);
}
base .Draw( ref program);
}
public 覆盖 void OnKeyboardDown( byte 键, int x, int y)
{
if (key == ' d')right = true ;
else if (key == ' a')left = true ;
else if (key == ' w')forward = true ;
else if (key == ' s')back = true ;
else if (key == ' ')up = true ;
base .OnKeyboardDown(key,x,y);
}
public 覆盖 void OnKeyboardUp( byte 键, int x, int y)
{
if (key == ' d')right = false ;
else if (key == ' a')left = false ;
else if (key == ' w')forward = false ;
else if (key == ' s')back = false ;
else if (key == ' ')up = false ;
base .OnKeyboardUp(key,x,y);
}
private int prevX = 0 ,prevY = 0 ;
public 覆盖 void OnMove ( int x, int y)
{
// 如果鼠标移动事件是由glutWarpPointer引起的,则什么都不做
if (x == prevX&& y == prevY) return ;
if (prevX == 0 && prevY == 0
{
Program.WarpPointer(width / 2 ,height / 2 );
prevX = x;
prevY = y;
return ;
}

// 鼠标停止时移动相机
float yaw = - (x - width / 2 )* 0 .002f;
camera.Yaw(偏航);

float pitch = - (y - height / 2 )* 0 .002f;
camera.Pitch(pitch);

prevX = x;
prevY = y;
Program.WarpPointer(width / 2 ,height / 2 );
base .OnMove(x,y);
}
private int layerIndex = 0 ;
private int layerDim = 2 ;
private int state = 0 ;
private Vector3 startChunk = new Vector3(-1, 0 , - 1);
private void CreateChunk()
{
while true
{
int size = 8 ;
// chunks.Add(new Chunk(new Vector3(nextChunk.X,nextChunk.Y,nextChunk。 Z),size));
// Console.WriteLine(nextChunk.X.ToString ()+,+ nextChunk.Y.ToString()+,+ nextChunk.Z.ToString());
AddChunkFromThread( new Vector3(nextChunk.X,nextChunk.Y,nextChunk.Z),size);

if (state == 0 )nextChunk.X ++;
else if (state == 1 )nextChunk.Z ++;
else if (state == 2 )nextChunk.X--;
else if (state == 3 )nextChunk.Z--;

layerIndex ++;
if (layerIndex > = layerDim)
{
layerIndex = 0 ;
state ++;
}
if (state == 4
{
layerDim + = 2 ;
startChunk = new Vector3(startChunk.X - 1 0 ,startChunk.Z - 1 );
nextChunk = new Vector3(startChunk.X,startChunk.Y,startChunk.Z);
state = 0 ;
}
}
}
私有 void AddChunkFromThread (Vector3 pos, int size)
{
/ * if(this.InvokeRequired)
this.Invoke(new MethodInvoker(AddChunkFromThread));
else
{
chunks.Add(new Chunk(pos,size));
} * /

chunks.Add( new Chunk(pos,size));
}
public 覆盖 void OnClose()
{
/ * for(int i = 0; i < chunks.Count; i ++)
{
for(int q = 0; q< chunks [i] .block.GetLength(1); q ++)
for(int y = 0; y< chunks [i] .block.GetLength(0); y ++)
chunks [i] .block [y,q] .Dispose();
} * /

if (chunkThread!= null ) chunkThread.Abort();
base .OnClose();
}

}
}





块的代码:

 使用系统; 
使用 OpenGL;
使用 Tao.FreeGlut;
使用 System.Collections.Concurrent;

命名空间 OpenGLTutorial1
{
public class
{
public Vector3位置;
// public Block [,] block;
public ConcurrentBag块;
public Vector2 Size;
public 块(Vector3 pos, int size)
{
position = pos * new Vector3(size * 2,size * 2,size * 2);
// block = new Block [size,size];
blocks = new ConcurrentBag();
/ * for(int z = 0; z< block.GetLength(1); z ++)
for(int x = 0; x< block.GetLength(0); x ++)
{
block [x,z] = new Block((x * 2)+ position.X ,position.Y,(z * 2)+ position.Z,0);
} * /

for int z = 0 ; z < size; z ++)
for int x = 0 ; x < ; size; x ++)
{
blocks.Add( new Block((x * 2 )+ position.X,position.Y,(z * 2 )+ position.Z, 0 ));
// block [x,z] = new Block((x * 2)+ position.X, position.Y,(z * 2)+ position.Z,0);
}
Size = new Vector2(size ,大小);
}
public void 绘制( ref ShaderProgram程序)
{
/ * for(int z = 0 ; z< block.GetLength(1); z ++)
for(int x = 0; x< block.GetLength(0); x ++)
{
blocks [x,z ] .Draw(ref program);
} * /

foreach var item 块)
{
Block block =(Block)item;
block.Draw( ref program);
}
}
}
}





代码:

  public   class  Block 
{
public Vector3位置;
public string name;
public 纹理纹理;
私人多维数据集cube1;
public 块( float x, float y, float z, int id)
{
position = new Vector3(x,y,z);
cube1 = new 多维数据集(位置, 1 );
}
public void SetTexture(Texture newTexture)
{
texture = newTexture;
cube1.SetTexture(newTexture);
}
public void 绘制( ref ShaderProgram程序)
{
cube1.Draw( ref program);
}
public void Dispose()
{
cube1.Dispose();
}
}





这是来源



我尝试过:



我试图从List< chunk>切换到ConcurrentBag< chunk>,因为这是线程安全的,所以这可能不是问题。我是OpenGL的新手,我不习惯线程和东西,sooooo是的。

解决方案

您应该研究OpenGL共享上下文以更好地理解如何在OpenGL应用程序中执行线程。我承认我没有查看你的代码,但我相信我可以解释一下。您不能在应用程序的主UI线程以外的线程中绑定和写入资源。根据GPU驱动程序绘制时发生的情况考虑您的问题,同时从另一个线程执行对GPU的数据上载操作。虽然使用共享上下文允许您跨线程传输几何和纹理数据,但另一方面,着色器程序,VAO,VBO,Framebuffers必须绑定并仅从主UI线程分配数据。一种常见的策略是对昂贵的操作(例如位图加载)进行编程,以便为GPU上传准备数据,并在主UI线程上排队与该数据相关的OpenGL请求(最有可能是OnUpdateFrame()函数)。您应该考虑的另一个重要因素是,并非所有驱动程序实现都支持使用OpenGL共享上下文共享资源数据。


So I've had this problem for some time now and I'm hoping you guys have a solution for it. I'm trying to create chunks through a thread, and then add the chunk to my list in my main class, where I so draw the chunk. But it fails when trying to set the VBO that contains the vertices of a cube, and I get this exception: 'System.AccessViolationException'.

This is my code for the cube:

public Cube(Vector3 pos, float dimension)
{
    position = pos;
    dimensions = dimension;

    float cubePos = dimension;
    cube = new VBO(new Vector3[] {
        new Vector3(cubePos, cubePos, -cubePos), new Vector3(-cubePos, cubePos, -cubePos), new Vector3(-cubePos, cubePos, cubePos), new Vector3(cubePos, cubePos, cubePos),
        new Vector3(cubePos, -cubePos, cubePos), new Vector3(-cubePos, -cubePos, cubePos), new Vector3(-cubePos, -cubePos, -cubePos), new Vector3(cubePos, -cubePos, -cubePos),
        new Vector3(cubePos, cubePos, cubePos), new Vector3(-cubePos, cubePos, cubePos), new Vector3(-cubePos, -cubePos, cubePos), new Vector3(cubePos, -cubePos, cubePos),
        new Vector3(cubePos, -cubePos, -cubePos), new Vector3(-cubePos, -cubePos, -cubePos), new Vector3(-cubePos, cubePos, -cubePos), new Vector3(cubePos, cubePos, -cubePos),
        new Vector3(-cubePos, cubePos, cubePos), new Vector3(-cubePos, cubePos, -cubePos), new Vector3(-cubePos, -cubePos, -cubePos), new Vector3(-cubePos, -cubePos, cubePos),
        new Vector3(cubePos, cubePos, -cubePos), new Vector3(cubePos, cubePos, cubePos), new Vector3(cubePos, -cubePos, cubePos), new Vector3(cubePos, -cubePos, -cubePos) });

    color = new VBO(new Vector3[] {
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
        new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1), });

    elements = new VBO(new int[] { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}, BufferTarget.ElementArrayBuffer);
}



This is my code in my main class:

using System;
using System.Threading;
using System.Windows.Forms;
using System.Collections.Generic;
using OpenGL;
using Tao.FreeGlut;
using System.Collections.Concurrent;

namespace OpenGLTutorial1
{
    public class Game1 : Game
    {
        private Block block;
        private Camera camera;
        private bool left = false, forward = false, back = false, right = false, up = false;

        //private List chunks = new List();
        private ConcurrentBag chunks = new ConcurrentBag();
        private Thread chunkThread;

        private Vector3 nextChunk;
        public override void LoadContent()
        {
            camera = new Camera(new Vector3(0, 50, 0), Quaternion.Identity);
            camera.SetDirection(new Vector3(0, 0, -1));
            //cube1 = new Cube(Vector3.Zero, 1, "dirt.jpg");
            Program.SetCursor(Glut.GLUT_CURSOR_NONE);

            Global.Manager.LoadBlocks("Blocks.xml");

            block = Global.Manager.NewBlock(new Vector3(0, 0, 0), 0);

            chunks.Add(new Chunk(Vector3.Zero, 8));
            chunkThread = new Thread(CreateChunk);
            //chunkThread.SetApartmentState(ApartmentState.STA);
            chunkThread.Start();

            nextChunk = new Vector3(startChunk.X, startChunk.Y, startChunk.Z);

            Program.SetViewMatrix(camera.ViewMatrix);
            base.LoadContent();
        }
        private static float add = 0;
        private static int speed = 5;
        public override void Update(float deltaTime)
        {
            Program.SetViewMatrix(camera.ViewMatrix);

            if (back) camera.MoveRelativeXZ(Vector3.UnitZ * deltaTime * speed);
            if (forward) camera.MoveRelativeXZ(-Vector3.UnitZ * deltaTime * speed);
            if (left) camera.MoveRelativeXZ(-Vector3.UnitX * deltaTime * speed);
            if (right) camera.MoveRelativeXZ(Vector3.UnitX * deltaTime * speed);
            if (up) camera.Move(new Vector3(0, deltaTime * 2.5f, 0));

            /*add += deltaTime*100;
            if (add >= 20)
            {
                CreateChunk();
                add = 0;
            }*/
            base.Update(deltaTime);
        }
        public override void Draw(ref ShaderProgram program)
        {
            block.Draw(ref program);
            foreach (var item in chunks)
            {
                Chunk chunk= (Chunk)item;
                chunk.Draw(ref program);
            }
            base.Draw(ref program);
        }
        public override void OnKeyboardDown(byte key, int x, int y)
        {
            if (key == 'd') right = true;
            else if (key == 'a') left = true;
            else if (key == 'w') forward = true;
            else if (key == 's') back = true;
            else if (key == ' ') up = true;
            base.OnKeyboardDown(key, x, y);
        }
        public override void OnKeyboardUp(byte key, int x, int y)
        {
            if (key == 'd') right = false;
            else if (key == 'a') left = false;
            else if (key == 'w') forward = false;
            else if (key == 's') back = false;
            else if (key == ' ') up = false;
            base.OnKeyboardUp(key, x, y);
        }
        private int prevX = 0, prevY = 0;
        public override void OnMove(int x, int y)
        {
            // if the mouse move event is caused by glutWarpPointer then do nothing
            if (x == prevX && y == prevY) return;
            if (prevX == 0 && prevY == 0)
            {
                Program.WarpPointer(width / 2, height / 2);
                prevX = x;
                prevY = y;
                return;
            }

            // move the camera when the mouse is down
            float yaw = -(x - width / 2) * 0.002f;
            camera.Yaw(yaw);

            float pitch = -(y - height / 2) * 0.002f;
            camera.Pitch(pitch);

            prevX = x;
            prevY = y;
            Program.WarpPointer(width / 2, height / 2);
            base.OnMove(x, y);
        }
        private int layerIndex = 0;
        private int layerDim = 2;
        private int state = 0;
        private Vector3 startChunk = new Vector3(-1, 0, -1);
        private void CreateChunk()
        {
            while (true)
            {
                int size = 8;
                //chunks.Add(new Chunk(new Vector3(nextChunk.X, nextChunk.Y, nextChunk.Z), size));
                //Console.WriteLine(nextChunk.X.ToString() + ", " + nextChunk.Y.ToString() + ", " + nextChunk.Z.ToString());
                AddChunkFromThread(new Vector3(nextChunk.X, nextChunk.Y, nextChunk.Z), size);

                if (state == 0) nextChunk.X++;
                else if (state == 1) nextChunk.Z++;
                else if (state == 2) nextChunk.X--;
                else if (state == 3) nextChunk.Z--;

                layerIndex++;
                if (layerIndex >= layerDim)
                {
                    layerIndex = 0;
                    state++;
                }
                if (state == 4)
                {
                    layerDim += 2;
                    startChunk = new Vector3(startChunk.X - 1, 0, startChunk.Z - 1);
                    nextChunk = new Vector3(startChunk.X, startChunk.Y, startChunk.Z);
                    state = 0;
                }
            }
        }
        private void AddChunkFromThread(Vector3 pos, int size)
        {
            /*if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(AddChunkFromThread));
            else
            {
                chunks.Add(new Chunk(pos, size));
            }*/
            chunks.Add(new Chunk(pos, size));
        }
        public override void OnClose()
        {
            /*for (int i = 0; i < chunks.Count; i++)
            {
                for (int q = 0; q < chunks[i].block.GetLength(1); q++)
                    for (int y = 0; y < chunks[i].block.GetLength(0); y++)
                        chunks[i].block[y, q].Dispose();
            }*/
            if (chunkThread != null) chunkThread.Abort();
            base.OnClose();
        }

    }
}



Code for the Chunk:

using System;
using OpenGL;
using Tao.FreeGlut;
using System.Collections.Concurrent;

namespace OpenGLTutorial1
{
    public class Chunk
    {
        public Vector3 position;
        //public Block[,] block;
        public ConcurrentBag blocks;
        public Vector2 Size;
        public Chunk(Vector3 pos, int size)
        {
            position = pos * new Vector3(size*2, size*2, size*2);
            //block = new Block[size, size];
            blocks = new ConcurrentBag();
            /*for(int z = 0; z < block.GetLength(1); z++)
                for(int x = 0; x < block.GetLength(0); x++)
                {
                    block[x, z] = new Block((x*2)+ position.X, position.Y,(z*2)+ position.Z, 0);
                }*/
            for (int z = 0; z < size; z++)
                for (int x = 0; x < size; x++)
                {
                    blocks.Add(new Block((x * 2) + position.X, position.Y, (z * 2) + position.Z, 0));
                    //block[x, z] = new Block((x * 2) + position.X, position.Y, (z * 2) + position.Z, 0);
                }
            Size = new Vector2(size, size);
        }
        public void Draw(ref ShaderProgram program)
        {
            /*for (int z = 0; z < block.GetLength(1); z++)
                for (int x = 0; x < block.GetLength(0); x++)
                {
                    blocks[x, z].Draw(ref program);
                }*/
            foreach(var item in blocks)
            {
                Block block = (Block)item;
                block.Draw(ref program);
            }
        }
    }
}



Code for Block:

public class Block
{
    public Vector3 position;
    public string name;
    public Texture texture;
    private Cube cube1;
    public Block(float x, float y, float z, int id)
    {
        position = new Vector3(x, y, z);
        cube1 = new Cube(position, 1);
    }
    public void SetTexture(Texture newTexture)
    {
        texture = newTexture;
        cube1.SetTexture(newTexture);
    }
    public void Draw(ref ShaderProgram program)
    {
        cube1.Draw(ref program);
    }
    public void Dispose()
    {
        cube1.Dispose();
    }
}



Here is the source

What I have tried:

I've tried to switch from a List<chunk> to a ConcurrentBag<chunk>, because that is thread safe, so that might not be the problem. I'm pretty new to OpenGL and I'm not used to threads and stuff, sooooo yeah.

解决方案

You should research OpenGL shared context to get a better understanding of how to perform threading in an OpenGL application. I admit I did not look into your code but I believe I can shed some light. You cannot bind and write resources in a thread other than the main UI thread of your application. Think about your problem in terms of what happens when the GPU driver is drawing while at the same time data upload operations to the GPU are performed from another thread. While using shared context allows you to transfer geometry and texture data across threads, on the other hand shader programs, VAOs, VBOs, Framebuffers must be bound and assigned data from the main UI thread only. A common strategy is to thread expensive operations (such as bitmap loading) in order to prepare data for GPU upload and queue the OpenGL requests relevant to that data on the main UI thread (OnUpdateFrame() function most likely). Another important factor you should consider is that sharing resource data using OpenGL shared context is not always supported by all driver implementations.


这篇关于使用opengl和列表的C#线程问题!的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆