国内net开发的网站建设/seo外包杭州
OpenGL
- Assimp
- 模型加载库
- 构建Assimp
- 网格
- 网格渲染
Assimp
我们不太能够对像是房子、汽车或者人形角色这样的复杂形状手工定义所有的顶点、法线和纹理坐标。我们要的是将这些模型(Model)导入(Import)到程序当中。模型通常都由3D艺术家在Blender、3DS Max或者Maya这样的工具中精心制作。上述的建模工具,可以让艺术家创建复杂的形状,使用一种叫做UV映射的手段来应用贴图。将会在导出到模型文件的时候自动生成所有的顶点坐标、顶点法线以及纹理坐标。
我们需要解析这些导出的模型文件以及提取有用的信息,把它们存储为OpenGL能够理解的格式。
模型的文件格式有很多种,每一种都会以它们自己的方式来导出模型数据。像是Wavefront的.obj这样的模型格式,只包含了模型数据以及材质信息,比如模型颜色和漫反射/镜面光贴图。而以XML为基础的Collada文件格式则非常的丰富,包含模型、光照、多种材质、动画数据、摄像机、完整的场景信息等等。
Wavefront的.obj格式通常被认为是一个易于解析的模型格式。建议至少去Wavefront的wiki页面上看看文件格式的信息是如何封装的。这应该能让你认识到模型文件的基本结构。不同种类的文件格式有很多,它们之间通常并没有一个通用的结构。想从这些文件格式中导入模型的话,我们必须要去自己对每一种需要导入的文件格式写一个导入器。很幸运的是,正好有一个库专门处理这个问题。
模型加载库
模型导入库Assimp,它是Open Asset Import Library(开放的资产导入库)的缩写。
能够导入很多种不同的模型文件格式,它会将所有的模型数据加载到Assimp的通用数据结构种。当Assimp加载完模型之后,我们就能够从Assimp的数据结构中提取我们所需的所有数据了。由于Assimp的数据结构保持不变,不论导入的是什么种类的文件格式,它都能够将我们从这些不同的文件格式中抽象出来,用同一种方式访问我们需要的数据。
当使用Assimp导入一个模型的时候,通常会将整个模型加载到一个场景对象。包含:导入的模型、场景中的所有数据。Assimp会将场景载入为一系列的节点,每个节点包含了场景对象种所存储数据的索引,每个节点都可以有任意数量的子节点。简化数据模型如下:
- 和材质和网格(Mesh)一样,所有的场景/模型数据都包含在Scene对象中。Scene对象也包含了场景根节点的引用。
- 场景的Root node(根节点)可能包含子节点(和其它的节点一样),它会有一系列指向场景对象中mMeshes数组中储存的网格数据的索引。Scene下的mMeshes数组储存了真正的Mesh对象,节点中的mMeshes数组保存的只是场景中网格数组的索引。
- 一个Mesh对象本身包含了渲染所需要的所有相关数据,像是顶点位置、法向量、纹理坐标、面(Face)和物体的材质。
- 一个网格包含了多个面。Face代表的是物体的渲染图元(Primitive)(三角形、方形、点)。一个面包含了组成图元的顶点的索引。由于顶点和索引是分开的,使用一个索引缓冲来渲染是非常简单的(之前章节中画三角形)。
- 最后,一个网格也包含了一个Material对象,它包含了一些函数能让我们获取物体的材质属性,比如说颜色和纹理贴图(比如漫反射和镜面光贴图)。
所以,我们需要做的第一件事是将一个物体加载到Scene对象中,遍历节点,获取对应的Mesh对象(我们需要递归搜索每个节点的子节点),并处理每个Mesh对象来获取顶点数据、索引以及它的材质属性。最终的结果是一系列的网格数据,我们会将它们包含在一个Model对象中。
补充:网格
当使用建模工具对物体建模的时候,艺术家通常不会用单个形状创建出整个模型。通常每个模型都由几个子模型/形状组合而成。组合模型的每个单独的形状就叫做一个网格(Mesh)。比如说有一个人形的角色:艺术家通常会将头部、四肢、衣服、武器建模为分开的组件,并将这些网格组合而成的结果表现为最终的模型。一个网格是我们在OpenGL中绘制物体所需的最小单位(顶点数据、索引和材质属性)。一个模型(通常)会包括多个网格。
构建Assimp
需要创建自己的Model和Mesh类来加载并使用刚才的结构存储导入后的模型。
要绘制一个模型,不需要将整个模型渲染成一个整体,只需要渲染组成模型的每个独立的网格就可以了。先将Assimp包包含到工程当中。
下载Assimp可以参考这两个文章:
https://blog.csdn.net/derbi123123/article/details/105783048/
https://blog.csdn.net/xiaopenga520/article/details/126522776
网格
网格代表的是单个可绘制实体,先定义一个网格类。
一个网格最少需要一系列顶点,每个顶点包含一个位置向量,一个法向量,一个纹理坐标向量。还要包含用于索引绘制的索引,纹理形式的材质数据——漫反射/镜面光贴图:
把需要的向量存储到下面的结构体中,可以用来索引每个顶点属性。
struct Vertex {glm::vec3 Position;glm::vec3 Normal;glm::vec2 TexCoords;
};
再将纹理数据整理到一个结构体中:
struct Texture {unsigned int id;string type;
};
存储了纹理ID和纹理类型,比如:漫反射贴图或者是镜面光贴图
再定义网格类:
class Mesh {public:/* 网格数据 */vector<Vertex> vertices;vector<unsigned int> indices;vector<Texture> textures;/* 函数 */Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures);void Draw(Shader shader);private:/* 渲染数据 */unsigned int VAO, VBO, EBO;/* 函数 */void setupMesh();
};
上述类结构,把所有数据在构造器中进行赋值,在setupMesh函数中初始化缓冲,最后使用Draw来绘制网格。构造器函数如下:
//只需要使用构造器的参数设置类的公有变量
Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
{this->vertices = vertices;this->indices = indices;this->textures = textures;setupMesh();
}
在把网格数据用于渲染之前,还需要配置正确的缓冲,通过顶点属性指针 定义顶点着色器。setupMesh函数如下:
void setupMesh()
{glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);// 顶点位置glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);// 顶点法线glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));// 顶点纹理坐标glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));glBindVertexArray(0);
}
C++结构体有一个很棒的特性,它们的内存布局是连续的。如果我们将结构体作为一个数据数组使用,那么它将会以顺序排列结构体的变量,这将会直接转换为我们在数组缓冲中所需要的float(实际上是字节)数组。比如:
Vertex vertex;
vertex.Position = glm::vec3(0.2f, 0.4f, 0.6f);
vertex.Normal = glm::vec3(0.0f, 1.0f, 0.0f);
vertex.TexCoords = glm::vec2(1.0f, 0.0f);
// = [0.2f, 0.4f, 0.6f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f];
所以直接传入一大列的Vertex结构体的指针作为缓冲的数据,它们将会完美地转换为glBufferData所能用的参数:
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
sizeof运算也可以用在结构体上来计算它的字节大小。这个应该是32字节的(8个float * 每个4字节)
结构体的另一个很好的用途是:它的预处理指令offsetof(s, m),它的第一个参数是一个结构体,第二个参数是这个结构体中变量的名字。这个宏会返回那个变量距结构体头部的字节偏移量(Byte Offset)。这正好可以用在定义glVertexAttribPointer函数中的偏移参数:
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
偏移量现在是使用offsetof来定义了,在这里它会将法向量的字节偏移量设置为结构体中法向量的偏移量,也就是3个float,即12字节。注意,我们同样将步长参数设置为了Vertex结构体的大小。
网格渲染
在渲染网格之前,在调用glDrawElements函数之前需要先绑定相应的纹理。(并不知道这个网格(如果有的话)有多少纹理、纹理是什么类型的。所以我们该如何在着色器中设置纹理单元和采样器?)
设定一个命名标准:每个漫反射纹理被命名为:texture_diffuseN,每个镜面光纹理被命名为:texture_specularN。N的范围是1到纹理采样器最大允许的数字。
根据这个标准,在着色器中定义任意需要数量的纹理采样器。渲染代码如下:
void Draw(Shader shader)
{unsigned int diffuseNr = 1;unsigned int specularNr = 1;for(unsigned int i = 0; i < textures.size(); i++){glActiveTexture(GL_TEXTURE0 + i); // 在绑定之前激活相应的纹理单元// 获取纹理序号(diffuse_textureN 中的 N)string number;string name = textures[i].type;if(name == "texture_diffuse")number = std::to_string(diffuseNr++);else if(name == "texture_specular")number = std::to_string(specularNr++);shader.setInt(("material." + name + number).c_str(), i);glBindTexture(GL_TEXTURE_2D, textures[i].id);}glActiveTexture(GL_TEXTURE0);// 绘制网格glBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);glBindVertexArray(0);
}
我们首先计算了每个纹理类型的N-分量,并将其拼接到纹理类型字符串上,来获取对应的uniform名称。接下来我们查找对应的采样器,将它的位置值设置为当前激活的纹理单元,并绑定纹理。这也是我们在Draw函数中需要着色器的原因。我们也将"material."添加到了最终的uniform名称中,因为我们希望将纹理储存在一个材质结构体中(这在每个实现中可能都不同)。
综上,代码如下:
#ifndef MESH_H
#define MESH_H#include <glad/glad.h> // holds all OpenGL type declarations#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>#include <learnopengl/shader.h>#include <string>
#include <vector>
using namespace std;#define MAX_BONE_INFLUENCE 4struct Vertex {// positionglm::vec3 Position;// normalglm::vec3 Normal;// texCoordsglm::vec2 TexCoords;// tangentglm::vec3 Tangent;// bitangentglm::vec3 Bitangent;//bone indexes which will influence this vertexint m_BoneIDs[MAX_BONE_INFLUENCE];//weights from each bonefloat m_Weights[MAX_BONE_INFLUENCE];
};struct Texture {unsigned int id;string type;string path;
};class Mesh {
public:// mesh Datavector<Vertex> vertices;vector<unsigned int> indices;vector<Texture> textures;unsigned int VAO;// constructorMesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures){this->vertices = vertices;this->indices = indices;this->textures = textures;// now that we have all the required data, set the vertex buffers and its attribute pointers.setupMesh();}// render the meshvoid Draw(Shader &shader) {// bind appropriate texturesunsigned int diffuseNr = 1;unsigned int specularNr = 1;unsigned int normalNr = 1;unsigned int heightNr = 1;for(unsigned int i = 0; i < textures.size(); i++){glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding// retrieve texture number (the N in diffuse_textureN)string number;string name = textures[i].type;if(name == "texture_diffuse")number = std::to_string(diffuseNr++);else if(name == "texture_specular")number = std::to_string(specularNr++); // transfer unsigned int to stringelse if(name == "texture_normal")number = std::to_string(normalNr++); // transfer unsigned int to stringelse if(name == "texture_height")number = std::to_string(heightNr++); // transfer unsigned int to string// now set the sampler to the correct texture unitglUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i);// and finally bind the textureglBindTexture(GL_TEXTURE_2D, textures[i].id);}// draw meshglBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);glBindVertexArray(0);// always good practice to set everything back to defaults once configured.glActiveTexture(GL_TEXTURE0);}private:// render data unsigned int VBO, EBO;// initializes all the buffer objects/arraysvoid setupMesh(){// create buffers/arraysglGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);glBindVertexArray(VAO);// load data into vertex buffersglBindBuffer(GL_ARRAY_BUFFER, VBO);// A great thing about structs is that their memory layout is sequential for all its items.// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which// again translates to 3/2 floats which translates to a byte array.glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);// set the vertex attribute pointers// vertex PositionsglEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);// vertex normalsglEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));// vertex texture coordsglEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));// vertex tangentglEnableVertexAttribArray(3);glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent));// vertex bitangentglEnableVertexAttribArray(4);glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent));// idsglEnableVertexAttribArray(5);glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, m_BoneIDs));// weightsglEnableVertexAttribArray(6);glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_Weights));glBindVertexArray(0);}
};
#endif
相关文章:

