【OpenGL】CPP读取STL文件并通过OpenGL显示

在这里插入图片描述

1. 引言

在学习OpenGL的过程中,有很多同学都卡在了导入模型这一步。由于assimp库的编译和配置比较复杂,如果使用官方编译好的库会则不具有良好的跨平台覆盖;而如果自己进行编译,有可能会在进行CMAKE编译的时候出现类似于‘DirectX库缺失’这样的错误。此外,虽然assimp库支持几十种模型文件的读取,但对于初学者来说,这并不是必须的。为了在一些特殊场景下读取并显示STL文件,本文尝试采用相对简单的语法手写STL文件的读取,便于大家认识STL文件及其结构,并通过OpenGL将所读取的模型显示出来。


2. 认识STL

STL文件是一种以记录三角形面片来描述立体模型的文件结构,通常作为CAD以及3D打印的常用交换格式。常见的STL文件主要有二进制和ASCII两种记录方式。在Inventor等软件中,导出模型时可以自行选择导出格式。
在这里插入图片描述

ASCII格式的STL文件非常易读,一个立方体的文件如下。

solid ASCII // 表示文件采用ASCII存储
  facet normal -1.000000e+00 0.000000e+00 0.000000e+00 //面的法向量,指向立方体的外部,可以通过右手定则恢复顶点顺序
    outer loop
      vertex   -5.000000e+00 0.000000e+00 -5.000000e+00//顶点的x,y,z坐标
      vertex   -5.000000e+00 0.000000e+00 5.000000e+00
      vertex   -5.000000e+00 1.000000e+01 -5.000000e+00//三个顶点构成三角形
    endloop
endfacet
//……省略其余7个顶点……
endsolid//文件结束

值得注意的是,顶点坐标的单位是由生成STL文件的软件决定的,但并不会体现在stl文件中。例如上面数据的单位是毫米,在我们导入时需要注意单位可能需要转换。

二进制的STL Binary文件结构也很清晰。因其冗余内容较少,大多数软件默认导出的STL文件都是二进制格式的。

UINT8//Header//文件头,共80字节,存贮文件名;
UINT32//Numberoftriangles//4个字节的整数描述三角面片数量
//foreachtriangle(每个三角面片中占用50字节)
REAL32[3] //Normalvector//法线矢量,3个4字节浮点数
REAL32[3] //Vertex1//顶点1坐标,3个4字节浮点数
REAL32[3] //Vertex2//顶点2坐标,3个4字节浮点数
REAL32[3] //Vertex3//顶点3坐标,3个4字节浮点数
UINT16//Attributebytecountend//二个字节,文件属性统计

本文优先关注方便读取的ASCII格式的STL文件,二进制文件则留待以后再研究。


3. STL文件读取

本文为了简化读入的逻辑,对于STL文件的读取没有进行任何的读入优化,用一个word字符串来读取所有的英文单词。
代码如下:

