OPenGL实例化绘制、普通绘制说明

OpenGL 入门 21:实例化 OpenGL 实例化 阅读详情
AI摘要

OpenGL实例化渲染是一种优化技术,通过一次性发送数据并使用glDrawArraysInstanced或glDrawElementsInstanced等函数,减少CPU与GPU间的通讯,提升渲染多个物体的效率。利用gl_InstanceID内建变量,可以实现位置、大小等变化的多个实例。此外,通过顶点属性定义的实例化数组(InstancedArray)和glVertexAttribDivisor函数,可以解决uniform数据上限问题,进一步提高性能。文章详细介绍了实例化的概念、工作原理和实现方法。

       OpenGL 实例化(Instancing)是一种只调用一次渲染函数就能绘制出不少物体的技术,能够实现将数据一次性而不是多次发送给 GPU ,告诉 OpenGL使用一个绘制函数,将这些数据绘制成多个物体。数组实例化(Instancing)避免了 CPU 屡次向 GPU 下达渲染命令(避免屡次调用 glDrawArrays 或 glDrawElements 等绘制函数),节省了绘制多个物体时 CPU 与 GPU 之间的通讯时间,提高了渲染性能。 实例化是因为Verilog等语言里面有实例化,相当于提前定义好的一个模块,在别的模块中可以直接调用(即例化)。OpenGL的实例化与Verilog的例化很像,所以名字叫这个,本质上是对一个模块的多次调用,和批量渲染是一个意思。

//普通渲染
glDrawArrays (GLenum mode, GLint first, GLsizei count);

glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);

//实例化渲染
glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);

glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);

       相对于普通绘制,实例化绘制多了一个参数instancecount,表示须要渲染的实例数量,调用完实例化绘制函数后,咱们便将绘制数据一次性发送给 GPU,而后告诉它该如何使用一个函数来绘制这些实例。

实例化(Instancing)的目标并非实现将同一物体绘制屡次,而是能基于某一物体绘制出位置、大小、形状或者颜色不一样的多个物体。glDrawArraysInstanced函数内部实现如下:

if ( mode or count is invalid )
        generate appropriate error
    else {
        for (int i = 0; i < primcount ; i++) {
            instanceID = i;
            glDrawArrays(mode, first, count);
        }
        instanceID = 0;
    }

其中上述伪代码中的instanceID就是类似于OpenGL  着色器中有一个与实例化绘制相关的内建变量 gl_InstanceID。gl_InstanceID表示当前正在绘制实例的 ID ,每一个实例对应一个惟一的 ID ,经过这个 ID 能够轻易实现基于一个物体而绘制出位置、大小、形状或者颜色不一样的多个物体(实例)。

         利用内建变量gl_InstanceID在 3D 空间绘制多个位于不一样位置的立方体,利用 u_offsets[gl_InstanceID]对当前实例的位置进行偏移,对应的着色器脚本如下:

// vertex shader GLSL
#version 300 es                            
layout(location = 0) in vec4 a_position;   
layout(location = 1) in vec2 a_texCoord;   
out vec2 v_texCoord;                       
uniform mat4 u_MVPMatrix;   
uniform vec3 u_offsets[125];               
void main()                                
{
   //经过 u_offsets[gl_InstanceID] 对当前实例的位置进行偏移                                          
   gl_Position = u_MVPMatrix * (a_position + vec4(u_offsets[gl_InstanceID], 1.0));
   v_texCoord = a_texCoord;                
}   

// fragment shader GLSL
#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;
void main()
{
    outColor = texture(s_TextureMap, v_texCoord);
}                      

在 3D 空间中产生 125 个偏移量(offset):

glm::vec3 translations[125];
int index = 0;
GLfloat offset = 0.2f;
for(GLint y = -10; y < 10; y += 4)
{
    for(GLint x = -10; x < 10; x += 4)
    {
        for(GLint z = -10; z < 10; z += 4)
        {
            glm::vec3 translation;
            translation.x = (GLfloat)x / 10.0f + offset;
            translation.y = (GLfloat)y / 10.0f + offset;
            translation.z = (GLfloat)z / 10.0f + offset;
            translations[index++] = translation;
        }
    }
}