第十二章 opengl之模型加载(Assimp)
OpenGLAssimp模型加载库构建Assimp网格网格渲染Assimp 我们不太能够对像是房子、汽车或者人形角色这样的复杂形状手工定义所有的顶点、法线和纹理坐标。我们要的是将这些模型(Model)导入(Import)到程序当中。模型通常都由3D艺术家在Blender、3DS Max或者Maya这样的工具中精心制…...

Stable Matching-稳定匹配问题【G-S算法,c++】
Stable Matching-稳定匹配问题【G-S算法,c】题目描述:(Gale-Shapley算法)解题思路一:G-S算法(Gale-Shapley算法)题目描述:(Gale-Shapley算法) Teenagers from the local high school have asked you to help them with the organ…...

TypeScript(四)接口
目录 前言 定义 用法 基本用法 约定规则 属性控制 任意属性 可选属性 只读属性 定义函数 冒号定义 箭头定义 接口类型 函数接口 索引接口 继承接口 类接口 总结 前言 在介绍TS对象类型中,为了让数组每一项更具体,我们使用 string [ ]…...

Python-基础知识
目录 Python 简介 Python 发展历史 Python 特点 Python 标识符 Python 保留字符 行和缩进 多行语句 Python 引号 Python注释 Python 简介 Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性,相比…...