float pow0_1(int a)
{
    float pow = 1.0;
    for(;a>=0;a--)
        pow *= 0.1;
    return pow;
}
float pow10(int a)
{
    float pow = 1.0;
    for(;a>=0;a--)
        pow *= 10.0;
    return pow;
}
float gen_vertex(char input[15])
{
    int temp1,temp2;float v;float multipler=0.0000001;
    if(input[0]=='-')
    {
        temp1=(input[1]-48)*1000000+(input[3]-48)*100000+(input[4]-48)*10000+(input[5]-48)*1000+(input[6]-48)*100+(input[7]-48)*10+(input[8]-48)*1;
        temp2=(input[11]-48)*10+(input[12]-48);
        if(input[10]=='-')
            multipler *= pow0_1(temp2);
        else
            multipler *= pow10(temp2);
        v = (float)temp1 * multipler * (-1.0);
    }
    else
    {
        temp1=(input[0]-48)*1000000+(input[2]-48)*100000+(input[3]-48)*10000+(input[4]-48)*1000+(input[5]-48)*100+(input[6]-48)*10+(input[7]-48)*1;
        temp2=(input[10]-48)*10+(input[11]-48);
        if(input[9]=='-')
            multipler *= pow0_1(temp2);
        else
            multipler *= pow10(temp2);
        v = (float)temp1 * multipler;
    }
    return v;
}/这三个函数返回顶点某个分量的浮点数值
void STL_Read()
{
	char word[15];
    freopen("2_ASCII.stl","r",stdin);
    cin >> word;cin >> word;//solid ascii
    int i;
    char vertex[15];
    for(i=1;;i++)
    {
        cin >> word;
        if(word[0]=='e')
        {
            break;
        }//如果读入的是endsolid,则结束顶点输入
        cin >> word;cin >> word;cin >> word;cin >> word;/facet normal
        cin >> word;cin >> word;/outer loop
        ///读入第一个顶点
        cin >> word;
        cin >> vertex;vertices[VerticesCnt] = gen_vertex(vertex) * 0.1;
		cin >> vertex;vertices[VerticesCnt+1] = gen_vertex(vertex)*0.1;
		cin >> vertex;vertices[VerticesCnt+2] = gen_vertex(vertex)*0.1;
		vertices[VerticesCnt+3] = 0.3f;
		vertices[VerticesCnt+4] = 0.4f;
		vertices[VerticesCnt+5] = 0.5f;//设置顶点颜色
		VerticesCnt += 6;
		读入第二个顶点
		cin >> word;
        cin >> vertex;vertices[VerticesCnt] = gen_vertex(vertex) * 0.1;
		cin >> vertex;vertices[VerticesCnt+1] = gen_vertex(vertex)*0.1;
		cin >> vertex;vertices[VerticesCnt+2] = gen_vertex(vertex)*0.1;
		vertices[VerticesCnt+3] = 0.5f;
		vertices[VerticesCnt+4] = 0.5f;
		vertices[VerticesCnt+5] = 1.0f;//设置顶点颜色
		VerticesCnt += 6;
		//读入第三个顶点
		cin >> word;
        cin >> vertex;vertices[VerticesCnt] = gen_vertex(vertex) * 0.1;
		cin >> vertex;vertices[VerticesCnt+1] = gen_vertex(vertex)*0.1;
		cin >> vertex;vertices[VerticesCnt+2] = gen_vertex(vertex)*0.1;
		vertices[VerticesCnt+3] = 0.5f;
		vertices[VerticesCnt+4] = 0.4f;
		vertices[VerticesCnt+5] = 0.0f;//设置顶点颜色
		VerticesCnt += 6;
		
		cin >> word;//endloop
		cin >> word;//endfacet

    }
    fclose(stdin);
}


然后,在main函数里运行STL_Read函数,就可以得到STL的顶点数据,再调用OpenGL显示就十分方便了。


4. 代码全文

总体流程是:

  1. 初始化并创建窗口
  2. 加载立方体顶点VAOVBO以及着色器并开启深度测试、
  3. 进入主循环清除缓冲
  4. 使用立方体着色器,构造并传入pvm矩阵,绘制
  5. 循环结束,释放VAOVBO

关于OpenGL的部分可以配合注释自行理解,之后我也会尝试更新关于OpenGL的内容。

#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <math.h>
#include <vector>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "shader.h"
using namespace std;
float vertices[1000000];//顶点数组
float screen_width = 1440.0f;          //窗口宽度
float screen_height = 960.0f;          //窗口高度
//鼠标键盘响应函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);

