跟着cherno手搓游戏引擎【18】抽象Shader、项目小修改

抽象:

Shader.h:

#pragma once
#include <string>namespace YOTO {class Shader {public:virtual~Shader()=default;virtual void Bind()const=0;virtual void UnBind()const=0;static Shader* Create(const std::string& vertexSrc, const std::string& fragmentSrc);};
}

Shader.cpp:

#include "ytpch.h"
#include "Shader.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLShader.h"
namespace YOTO {Shader* Shader::Create(const std::string& vertexSrc, const std::string& fragmentSrc){switch (Renderer::GetAPI()){case RendererAPI::API::None:YT_CORE_ASSERT(false, "Buffer:API为None不支持");return nullptr;case RendererAPI::API::OpenGL:return new OpenGLShader(vertexSrc, fragmentSrc);}YT_CORE_ASSERT(false, "Buffer:未知API");return nullptr;}
}

实现:

新建OpenGLShader类:

OpenGLShader.h

#pragma once
#include <string>
#include "YOTO/Renderer/Shader.h"
#include <glm/glm.hpp>
namespace YOTO {class OpenGLShader:public Shader {public:OpenGLShader(const std::string& vertexSrc, const std::string& fragmentSrc);~OpenGLShader();void Bind()const override;void UnBind()const override;void UploadUniformMat4(const std::string& name, const glm::mat4& matrix);void UploadUniformMat3(const std::string& name, const glm::mat3& matrix);void UploadUniformFloat4(const std::string& name, const glm::vec4& values);void UploadUniformFloat3(const std::string& name, const glm::vec3& values);void UploadUniformFloat2(const std::string& name, const glm::vec2& values);void UploadUniformFloat(const std::string& name, float values);void UploadUniformInt(const std::string& name, int values);private:uint32_t m_RendererID;};
} 

 OpenGLShader.cpp