【java基础】集合基础说明
文章目录基本介绍Collection接口Iterator和Iterable接口Map接口关于Iterator接口的一些说明框架中的接口具体集合总结基本介绍 集合就是存储用来存储一系列数据的一种数据结构。在这篇文章中会介绍集合的一些基本概念。 Collection接口 集合的基本接口是Collection接口&…...

MySQL的下载及安装详细教程
提示:本文仅为MySQL初学者的安装MySQL过程提供参考,创作不易,请多点赞支持! MySQL的下载及安装前言一、MySQL的下载及安装1.MySQL的下载2.MySQL的安装3.配置环境变量4.连接MySQL4.1 方式一4.2 方式二前言 本文内容主要是帮助初学…...

SSL/TLS协议工作原理
SSL/TLS协议工作原理 SLL/TLS协议工作在应用层和传输层之间,应用层数据需要经过SSL/TLS层的加密之后才会发送到传输层。SSL/TLS协议有两个重要协议:握手协议、记录协议。 1. 握手协议 TCP三次握手完成后,才能进行SSL/TLS的握手。 因为&#…...

大数据项目实战之数据仓库:用户行为采集平台——第4章 用户行为数据采集模块
第4章 用户行为数据采集模块 4.1 数据通道 4.2 环境准备 4.2.1 集群所有进程查看脚本 1)在/home/atguigu/bin目录下创建脚本xcall [atguiguhadoop102 bin]$ vim xcall2)在脚本中编写如下内容 #! /bin/bashfor i in hadoop102 hadoop103 hadoop104 d…...

