用glLightfv函数实现简单的光照效果

制作真实的动画往往需要添加光照效果。

首先介绍OpenGL的简单光照模型,它的反射光可以分为三个分量:环境反射光,漫反射光,镜面反射光。就是你要实现一个光照效果,需要设置这三个分量,三者之和达到你想要的光照效果。

1.环境光,简单来说就是环境中的光,似乎来自于各个方向

2.漫反射,来自一个方向,光它照射到物体上,则在各个方向上均匀地发散出去,不管视点在哪,物体都是一样亮。

3.镜面光,来自特定方向,并沿着另一方向反射出去。

glLightfv函数原型:void glLightfv(光源名, 类型, 赋值);

类型主要有四类:光源颜色---AMBIENTDIFFUSESPECULAR和光源位置---POSITION

其中DIFFUSE的参数与光源颜色紧密,一般简单的光照模型只设置DIFFUSE就足够用了

GLfloat light0_diffuse[]= { 1.0, 0.0, 0, 1.0};
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);

下面是赋值的代码:

GLfloat light0_ambient[]= { 0.2, 0.2, 0.2, 1.0 };
GLfloat light0_diffuse[]= { 1.0, 0.0, 0, 1.0};
GLfloat light0_specular[] = { 1.0, 0, 0, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR,light0_specular);

设置光源位置

GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 };

glLightfv(GL_LIGHT0, GL_POSITION,light0_position);

开启光源

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);

glEnable(GL_LIGHTING);表示启动光照的总开关 glEnable(GL_LIGHT0);//打开0号光源

glEnable(GL_DEPTH_TEST);//打开深度缓冲区,绘制3D图像时候使用

完整代码


#include "stdafx.h"
#include <GL/glut.h>
#include "math.h"
void reshape(int w,int h)
{
	glViewport(0,0,(GLsizei)w,(GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if(w<h)
	glOrtho(-1.5, 1.5, -1.5,1.5 * (GLfloat)h / (GLfloat)w, -1.5,1.5);
	else
		glOrtho(-1.5* (GLfloat)w / (GLfloat)h, 1.5, -1.5,1.5, -1.5,1.5 );
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
}

void init ()
{
glClearColor(1.0,1.0,1.0,0.0);
glColor3f(1.0,1.0,0.0);
GLfloat light0_ambient[]= { 0.2, 0.2, 0.2, 1.0 };
GLfloat light0_diffuse[]= { 1.0, 0.0, 0, 1.0};//红色点光源
GLfloat light0_specular[] = { 1.0, 0, 0, 1.0 };
GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR,light0_specular);
glLightfv(GL_LIGHT0, GL_POSITION,light0_position);
glShadeModel(GL_SMOOTH);//光滑着色,过渡色效果
glEnable(GL_LIGHTING);//启动光照,总开关
glEnable(GL_LIGHT0);//打开0号光源
glEnable(GL_DEPTH_TEST);

}
void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glutSolidTeapot(0.5);
	glFlush();
}
int main(int argc, char* argv[])
{
	glutInit(&argc,argv);
	glutInitWindowPosition(200,200);
    glutInitWindowSize(500,500);
	glutCreateWindow("001");
	init();
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutMainLoop();
	return 0;
}

运行结果

 

 我们发现茶壶的颜色被设置的光照给覆盖了,本身的颜色(黄色)并没有显示出来。这里引入一个新的函数---颜色材质函数glEnable(GL_COLOR_MATERIAL); 它确保了打开灯光效果之后还能保留图形颜色。使用时候放在init函数里即可。

添加后茶壶效果如下

 

