必须启用GL_LIGHTING和至少一个光源(如GL_LIGHT0),否则glutSolidSphere不参与光照计算;还需正确设置光源位置、材质、法向量归一化(GL_NORMALIZE)、深度测试与面剔除,且光源须在模型变换前于眼坐标系中设定。

用glutSolidSphere加光照前必须启用GL_LIGHTING和至少一个光源
很多人调用glutSolidSphere后发现球体是纯白或全黑,不是光照没生效,而是根本没打开光照系统。OpenGL默认关闭光照计算,即使你设置了材质、法向量、光源位置,也完全不参与渲染。
必须在绘制前确保:
- 调用glEnable(GL_LIGHTING)
- 启用至少一个光源,例如glEnable(GL_LIGHT0)
- 设置光源位置(glLightfv(GL_LIGHT0, GL_POSITION, ...))和基础属性(环境光、漫反射光)
- 设置球体材质(glMaterialfv),否则会沿用默认的灰暗材质,光照看起来“没反应”
球体法向量必须正确——glutSolidSphere自带法向量但依赖GL_NORMALIZE开关
glutSolidSphere生成的顶点附带单位法向量,但如果你启用了模型变换(比如glScalef(2,1,1)),法向量会被缩放,导致光照计算错误(高光偏移、明暗颠倒)。这时不能只靠原始法向量。
解决方法只有两个:
- 在变换前调用glEnable(GL_NORMALIZE):让OpenGL自动将变换后的法向量重归一化(开销小,推荐)
- 或手动启用GL_RESCALE_NORMAL(仅当没有非统一缩放时可用,兼容性略差)
- 切忌关闭GL_LIGHTING来“绕过”问题——那等于放弃光照
光照坐标系是眼坐标系,光源位置传入前要确认矩阵状态
OpenGL光照计算发生在眼坐标空间(即GL_MODELVIEW矩阵作用后的空间)。如果你在glLoadIdentity()之后设置光源,它就在原点附近;但若你在gluLookAt之后、绘制球体前才设置光源,且中间有平移/旋转,光源位置就会被错误变换。
标准做法是:
- 在设置摄像机(gluLookAt)之后、任何模型变换(如glTranslatef)之前,调用glLightfv(GL_LIGHT0, GL_POSITION, pos)
- pos用4元组,如{1.0f, 1.0f, 2.0f, 1.0f}表示眼坐标系中的定点光源
- 若第四个分量为0.0f,则为方向光(需注意归一化)
- 常见错误:glLightfv写在glutSolidSphere之后,或混在模型变换块里,导致光源随球体一起移动
深度测试和面剔除顺序不能错,否则球体背面光照异常或被裁掉
球体是封闭曲面,如果不开启深度测试(glEnable(GL_DEPTH_TEST)),前后表面会相互覆盖,光照结果混乱;如果开了面剔除(glEnable(GL_CULL_FACE))但没设对剔除面(glCullFace(GL_BACK)),可能把本该受光照的正面给剔掉了。
立即学习“C++免费学习笔记(深入)”;
初始化时至少要保证:
- glEnable(GL_DEPTH_TEST)
- glDepthFunc(GL_LESS)
- glEnable(GL_CULL_FACE) + glCullFace(GL_BACK)(默认正面为逆时针,与glutSolidSphere一致)
- 清屏时调用glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT),漏掉GL_DEPTH_BUFFER_BIT会导致深度值残留
光照效果是否真实,不取决于球体画得有多圆,而取决于法向量、坐标系、矩阵栈和状态开关这四者的同步精度。最容易被忽略的是GL_NORMALIZE和光源设置时机——它们不出错时一切正常,一出错就表现为“光照像没开一样”,但调试器里又查不到明显报错。


