《统计学习方法》(李航)——学习笔记
第一章 概论统计学习,又称统计机器学习(机器学习),现在提到的 机器学习 往往指的就是 统计机器学习。统计学习研究的对象是数据,其对数据的基本假设是同类数据存在一定的统计规律性,因此可以用概率统计方法…...

阿里云EMR集群搭建及使用
目录 1.简介 1.什么是EMR 2.组成 3.与自建hadoop集群对比 4.产品架构 2.使用 1.创建EMR集群 1.登录EMR on ECS控制台 2.软件设置 3.硬件设置 3.基础配置 2.配置 1.组件配置 2.用户管理 3.安全组 4.Gateway 3.组件UI 1.简介 1.什么是EMR EMR是运行在阿里云平台…...

学习streamlit-4
st.slider 今天学习st.slider滑块组件的使用。 st.slider滑块组件通常被用来作为应用的输入,支持整数、浮点数、日期、时间和日期时间。 下面的示例程序包含以下简单功能,以演示st.slider滑块组件: 用户通过调整滑块选择值应用打印出所选…...

高级Oracle DBA面试题及答案
作为高级 Oracle DBA,您将负责 Oracle 数据库基础架构的设计、安装、配置、监控和维护。您还将负责制定和实施备份和恢复计划,并确保数据的安全性和完整性。要成功担任此职位,您需要对 Oracle 数据库架构有深入的了解,并能够有效地…...

程序员成长路线
程序员在成长的过程中,不同的阶段,需要关注的问题点一会都会有所不同,今天给大家分享下自己的感受。 0-1年,入门,掌握语言基础、提高工具的使用熟练度。 工作第一年,主要围绕ssm三件套、mysql、red…...

【Galois工具开发之路】关于类的重新装载思路
思路 当一个java的类文件发生变更,如果动态的热更新这个新的类文件?目前来说,有两种可能的方式 新增一个自定义ClassLoader,名为NC,让NC去load这个新的类文件,这样就完成了新的类定义的替换 但目前Java有…...

哪款蓝牙耳机音质好?内行推荐四款高音质蓝牙耳机
蓝牙耳机经过近几年的快速发展,在音质上的表现也越来越好。哪款蓝牙耳机音质好?最近看到很多人问。接下来,我来给大家推荐四款高音质蓝牙耳机,可以当个参考。 一、南卡小音舱蓝牙耳机 参考价:246 发声单元ÿ…...