对偏移量数组进行赋值,而后进行实例化绘制,绘制出 125 个不一样位置的立方体:

glUseProgram(m_ProgramObj);
glBindVertexArray(m_VaoId);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);

for(GLuint i = 0; i < 125; i++)
{
    stringstream ss;
    string index;
    ss << i;
    index = ss.str();
    GLint location = glGetUniformLocation(m_ProgramObj, ("u_offsets[" + index + "]").c_str())
    glUniform2f(location, translations[i].x, translations[i].y, translations[i].z);
}
glDrawArraysInstanced(GL_TRIANGLES, 0, 36, 125);
glBindVertexArray(0);

利用内建变量 gl_InstanceID和偏移数组进行实例化绘制还存在一个问题,那就是着色器中 uniform 类型数据存在上限(为何存在上限,参考《OpenGL中的Uniform block size 的大小限制》博文),也就是 u_offsets 这个数组的大小有限制,最终致使咱们绘制的实例存在上限。为了避免这个问题,咱们可使用实例化数组(Instanced Array),它使用顶点属性来定义,这样就容许咱们使用更多的数据,并且仅当顶点着色器渲染一个新实例时它才会被更新。这个时候咱们须要用到函数 glVertexAttribDivisor 。其在官方手册中用法如下:

glVertexAttribDivisor modifies the rate at which generic vertex attributes advance when rendering multiple instances of primitives in a single draw call. If divisor is zero, the attribute at slot index advances once per vertex. If divisor is non-zero, the attribute advances once per divisor instances of the set(s) of vertices being rendered. An attribute is referred to as instanced if its GL_VERTEX_ATTRIB_ARRAY_DIVISOR value is non-zero.

大概的意思是:当单次调用绘制函数渲染多个图元实例时,glVertexAttribDivisor修改了通用顶点属性向前的比例即每次绘制的步长,即是逐顶点还是每隔divisor 个实例渲染一次。如果参数divisor 是0,则glVertexAttribDivisor函数第一个参数index表示的顶点属性每个顶点就执行渲染一次,如果divisor 非0,则参数index表示的顶点属性每隔divisor 实例就渲染一次。这就话的意思说白了就是当divisor 为0时,则每个顶点中参数index表示的顶点属性就渲染一次(逐顶点渲染,以点为单位渲染);而如果divisor 非0,则每divisor 实例,就渲染一次。例如:一次渲染100个三角形(这里每个三角形就是一个实例),如果divisor为0,则每个三角形都绘制(逐顶点渲染,以点为单位渲染,当然,这还跟硬件的UFO有关,参考《OpenGL中的Uniform block size 的大小限制》);如果divisor为1,则第0, 1, 2, 3,4,5.....个三角形会被绘制即每个三角形都会被绘制(逐实例渲染,以实例为单位渲染),也就是说每1个三角形才绘制一次(相比前面的divisor为0结果相同,但效率要高很多);如果divisor为3,则第0, 3, 6, 9,12,15......个三角形会被绘制,而第1,2,4,5,7,8,9,10,11,13,14......不会绘制,直接丢弃,也就是说每隔3个三角形才绘制一次,以此类推。

glVertexAttribDivisor(GLuint index, GLuint divisor)

该函数表示每隔divisor个实例,就会往顶点着色器中传入buffer中的一个新的属性值,其中index为属性在着色器中的位置索引值即下面代码中的location = 0、location = 1、location = 2等。默认的情况下本函数的第二个参数为0,即每次将指定index索引表示的所有属性数据更新到着色器中,比如:一个模型由30万个三角形组成,则这30万个三角形共90万(假设每个三角形不共顶点)个顶点,一次性更新到着色器,这对性能及Uniform block size无疑是一场灾难。当第二个参数为非0值时,如:1,则表示每隔1个三角形即3个顶点下的index索引表示的属性数据载入一次。即先载入更新第0个三角形数据到着色器,处理完后再更新第1个三角形数据到着色器,以此类推,直到全部三角形都处理完。如:2,则表示每隔2个三角形index索引表示的属性数据载入一次。即先载入更新第0个三角形数据到着色器,处理完后再更新第2个三角形数据到着色器,处理完后再更新第4个三角形数据到着色器,丢弃、不处理第1、3.....个三角形的数据,以此类推,直到全部三角形都处理完。