//相机参数
glm::vec3 camera_position = glm::vec3(0.0f, 0.0f, 3.0f);     //摄像机位置
glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f);       //摄像机方向
glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f);           //摄像机上向量
glm::vec3 camera_right = glm::cross(camera_front,camera_up);
//视野
float fov = 45.0f;
float deltaTime = 0.0f;
float lastFrame = 0.0f;
float currentFrame = 0.0f;
int fpscnt=0;
float fpsTime = 0.0f;
int VerticesCnt = 0;
///
float pow0_1(int a)
{
    float pow = 1.0;
    for(;a>=0;a--)
        pow *= 0.1;
    return pow;
}
float pow10(int a)
{
    float pow = 1.0;
    for(;a>=0;a--)
        pow *= 10.0;
    return pow;
}
float gen_vertex(char input[15])
{
    int temp1,temp2;float v;float multipler=0.0000001;
    if(input[0]=='-')
    {
        temp1=(input[1]-48)*1000000+(input[3]-48)*100000+(input[4]-48)*10000+(input[5]-48)*1000+(input[6]-48)*100+(input[7]-48)*10+(input[8]-48)*1;
        temp2=(input[11]-48)*10+(input[12]-48);
        if(input[10]=='-')
            multipler *= pow0_1(temp2);
        else
            multipler *= pow10(temp2);
        v = (float)temp1 * multipler * (-1.0);
    }
    else
    {
        temp1=(input[0]-48)*1000000+(input[2]-48)*100000+(input[3]-48)*10000+(input[4]-48)*1000+(input[5]-48)*100+(input[6]-48)*10+(input[7]-48)*1;
        temp2=(input[10]-48)*10+(input[11]-48);
        if(input[9]=='-')
            multipler *= pow0_1(temp2);
        else
            multipler *= pow10(temp2);
        v = (float)temp1 * multipler;
    }
    return v;
}
///
void STL_Read()
{
	char word[15];
    freopen("2_ASCII.stl","r",stdin);
    cin >> word;cin >> word;//solid ascii
    int i;
    char vertex[15];
    for(i=1;;i++)
    {
        cin >> word;
        if(word[0]=='e')
        {
            break;
        }
        cin >> word;cin >> word;cin >> word;cin >> word;/facet normal
        cin >> word;cin >> word;/outer loop
        ///
        cin >> word;
        cin >> vertex;vertices[VerticesCnt] = gen_vertex(vertex) * 0.1;
		cin >> vertex;vertices[VerticesCnt+1] = gen_vertex(vertex)*0.1;
		cin >> vertex;vertices[VerticesCnt+2] = gen_vertex(vertex)*0.1;
		vertices[VerticesCnt+3] = 0.3f;
		vertices[VerticesCnt+4] = 0.4f;
		vertices[VerticesCnt+5] = 0.5f;
		VerticesCnt += 6;
		
		cin >> word;
        cin >> vertex;vertices[VerticesCnt] = gen_vertex(vertex) * 0.1;
		cin >> vertex;vertices[VerticesCnt+1] = gen_vertex(vertex)*0.1;
		cin >> vertex;vertices[VerticesCnt+2] = gen_vertex(vertex)*0.1;
		vertices[VerticesCnt+3] = 0.5f;
		vertices[VerticesCnt+4] = 0.5f;
		vertices[VerticesCnt+5] = 1.0f;
		VerticesCnt += 6;
		//
		cin >> word;
        cin >> vertex;vertices[VerticesCnt] = gen_vertex(vertex) * 0.1;
		cin >> vertex;vertices[VerticesCnt+1] = gen_vertex(vertex)*0.1;
		cin >> vertex;vertices[VerticesCnt+2] = gen_vertex(vertex)*0.1;
		vertices[VerticesCnt+3] = 0.5f;
		vertices[VerticesCnt+4] = 0.4f;
		vertices[VerticesCnt+5] = 0.0f;
		VerticesCnt += 6;
		
		cin >> word;//endloop
		cin >> word;//endfacet
	}
    fclose(stdin);
}
int main() {
	// 初始化GLFW
	STL_Read();
	printf("Vertices = %d\n",VerticesCnt);
	for(int qiuzili = 0;qiuzili<=VerticesCnt;qiuzili++)
	{
		printf("%.6f\n",vertices[qiuzili]);
	}
	glfwInit();                                                     // 初始化GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);                  // OpenGL版本为3.3,主次版本号均设为3
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 使用核心模式(无需向后兼容性)
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 如果使用的是Mac OS X系统,需加上这行
	glfwWindowHint(GLFW_RESIZABLE, 0);						    // 不可改变窗口大小

																	// 创建窗口(宽、高、窗口名称)
	auto window = glfwCreateWindow(screen_width, screen_height, "Cube", nullptr, nullptr);
	if (window == nullptr) {                                        // 如果窗口创建失败,输出Failed to Create OpenGL Context
		std::cout << "Failed to Create OpenGL Context" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);                                 // 将窗口的上下文设置为当前线程的主上下文
																	// 初始化GLAD,加载OpenGL函数指针地址的函数
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}
	// 指定当前视口尺寸(前两个参数为左下角位置,后两个参数是渲染窗口宽、高)
	glViewport(0, 0, screen_width, screen_height);
	Shader shader("res/shader/task-cube.vs", "res/shader/task-cube.fs");//加载着色器
	// 生成并绑定VAO和VBO
	GLuint vertex_array_object; // == VAO
	glGenVertexArrays(1, &vertex_array_object);
	glBindVertexArray(vertex_array_object);
	GLuint vertex_buffer_object; // == VBO
	glGenBuffers(1, &vertex_buffer_object);
	glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);
	// 将顶点数据绑定至当前默认的缓冲中
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	// 设置顶点属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	glEnable(GL_DEPTH_TEST);
	// Render loop主循环
	while (!glfwWindowShouldClose(window)) {
		//计算每帧的时间差
		currentFrame = (float)glfwGetTime();
		deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;
		++fpscnt;
		if(currentFrame - fpsTime >= 2.0)
		{
			printf("fps=%d     fov=%.2f    ",fpscnt/2,fov);
			printf("pos= %.2f %.2f %.2f\n",camera_position[0],camera_position[1],camera_position[2]);
			fpscnt = 0;
			fpsTime = currentFrame;
		}
		processInput(window);
		//进入主循环,清理颜色缓冲深度缓冲
		glClearColor(0.0f, 0.34f, 0.57f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清理颜色缓冲和深度缓冲
		shader.Use();
		// Transform坐标变换矩阵
		glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标
		model = glm::translate(model, glm::vec3(0.0,0.0,0.0));
		model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f));
		model = glm::scale(model, glm::vec3(1.0f,1.0f,1.0f));
		glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系
		view = glm::lookAt(camera_position, camera_position + camera_front, camera_up);
		glm::mat4 projection(1);//projection矩阵,投影矩阵
		projection = glm::perspective(glm::radians(fov), (float)screen_width / screen_height, 0.1f, 100.0f);
		// 向着色器中传入参数
		int model_location = glGetUniformLocation(shader.ID, "model"); //获取着色器内某个参数的位置
		glUniformMatrix4fv(model_location, 1, GL_FALSE, glm::value_ptr(model));//写入参数值
		int view_location = glGetUniformLocation(shader.ID, "view");
		glUniformMatrix4fv(view_location, 1, GL_FALSE, glm::value_ptr(view));
		int projection_location = glGetUniformLocation(shader.ID, "projection");
		glUniformMatrix4fv(projection_location, 1, GL_FALSE, glm::value_ptr(projection));
		//绘制
		glBindVertexArray(vertex_array_object);
		glDrawArrays(GL_TRIANGLES, 0, VerticesCnt / 6);
		glBindVertexArray(0);
		
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	//释放VAOVBO
	glDeleteVertexArrays(1, &vertex_array_object);
	glDeleteBuffers(1, &vertex_buffer_object);

	// 清理所有的资源并正确退出程序
	glfwTerminate();
	return 0;
}
void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);

	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
		camera_position += camera_front * deltaTime ;
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
		camera_position -= camera_front * deltaTime ;
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
		camera_position -= camera_right * deltaTime;
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
		camera_position += camera_right * deltaTime;
	
	if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
		camera_front += camera_up * deltaTime;	
	if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
		camera_front -= camera_up * deltaTime;	
	if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
		camera_front -= camera_right * deltaTime;
	if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
		camera_front += camera_right * deltaTime;

	if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS)
	{
		fov=fov+10.0*deltaTime;
		if(fov>179.0)
			fov=179.0;
		//printf("%.5f %.2f\n",deltaTime,fov);
	}
	if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS)
	{
		fov=fov-10.0*deltaTime;
		if(fov<1.0)
			fov=1.0;
		//printf("%.5f %.2f\n",deltaTime,fov);
	}
}

