本文基础:C#+OpenGL编程之环境搭建
载入一个模型,光秃秃的可不好,这课开始学习纹理载入,纹理载入需要注意的地方就是最好只载入一次纹理,否则容易影响性能。
C# 载入纹理要比C方便多了,问题在于C# 的GDI+不支持TGA载入,我就网上找了个类,这里请大家去原作者那里看了。
如需素材或C代码请参考原书资料下载http://down.51cto.com/data/201697
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Tao.Glfw;
using Tao.OpenGl;
namespace OpenGL
{
/// <summary>
/// 第四章 OpenGl 纹理载入 C# by 大师♂罗莊
/// </summary>
class OpenGLTexture : Examplefirst
{
float rot = 0;
TextureLoad texture2 = new TextureLoad(), texture1 = new TextureLoad();
public OpenGLTexture()
: base()
{
LoadTexture();///原则上材质只应该在初始化时候载入一次,否则会影响性能
base.title = "第四章 OpenGl 纹理载入";
}
/** 载入纹理数据 */
bool LoadTexture()
{
/** 载入位图文件 */
if (texture1.Load(Path.Combine(Application.StartupPath, @"Image\image.bmp").ToString()) == false) /**< 载入位图文件 */
{
MessageBox.Show("无法载入");
return false;
}
/** 载入TGA文件 */
if (texture2.Load(Path.Combine(Application.StartupPath, @"Image\sphere.tga").ToString()) == false) /**< 载入TGA文件 */
{
MessageBox.Show("无法载入"); /**< 如果载入失败则弹出对话框 */
return false;
}
/** 启用纹理映射 */
Gl.glEnable(Gl.GL_TEXTURE_2D);
return true;
}
/** 设置光源 */
void SetLight()
{
/** 定义光源的属性值 */
float[] LightAmbient = new float[] { 0.5f, 0.5f, 0.5f, 1.0f }; /**< 环境光参数 */
float[] LightDiffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; /**< 漫射光参数 */
float[] LightSpecular = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; /**< 镜面光参数 */
float[] LightPosition = new float[] { 0.0f, 0.0f, 2.0f, 1.0f }; /**< 光源位置 */
/** 设置光源的属性值 */
Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, LightAmbient); /**< 设置环境光 */
Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, LightDiffuse); /**< 设置漫射光 */
Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_SPECULAR, LightSpecular); /**< 设置漫射光 */
Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, LightPosition); /**< 设置光源位置 */
/** 启用光源 */
Gl.glEnable(Gl.GL_LIGHTING);
Gl.glEnable(Gl.GL_LIGHT1);
}
/// <summary>
/// 初始化视口投影,恢复原书的视口
/// </summary>
public override void iniView(int windowWidth, int windowHeight)
{
Glu.gluPerspective(45.0f, windowWidth / windowHeight, 1.0f, 100.0f);
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glLoadIdentity();
//启用深度测试
Gl.glClearDepth(1.0f);
Gl.glDepthFunc(Gl.GL_LEQUAL);
Gl.glEnable(Gl.GL_DEPTH_TEST);
//反锯齿
Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
Gl.glEnable(Gl.GL_NORMALIZE);
Gl.glEnable(Gl.GL_NORMALIZE);
/** 设置光源 */
SetLight();
}
/// <summary>
/// 重载
/// </summary>
/// <param name="mouseX"></param>
/// <param name="currentTime"></param>
public override void Update(float milliseconds)
{
//按下ESC结束
isRunning = ((Glfw.glfwGetKey(Glfw.GLFW_KEY_ESC) == Glfw.GLFW_RELEASE) &&
Glfw.glfwGetWindowParam(Glfw.GLFW_OPENED) == Gl.GL_TRUE);
rot =rot+ milliseconds * 10;
}
/** 用户自定义的卸载函数 */
public new void Dispose()
{
base.Dispose();
///** 用户自定义的卸载过程 */
texture1.FreeImage(); /** 释放纹理图像占用的内存 */
Gl.glDeleteTextures(1, texture1.ID); /**< 删除纹理对象 */
texture2.FreeImage(); /** 释放纹理图像占用的内存 */
Gl.glDeleteTextures(1, texture2.ID); /**< 删除纹理对象 */
}
/** 绘制球体 */
void DrawSphere()
{
Gl.glPushMatrix();
Gl.glTranslatef(2.0f, 0.0f, -10.0f);
Gl.glRotatef(rot, 0.0f, 1.0f, 1.0f);
/** 指定纹理 */
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture2.ID[0]);
Glu.GLUquadric sphere = Glu.gluNewQuadric();
Glu.gluQuadricOrientation(sphere, Glu.GLU_OUTSIDE);
Glu.gluQuadricNormals(sphere, Glu.GLU_SMOOTH);
Glu.gluQuadricTexture(sphere, Gl.GL_TRUE);
Glu.gluSphere(sphere, 1.5, 50, 50);
Glu.gluDeleteQuadric(sphere);
Gl.glPopMatrix();
}
/** 绘制木箱 */
void DrawBox()
{
/** 设置材质属性 */
float[] mat_ambient = new float[] { 0.8f, 0.8f, 0.8f, 1.0f };
float[] mat_diffuse = new float[] { 0.8f, 0.8f, 0.8f, 1.0f };
Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT, mat_ambient);
Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_DIFFUSE, mat_diffuse);
Gl.glPushMatrix();
Gl.glTranslatef(-2.0f, 0.0f, -10.0f);
Gl.glRotatef(rot, 1.0f, 1.0f, 0.0f);
/** 选择纹理 */
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture1.ID[0]);
/** 开始绘制四边形 */
Gl.glBegin(Gl.GL_QUADS);
/// 前侧面
Gl.glNormal3f(0.0f, 0.0f, 1.0f); /**< 指定法线指向观察者 */
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(-1.0f, -1.0f, 1.0f);
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(1.0f, -1.0f, 1.0f);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(1.0f, 1.0f, 1.0f);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(-1.0f, 1.0f, 1.0f);
/// 后侧面
Gl.glNormal3f(0.0f, 0.0f, -1.0f); /**< 指定法线背向观察者 */
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(-1.0f, -1.0f, -1.0f);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(-1.0f, 1.0f, -1.0f);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(1.0f, 1.0f, -1.0f);
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(1.0f, -1.0f, -1.0f);
/// 顶面
Gl.glNormal3f(0.0f, 1.0f, 0.0f); /**< 指定法线向上 */
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(-1.0f, 1.0f, -1.0f);
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(-1.0f, 1.0f, 1.0f);
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(1.0f, 1.0f, 1.0f);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(1.0f, 1.0f, -1.0f);
/// 底面
Gl.glNormal3f(0.0f, -1.0f, 0.0f); /**< 指定法线朝下 */
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(-1.0f, -1.0f, -1.0f);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(1.0f, -1.0f, -1.0f);
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(1.0f, -1.0f, 1.0f);
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(-1.0f, -1.0f, 1.0f);
/// 右侧面
Gl.glNormal3f(1.0f, 0.0f, 0.0f); /**< 指定法线朝右 */
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(1.0f, -1.0f, -1.0f);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(1.0f, 1.0f, -1.0f);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(1.0f, 1.0f, 1.0f);
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(1.0f, -1.0f, 1.0f);
/// 左侧面
Gl.glNormal3f(-1.0f, 0.0f, 0.0f); /**< 指定法线朝左 */
Gl.glTexCoord2f(0.0f, 0.0f); Gl.glVertex3f(-1.0f, -1.0f, -1.0f);
Gl.glTexCoord2f(1.0f, 0.0f); Gl.glVertex3f(-1.0f, -1.0f, 1.0f);
Gl.glTexCoord2f(1.0f, 1.0f); Gl.glVertex3f(-1.0f, 1.0f, 1.0f);
Gl.glTexCoord2f(0.0f, 1.0f); Gl.glVertex3f(-1.0f, 1.0f, -1.0f);
Gl.glEnd();
Gl.glPopMatrix();
}
/// <summary>
/// 重载,使用Draw方法绘图
/// </summary>
/// <param name="mouseX"></param>
/// <param name="currentTime"></param>
public override void DrawGLScene(int mouseX, double currentTime)
{
Draw();
}
/** 绘制函数 */
void Draw()
{
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
Gl.glLoadIdentity();
/** 绘制过程 */
DrawSphere();
DrawBox();
/** 强制执行所有的OpenGl命令 */
Gl.glFlush();
}
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Tao.Glfw;
using Tao.OpenGl;
namespace OpenGL
{
/// <summary>
/// 自制的纹理载入类 C# by 大师♂罗莊
/// </summary>
class TextureLoad : IDisposable
{
public int[] ID = new int[3];
Bitmap image;
public bool Load(String fileName)
{
///原则上材质只应该在初始化时候载入一次,否则会影响性能
if (image != null)
{
return true;
}
FileInfo file = new FileInfo(fileName);
if (file.Exists == false)
{
MessageBox.Show("无法载入" + fileName);
return false;
}
try
{
if (file.Extension.ToUpper() == ".TGA")
{
///C# 载入TGA 类,自行参考,这里不再列出
ImageTGA tga = new ImageTGA(fileName);
image = tga.Image;
}
else
{
image = new Bitmap(fileName);
}
}
catch (System.ArgumentException)
{
MessageBox.Show("无法载入" + fileName);
return false;
}
if (image != null)
{
image.RotateFlip(RotateFlipType.RotateNoneFlipY);
System.Drawing.Imaging.BitmapData bitmapdata;
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
///Nearest Linear MipMapped三个纹理实现,本文暂时不考虑
//bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//Gl.glGenTextures(3, this.texture);
Create Nearest Filtered Texture
//Gl.glBindTexture(Gl.GL_TEXTURE_2D, this.texture[0]);
//Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
//Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
//Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, (int)Gl.GL_RGB, image.Width, image.Height, 0, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE, bitmapdata.Scan0);
Create Linear Filtered Texture
//Gl.glBindTexture(Gl.GL_TEXTURE_2D, this.texture[1]);
//Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
//Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
//Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, (int)Gl.GL_RGB, image.Width, image.Height, 0, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE, bitmapdata.Scan0);
Create MipMapped Texture
//Gl.glBindTexture(Gl.GL_TEXTURE_2D, this.texture[2]);
//Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
//Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_NEAREST);
//Gl.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, (int)Gl.GL_RGB, image.Width, image.Height, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE, bitmapdata.Scan0);
//image.UnlockBits(bitmapdata);
/** 生成纹理对象名称 */
Gl.glGenTextures(3, ID);
/** 创建纹理对象 */
Gl.glBindTexture(Gl.GL_TEXTURE_2D, ID[0]);
/** 控制滤波 */
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
/** 创建纹理 */
Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB, image.Width,
image.Height, Gl.GL_BGR_EXT, Gl.GL_UNSIGNED_BYTE,
bitmapdata.Scan0);
image.UnlockBits(bitmapdata);
}
return true;
}
public void FreeImage()
{
/** 释放内存 */
if (image != null)
{
image.Dispose();
}
}
public void Dispose()
{
FreeImage();
}
}
}