所谓的摄像机漫游,就是可以在场景中来回走动。

现实中,我们通过眼睛观察东西,身体移动带动眼睛移动观察身边的事物,这也是在漫游。

在OpenGL中我们使用函数LookAt()来操作摄像机在三维场景中进行漫游。

LookAt(double eyex, double eyey, double eyez, double centerx, double centery, double centerz, double upx, double upy, double upz);

我们通过改变LookAt的参数实现漫游效果,说明如下:

  • 改变视点eyeX,可以实现在场景中横向移动
  • 改变视点eyeY,可以实现在场景中蹲下,跳起这样的动作
  • 改变视点Z分量eyeZ,能实现在场景中前后的动作
  • 对于摄像机目标点centerx,y,z 的变化,相当于观察者站着不动,但其观察方向在上下左右方向进行变化。

效果缩略图:

源代码:

  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. using System.Runtime.InteropServices;
  11.  
  12. namespace cameraRove
  13. {
  14. //原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/
  15. public partial class SharpGLForm : Form
  16. {
  17. SharpGL.SceneGraph.Assets.Texture texture = new SharpGL.SceneGraph.Assets.Texture();
  18. Camera m_Camera = new Camera();
  19.  
  20. //光源位置
  21. float lx = 2f;
  22. float ly = 1f;
  23. float lz = 9f;
  24.  
  25. float[] fLightPosition = new float[];// 光源位置
  26. float[] fLightAmbient = new float[] { 1f, 1f, 1f, 1.0f };// 环境光参数
  27. float[] fLightDiffuse = new float[] { 1f, 1f, 1f, 1f };// 漫射光参数
  28.  
  29. public SharpGLForm()
  30. {
  31. InitializeComponent();
  32. }
  33.  
  34. private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
  35. {
  36. OpenGL gl = openGLControl.OpenGL;
  37. gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
  38. gl.LoadIdentity();
  39.  
  40. gl.DrawText(,this.Height-, 1f, 1f, 1f, "黑体", 12f, string.Format(
  41. "当前位置:X={0} Y={1} Speed ={2} ", m_Camera.getView().x.ToString("0.0"),
  42. (-m_Camera.getView().z).ToString("0.0"), m_Camera.getSpeed()));
  43.  
  44. m_Camera.setLook(gl);
  45.  
  46. drawBox(gl, 1f, 1f, 0f);
  47.  
  48. m_Camera.setViewByMouse();
  49. }
  50.  
  51. void drawGrid(OpenGL gl)
  52. {
  53. //获得场景中一些状态
  54. byte[] lp = new byte[] { , };
  55. byte[] tp = new byte[] { , };
  56. gl.GetBooleanv(OpenGL.GL_LIGHTING, lp);
  57. gl.GetBooleanv(OpenGL.GL_TEXTURE_2D, tp);
  58.  
  59. //关闭纹理和光照
  60. gl.Disable(OpenGL.GL_TEXTURE_2D);
  61. gl.Disable(OpenGL.GL_LIGHTING);
  62.  
  63. //绘制过程
  64. gl.PushAttrib(OpenGL.GL_CURRENT_BIT); //保存当前属性
  65. gl.PushMatrix(); //压入堆栈
  66. gl.Translate(0f, 0f, 0f);
  67. gl.Color(0f, 0f, 1f);
  68.  
  69. //在X,Z平面上绘制网格
  70. for (float i = -; i <= ; i += )
  71. {
  72. //绘制线
  73. gl.Begin(OpenGL.GL_LINES);
  74. //X轴方向
  75. gl.Vertex(-50f, 0f, i);
  76. gl.Vertex(50f, 0f, i);
  77. //Z轴方向
  78. gl.Vertex(i, 0f, -50f);
  79. gl.Vertex(i, 0f, 50f);
  80. gl.End();
  81. }
  82. gl.PopMatrix();
  83. gl.PopAttrib();
  84.  
  85. //恢复场景状态
  86. if (tp[] != )
  87. gl.Enable(OpenGL.GL_TEXTURE_2D);
  88. if (lp[] != )
  89. gl.Enable(OpenGL.GL_LIGHTING);
  90. }
  91.  
  92. void drawSphere(OpenGL gl)
  93. {
  94. //设置材质属性
  95. float[] mat_ambient = { 0.9f, 0.5f, 0.8f, 1.0f };
  96. float[] mat_diffuse = { 0.9f, 0.5f, 0.8f, 1.0f };
  97. float[] mat_shininess = { 100.0f };
  98. gl.Material(OpenGL.GL_FRONT, OpenGL.GL_AMBIENT, mat_ambient);
  99. gl.Material(OpenGL.GL_FRONT, OpenGL.GL_DIFFUSE, mat_diffuse);
  100. gl.Material(OpenGL.GL_FRONT, OpenGL.GL_SHININESS, mat_shininess);
  101.  
  102. //获得纹理启用状态
  103. byte[] tp = { , };
  104. gl.GetBooleanv(OpenGL.GL_TEXTURE_2D, tp);
  105. gl.Disable(OpenGL.GL_TEXTURE_2D); //关闭纹理
  106.  
  107. //绘制过程
  108. gl.PushMatrix();
  109. gl.Translate(2f, 1f, 5f);
  110. var sphere= gl.NewQuadric();
  111. gl.QuadricNormals(sphere, OpenGL.GLU_OUTSIDE);
  112. gl.QuadricNormals(sphere, OpenGL.GLU_SMOOTH);
  113. gl.Sphere(sphere, 1f, , );
  114. gl.DeleteQuadric(sphere);
  115. gl.PopMatrix();
  116.  
  117. if (tp[] != )
  118. gl.Enable(OpenGL.GL_TEXTURE_2D);
  119. }
  120.  
  121. private void drawBox(OpenGL gl, float xPos, float yPos, float zPos)
  122. {
  123. gl.PushMatrix();
  124. texture.Bind(gl);
  125. gl.Scale(, , );
  126. gl.Translate(xPos, yPos, zPos);
  127. gl.Begin(OpenGL.GL_QUADS);
  128. {
  129. //前
  130. gl.TexCoord(, ); gl.Vertex(, , );
  131. gl.TexCoord(, ); gl.Vertex(-, , );
  132. gl.TexCoord(, ); gl.Vertex(-, -, );
  133. gl.TexCoord(, ); gl.Vertex(, -, );
  134.  
  135. //底
  136. gl.TexCoord(, ); gl.Vertex(, , );
  137. gl.TexCoord(, ); gl.Vertex(, , -);
  138. gl.TexCoord(, ); gl.Vertex(-, , -);
  139. gl.TexCoord(, ); gl.Vertex(-, , );
  140.  
  141. //左
  142. gl.TexCoord(, ); gl.Vertex(-, , );
  143. gl.TexCoord(, ); gl.Vertex(-, , -);
  144. gl.TexCoord(, ); gl.Vertex(-, -, -);
  145. gl.TexCoord(, ); gl.Vertex(-, -, );
  146.  
  147. //右
  148. gl.TexCoord(, ); gl.Vertex(, , );
  149. gl.TexCoord(, ); gl.Vertex(, , -);
  150. gl.TexCoord(, ); gl.Vertex(, -, -);
  151. gl.TexCoord(, ); gl.Vertex(, -, );
  152.  
  153. //后
  154. gl.TexCoord(, ); gl.Vertex(, , -);
  155. gl.TexCoord(, ); gl.Vertex(-, , -);
  156. gl.TexCoord(, ); gl.Vertex(-, -, -);
  157. gl.TexCoord(, ); gl.Vertex(, -, -);
  158.  
  159. //顶
  160. gl.TexCoord(, ); gl.Vertex(, -, );
  161. gl.TexCoord(, ); gl.Vertex(, -, -);
  162. gl.TexCoord(, ); gl.Vertex(-, -, -);
  163. gl.TexCoord(, ); gl.Vertex(-, -, );
  164. }
  165. gl.End();
  166.  
  167. gl.PopMatrix();
  168. drawGrid(gl);
  169. drawSphere(gl);
  170. }
  171.  
  172. private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
  173. {
  174. OpenGL gl = openGLControl.OpenGL;
  175. texture.Create(gl, "image.bmp");
  176. gl.Enable(OpenGL.GL_TEXTURE_2D);
  177.  
  178. fLightPosition = new float[] { lx, ly, lz, 1f };
  179. gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_AMBIENT, fLightAmbient);//环境光源
  180. gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, fLightDiffuse);//漫射光源
  181. gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, fLightPosition);//光源位置
  182. gl.Enable(OpenGL.GL_LIGHTING);//开启光照
  183. gl.Enable(OpenGL.GL_LIGHT0);
  184.  
  185. gl.Enable(OpenGL.GL_NORMALIZE);
  186.  
  187. gl.ClearColor(, , , );
  188.  
  189. m_Camera.setCamera(0.0f, 1.5f, 6.0f, 0.0f, 1.5f, 0.0f, 0.0f, 1.0f, 0.0f);
  190. m_Camera.setSpeed(1f);
  191.  
  192. }
  193.  
  194. private void openGLControl_Resized(object sender, EventArgs e)
  195. {
  196. OpenGL gl = openGLControl.OpenGL;
  197. gl.MatrixMode(OpenGL.GL_PROJECTION);
  198. gl.LoadIdentity();
  199. gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);
  200. gl.LookAt(-, , , , , , , , );
  201. gl.MatrixMode(OpenGL.GL_MODELVIEW);
  202. }
  203.  
  204. private void openGLControl_KeyDown(object sender, KeyEventArgs e)
  205. {
  206.  
  207. switch (e.KeyCode)
  208. {
  209. case Keys.W: //上
  210. m_Camera.yawCamera(m_Camera.getSpeed());
  211.  
  212. break;
  213. case Keys.S: //下
  214. m_Camera.yawCamera(-m_Camera.getSpeed());
  215.  
  216. break;
  217. case Keys.A: //左
  218. m_Camera.moveCamera(m_Camera.getSpeed());
  219. break;
  220. case Keys.D: //右
  221. m_Camera.moveCamera(-m_Camera.getSpeed());
  222.  
  223. break;
  224. default:
  225. break;
  226. }
  227. }
  228.  
  229. }
  230.  
  231. class Camera
  232. {
  233. private Vector3 m_Position; //位置
  234. private Vector3 m_View; //朝向
  235. private Vector3 m_UpVector; //向上向量
  236. private float m_Speed; //速度
  237.  
  238. public Camera()
  239. {
  240. Vector3 zero =new Vector3(0f, 0f, 0f);
  241. Vector3 view =new Vector3(0f, 1f, 0.5f);
  242. Vector3 up =new Vector3(0f, 0f, 1f);
  243. m_Position = zero;
  244. m_View = view;
  245. m_UpVector = up;
  246. m_Speed = 0.1f;
  247. }
  248.  
  249. public void setSpeed(float speed)
  250. {
  251. m_Speed = speed;
  252. }
  253.  
  254. public float getSpeed()
  255. {
  256. return m_Speed;
  257. }
  258.  
  259. public Vector3 getPosition()
  260. {
  261. return m_Position;
  262. }
  263.  
  264. public Vector3 getView()
  265. {
  266. return m_View;
  267. }
  268.  
  269. public Vector3 getUpVector()
  270. {
  271. return m_UpVector;
  272. }
  273.  
  274. //设置摄像机的位置,朝向和向上向量
  275. public void setCamera(float positionX,float positionY,
  276. float positionZ, float viewX,float viewY,
  277. float viewZ,float upVectorX,float upVectorY,
  278. float upVectorZ)
  279. {
  280. //构造向量
  281. Vector3 Position =new Vector3(positionX, positionY, positionZ);
  282. Vector3 View = new Vector3(viewX, viewY, viewZ);
  283. Vector3 UpVector = new Vector3(upVectorX, upVectorY, upVectorZ);
  284.  
  285. //设置摄像机
  286. m_Position = Position;
  287. m_View = View;
  288. m_UpVector = UpVector;
  289. }
  290.  
  291. //旋转摄像机方向
  292. void rotateView(float angle, float x, float y, float z)
  293. {
  294. Vector3 newView=new Vector3();
  295. //计算方向向量
  296. Vector3 view = m_View - m_Position;
  297. //计算 sin 和cos值
  298. float cosTheta =(float) Math.Cos(angle);
  299. float sinTheta = (float)Math.Sin(angle);
  300.  
  301. //计算旋转向量的x值
  302. newView.x = (cosTheta + ( - cosTheta) * x * x) * view.x;
  303. newView.x += (( - cosTheta) * x * y - z * sinTheta) * view.y;
  304. newView.x += (( - cosTheta) * x * z + y * sinTheta) * view.z;
  305.  
  306. //计算旋转向量的y值
  307. newView.y = (( - cosTheta) * x * y + z * sinTheta) * view.x;
  308. newView.y += (cosTheta + ( - cosTheta) * y * y) * view.y;
  309. newView.y += (( - cosTheta) * y * z - x * sinTheta) * view.z;
  310.  
  311. //计算旋转向量的y值
  312. newView.z = (( - cosTheta) * x * z - y * sinTheta) * view.x;
  313. newView.z += (( - cosTheta) * y * z + x * sinTheta) * view.y;
  314. newView.z += (cosTheta + ( - cosTheta) * z * z) * view.z;
  315.  
  316. //更新摄像机的方向
  317. m_View = m_Position + newView;
  318. }
  319.  
  320. [DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
  321. public static extern int GetSystemMetrics(int which);
  322.  
  323. [DllImport("user32.dll", CharSet = CharSet.Auto)]
  324. public static extern bool GetCursorPos(out Point pt);
  325.  
  326. [DllImport("user32.dll", EntryPoint = "ShowCursor", CharSet = CharSet.Auto)]
  327. public extern static void ShowCursor(int status);
  328.  
  329. [DllImport("user32.dll", EntryPoint = "SetCursorPos")]
  330. private static extern int SetCursorPos(int x, int y);
  331.  
  332. float lastRotX = 0.0f; // 用于保存旋转角度
  333. float currentRotX = 0.0f;
  334. public void setViewByMouse()
  335. {
  336. const int SM_CXSCREEN = ;
  337. const int SM_CYSCREEN = ;
  338. Point mousePos; /**< 保存当前鼠标位置 */
  339. int middleX = GetSystemMetrics(SM_CXSCREEN) >> ; /**< 得到屏幕宽度的一半 */
  340. int middleY = GetSystemMetrics(SM_CYSCREEN) >> ; /**< 得到屏幕高度的一半 */
  341. float angleY = 0.0f; /**< 摄像机左右旋转角度 */
  342. float angleZ = 0.0f; /**< 摄像机上下旋转角度 */
  343.  
  344. // 得到当前鼠标位置
  345. GetCursorPos(out mousePos);
  346. ShowCursor();
  347.  
  348. // 如果鼠标没有移动,则不用更新
  349. if ((mousePos.X == middleX) && (mousePos.Y == middleY))
  350. return;
  351.  
  352. // 设置鼠标位置在屏幕中心
  353. SetCursorPos(middleX, middleY);
  354.  
  355. // 得到鼠标移动方向
  356. angleY = (float)((middleX - mousePos.X)) / 1000.0f;
  357. angleZ = (float)((middleY - mousePos.Y)) / 1000.0f;
  358.  
  359. lastRotX = currentRotX;
  360.  
  361. // 跟踪摄像机上下旋转角度
  362. currentRotX += angleZ;
  363.  
  364. // 如果上下旋转弧度大于1.0,我们截取到1.0并旋转
  365. if (currentRotX > 1.0f)
  366. {
  367. currentRotX = 1.0f;
  368.  
  369. // 根据保存的角度旋转方向
  370. if (lastRotX != 1.0f)
  371. {
  372. // 通过叉积找到与旋转方向垂直的向量
  373. Vector3 vAxis = m_View - m_Position;
  374. vAxis = vAxis.crossProduct(m_UpVector);
  375. vAxis = vAxis.normalize();
  376.  
  377. ///旋转
  378. rotateView(1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z);
  379. }
  380. }
  381. // 如果旋转弧度小于-1.0,则也截取到-1.0并旋转
  382. else if (currentRotX < -1.0f)
  383. {
  384. currentRotX = -1.0f;
  385. if (lastRotX != -1.0f)
  386. {
  387.  
  388. // 通过叉积找到与旋转方向垂直的向量
  389. Vector3 vAxis = m_View - m_Position;
  390. vAxis = vAxis.crossProduct(m_UpVector);
  391. vAxis = vAxis.normalize();
  392.  
  393. rotateView(-1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z);
  394. }
  395. }
  396. // 否则就旋转angleZ度
  397. else
  398. {
  399. // 找到与旋转方向垂直向量
  400. Vector3 vAxis = m_View - m_Position;
  401. vAxis = vAxis.crossProduct(m_UpVector);
  402. vAxis = vAxis.normalize();
  403.  
  404. rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
  405. }
  406.  
  407. // 总是左右旋转摄像机
  408. rotateView(angleY, , , );
  409. }
  410.  
  411. public void yawCamera(float speed)
  412. {
  413. Vector3 yaw = new Vector3();
  414. Vector3 cross = m_View - m_Position;
  415. cross = cross.crossProduct(m_UpVector);
  416.  
  417. //归一化向量
  418. yaw = cross.normalize();
  419.  
  420. m_Position.x += yaw.x * speed;
  421. m_Position.z += yaw.z * speed;
  422.  
  423. m_View.x += yaw.x * speed;
  424. m_View.z += yaw.z * speed;
  425. }
  426.  
  427. public void moveCamera(float speed)
  428. {
  429. //计算方向向量
  430. Vector3 vector = m_View - m_Position;
  431. vector = vector.normalize(); //单位化
  432.  
  433. //更新摄像机
  434. m_Position.x += vector.x * speed; //根据速度更新位置
  435. m_Position.z += vector.z * speed;
  436. m_Position.y += vector.y * speed;
  437.  
  438. m_View.x += vector.x * speed; //根据速度更新方向
  439. m_View.y += vector.y * speed;
  440. m_View.z += vector.z * speed;
  441. }
  442.  
  443. //设置视点
  444. public void setLook(OpenGL gl)
  445. {
  446. gl.LookAt(m_Position.x, m_Position.y, m_Position.z,
  447. m_View.x, m_View.y, m_View.z,
  448. m_UpVector.x, m_UpVector.y, m_UpVector.z);
  449. }
  450. }
  451.  
  452. //向量运算类
  453. class Vector3
  454. {
  455. public float x, y, z;
  456. public Vector3()
  457. {
  458. x = ; y = ; z = ;
  459. }
  460.  
  461. public Vector3(float x, float y, float z)
  462. {
  463. this.x = x;
  464. this.y = y;
  465. this.z = z;
  466. }
  467.  
  468. public Vector3(Vector3 vec)
  469. {
  470. this.x = vec.x;
  471. this.y = vec.y;
  472. this.z = vec.z;
  473. }
  474.  
  475. public float length()
  476. {
  477. return (float)(x * x + y * y + z * z);
  478. }
  479.  
  480. public Vector3 normalize()
  481. {
  482. float len = length();
  483. if (len == ) len = ;
  484. x = x / len;
  485. y = y / len;
  486. z = z / len;
  487. return this;
  488. }
  489.  
  490. //点积
  491. public float dotProduct(Vector3 vec)
  492. {
  493. return 0f;
  494. }
  495.  
  496. public Vector3 crossProduct(Vector3 vec)
  497. {
  498. Vector3 v = new Vector3();
  499. v.x = y * vec.z - z * vec.y;
  500. v.y = z * vec.x - x * vec.z;
  501. v.z = x * vec.y - y * vec.x;
  502. return v;
  503. }
  504.  
  505. public static Vector3 operator +(Vector3 v1,Vector3 v2)
  506. {
  507. var res = new Vector3();
  508. res.x=v1.x+v2.x;
  509. res.y=v1.y+v2.y;
  510. res.z=v1.z+v2.z;
  511. return res;
  512. }
  513.  
  514. public static Vector3 operator -(Vector3 v1,Vector3 v2)
  515. {
  516. var res = new Vector3();
  517. res.x=v1.x-v2.x;
  518. res.y=v1.y-v2.y;
  519. res.z=v1.z-v2.z;
  520. return res;
  521. }
  522.  
  523. public static Vector3 operator *(Vector3 v1, Vector3 v2)
  524. {
  525. var res = new Vector3();
  526. res.x = v1.x * v2.x;
  527. res.y = v1.y * v2.y;
  528. res.z = v1.z * v2.z;
  529. return res;
  530. }
  531.  
  532. public static Vector3 operator /(Vector3 v1, Vector3 v2)
  533. {
  534. var res = new Vector3();
  535. res.x = v1.x / v2.x;
  536. res.y = v1.y / v2.y;
  537. res.z = v1.z / v2.z;
  538. return res;
  539. }
  540.  
  541. public static Vector3 operator -(Vector3 vec)
  542. {
  543. vec.x=-*vec.x;
  544. vec.y=-*vec.y;
  545. vec.z=-*vec.z;
  546. return vec;
  547. }
  548.  
  549. }
  550.  
  551. }