运行效果:

觉得有用的话,不要吝惜评论点赞分享哦,希望大家多多包涵,有任何问题欢迎指正、讨论。
本文基于CC-BY-SA 4.0协议,欢迎转载
(博客看累了?去我的B站瞧一瞧?)

  • 19
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 27
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com
### 回答1: 使用MFC和OpenGL读取显示STL三维模型需要以下几个步骤: 1. 创建一个新的MFC项目,选择对话框应用程序作为模板。 2. 将OpenGL文件添加到项目中,并进行相关配置,以便在对话框中使用OpenGL绘图。 3. 在对话框中添加一个静态文本框和一个自定义的OpenGL绘图区域。 4. 创建一个自定义的OpenGL绘图类,用于在绘图区域中显示STL模型。在该类中,定义一个透视投影矩阵、模型矩阵和视图矩阵,通过OpenGL函数来加载和渲染STL文件中的三角形。 5. 在对话框类中,添加一个自定义的OpenGL绘图类的成员变量,并在OnInitDialog()函数中对其进行初始化。 6. 在OnInitDialog()函数中,调用自定义OpenGL绘图类的初始化函数,传入STL模型文件的路径,将模型加载到内存中。 7. 在OnPaint()函数中,调用自定义OpenGL绘图类的绘制函数,将模型渲染到OpenGL绘图区域。 8. 处理对话框中的事件,例如按钮点击事件,调用自定义OpenGL绘图类的相应函数进行操作,如旋转、平移等。 9. 在应用程序类的InitInstance()函数中,创建对话框类的对象,并显示对话框。 通过以上步骤,可以实现在MFC应用程序中读取显示STL三维模型。 ### 回答2: MFC是Microsoft Foundation Classes的缩写,是一种用于Windows平台的C++应用程序框架。OpenGL是一种跨平台的图形API,用于开发图形和计算机视觉应用程序。STL(Standard Template Library)是C++的一部分,提供了一组通用的数据结构和算法。 要在MFC应用程序中读取显示STL三维模型,可以按照以下步骤进行操作: 1. 首先,创建一个MFC应用程序项目,并在项目中添加OpenGL支持。这可以通过在项目属性中启用OpenGL选项来实现。 2. 在MFC应用程序中创建一个窗口,用于显示3D模型。这可以通过创建一个自定义的CStatic控件,并在其上绘制OpenGL图形来实现。 3. 接下来,编写代码来读取STL文件的数据。STL文件中包含三角形网格的顶点和法线信息。可以使用标准的文件处理函数来读取和解析STL文件的内容,并将其存储在一个适当的数据结构中。 4. 通过OpenGL的API函数,将STL模型数据绘制到窗口中。可以使用OpenGL的顶点数组和绘制函数来绘制三角形网格的各个面。 5. 最后,将OpenGL绘制的结果显示在MFC窗口中。可以通过重载绘图消息处理函数,并在其中调用OpenGL的绘制函数来实现。 需要注意的是,由于MFC和OpenGL都是底层的图形库,对于初学者来说,可能需要一定的编程经验和对图形编程的理解。这个过程可能需要一些时间和尝试来完善和调试。 ### 回答3: 在 MFC 中使用 OpenGL读取显示 STL 三维模型可以通过以下步骤实现: 1. 添加准备创建 OpenGL 窗口的代码。在 MFC 的窗体类中,可以使用 `COpenGLControl` 类或 `CView` 类来实现 OpenGL 窗口。 2. 创建一个函数来读取 STL 三维模型文件。你可以使用 STL 文件解析库,例如 `std::ifstream` 类来读取 STL 文件的内容。 3. 在创建的 OpenGL 窗口中,使用 OpenGL 函数来绘制三维模型。你可以使用 `glBegin`、`glEnd` 和 `glVertex3f` 等函数来绘制模型的顶点和三角面片。 4. 在 OpenGL 窗口中,将读取到的 STL 三维模型数据传入 OpenGL 函数来进行绘制。你可以使用 `glColor3f` 函数来设置模型的颜色。 5. 在 MFC 的窗体类中,实现绘制 OpenGL 窗口的函数。通过重写 `OnDraw` 或 `OnPaint` 函数,调用 OpenGL 窗口的绘制函数。 6. 在 MFC 的窗体类中,重写 `OnCreate` 函数来初始化 OpenGL 窗口,调用读取显示 STL 模型的函数。 7. 在 MFC 的窗体类中,为了在窗口中显示 OpenGL 窗口,重写 `OnSize` 函数,并调用 OpenGL 窗口的调整大小函数。 通过上述步骤,你可以在 MFC 中使用 OpenGL读取显示 STL 三维模型。你可以进一步优化代码,例如添加相机控制、光照设置等来增强模型的显示效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值