void glVertexAttribDivisor (GLuint index, GLuint divisor);
// index 表示顶点属性的索引
// divisor 表示每 divisor 个实例更新下顶点属性到下个元素,默认为 0

利用顶点属性来定义的实例化数组(Instanced Array) 在 3D 空间绘制多个位于不一样位置的立方体,对应的着色器脚本:

// vertex shader GLSL
#version 300 es                            
layout(location = 0) in vec4 a_position;   
layout(location = 1) in vec2 a_texCoord;  
layout(location = 2) in vec2 a_offset;
out vec2 v_texCoord;                       
uniform mat4 u_MVPMatrix;   
void main()                                
{
   gl_Position = u_MVPMatrix * (a_position + vec4(a_offset, 1.0));
   v_texCoord = a_texCoord;                
}   

// fragment shader GLSL
#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;
void main()
{
    outColor = texture(s_TextureMap, v_texCoord);
}                 

设置 VAO 和 VBO :

// Generate VBO Ids and load the VBOs with data
glGenBuffers(2, m_VboIds);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 125, &translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

// Generate VAO Id
glGenVertexArrays(1, &m_VaoId);

glBindVertexArray(m_VaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (const void *) (3* sizeof(GLfloat)));
glEnableVertexAttribArray(2);

//利用顶点属性来定义的实例化数组(Instanced Array)
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//指定 index=2 的属性为实例化数组,1 表示每绘制一个实例,更新一次数组中的元素
glVertexAttribDivisor(2, 1); // Tell OpenGL this is an instanced vertex attribute.
glBindVertexArray(GL_NONE);

其中glVertexAttribDivisor(2, 1);是上述最重要的一步,用于指定 index = 2 的属性为实例化数组,1 表示每绘制一个实例,更新一次数组中的元素。利用顶点属性来定义的实例化数组,而后绘制出 125 个不一样位置的立方体:

glUseProgram(m_ProgramObj);
glBindVertexArray(m_VaoId);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);

glDrawArraysInstanced(GL_TRIANGLES, 0, 36, 125);
glBindVertexArray(0);

另外《实例化》这篇文章也深刻阐述了实例化。

实例渲染Instanced Rendering 在此之前红宝书已经介绍了不少关于缓存和绘制的命令,并给出了用同样的顶点绘制几个三角形的例程,但是此前的例程实现起来非常麻烦,每个三角形要指定一次变换矩阵,假如还要更换颜色的话还要增加相应语句。如果想绘制的物体成千上万,这么一一指定管理起来比较混乱,因此,OpenGL给出了一个新的命令类型:实例渲染——Instanced Rendering。 阅读详情

相关推荐

OpenGL学习脚印:创建更多的实例(instancing object)

写在前面 前面我们学习了模型加载的相关内容,并成功加载了模型,令人十分兴奋。那时候加载的是少量的模型,如果需要加载多个模型,就需要考虑到效率问题了,例如下图所示的是加载了400多个纳米战斗服机器人的效果图:渲染一个模型更多的实例,需要使用到实例化技术,就是本节要介绍的instancing object方法。本节示例代码均可以从我的github下载。 本节内容整理自: www.l

王定桥的专栏 8326

glDrawElements与glDrawElementsInstanced简介(含glDrawArraysInstanced)

当我们想要绘制大量实例时,为了减少开销,可以使用glDrawElementsInstanced,可以将它们与程序中断和DMA方式(这两个是计算机组成原理的内容)进行类比。是索引的数据类型,可以是 GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT 或 GL_UNSIGNED_INT。索引绘制的优点是可以使用一个顶点多次,从而减少顶点数据的存储和传输。是一个 OpenGL 函数,用于绘制图元。是图元的类型,可以是点、线、三角形等。指向索引数组的指针。

m0_57236802的博客 2841

QOpenGL入门教程(一)——OpenGL渲染管线