效果如下图:

移动鼠标可以旋转摄像机,按键盘的WASD四个键可以XY方向移动摄像机。

本例子改编自徐明亮《OpenGL游戏编程》一书中“摄像机漫游” 一章节。

通过这个例子,发现了一个让笔者不解的问题。为什么我办公电脑那种垃圾配置(双核2G,集成显卡)跑这个例子比较快,但我家里的电脑(四核,显卡是geForce GTX 750Ti) 运行起来却蛮慢?

貌似根本就没有发挥强大显卡的性能嘛!

还有,VC6写的实现同样效果的程序要跑得快些哦!这又是昨回事? 这摆明让人羡慕嫉妒恨嘛!

补充一点:这个程序请按Alt+F4退出.

本节源代码下载

原创文章,出自"博客园, 猪悟能'S博客" : http://www.cnblogs.com/hackpig/

SharpGL学习笔记(十九) 摄像机漫游的更多相关文章

  1. python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法

    python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...

  2. (C/C++学习笔记) 十九. 模板

    十九. 模板 ● 模板的基本概念 模板(template) 函数模板:可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计. 语法: template <<模 ...

  3. SharpGL学习笔记(十八) 解析3ds模型并显示

    笔者设想的3D仿真中的元件,是不可能都是“画”出来的.这样就玩复杂了,应该把任务分包出去,让善于制作模型的软件来制作三维模型,我们只需要解析并且显示它即可. 3dsmax制作三维模型的方便,快捷,专业 ...

  4. SharpGL学习笔记(十六) 多重纹理映射

    多重纹理就把多张贴图隔和在一起.比如下面示例中,一个表现砖墙的纹理,配合一个表现聚光灯效果的灰度图,就形成了砖墙被一个聚光灯照亮的效果,这便是所谓的光照贴图技术. 多重纹理只在OpenGL扩展库中才提 ...

  5. SharpGL学习笔记(十五) 纹理映射

    纹理映射非常实用,在游戏场景中已经无所不在了. 一个较少的多边形构成的模形,配合好的纹理贴图进行映射,可以得到逼真的效果.游戏中的天空,地面,墙面,和植物都是纹理贴图进行映射的. 例如最终幻想8的男女 ...

  6. SharpGL学习笔记(十四) 材质:十二个材质球

    材质颜色 OpenGL用材料对光的红.绿.蓝三原色的反射率来近似定义材料的颜色.象光源一样,材料颜色也分成环境.漫反射和镜面反射成分,它们决定了材料对环境光.漫反射光和镜面反射光的反射程度.在进行光照 ...

  7. SharpGL学习笔记(十二) 光源例子:解决光源场景中的常见问题

    笔者学到光源这一节,遇到的问题就比较多了,收集了一些如下所述: (1) 导入的3ds模型,如果没有材质光照效果很奇怪.如下图 (2) 导入的3ds模型,有材质,灯光效果发暗,材质偏色,效果也很奇怪. ...

  8. Java基础学习笔记十九 IO

    File IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再 ...

  9. Java基础学习笔记十九 File

    IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据 ...