STLViewer::STLViewer(QWidget* parent) : QOpenGLWidget(parent), m_scaleFactor(1.0f) { QSurfaceFormat format; format.setVersion(2, 1); format.setProfile(QSurfaceFormat::CompatibilityProfile); setFormat(format); } void STLViewer::loadSTL(const QString& filePath) { Assimp::Importer importer; m_scene = importer.ReadFile(filePath.toStdString(), aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_CalcBoundingBox); if (!m_scene || !m_scene->HasMeshes()) { qWarning() << "Failed to load STL file:" << importer.GetErrorString(); return; } m_meshData.clear(); processNode(m_scene->mRootNode); // 计算模型包围盒和中心点 aiAABB bbox; bbox.mMin = aiVector3D(1e10f, 1e10f, 1e10f); bbox.mMax = aiVector3D(-1e10f, -1e10f, -1e10f); for (const auto& mesh : m_meshData) { for (size_t i = 3; i < mesh.size(); i += 6) { // 跳过法线数据 QVector3D vertex(mesh[i], mesh[i+1], mesh[i+2]); bbox.mMin.x = qMin(bbox.mMin.x, vertex.x()); bbox.mMin.y = qMin(bbox.mMin.y, vertex.y()); bbox.mMin.z = qMin(bbox.mMin.z, vertex.z()); bbox.mMax.x = qMax(bbox.mMax.x, vertex.x()); bbox.mMax.y = qMax(bbox.mMax.y, vertex.y()); bbox.mMax.z = qMax(bbox.mMax.z, vertex.z()); } } m_center = QVector3D( (bbox.mMax.x + bbox.mMin.x) * 0.5f, (bbox.mMax.y + bbox.mMin.y) * 0.5f, (bbox.mMax.z + bbox.mMin.z) * 0.5f ); // 自动缩放计算 QVector3D size = QVector3D(bbox.mMax.x - bbox.mMin.x, bbox.mMax.y - bbox.mMin.y, bbox.mMax.z - bbox.mMin.z); float maxSize = qMax(size.x(), qMax(size.y(), size.z())); m_scaleFactor = 2.0f / maxSize; update(); } void STLViewer::initializeGL() { initializeOpenGLFunctions(); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // 设置光源参数 GLfloat lightAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f}; GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; GLfloat lightSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat lightPosition[] = {0.0f, 0.0f, 5.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular); glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); } void STLViewer::resizeGL(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, static_cast<float>(w)/h, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); } void STLViewer::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0); // 应用模型变换 glTranslatef(-m_center.x(), -m_center.y(), -m_center.z()); // 居中模型 glScalef(m_scaleFactor, m_scaleFactor, m_scaleFactor); // 材质属性 GLfloat matAmbient[] = {0.7f, 0.7f, 0.7f, 1.0f}; GLfloat matDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; GLfloat matSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat shininess[] = {50.0f}; glMaterialfv(GL_FRONT, GL_AMBIENT, matAmbient); glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular); glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // 渲染网格 for (const auto& mesh : m_meshData) { glBegin(GL_TRIANGLES); for (size_t i = 0; i < mesh.size(); i += 6) { glNormal3f(mesh[i], mesh[i+1], mesh[i+2]); glVertex3f(mesh[i+3], mesh[i+4], mesh[i+5]); } glEnd(); } }识别不了aiProcess_CalcBoundingBox和aiAABB,请修改代码
最新发布
03-11
<think>好的,用户的问题是关于他们的C++代码中使用Assimp库时遇到的编译错误,具体是识别不了aiProcess_CalcBoundingBox和aiAABB。我需要先分析这些错误的原因,然后提供修改建议。 首先,aiProcess_CalcBoundingBox是Assimp中的一个处理标志,用于在导入模型时计算每个网格的包围盒。但根据用户提供的代码,他们似乎在加载STL文件时使用了这个标志。然而,可能的问题在于,用户使用的Assimp版本可能较旧,这个标志是在某个较新的版本中才引入的。或者,用户可能没有包含正确的头文件,因为aiProcess_CalcBoundingBox可能位于不同的头文件中,比如assimp/postprocess.h。 接下来是aiAABB结构体,这个结构体在Assimp中是否存在呢?在较新的版本中,Assimp确实有aiAABB,但在旧版本中可能不存在,取而代之的是aiMesh中的mVertices数组,用户可能需要手动计算包围盒。因此,如果用户的Assimp版本较旧,他们需要自己遍历顶点数据来计算包围盒,而不是依赖aiProcess_CalcBoundingBox。 用户当前的代码在loadSTL函数中使用了importer.ReadFile并传入了aiProcess_CalcBoundingBox标志,这可能导致编译错误,如果该标志不存在。同时,他们尝试使用aiAABB类型,如果该类型不存在,同样会报错。 解决方案应该是: 1. 移除aiProcess_CalcBoundingBox标志,改为手动计算包围盒。因为即使用户更新了Assimp版本,STL文件通常不包含预计算的包围盒信息,所以自动计算可能不可靠,手动计算更可控。 2. 替换aiAABB为手动计算的min和max变量,比如使用QVector3D或者自定义的结构来存储最小和最大点。 在代码中,用户已经有一个循环遍历所有顶点来更新bbox的过程,但初始的bbox初始化可能有误。需要将初始的min设为极大值,max设为极小值,然后逐个顶点比较更新。 此外,用户可能在代码中错误地处理了顶点数据。在processNode函数中,可能将顶点数据存储到m_meshData中,每个顶点数据包含法线和位置,所以循环步长是6(3个法线,3个位置)。因此,在遍历mesh数组时,i从3开始,每次增加6,可以正确获取顶点位置数据。 综上,修改步骤包括: - 移除aiProcess_CalcBoundingBox标志,使用aiProcess_Triangulate和aiProcess_GenNormals。 - 手动初始化min和max,遍历所有顶点来更新它们。 - 替换aiAABB为自定义的变量,比如QVector3D的min和max。 然后,检查是否有其他依赖问题,比如头文件是否包含正确,Assimp的版本是否需要升级等。如果用户无法升级Assimp,手动计算包围盒是必要的。 最后,确保代码中所有用到aiAABB的地方都被替换为手动计算的min和max,并正确计算中心点和缩放因子。</think>该代码的问题在于使用了错误的Assimp API(旧版本可能不支持`aiProcess_CalcBoundingBox`标志和`aiAABB`结构体)。以下是修改后的代码: ```cpp // 构造函数保持不变 STLViewer::STLViewer(QWidget* parent) : QOpenGLWidget(parent), m_scaleFactor(1.0f) { /* ... */ } void STLViewer::loadSTL(const QString& filePath) { Assimp::Importer importer; // 移除不支持的aiProcess_CalcBoundingBox m_scene = importer.ReadFile(filePath.toStdString(), aiProcess_Triangulate | aiProcess_GenNormals); // 移除非法的post process flag // ... [保持原有错误处理] ... // 手动计算包围盒 QVector3D bboxMin(1e10f, 1e10f, 1e10f); QVector3D bboxMax(-1e10f, -1e10f, -1e10f); for (const auto& mesh : m_meshData) { for (size_t i = 3; i < mesh.size(); i += 6) { // pos数据从索引3开始 QVector3D vertex(mesh[i], mesh[i+1], mesh[i+2]); bboxMin.setX(qMin(bboxMin.x(), vertex.x())); bboxMin.setY(qMin(bboxMin.y(), vertex.y())); bboxMin.setZ(qMin(bboxMin.z(), vertex.z())); bboxMax.setX(qMax(bboxMax.x(), vertex.x())); bboxMax.setY(qMax(bboxMax.y(), vertex.y())); bboxMax.setZ(qMax(bboxMax.z(), vertex.z())); } } // 计算中心点 m_center = (bboxMax + bboxMin) * 0.5f; // 计算缩放因子 QVector3D size = bboxMax - bboxMin; float maxSize = qMax(size.x(), qMax(size.y(), size.z())); m_scaleFactor = 2.0f / maxSize; update(); } // 其他函数保持不变... ``` **修改说明:** 1. **移除不支持的标志**:旧版Assimp(<5.0)没有`aiProcess_CalcBoundingBox`标志,需要手动计算包围盒 2. **手动包围盒计算**:改用QVector3D存储最小/最大顶点坐标 3. **保持数据遍历逻辑**:假设mesh数据存储格式为[nx, ny, nz, vx, vy, vz]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值