C# 和 OpenGL 实现 3D 广场探索





5.00/5 (20投票s)
在 OpenGL 和 C# 中探索一个简单的 3D 广场
引言
这个演示使用了TAO框架,它基本上是一个从.NET到Windows OpenGL的Interop库。它还包含一个由我自己编写的小引擎,名为ShadowEngine
,它封装了图形初始化、纹理和模型加载等任务。
好的,让我一步一步地解释这个项目。
SkyBox.cs
这个类用于绘制你在演示中看到的天空和山脉,它基本上是一个带有图像的盒子。这种技术被用于当今90%的游戏中,当然,它会与其他技术混合使用以使其更逼真。
看看我是如何绘制天空盒的一部分的
Gl.glEnable(Gl.GL_TEXTURE_2D); // enable opengl texturing
Gl.glBindTexture(Gl.GL_TEXTURE_2D,ContentManager.GetTextureByName
("back.bmp")); //enabling texture for the portion of the skybox
Gl.glBegin(Gl.GL_QUADS);
Gl.glNormal3d(-1, 1, 1);
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3d(x + width, y, z);
Gl.glNormal3d(-1, -1, 1);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3d(x + width, y + height, z);
Gl.glNormal3d(1, -1, 1);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3d(x, y + height, z);
Gl.glNormal3d(1, 1, 1);
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3d(x, y, z);
Gl.glEnd();
使用Gl.glVertex3d
,
我在屏幕上绘制一个正方形的点,使用Gl.
glTexCoord2f
, 我告诉OpenGL正方形上的图像在哪里,使用Gl.glNormal3d
, 我告诉openGL正方形的方向。所有这些调用都是在Gl.glBegin(Gl.GL_QUADS)
和Gl.glEnd()
之间进行的。
Plaza.cs 和 碰撞
这个类处理绘制广场,它基本上是用纹理绘制3D模型。这个过程被封装起来,所以你只能在create
函数中看到它
m = ContentManager.GetModelByName("plaza.3DS"); // get the model
m.CreateDisplayList(); // this loads the model in opengl memory(displays lists)
以及在Draw
函数中
Gl.glPushMatrix();
Gl.glTranslatef(0, 1.4f, 0);
Gl.glScalef(0.2f, 0.2f, 0.2f);
m.DrawWithTextures();
Gl.glPopMatrix();
广场的碰撞以一种非常简单的方式实现,并且仅用于学习目的,因为当今的游戏使用非常复杂的架构来处理碰撞,这让地球上的普通人无法理解。碰撞针对摄像机,并且有两种类型的碰撞。第一种是碰撞点,例如喷泉和支撑旗帜的杆子,对于这种碰撞,你只需要告诉碰撞管理器这些点的3D位置,然后告诉一个数字,即在触发碰撞之前你希望摄像机靠近它的距离。另一种是碰撞线,例如,如果你不希望用户离开广场,则会有四条碰撞线,这里是代码的示例。
public void CreateCollisions()
{
CollisionPoint c1 = new CollisionPoint();
c1.point = new Point3D(1.5f, 9.0f, 0);
c1.ColitionDistance = 2.3f;
c1.enabled = true;
CollisionPoint c2 = new CollisionPoint();
c2.point = new Point3D(-0.35f, -3.97f, 0);
c2.ColitionDistance = 0.3f;
c2.enabled = true;
Collision.AddCollisionPoint(c1);
Collision.AddCollisionPoint(c2);
Collision.AddCollisionSegment(new Point3D(-14.4f, 28.3f, 0),
new Point3D(-14.5f, -11.6f, 0), 0.5f);
Collision.AddCollisionSegment(new Point3D(-14.4f, -11.6f, 0),
new Point3D(20.1f, -11.7f, 0), 0.5f);
}
Flag.cs
解释旗帜的制作超出了本文的范围,我从www.nehe.com的旗帜教程中借用了大部分代码。为了使一个困难的解释变得容易,我告诉说旗帜是一个点的网格,这些点乘以一个正弦函数,为什么是正弦函数,看看正弦函数是什么样的,你就会明白。
然后,每一帧我都会绘制,我将所有点从左向右移动一步,并将最右边的点移动到第一个左边的点。瞧,你看到一面飘扬的旗帜。这是代码的一部分
for (int x = 0; x < 47; x++)
{
// Loop Through The Y Plane
for (int y = 0; y < 10; y++)
{
// Apply The Wave To Our Mesh
points[x, y, 0] = (float)((x / 5.0f) - 0.1f);
points[x, y, 1] = (float)((y / 1.125f) - 0.1f);
points[x, y, 2] =
(float)(Math.Sin(Helper.DegreeToRad(((x/ 5.0f) * 40.0f)) * 2.0f));
}
}
Camera.cs
这个类用于处理摄像机的移动;它有一个第一人称射击摄像机。这个想法是将鼠标放在屏幕的中心,并将鼠标在X和Y方向上的每次移动转换为角度旋转,然后再次将鼠标放在屏幕中心。此外,摄像机在向某个方向移动之前会查询碰撞管理器。这是一个例子
if (!Collision.CheckCollision(new Point3D(-newEyeX, -newEyeZ, 0)))
{
eyex = newEyeX;
eyez = newEyeZ;
}
MainClass.cs 和 Mainform.cs
Mainclass
是Manager
类,它包含将在屏幕上绘制的所有对象,如果你希望某个对象不被绘制,只需在draw
函数中注释掉该对象即可
public void DrawScene()
{
plaza.Draw();
sky.Draw();
flag.Draw();
//DebugMode.WriteCamaraPos(200, 200); //work only in
32bits system
Collision.DrawColissions();
}
Mainform
是显示项目的Windows Form。它包含一个用于绘制和更新整个场景的计时器。
我希望收到关于这个例子的反馈。如果你喜欢它,你可以在下面留言。
历史
- 2014年7月15日:初始版本