前言 这是本教程的第一个篇章,你是否已经迫不及待的想动手写代码了?真是太可惜了,这一篇章我们并不会涉及到Qt和代码,而是说一些有用并且有意思的事情。 没有进行思考就直接上手写代码会让你产生一些“先入为主”的错误观念,它们将成为你之后学习过程中的阻碍,因此,身体放松,然后沉住气,认真看完这一章,到之后你真正学习的代码时候就会发现自己tm跟开了挂一样:“卧槽,原来OpenGL这么简单!!!?” 能够看到这篇文章,说明你大概率也是一名程序开发者,你为什么来学OpenGL呢?是因为兴趣使然,还是工作需要呢?如

ItaLink 7447

GLES3.0中文API-glDrawArraysInstanced

名称 glDrawArraysInstanced — 绘制一系列元素的多个实例 C 规范 void glDrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei primcount); 参数 mode 指定要渲染的原语类型。 接受符号常量GL_POINTS,GL_LINE_STRIP,GL_LINE_LOOP,GL_...

MSK1111的博客 1320

AWTK绘制原理的分析总结

在学习、使用以及完善 AWTK 的过程中,我逐渐对 AWTK 的绘制流程即原理有了大致的了解,在此非常感谢领导和同事对我的指导与培训,本文对学到的东西做个记录。

Rain_Mic的博客 3264

c++ opengl 绘制地面_铝合金门窗设计之绘制节点图

铝合金门窗设计之绘制节点图过程讲解上节在我们绘制好门窗方案大样图之后,接下来就可以进行门窗节点图的绘制了。首先我们先来认识一下铝合金门窗节点图。铝型材厂家的宣传图都配有节点图,以方便使用者选料。对于初学者怎么看门窗的节点图呢?现在就简单介绍下。一、 门窗节点图的构成节点图,又叫结构图或构造图,是显示各门窗型材结构关系的,图中有门窗分格图、型材品种、玻璃、胶条等,这里主要还是讲各型材品种之间的关系,...

weixin_33230532的博客 3513

基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十六)实例化

  (Vries的原教程地址如下,https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/10%20Instancing/ 关于实例化的详细设置介绍与设置与参数设置请查看这个教程,本篇旨在对Vires基于visual studio平台的编程思想与代码做Qt平台的移植,重在记录自身学习之用) 在Vires的教程中,实例化的顺序比较靠后,但这...

博客 1729

opengl编程学习笔记(三)(2D绘图)

在opengl中可以绘制二维图像,分为两种,BITMAP和image1.bitmap和image的区别有:bitmap中对图像的每个像素只存储一位(0或1),用来表示用当前颜色绘制还是不绘制,而image是图像的每个像素存储可能很多位,存储它的各个通道的颜色信息;bitmap是绘制在三位空间中的一群点,其中每个点都受各变换矩阵的影响,等同于一群Gl_begin(GL_POINTS)操作

leon 1万+

OpenGL 实例化渲染:构建小行星带 (Asteroid Field)

在游戏开发和实时渲染中,我们经常需要渲染大量相同的物体——比如一片森林中的树木、地面上散落的石子、天空中飘落的雪花、或者战斗场景中成千上万的粒子。这些场景如果用传统的绘制方式,每次绘制都调用一次或,性能会急剧下降。本文将详细讲解 OpenGL 中的Instancing(实例化渲染)技术,它能让我们用一次绘制调用渲染成千上万个物体。-0.05f, 0.05f, 1.0f, 0.0f, 0.0f, // 顶点0: 左上, 红色。

Lee notes 611

OpenGL学习(十)天空盒