随机推荐

  1. ART:Android 摆脱卡顿的希望?

    与 iOS 相比,Android 的用户体验有个相对糟糕的开始.在很长的时间里,界面一直丑小鸭,卡顿也是挥不去的痛.不过,在 Google 的全力推动,以及硬件厂商的响应下,Android 还是跨越各 ...

  2. 创建 iPhone/iOS8 弹出菜单(窗口)

    基本步骤 添加视图:主视图与弹出视图 关联视图 配置弹出视图 编码实现:弹出菜单样式及控制器委托 override func prepareForSegue(segue: UIStoryboardSe ...

  3. SGU 422 Fast Typing(概率DP)

    题目大意 某人在打字机上打一个字符串,给出了他打每个字符出错的概率 q[i]. 打一个字符需要单位1的时间,删除一个字符也需要单位1的时间.在任意时刻,他可以花 t 的时间检查整个打出来的字符串,并且 ...

  4. css压缩(一)

    基于require.js的压缩,至于require.js,网上有比较权威的解说 RequireJS进阶(一) RequireJS进阶(二) RequireJS进阶(三) 目前我所做的项目是把各个模块下 ...

  5. JAVA多线程编程之生产者消费者模式

    Java中有一个BlockingQueue可以用来充当堵塞队列,下面是一个桌面搜索的设计 package net.jcip.examples; import java.io.File; import ...

  6. 另类angularjs应用

    回顾 上一篇文章主要讲解了创建兼容任意浏览器(主要是ie的一些奇葩问题)的angularjs web应用,但是项目开发中其实更重要的还是在功能的模块化.代码自动压缩上面,这样项目在后期维护或者功能的重 ...

  7. 【转载】linux tail命令的使用方法详解

    本文介绍Linux下tail命令的使用方法.linux tail命令用途是依照要求将指定的文件的最后部分输出到标准设备,通常是终端,通俗讲来,就是把某个档案文件的最后几行显示到终端上,假设该档案有更新 ...

  8. .NET框架面向对象分层的个人想理

    简单.层次清晰不要过度优化,接口这玩意儿就是个双刃剑,玩好了解藕,玩不好自找麻烦,好的代码永远都是傻瓜都能看懂的. 总结成以下几条: 公用层 代码公用并且与第三方DLL和业务逻辑无关的 独立出来 逻辑 ...

  9. JS魔法堂:通过marquee标签实现信息滚动效果

    一.前言   有限的空间展现无限的内容,这是滚动最常用到的地方.根据信息滚动效果我们可以有很多的实现方式,但HTML自带的 marquee标签 是其中一个较简单的实现方式.下面记录一下,供日后查阅. ...

  10. ASP.NET MVC 5 默认模板的JS和CSS 是怎么加载的?

    当创建一个默认的mvc模板后,项目如下: 运行项目后,鼠标右键查看源码,在源码里看到头部和尾部都有js和css文件被引用,他们是怎么被添加进来的呢? 首先我们先看对应的view文件index.csht ...