hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

C# winform用sharpGL(OpenGl)剖析读取3D模子obj

2019-11-18杂谈搜奇网25°c
A+ A-

 

 

原文作者:aircraft

原文链接:https://www.cnblogs.com/DOMLX/p/11783026.html

 

    本身写了个简朴的类读取剖析obj模子,运用导入类,然后new个对象,在读取obj模子,然后挪用显现列表显现就能够了。至于其他什么扭转挪动的你们本身加起来应当很轻易的,因为我有看过c#下他人写的obj模子剖析的代码项目,加了许多东西,我都找不到本身要用的代码在那里,而我只须要读取剖析obj模子这块代码罢了,气的我本身写了个类本身剖析,所以我怕我代码写多了,

你们反而看起来不好明白hhhhhh

 

 在c++下用OpenGL剖析的话能够看我其他博客

 

运转环境:vs2017,须要设置的库为:sharpGL

一.读取3D模子

 

  在3d图形处置惩罚中,一个模子(model)平常由一个或许多个Mesh(网格)构成,一个Mesh是可绘制的自力实体。比方庞杂的人物模子,能够离别划分为头部,四肢,衣饰,兵器等各个部分来建模,这些Mesh组合在一起终究构成人物模子。

Mesh由极点、边、面Faces构成的,它包括绘制所需的数据,比方极点位置、纹理坐标、法向量,材质属性等内容,它是OpenGL用来绘制的最小实体。Mesh的观点示意如下图所示(来自:What is a mesh in OpenGL?):


Mesh

Mesh能够包括多个Face,一个Face是Mesh中一个可绘制的基本图元,比方三角形,多边形,点。要想模子越发传神,平常须要增添更多图元使Mesh越发邃密,固然这也会遭到硬件处置惩罚才能的限定,比方PC游戏的处置惩罚才能要强于挪动装备。因为多边形都能够划分为三角形,而三角形是图形处置惩罚器中都支撑的基本图元,因而运用得较多的就是三角形网格来建模。比方下面的图(来自:What is a mesh in OpenGL?)表达了运用愈来愈庞杂的Mesh建模一只兔子的历程:

Mesh2

 

 

 


随着增添三角形个数,兔子模子变得愈来愈实在。

 

  读取3d模子有许多种要领,然则最常常使用的不过就是挪用他人写好的库,比方(openmesh),其次呢就是本身读取剖析3d模子文件内里的一个个坐标数据,什么v  vf  vn之类的。

 

那末如今就是讲一下第二种要领,就是直接剖析读取3d模子文件,提取内里我们所需的数据。下面是一个obj的模子文件,我们能够运用记事本翻开看看内里是什么:

 

# Blender3D v249 OBJ File: untitled.blend
# www.blender3d.org
mtllib cube.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.748573 0.750412
vt 0.749279 0.501284
vt 0.999110 0.501077
vt 0.999455 0.750380
vt 0.250471 0.500702
vt 0.249682 0.749677
vt 0.001085 0.750380
vt 0.001517 0.499994
vt 0.499422 0.500239
vt 0.500149 0.750166
vt 0.748355 0.998230
vt 0.500193 0.998728
vt 0.498993 0.250415
vt 0.748953 0.250920
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000001 0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn 0.000000 1.000000 -0.000000
vn -0.000000 -1.000000 0.000000
usemtl Material_ray.png
s off
f 5/1/1 1/2/1 4/3/1
f 5/1/1 4/3/1 8/4/1
f 3/5/2 7/6/2 8/7/2
f 3/5/2 8/7/2 4/8/2
f 2/9/3 6/10/3 3/5/3
f 6/10/4 7/6/4 3/5/4
f 1/2/5 5/1/5 2/9/5
f 5/1/6 6/10/6 2/9/6
f 5/1/7 8/11/7 6/10/7
f 8/11/7 7/12/7 6/10/7
f 1/2/8 2/9/8 3/13/8
f 1/2/8 3/13/8 4/14/8

 

对这个文本花样做一个扼要申明:

  1.     以#最先的行动解释行
  2.     usemtl和mtllib示意的材质相干数据,剖析材质数据轻微烦琐,本节我们只是为了申明加载模子的道理,不做议论。
  3.     o 引入一个新的object
  4.     v 示意极点位置
  5.     vt 示意极点纹理坐标
  6.     vn 示意极点法向量
  7.     f 示意一个面,面运用1/2/8如许花样,示意极点位置/纹理坐标/法向量的索引,这里索引的是前面用v,vt,vn定义的数据 注重这里Obj的索引是从1最先的,而不是0

那末我们只需拿到这些数据,根据opengl的绘制的划定规矩,不就能够把他们都绘制出来了吗?

 