目录写在前面天空盒简介创建立方体贴图渲染一个立方体立方体贴图着色器开始绘制天空盒完整代码着色器c++ 写在前面 上一篇博客回顾:OpenGL学习(九)阴影映射(shadowMapping) 在昨天我们实现了非常简单的阴影映射特效,今天来更新立方体贴图的内容。这部分的内容相当简单,前提是要对 OpenGL 及其绘制过程有一个基本的理解。 相信我,仅 10 分钟足够你完成一个立方体贴图,并且用于天空盒的渲染。 天空盒简介 注意到我们之前的代码都是利用: glClearColor(1.0, 1.0, 1.0, 1

AKGWSB 's blog 8268

OpenGL之矩阵堆栈绘制立体图元

渲染环境准备 需要用到的工具类,已做详细的注释说明: // GLTool.h头⽂文件包含了大部分GLTool中类似C语言的独立函数 #include "GLTools.h" // 矩阵的⼯具类.可以利于GLMatrixStack 加载单元矩阵/矩阵/矩阵相乘/压栈/出栈/缩放/平移/旋转 #include "GLMatrixStack.h" // 矩阵工具类,表示位置.通过设置vOrigin,vForward,vUps等 #include "GLFrame.h" // 矩阵⼯具类,⽤来快速设置正/透视投

╰つ栺尖篴夢ゞ 798

C++ OpenGL学习笔记(2、绘制橙色三角形绘制、绿色随时间变化的三角形绘制)

openGL 2: 绘制橙色三角形、绘制绿色随时间变化的三角形。三角形是最基础的一个面图形,要在一个空的窗口上绘制三角形,就需要在上一节代码基础上进行修改。

静以修身,简以养德 1222

Qt OpenGL中实现Mipmap纹理的高级指南

Mipmap是一种纹理过滤技术,其设计目的是提高纹理映射的性能,并减少图像渲染时的锯齿现象。当一个纹理映射到一个多边形上时,如果映射比例变化较大,比如从远处看一个纹理很大的表面,或从近处看一个很小的表面时,普通的纹理映射会产生视觉失真。Mipmap通过为不同的映射比例预先计算一系列不同分辨率的纹理图像,使系统能够在渲染过程中选择最合适的纹理级别进行绘制,从而有效避免了这些失真。纹理过滤器是决定纹理如何映射到屏幕上像素的算法。

weixin_35899324的博客 790

基于C++、OpenGL绘制贝塞尔曲线(Bézier curve)

本文主要参考了 计算机图形学8——Bezier curve(贝塞尔曲线) (https://blog.youkuaiyun.com/qq_41856733/article/details/85309521),如有侵权行为请联系作者:2803168649@qq.com。非常感谢文章提供的帮助。 第一次使用GL写C++程序,自我感觉良好(也是第一次写博客,刺激)。代码主要实现了在程序中随意点击画控制点,自动画出贝塞尔曲线,同时会显示各个点的坐标,控制点可拖动。代码中有详细的注释(我觉得挺详细的)。 算二项式系数时直接使

m0_50679204的博客 8233

从零构建Elasticsearch MCP代理:自然语言查询背后的技术揭秘

本文深入解析如何从零构建Elasticsearch MCP代理,实现自然语言查询的技术架构与实战应用。通过MCP协议与Elasticsearch的结合,系统能够将自然语言转换为精确的DSL查询,提升非技术用户的数据查询效率。文章详细介绍了核心架构、DSL生成引擎、端到端系统搭建及生产环境最佳实践,为开发者提供全面的技术指南。

lll78的博客 877

OpenGL绘制的图形显示在QT的ui界面上

首先声明: 需求是osg显示在ui界面上,然而这些资料参差不齐,看起来并不是很完善,因为opengl是osg的底层,所以想先尝试这将opengl绘制的图形显示在Qt的ui上,这方面的资料相对多一点。 本篇文章参考:https://blog.youkuaiyun.com/u014546553/article/details/74332153,给出的方法是窗口提升,也尝试了,最后也成功了,只不过走了一点弯路,文中给出的代码有些许错误,不可直接拿来用,我是在他的基础上进一步具体和完善。 Qt 5.13.2版本的mingw 步

qq_39694792的博客 2194

Canoe主要功能的详细介绍

CANoe是德国Vetor公司推出的一款用于总线开发的设备,全程为CAN open environment。后来随着总线技术的发展,CANoe不仅限于CAN类型的总线开发,还包含LIN、FlexRay、MOST和以太网等开发。在车载网络和ECU开发、测试和分析方面,CANoe几乎长期占据着垄断地位,当然是因为其强大的功能性了。目前用这个工具的主要是整车厂和供应商的网络设计工程是、开发工程师和测试工程师。小编当时安装CANoe的时候也是花了一定的时间和精力,好在没有崩溃。

车载测试 3724

使用OpenGL模拟水面

本文会对一个基于波动方程来模拟水面实现的OpenGL程序进行分析。会给出程序基本组成,绘制流程示意图。并且对着色器中使用的原理进行推导并给出比较详细的注释。 前言 关于程序源代码,其中使用的着色器其实都是来自于一个别人的js项目,我把它们应用到了Qt中,只做了少量修改。你可以在我之前的文章Qt使用OpenGL实现水波特效中获得源代码和一些基本的解释。 即使你不使用Qt,只要你对这个项目实现的效果感兴趣,想做一些修改或者是移植,也可以阅读本文章,因为尽管不同的图形界面开发框架和语言使用OpenGL的方法不.

TinyHou的博客 5459

PCL 点云圆柱形邻域搜索【2026最新版】

圆柱形邻域搜索是KD-tree算法在点云数据处理中的扩展应用,在一些特定场景应用中具有无与伦比的优势。博客长期更新,本文最近一次更新时间为:2026年5月4日。

点云侠的博客 3451

SQL的基本介绍

1.什么是数据库?2.什么是数据库管理系统?3.什么是 SQL?1.数据库是保存有组织的数据的容器,通常是一个文件或一组文件,可以将其看作电子化的文件柜。用户可以对文件中的数据执行新增、删除、更新、查询等操作。2.数据库管理系统是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户可以通过 DBMS 访问数据库中的数据,数据库管理员也可以通过 DBMS 进行数据库的维护工作。

shiwei0813的博客 2879

opengl球体纹理贴图_OpenGL游戏引擎开发[4]在OpenGL使用纹理

上一节我们学会了使用OpenGL着色器,但是在片段着色器中,我们使用简单纯色来绘制物体,这一节,我们要在片段着色器中使用采用器对纹理进行采样输出,作为物体表面的颜色,进而绘制带有纹理贴图的物体。纹理纹理简单来说就是一张图片,最常见的就是王者荣耀中英雄的皮肤,当然,这里只说游戏角色的外观,因为不同的皮肤还有不同的特效,甚至有不同的人物动作。不同的游戏人物外观就是换了不同纹理贴图。根据纹理的...

weixin_35334000的博客 1564

windows版vCenter STS证书替换步骤说明

windows版vCenter STS证书,手动更新步骤

技术是手段,服务才是目的。开源与协作是创新的活水,而核心技术的自主可控是立足之本。身处黄金时代,唯持续学习,方能不惧变化。从使用者到创造者,中国技术的未来,正待你们接过火炬,走得更远、更稳、更好。 1043

OpenGL-贴纸方案

OpenGL渲染区域使用正交投影换算,正常OpenGL坐标是vertexData,这样的进行换算以上面的基础的渲染区域设置FBO的绘制区,进行贴纸绘制,对应的缩放、旋转、平移时候对矩阵的处理和顶点点位处理的方法说明m_position对应的是贴纸的坐标,对应的xy轴的坐标和宽高。

u012836015的博客 1276

Python 爬虫实战:共享单车数据采集全流程与市场洞察深度剖析

本文介绍了如何利用Python爬虫技术获取和分析共享单车运营数据。文章从项目背景出发,详细阐述了系统架构设计,包括数据抓取、清洗存储、分析和可视化模块。通过Scrapy、BeautifulSoup等工具实现数据采集,使用Pandas进行数据清洗,并借助Matplotlib进行可视化分析。实战部分展示了爬虫代码示例和城市分布、使用频率等分析案例。最终指出数据驱动分析有助于了解行业现状和市场趋势,未来可结合机器学习等方法进行深入洞察。该技术方案为共享单车行业研究提供了有效的数据支持。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2233

使用 MATLAB/Simulink 对基于同步发电机的双机系统进行建模

双机系统(Two-Machine System)是电力系统中用于研究动态稳定性和控制策略的一个典型模型。它由两台同步发电机通过输电网络相互连接,模拟实际电网中的互联操作。当发生短路故障时,系统的暂态稳定性会受到挑战,可能导致发电机失步或电压崩溃。本教程将带你使用 MATLAB/Simulink 对基于同步发电机的双机系统进行建模,并对其在短路故障条件下的暂态稳定性进行仿真和分析。

amy_mhd的博客 216
上一篇: OpenGL中的Uniform block size 的大小限制
下一篇: map的extract 是更换 map 的键而不重分配的唯一方式:
荆楚闲人
博客等级 码龄20年 3万+粉丝 473原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值