笔者学到光源这一节,遇到的问题就比较多了,收集了一些如下所述:
- (1) 导入的3ds模型,如果没有材质光照效果很奇怪.如下图
- (2) 导入的3ds模型,有材质,灯光效果发暗,材质偏色,效果也很奇怪.下图中是有灯光的,但效果惨不忍睹.
- (3) 场景引入灯光后,场景中的物体的颜色就全部消失了,即合引入颜色材质,效果也是怪怪的.如下图中的栅格,它原本应该是蓝色的.
- (4) 场景中有物体引入材质后,整个场景的颜色就变得很奇怪下图中球体引入材质后,整个场景的颜色就变得很奇怪了.
-
(5) 导入的3ds模型,贴图颜色失真。
下图中的茶壶,柱体,地板的贴图分别对应上图材质图片,可以看到经过纹理映射后,贴图颜色失真。
这种问题并不是光源的问题,但是我也在这里一并列出来。-
像这些问题,因为不好形容,网上也找不到合适的答案.群里的高手们也不屑回答这些菜鸟问题,因此只好自力更生了.
我先上一段演示场景的代码:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using SharpGL; 10 11 namespace SharpGLWinformsApplication1 12 { 13 ///14 /// 原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/ 15 /// 16 public partial class SharpGLForm : Form 17 { 18 private float rotation = 0.0f,rotation2=0f,rotation3=0f; 19 SharpGL.SceneGraph.Assets.Texture textureBox = new SharpGL.SceneGraph.Assets.Texture(); 20 21 float[] fLightPosition = new float[4] { 16f, 9f, -18f, 0f };// 光源位置 22 float[] fLightAmbient = new float[4] { 1f, 1f, 1f, 0f };// 环境光参数 23 float[] fLightDiffuse = new float[4] { 1f, 1f, 1f,0f };// 漫射光参数 24 25 float[] fLightPosition2 = new float[4] { -7f, 5f, 2f, 0f };// 光源位置 26 float[] fLightAmbient2 = new float[4] { 0f, 0f, 1f, 0f };// 环境光参数 27 float[] fLightDiffuse2 = new float[4] { 0f, 0f, 1f, 0f };// 漫射光参数 28 29 bool f1 = false; 30 31 public SharpGLForm() 32 { 33 InitializeComponent(); 34 } 35 36 private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e) 37 { 38 OpenGL gl = openGLControl.OpenGL; 39 gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); 40 gl.LoadIdentity(); 41 gl.Rotate(rotation3, 0, 1, 0); 42 drawGrid(gl); 43 drawLightPT(gl); 44 drawLightPT2(gl); 45 drawTextrueBox(gl, 1, 0, 2); 46 drawSphere(gl, 2, 20, 20, false); 47 48 moveLightA(gl); 49 rotation3+=0.1f; 50 } 51 52 53 private void moveLightA(OpenGL gl) 54 { 55 if (!f1) 56 --fLightPosition[0]; 57 else 58 ++fLightPosition[0]; 59 if (fLightPosition[0] > 15f) 60 { 61 f1 = !f1; 62 } 63 else if (fLightPosition[0] < -25f) 64 { 65 f1 = !f1; 66 } 67 gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, fLightPosition);//光源位置 68 } 69 70 71 72 private void drawLightPT(OpenGL gl) 73 { 74 gl.PushMatrix(); 75 { 76 gl.Disable(OpenGL.GL_TEXTURE_2D); 77 gl.Color(0f,1f, 1f); 78 gl.Scale(0.2, 0.2, 0.2); 79 gl.Translate(fLightPosition[0]-5 , fLightPosition[1]+5, fLightPosition[2]); 80 drawBox(gl, 0, 0, 0); 81 } 82 gl.PopMatrix(); 83 } 84 85 private void drawLightPT2(OpenGL gl) 86 { 87 88 rotation2+=4f; 89 gl.PushMatrix(); 90 { 91 gl.LoadIdentity(); 92 gl.Disable(OpenGL.GL_TEXTURE_2D); 93 gl.Color(0f, 1f, 1f); 94 gl.Scale(0.2, 0.2, 0.2); 95 gl.Rotate(rotation2, 0, 1, 0); 96 gl.Translate(-28 , 8 , 5); 97 98 drawBox(gl, 0, 0, 0); 99 }100 gl.PopMatrix();101 }102 103 private void drawTextrueBox(OpenGL gl, float xPos, float yPos, float zPos)104 {105 rotation += 3.0f;106 gl.PushMatrix();107 {108 textureBox.Bind(gl);109 gl.Enable(OpenGL.GL_TEXTURE_2D);110 gl.Rotate(rotation, 0, 1, 0);111 gl.Translate(-1, 2, -5);112 gl.Scale(3, 3, 3);113 drawBox(gl,xPos, yPos, zPos);114 }115 gl.PopMatrix();116 }117 118 private void drawBox(OpenGL gl, float xPos, float yPos, float zPos)119 { 120 gl.PushMatrix();121 gl.Translate(xPos, yPos, zPos);122 123 gl.Begin(OpenGL.GL_QUADS);124 125 //前126 gl.TexCoord(0, 0); gl.Vertex(0, 0, 0);127 gl.TexCoord(1, 0); gl.Vertex(-1, 0, 0);128 gl.TexCoord(1, 1); gl.Vertex(-1, -1, 0);129 gl.TexCoord(0, 1); gl.Vertex(0, -1, 0);130 131 //底132 gl.TexCoord(0, 0); gl.Vertex(0, 0, 0);133 gl.TexCoord(1, 0); gl.Vertex(0, 0, -1);134 gl.TexCoord(1, 1); gl.Vertex(-1, 0, -1);135 gl.TexCoord(0, 1); gl.Vertex(-1, 0, 0);136 137 //左138 gl.TexCoord(0, 0); gl.Vertex(-1, 0, 0);139 gl.TexCoord(1, 0); gl.Vertex(-1, 0, -1);140 gl.TexCoord(1, 1); gl.Vertex(-1, -1, -1);141 gl.TexCoord(0, 1); gl.Vertex(-1, -1, 0);142 143 //右144 gl.TexCoord(0, 0); gl.Vertex(0, 0, 0);145 gl.TexCoord(1, 0); gl.Vertex(0, 0, -1);146 gl.TexCoord(1, 1); gl.Vertex(0, -1, -1);147 gl.TexCoord(0, 1); gl.Vertex(0, -1, 0);148 149 //后150 gl.TexCoord(0, 0); gl.Vertex(0, 0, -1);151 gl.TexCoord(1, 0); gl.Vertex(-1, 0, -1);152 gl.TexCoord(1, 1); gl.Vertex(-1, -1, -1);153 gl.TexCoord(0, 1); gl.Vertex(0, -1, -1);154 155 //顶156 gl.TexCoord(0, 0); gl.Vertex(0, -1, 0);157 gl.TexCoord(1, 0); gl.Vertex(0, -1, -1);158 gl.TexCoord(1, 1); gl.Vertex(-1, -1, -1);159 gl.TexCoord(0, 1); gl.Vertex(-1, -1, 0);160 161 162 gl.End();163 gl.PopMatrix();164 165 }166 167 void drawSphere(OpenGL gl, double radius, int segx, int segy, bool isLines)168 {169 170 gl.PushMatrix();171 gl.Disable(OpenGL.GL_TEXTURE_2D);172 gl.Translate(-7f, -1f, 2f);173 var sphere = gl.NewQuadric();174 175 if (isLines)176 gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);177 else178 gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);179 gl.QuadricNormals(sphere, OpenGL.GLU_SMOOTH);180 gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);181 gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);182 gl.Sphere(sphere, radius, segx, segy);183 gl.DeleteQuadric(sphere);184 gl.PopMatrix();185 186 }187 188 189 190 191 void drawGrid(OpenGL gl)192 {193 //关闭纹理和光照194 gl.Disable(OpenGL.GL_TEXTURE_2D);195 gl.Disable(OpenGL.GL_LIGHTING);196 197 //绘制过程198 gl.PushAttrib(OpenGL.GL_CURRENT_BIT); //保存当前属性199 gl.PushMatrix(); //压入堆栈200 gl.Translate(0f, -2f, 0f);201 gl.Color(0f, 0f, 1f);202 203 //在X,Z平面上绘制网格204 for (float i = -50; i <= 50; i += 1)205 {206 //绘制线207 gl.Begin(OpenGL.GL_LINES);208 {209 if (i == 0)210 gl.Color(0f, 1f, 0f);211 else212 gl.Color(0f, 0f, 1f);213 214 //X轴方向215 gl.Vertex(-50f, 0f, i);216 gl.Vertex(50f, 0f, i);217 //Z轴方向 218 gl.Vertex(i, 0f, -50f);219 gl.Vertex(i, 0f, 50f);220 221 }222 gl.End();223 }224 gl.PopMatrix();225 gl.PopAttrib();226 gl.Enable(OpenGL.GL_LIGHTING);227 }228 229 private void openGLControl_OpenGLInitialized(object sender, EventArgs e)230 {231 OpenGL gl = openGLControl.OpenGL;232 textureBox.Create(gl, "image.bmp");233 234 gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, fLightAmbient);//环境光源 235 gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, fLightDiffuse);//漫射光源 236 gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, fLightPosition);//光源位置 237 238 gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_AMBIENT, fLightAmbient2);//环境光源 239 gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_DIFFUSE, fLightDiffuse2);//漫射光源 240 gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, fLightPosition2);//光源位置 241 242 gl.Enable(OpenGL.GL_LIGHTING);//开启光照 243 gl.Enable(OpenGL.GL_LIGHT0);244 gl.Enable(OpenGL.GL_LIGHT1);245 246 gl.Enable(OpenGL.GL_NORMALIZE);247 gl.ClearColor(0, 0, 0, 0);248 249 }250 251 private void openGLControl_Resized(object sender, EventArgs e)252 {253 OpenGL gl = openGLControl.OpenGL;254 gl.MatrixMode(OpenGL.GL_PROJECTION);255 gl.LoadIdentity();256 gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);257 gl.LookAt(-2, 3, -7, -2, 0, 0, 0, 1, 0);258 gl.MatrixMode(OpenGL.GL_MODELVIEW);259 }260 261 262 263 }264 }
效果如下图:
场景中有两个光源,一个在X方向左右运行,一个绕点点在转圈.
Box上了材质贴图,球体没有材质.
从效果上看,已经解决了开头所述的问题(3),(4),我们提下关键点在哪里:
1. 第194,195行必须有,否则画栅格时会受到场景中的灯光,或者材质设定的影响,栅格原来颜色就没有了.
这个其实就是因为OpenGL是个状态机,其它部分代码改变了某些状态,画栅格时就会继承改变.
2. 同样原道理,第171行必须关闭纹理,否会受到Box材质设置状态的影响,球就不会是白色的了.
3. 第246行必须有,它用来自动归一化法线方向,因为光照效果由顶点和法线方向决定.
这就是问题(1),(2)之所以有问题的原因.
而导入的3ds模型,其画三角形的函数中也需要注意Normal()函数的向量值有没有方向问题.
下图是修正了法线后的光照效果,可以看到是正常的.
4. 对于问题5,因为在检查了灯光与贴图后都是正常的, 所以问题只会在出现在贴图的时候。
经检测,是在导入3ds模形的代码中,关于读取贴图的一个函数Build2DMipmaps()中,把RGB换BGR即可。
GL.Build2DMipmaps(OpenGL.GL_TEXTURE_2D, 3, image.Width, image.Height, OpenGL.GL_BGR, OpenGL.GL_UNSIGNED_BYTE, bitmapdata.Scan0);
可以看到,效果正常了。
5. 最后一个困绕笔者的问题是物体旋转中心点的问题.这个话题跟灯光无关,在这个场景中恰好碰到了这个问题,发现原来是知识上的一个盲点.
演示场景中,你会看到Box并不是绕世界坐标系的原点(绿色线的交汇点)在转,而是沿指定位置为轴心在转.
是绕世界坐标原点转,还是绕你指定的坐标为轴转动,关键在于你是先Translate(),还是先Rotate(). 读者可以参考下演示代码,然后自己尝试一下就知道了.
原创文章,出自"博客园, 猪悟能'S博客" :