读取数据obj的类myReadobj.cs

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Collections;

using SharpGL;
namespace WindowsFormsApp5
{
    class myReadObj
    {
        public myReadObj()
        {

        }
        public class POINT3
        {
            public double X;
            public double Y;
            public double Z;
        };
        public class WenLi
        {
            public double TU;
            public double TV;
        };
        public class FaXiangLiang
        {
            public double NX;
            public double NY;
            public double NZ;
        };
        public class Mian
        {
            public int[] V = new int[3];
            public int[] T = new int[3];
            public int[] N = new int[3];
        };
        public class Model
        {

            public List<POINT3> V = new List<POINT3>();//V:代表极点。花样为V X Y Z,V背面的X Y Z示意三个极点坐标。浮点型
            public List<WenLi> VT = new List<WenLi>();//示意纹理坐标。花样为VT TU TV。浮点型
            public List<FaXiangLiang> VN = new List<FaXiangLiang>();//VN:法向量。每一个三角形的三个极点都要指定一个法向量。花样为VN NX NY NZ。浮点型
            public List<Mian> F = new List<Mian>();//F:面。面背面随着的整型值离别是属于这个面的极点、纹理坐标、法向量的索引。
                                                   //面的花样为:f Vertex1/Texture1/Normal1 Vertex2/Texture2/Normal2 Vertex3/Texture3/Normal3
        }

        public Model mesh = new Model();
        public float movX;
        public float movY;
        public float movZ;
        public float xRotate;
        public float yRotate;
        public float x;
        public float y;

        //放缩参数
        public static float scale;
        //显现列表
        public uint showFaceList;

        public  int YU = 1;

        public void loadFile(String fileName)
        {
            // Mian[] f;
            //POINT3[] v;
            //FaXiangLiang[] vn;
            //WenLi[] vt;

            StreamReader objReader = new StreamReader(fileName);
            ArrayList al = new ArrayList();
            string texLineTem = "";
            while (objReader.Peek() != -1)
            {
                texLineTem = objReader.ReadLine();
                if (texLineTem.Length < 2) continue;
                if (texLineTem.IndexOf("v") == 0)
                {
                    if (texLineTem.IndexOf("t") == 1)//vt 0.581151 0.979929 纹理
                    {
                        string[] tempArray = texLineTem.Split(' ');
                        WenLi vt = new WenLi();
                        vt.TU = double.Parse(tempArray[1]);
                        vt.TV = double.Parse(tempArray[2]);
                        mesh.VT.Add(vt);
                    }
                    else if (texLineTem.IndexOf("n") == 1)//vn 0.637005 -0.0421857 0.769705 法向量
                    {
                        string[] tempArray = texLineTem.Split(new char[] { '/', ' ' }, System.StringSplitOptions.RemoveEmptyEntries); 
                        FaXiangLiang vn = new FaXiangLiang();
                        vn.NX = double.Parse(tempArray[1]);
                        vn.NY = double.Parse(tempArray[2]);
                        if (tempArray[3] == "\\")
                        {
                            texLineTem = objReader.ReadLine();
                            vn.NZ = double.Parse(texLineTem);
                        }
                        else vn.NZ = double.Parse(tempArray[3]);

                        mesh.VN.Add(vn);
                    }
                    else
                    {//v -53.0413 158.84 -135.806 点
                        string[] tempArray = texLineTem.Split(' ');
                        POINT3 v = new POINT3();
                        v.X = double.Parse(tempArray[1]);
                        v.Y = double.Parse(tempArray[2]);
                        v.Z = double.Parse(tempArray[3]);
                        mesh.V.Add(v);
                    }
                }
                else if (texLineTem.IndexOf("f") == 0)
                {
                    //f 2443//2656 2442//2656 2444//2656 面
                    string[] tempArray = texLineTem.Split(new char[] { '/', ' ' }, System.StringSplitOptions.RemoveEmptyEntries);
                    Mian f = new Mian();
                    int i = 0;
                    int k = 1;
                    while (i < 3)
                    {
                        if (mesh.V.Count() != 0)
                        {
                            f.V[i] = int.Parse(tempArray[k]) - 1;
                            k++;
                        }
                        if (mesh.VT.Count() != 0)
                        {
                            f.T[i] = int.Parse(tempArray[k]) - 1;
                            k++;
                        }
                        if (mesh.VN.Count() != 0)
                        {
                            f.N[i] = int.Parse(tempArray[k]) - 1;
                            k++;
                        }
                        i++;
                    }
                    mesh.F.Add(f);

                }
            }

           
        }
        