Android程序自动在线升级安装
安卓小白分享: Android程序自动在线升级安装.(通过GetSharedDownloadsPath方法) 1>.修改AndroidManifest.template.xml ( 此文件在你DELPHI项目的目录中,如找不到就文件查找吧) 最好把此文件拖到DELPHI, 用DELPHI打开,(这样,它会一行一行格式清楚) 找到文字<%u…...

JS的BroadcastChannel与MessageChannel
BroadcastChannel与MessageChannel BroadcastChannel BroadcastChannel以广播的形式进行通信 BroadcastChannel用于创建浏览器标签页之间的通信 使用BroadcastChannel的浏览器标签页面必须要遵循同源策略 页面1使用BroadcastChannel创建一个频道,页面2使用Broadc…...

nextjs开发 + vercel 部署 ssr ssg
前言 最近想实践下ssr 就打算用nextjs 做一个人博客 , vercel 部署 提供免费域名,来学习实践下ssr ssg nextjs 一个轻量级的react服务端渲染框架 vercel 由 Next.js 的创建者制作 支持nextjs 部署 免费静态网站托管 初始化项目 npx create-next-app p…...

Good Idea, 利用MySQL JSON特性优化千万级文库表
👳我亲爱的各位大佬们好😘😘😘 ♨️本篇文章记录的为 利用MySQL JSON特性优化千万级文库表 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉…...

【python游戏制作】快来跟愤怒的小鸟一起攻击肥猪们的堡垒吧
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 为了防止/报复偷走鸟蛋的肥猪们,鸟儿以自己的身体为武器, 仿佛炮弹一样去攻击肥猪们的堡垒,保卫自己的鸟蛋 这个游戏大家没玩过的想必也听说过~ 今天就给大家分享一下用python写的愤怒的…...

ARM 学习(一)
ARM 处理器的运行模式ARM处理器共有7种运行模式,如下表所示:处理器模式描述用户模式(User)正常程序运行模式中断模式(IRQ)用于通常的中断处理快速中断模式(FIQ)用于高速传输和通道处…...

深入分析Java的序列化与反序列化
序列化是一种对象持久化的手段。普遍应用在网络传输、RMI等场景中。本文通过分析ArrayList的序列化来介绍Java序列化的相关内容。主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了java.io.Serializable接口才能被序列化 transient的作用是什么 怎么自…...

、Tomcat源码分析-类加载器
接下来,我们再来看下 tomcat 是如何创建 common 类加载器的。关键代码如下所示,在创建类加载器时,会读取相关的路径配置,并把路径封装成 Repository 对象,然后交给 ClassLoaderFactory 创建类加载器。 Bootstrap.java…...

反转链表相关的练习(下)
目录 一、回文链表 二、 重排链表 三、旋转链表 一、回文链表 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:head [1,2,2,1] 输…...

2.进程和线程
1.进程1.1 终止正常退出(自愿)出错退出(自愿)严重错误(非自愿)被其他进程杀死(非自愿)1.2 状态就绪态:可运行,但因为其他进程正在运行而暂时停止阻塞态:除非某种外部事件发生,否则进程不能运行1.3 实现一个进程在执行过程中可能被…...

C++回顾(十四)—— 函数模板
14.1 概述 所谓函数模板(function template),实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数&a…...

如何做好项目各干系人的管理及应对?
如何更好地识别、分析和管理项目关系人?主要有以下几个方面: 1、项目干系人的分析 一般对项目干系人的分析有2种方法, 方法一:权利(影响),即对项目可以产生影响的人; 方法二…...

Elasticsearch使用系列-ES增删查改基本操作+ik分词
一、安装可视化工具KibanaES是一个NoSql数据库应用。和其他数据库一样,我们为了方便操作查看它,需要安装一个可视化工具 Kibana。官网:https://www.elastic.co/cn/downloads/kibana和前面安装ES一样,选中对应的环境下载࿰…...

07-PL/SQL基础(if语句,case语句,循环语句)
本章主要内容: 1.PL/SQL的基本构成:declare,begin,exception,end; 2.结构控制语句:IF语句,CASE语句 3.循环结构:loop循环,for loop循环,while loop循环 PL/SQL的基本构成 特点 PL/SQL语言是SQL语言的扩展ÿ…...

信捷 XDH Ethercat A_VELMOVE
本文描述信捷 EthercatA_VELMOVE指令,以设定的速度持续运行 上图中,在M100的上升沿,执行A_VELMOVE指令。A_VELMOVE HD100 D100 M101 K0HD100输入参数起始地址 ,HD118输入参数末尾地址HD100~HD103,双精度浮点数(64位&am…...