#include "ytpch.h"
#include "OpenGLShader.h"#include <glad/glad.h>
#include <YOTO/Log.h>
#include<glm/gtc/type_ptr.hpp>
namespace YOTO {OpenGLShader::OpenGLShader(const std::string& vertexSrc, const std::string& fragmentSrc){// 1.1.创建顶点着色器对象GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);// Send the vertex shader source code to GL// Note that std::string's .c_str is NULL character terminated.// 1.2.附加顶点着色器源码到顶点着色器对象中const GLchar* source = vertexSrc.c_str();glShaderSource(vertexShader, 1, &source, 0);// 1.3.编译顶点着色器对象glCompileShader(vertexShader);// 1.4.检查是否编译成功GLint isCompiled = 0;glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);if (isCompiled == GL_FALSE) {// 1.4.2编译失败可以打印报错信息GLint maxLength = 0;glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);// The maxLength includes the NULL characterstd::vector<GLchar> infoLog(maxLength);glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);// We don't need the shader anymore.glDeleteShader(vertexShader);YT_CORE_ERROR("{0}", infoLog.data());YT_CORE_ASSERT(false, "Vertex shader compilation failure!");return;}// 片段着色器一样// 2.1.创建片段着色器对象GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);// Send the fragment shader source code to GL// Note that std::string's .c_str is NULL character terminated.// 2.2.附加片段着色器源码到片段着色器对象中source = fragmentSrc.c_str();glShaderSource(fragmentShader, 1, &source, 0);// 2.3.编译片段着色器对象glCompileShader(fragmentShader);// 2.4.检查是否编译成功glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);if (isCompiled == GL_FALSE) {// 2.4.2编译失败可以打印报错信息GLint maxLength = 0;glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);// The maxLength includes the NULL characterstd::vector<GLchar> infoLog(maxLength);glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);// We don't need the shader anymore.glDeleteShader(fragmentShader);// Either of them. Don't leak shaders.glDeleteShader(vertexShader);YT_CORE_ERROR("{0}", infoLog.data());YT_CORE_ASSERT(false, "Fragment shader compilation failure!");return;}// Vertex and fragment shaders are successfully compiled.// Now time to link them together into a program.// Get a program object.// 3.1创建着色器程序对象m_RendererID = glCreateProgram();GLuint program = m_RendererID;// 3.2附加着色器对象给着色器程序对象glAttachShader(program, vertexShader);glAttachShader(program, fragmentShader);// 3.3链接着色器程序对象glLinkProgram(program);// 3.4可以检查链接是否成功// Note the different functions here: glGetProgram* instead of glGetShader*.GLint isLinked = 0;glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);if (isLinked == GL_FALSE) {GLint maxLength = 0;glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);// The maxLength includes the NULL characterstd::vector<GLchar> infoLog(maxLength);glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);// We don't need the program anymore.glDeleteProgram(program);// Don't leak shaders either.glDeleteShader(vertexShader);glDeleteShader(fragmentShader);YT_CORE_ERROR("{0}", infoLog.data());YT_CORE_ASSERT(false, "Shader link failure!");return;}// 4.删除着色器对象// Always detach shaders after a successful link.glDetachShader(program, vertexShader);glDetachShader(program, fragmentShader);}OpenGLShader::~OpenGLShader(){glDeleteProgram(m_RendererID);}void OpenGLShader::Bind() const{glUseProgram(m_RendererID);}void OpenGLShader::UnBind() const{glUseProgram(0);}void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniformMatrix4fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix));}void OpenGLShader::UploadUniformMat3(const std::string& name, const glm::mat3& matrix){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniformMatrix3fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix)); }void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform4f(loacation, values.x, values.y, values.z, values.w);}void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform3f(loacation, values.x, values.y, values.z);}void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform2f(loacation, values.x, values.y);}void OpenGLShader::UploadUniformFloat(const std::string& name, float values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform1f(loacation, values);}void OpenGLShader::UploadUniformInt(const std::string& name, int values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform1i(loacation, values);}
}

测试:

#include<YOTO.h>
#include "imgui/imgui.h"
#include<stdio.h>
#include <glm/gtc/matrix_transform.hpp>
#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
class ExampleLayer:public YOTO::Layer
{
public:ExampleLayer():Layer("Example"),  m_Camera(-2.0f, 2.0f, -2.0f, 2.0f), m_CameraPosition(0){uint32_t indices[3] = { 0,1,2 };float vertices[3 * 7] = {-0.5f,-0.5f,0.0f, 0.8f,0.2f,0.8f,1.0f,0.5f,-0.5f,0.0f,  0.2f,0.3f,0.8f,1.0f,0.0f,0.5f,0.0f,   0.8f,0.8f,0.2f,1.0f,};m_VertexArray.reset(YOTO::VertexArray::Create());std::shared_ptr<YOTO::VertexBuffer> m_VertexBuffer;m_VertexBuffer.reset(YOTO::VertexBuffer::Create(vertices, sizeof(vertices)));{YOTO::BufferLayout setlayout = {{YOTO::ShaderDataType::Float3,"a_Position"},{YOTO::ShaderDataType::Float4,"a_Color"}};m_VertexBuffer->SetLayout(setlayout);}m_VertexArray->AddVertexBuffer(m_VertexBuffer);std::shared_ptr<YOTO::IndexBuffer>m_IndexBuffer;m_IndexBuffer.reset(YOTO::IndexBuffer::Create(indices, sizeof(indices) / sizeof(uint32_t)));m_VertexArray->AddIndexBuffer(m_IndexBuffer);std::string vertexSource = R"(#version 330 corelayout(location = 0) in vec3 a_Position;layout(location = 1) in vec4 a_Color;uniform mat4 u_ViewProjection;uniform mat4 u_Transform;out vec3 v_Position;out vec4 v_Color;void main(){v_Position=a_Position;v_Color=a_Color;gl_Position =u_ViewProjection *u_Transform* vec4( a_Position,1.0);})";//绘制颜色std::string fragmentSource = R"(#version 330 corelayout(location = 0) out vec4 color;in vec3 v_Position;in vec4 v_Color;void main(){color=vec4(v_Color);})";m_Shader.reset(YOTO::Shader::Create(vertexSource, fragmentSource));///测试/m_SquareVA.reset(YOTO::VertexArray::Create());float squareVertices[3 * 4] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.5f,0.5f,0.0f,-0.5f,0.5f,0.0f};std::shared_ptr<YOTO::VertexBuffer> squareVB;squareVB.reset(YOTO::VertexBuffer::Create(squareVertices, sizeof(squareVertices)));squareVB->SetLayout({{YOTO::ShaderDataType::Float3,"a_Position"}});m_SquareVA->AddVertexBuffer(squareVB);uint32_t squareIndices[6] = { 0,1,2,2,3,0 };std::shared_ptr<YOTO::IndexBuffer> squareIB;squareIB.reset((YOTO::IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t))));m_SquareVA->AddIndexBuffer(squareIB);//测试:std::string BlueShaderVertexSource = R"(#version 330 corelayout(location = 0) in vec3 a_Position;uniform mat4 u_ViewProjection;uniform mat4 u_Transform;out vec3 v_Position;void main(){v_Position=a_Position;gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);})";//绘制颜色std::string BlueShaderFragmentSource = R"(#version 330 corelayout(location = 0) out vec4 color;in vec3 v_Position;uniform vec3 u_Color;void main(){color=vec4(u_Color,1.0);})";m_BlueShader.reset(YOTO::Shader::Create(BlueShaderVertexSource, BlueShaderFragmentSource));}void OnImGuiRender() override {ImGui::Begin("设置");ImGui::ColorEdit3("正方形颜色", glm::value_ptr(m_SquareColor));ImGui::End();}void OnUpdate(YOTO::Timestep ts)override {YT_CLIENT_TRACE("delta time {0}s ({1}ms)", ts.GetSeconds(), ts.GetMilliseconds());if (YOTO::Input::IsKeyPressed(YT_KEY_LEFT)) {m_CameraPosition.x -= m_CameraMoveSpeed* ts;}else if (YOTO::Input::IsKeyPressed(YT_KEY_RIGHT)) {m_CameraPosition.x += m_CameraMoveSpeed * ts;}if (YOTO::Input::IsKeyPressed(YT_KEY_DOWN)) {m_CameraPosition.y -= m_CameraMoveSpeed * ts;}else if (YOTO::Input::IsKeyPressed(YT_KEY_UP)) {m_CameraPosition.y += m_CameraMoveSpeed * ts;}if (YOTO::Input::IsKeyPressed(YT_KEY_A)) {m_CameraRotation += m_CameraRotationSpeed * ts;}else if (YOTO::Input::IsKeyPressed(YT_KEY_D)) {m_CameraRotation -= m_CameraRotationSpeed * ts;}YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });YOTO::RenderCommand::Clear();m_Camera.SetPosition(m_CameraPosition);m_Camera.SetRotation(m_CameraRotation);YOTO::Renderer::BeginScene(m_Camera);{static glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f)); glm::vec4  redColor(0.8f, 0.3f, 0.3f, 1.0f);glm::vec4  blueColor(0.2f, 0.3f, 0.8f, 1.0f);/*		YOTO::MaterialRef material = new YOTO::MaterialRef(m_FlatColorShader);YOTO::MaterialInstaceRef mi = new YOTO::MaterialInstaceRef(material);mi.setValue("u_Color",redColor);mi.setTexture("u_AlbedoMap", texture);squreMesh->SetMaterial(mi);*/std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->Bind();std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->UploadUniformFloat3("u_Color",m_SquareColor);for (int y = 0; y < 20; y++) {for (int x = 0; x <20; x++){glm::vec3 pos(x * 0.11f,y* 0.11f, 0.0);glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * scale;/*if (x % 2 == 0) {m_BlueShader->UploadUniformFloat4("u_Color", redColor);}else {m_BlueShader->UploadUniformFloat4("u_Color", blueColor);}*/YOTO::Renderer::Submit(m_BlueShader, m_SquareVA, transform);}}YOTO::Renderer::Submit(m_Shader, m_VertexArray);YOTO::Renderer::EndScene();}}void OnEvent(YOTO::Event& event)override {/*if (event.GetEventType() == YOTO::EventType::KeyPressed) {YOTO:: KeyPressedEvent& e = (YOTO::KeyPressedEvent&)event;YT_CLIENT_TRACE("ExampleLayer:{0}",(char)e.GetKeyCode());if (e.GetKeyCode()==YT_KEY_TAB) {YT_CLIENT_INFO("ExampleLayerOnEvent:TAB按下了");}}*///YT_CLIENT_TRACE("SandBoxApp:测试event{0}", event);}private:std::shared_ptr<YOTO::Shader> m_Shader;std::shared_ptr<YOTO::VertexArray> m_VertexArray;std::shared_ptr<YOTO::Shader> m_BlueShader;std::shared_ptr<YOTO::VertexArray> m_SquareVA;YOTO::OrthographicCamera m_Camera;glm::vec3 m_CameraPosition;float m_CameraMoveSpeed = 5.0f;float m_CameraRotation = 0;float m_CameraRotationSpeed = 180.0f;glm::vec3 m_SquareColor = { 0.2f,0.3f,0.7f };};class Sandbox:public YOTO::Application
{
public:Sandbox(){PushLayer(new ExampleLayer());//PushLayer(new YOTO::ImGuiLayer());}~Sandbox() {}private:};YOTO::Application* YOTO::CreateApplication() {printf("helloworld");return new Sandbox();
}

 cool!

小修改:

Core.h:

#pragma once
#include<memory>
//用于dll的宏
#ifdef YT_PLATFORM_WINDOWS
#if YT_DYNAMIC_LINK#ifdef YT_BUILD_DLL#define YOTO_API __declspec(dllexport) #else#define YOTO_API __declspec(dllimport) #endif // DEBUG
#else#define YOTO_API
#endif
#else
#error YOTO_ONLY_SUPPORT_WINDOWS
#endif // YOTO_PLATFORM_WINDOWS#ifdef YT_DEBUG
#define YT_ENABLE_ASSERTS
#endif#ifdef YT_ENABLE_ASSERTS
#define YT_CLIENT_ASSERT(x,...) {if(!(x)){YT_CLIENT_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#define YT_CORE_ASSERT(x,...) {if(!(x)){YT_CORE_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#else
#define YT_CLIENT_ASSERT(x,...)
#define YT_CORE_ASSERT(x,...)#endif // YT_ENABLE_ASSERTS#define BIT(x)(1<<x)
//绑定事件定义
#define YT_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)namespace YOTO {template<typename T>using  Scope = std::unique_ptr<T>;template<typename T>using  Ref = std::shared_ptr<T>;
}

之后把所有share_ptr的地方改成Ref就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664070.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

window 安装 jenkins 编写脚本

set JAVA_HOMED:\RuanJianKaiFa\jdk\jdk11 set CLASSPATH.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOMe%\lib\tools.jar; set Path%JAVA_HOME%\bin; java -jar jenkins.war 下载jenkins.war包&#xff0c;编写一个txt文档&#xff0c;把脚本复制进去&#xff0c;修改文件后缀为.bat文件…

MySQL EXPLAIN查询执行计划

EXPLAIN 可用来查看SQL执行计划&#xff0c;常用来分析调试SQL语句&#xff0c;来使SQL语句达到更好的性能。 1 前置知识 在学习EXPLAIN 之前&#xff0c;有些基础知识需要清楚。 1.1 JSON类型 MySQL 5.7及以上版本支持JSON数据类型。可以将数组存为JSON格式的字符串&#…

【Arduino】LGT8F328 UNO R3编译上传

LGT8F328 UNO R3编译上传 示例代码 这是一段示例代码&#xff0c;将示例代码编译打包上传到LGT8F328 UNO R3开发板。 #include <Servo.h> Servo myservo; int pos 0; void setup() {// put your setup code here, to run once:Serial.begin(9600);Serial.println(&qu…

uni-app切换页面刷新,返回上一页刷新(onShow钩子函数的使用)

切换页面刷新&#xff1a;通过onShow()便可实现 返回上一页通过uni.navigateBack({delta: 1});实现 以返回上一页刷新为例 从B页面返回上一页到A页面&#xff0c;在A页面写入方法refreshHandler() //a.vue methods: { // 执行刷新逻辑refreshHandler() {uni.request({ur…

NoSQL数据库管理系统和模型的比较

介绍 当大多数人想到数据库时&#xff0c;他们通常会想到传统的关系数据库模型&#xff0c;其中包括由行和列组成的表。虽然关系数据库管理系统仍然处理着互联网上的大部分数据&#xff0c;但近年来&#xff0c;随着开发人员寻求绕过关系模型的限制&#xff0c;替代数据模型变…

本体匹配方法概述

目录 前言1 基于术语匹配的方法1.1 字符串匹配1.2 语言方法 2 基于虚拟文档的方法3 基于结构的匹配方法3.1 结构信息利用3.2 Anchor-prompt方法 4 大型本体匹配4.1 本体划分4.2 匹配分块4.3 实体间映射 结语 前言 本文将深入探讨本体匹配的不同方法&#xff0c;从基于术语匹配…

springboot项目以jar包运行时,读取jar包内的静态文件

springboot项目以jar包运行时&#xff0c;读取jar包内的静态文件 java

从编程中理解:大脑的成瘾行为

成瘾行为在心理学中被定义为个体对某种物质或行为产生强烈的心理和生理依赖,无法自控地重复该行为。从编程的角度来看,我们可以将大脑的成瘾行为模型化为一种反馈循环系统,其中包含激励、奖赏、强化学习等机制。以下是一个用Unity C#代码模拟金庸武侠小说中人物成瘾行为的例…

Git指令大全:如何同步github代码,12个你必须了解的最常见Git命令!

&#x1f4e5; 准备好合作&#xff01;克隆仓库&#xff1a; git init - 初始化仓库。git clone [仓库URL] - 克隆仓库。 &#x1f575;️‍♂️ 监控变更&#xff1a; git status - 检查状态。git add [文件(们)] - 添加变更。git commit -m "[消息]" - 提交变更…

神经网络和深度学习吴恩达coursera笔记

Deep Learning 文章目录 Deep LearningBasicLogistic Regressionsome signLoss functioncost functionGradient DescentComputation Grapha VectorizationvectorizedImplementing:broadcasting Shallow Neural NetworkRepresentationcomputing:Vectorize:Activation functionsG…

DES加密原理

DES加密算法综合运用了置换、代替、代数等多种密码技术&#xff0c;具有设计精 巧、实现容易、使用方便等特点。DES加密算法的明文、密文和密钥的分组长度 都是64位&#xff0c;详细的DES加密算法结构如图6-10所示。 图6-10 DES加密算法结构图 DES加密过程如下所示&#xff…

2024PMP考试新考纲-【业务环境领域】典型真题和很详细解析(3)

华研荟继续分享【业务环境Business Environment领域】在新考纲下的真题&#xff0c;帮助大家体会和理解新考纲下PMP的考试特点和如何应用所学的知识和常识&#xff08;经验&#xff09;来解题&#xff0c;并且举一反三&#xff0c;一次性3A通过2024年PMP考试。 2024年PMP考试新…

0202-1-处理机调度与死锁

第三章:处理机调度与死锁 处理机调度算法的目标 处理机调度算法的共同目标 资源利用率:CPU的利用率CPU有效工作时间/(CPU有效工作时间CPU空闲等待时间)公平性平衡性策略强制执行 批处理系统的目标 平均周转时间短系统吞吐量高处理机利用率高 分时系统的目标 响应时间快均…

10MHz 到 80MHz、10:1 LVDS 并串转换器(串化器)/串并转换器(解串器)MS1023/MS1224

产品简述 MS1023 串化器和 MS1224 解串器是一对 10bit 并串 / 串并转 换芯片&#xff0c;用于在 LVDS 差分底板上传输和接收 10MHz 至 80MHz 的并行字速率的串行数据。起始 / 停止位加载后&#xff0c;转换为负载编 码输出&#xff0c;串行数据速率介于 120Mbps…

如何将 h5 页面快速转换成微信小程序

Hello各位朋友们大家新的一月好呀&#xff01;我是咕噜铁蛋&#xff01;我知道在小程序开发中&#xff0c;有时候需要将H5页面转换成微信小程序页面。这样可以将原本的网页内容适配到小程序中&#xff0c;让用户能够更方便地访问和使用。在本文中&#xff0c;我将分享如何快速将…

Vue实现公告循环横向播报组件

一、代码组件 注意&#xff1a;当公告字数很少时会固定不动&#xff0c;当字数达到最大宽度时&#xff0c;则会循环播报 <template><div class"TopCard"><!-- 小喇叭 --><div style"width: 70px"><notify style"width: 2…

git小白进阶之路

git是最常用的版本控制工具&#xff0c;我对其进行了整理后续补充&#xff0c;这个文档欢迎大家来讨论&#xff0c;当前我的视频梳理&#xff1a; git小白进阶之路_哔哩哔哩_bilibili&#xff0c;非常希望大佬们能够批评指正&#xff0c;并多多交流。 目录 初始配置 配置账号…

《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述(5)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述&#xff08;4&#xff09; 4.1.2 PCIe总线使用的信号 PCIe设备使用两种电源信号供电&#xff0c;分别是Vcc与Vaux&#xff0c;其额定电压为3.3V。其中Vcc为主电源&#xff0c;PCIe设备…

上位机图像处理和嵌入式模块部署(linux开发板的选择)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多图像算法是通过上位机来完成的&#xff0c;比如说工业视觉当中的halcon&#xff0c;一般都是要运行在windows平台上面&#xff0c;并且需要高性…

CC++内存泄露和检测

介绍 内存泄漏&#xff08;Memory Leak&#xff09;是指在计算机程序运行过程中&#xff0c;程序动态分配了一块内存空间后&#xff0c;在使用完毕之后没有及时释放&#xff0c;导致这块内存无法被再次有效利用的现象。换言之&#xff0c;当程序申请的内存不再需要时&#xff…