        public uint createListFace(ref SharpGL.OpenGL gl)
        {
            gl.NewList(showFaceList, OpenGL.GL_COMPILE);
            if(mesh.V.Count() == 0) return 119;
            for (int i = 0; i < mesh.F.Count(); i++)
            {
                gl.Begin(OpenGL.GL_TRIANGLES);                          // 绘制三角形
                if (mesh.VT.Count() != 0) gl.TexCoord(mesh.VT[mesh.F[i].T[0]].TU, mesh.VT[mesh.F[i].T[0]].TV);  //纹理    
                if (mesh.VN.Count() != 0) gl.Normal(mesh.VN[mesh.F[i].N[0]].NX, mesh.VN[mesh.F[i].N[0]].NY, mesh.VN[mesh.F[i].N[0]].NZ);//法向量
                gl.Vertex(mesh.V[mesh.F[i].V[0]].X / YU, mesh.V[mesh.F[i].V[0]].Y / YU, mesh.V[mesh.F[i].V[0]].Z / YU);        // 上极点

                if (mesh.VT.Count() != 0) gl.TexCoord(mesh.VT[mesh.F[i].T[1]].TU, mesh.VT[mesh.F[i].T[1]].TV);  //纹理
                if (mesh.VN.Count() != 0) gl.Normal(mesh.VN[mesh.F[i].N[1]].NX, mesh.VN[mesh.F[i].N[1]].NY, mesh.VN[mesh.F[i].N[1]].NZ);//法向量
                gl.Vertex(mesh.V[mesh.F[i].V[1]].X / YU, mesh.V[mesh.F[i].V[1]].Y / YU, mesh.V[mesh.F[i].V[1]].Z / YU);        // 左下

                if (mesh.VT.Count() != 0) gl.TexCoord(mesh.VT[mesh.F[i].T[2]].TU, mesh.VT[mesh.F[i].T[2]].TV);  //纹理
                if (mesh.VN.Count() != 0) gl.Normal(mesh.VN[mesh.F[i].N[2]].NX, mesh.VN[mesh.F[i].N[2]].NY, mesh.VN[mesh.F[i].N[2]].NZ);//法向量
                gl.Vertex(mesh.V[mesh.F[i].V[2]].X / YU, mesh.V[mesh.F[i].V[2]].Y / YU, mesh.V[mesh.F[i].V[2]].Z / YU);        // 右下
                gl.End();                                        // 三角形绘制完毕    
            }
            gl.EndList();
            return  showFaceList;
        }
    }
}

 

本身拿来用的话改一下这句 为你们的定名空间名字就好了 namespace WindowsFormsApp5

 

因为前天赋最先学c#,所以照样不太晓得c#的一些语法,写法作风也倾向我常常写的c++,人人将就着看吧。。。。。等我多学几天,学点c#的代码范例再从新改吧。。。

 

 

挪用要领也很简朴,在winform下的话,在openglControl控件的draw事宜中加下面的代码:

第一步:New一个对象

第二步:读取本身途径下的obj模子文件

第三步:挪用显现列表绘制图案

 

 private void openGLControl1_OpenGLDraw(object sender, SharpGL.RenderEventArgs args)
        {
            // 建立一个GL对象
            SharpGL.OpenGL gl = this.openGLControl1.OpenGL;

            gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);    // 清空屏幕
            gl.LoadIdentity();                    // 重置
            gl.Translate(0.0f, 0.0f, -6.0f);    // 设置坐标,间隔屏幕间隔为6

            gl.Rotate(0, 1.0f, 0.0f, 0.0f);    // 绕X轴扭转
            gl.Rotate(y, 0.0f, 1.0f, 0.0f);    // 绕Y轴扭转
            gl.Rotate(0, 0.0f, 0.0f, 1.0f);    // 绕Z轴扭转
            gl.Scale(0.003, 0.003, 0.003);
            myReadObj obj = new myReadObj();
            obj.loadFile("bunny.obj");
            obj.createListFace(ref gl);
            gl.CallList(obj.showFaceList);
            
        }

 

 

 

对了假如用opengl读取模子剖析3d模子后看起来像个2d的模样,不过就是你的光照题目,或许模子文件内里没有极点法线vt存在。。这时候能够借助一些3d模子操纵软件 导入从新生成保留。

 

 

运转效果:

 

 

项目代码百度云链接关注下面民众号,增加小编微信,发送文章题目加源码猎取。。。。。

 

 

如有兴致交换分享手艺,可关注本人民众号,内里会不定期的分享种种编程教程,和同享源码,诸如研讨分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机械进修深度进修之类有关于基本编程,图象处置惩罚和机械视觉开辟的学问

 

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
C# winform用sharpGL(OpenGl)剖析读取3D模子obj

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282079.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>