RenderStage::drawInner
文章目录
- RenderStage::drawInner
- OSG渲染后台关系图
- OSG的渲染流程
- RenderBin::draw(renderInfo,previous)
- RenderBin::drawImplementation
- RenderLeaf::render
- osg::State::apply(const StateSet*)
- Drawable::draw(RenderInfo& renderInfo)
- Drawable::drawInner(RenderInfo& renderInfo)
- Drawable::drawImplementation
RenderStage::drawInner
void RenderStage::drawInner(osg::RenderInfo& renderInfo,RenderLeaf*& previous, bool& doCopyTexture)
{struct SubFunc{static void applyReadFBO(bool& apply_read_fbo,const FrameBufferObject* read_fbo, osg::State& state){if (read_fbo->isMultisample()){OSG_WARN << "Attempting to read from a"" multisampled framebuffer object. Set a resolve"" framebuffer on the RenderStage to fix this." << std::endl;}if (apply_read_fbo){// Bind the monosampled FBO to read from// ogl操作://创建一个新的fbo//遍历设置的_attachments,编译纹理//ext->glBindFramebuffer(READ_FRAMEBUFFER, fboID);//调用glDrawBuffers(GLsizei n, const GLenum *bufs);,指定在一个渲染操作中输出到多个颜色缓冲区的目标//遍历设置的_attachments,添加附件read_fbo->apply(state, FrameBufferObject::READ_FRAMEBUFFER);apply_read_fbo = false;}}};osg::State& state = *renderInfo.getState();osg::GLExtensions* ext = _fbo.valid() ? state.get<osg::GLExtensions>() : 0;// 判断显示卡是否支持FBObool fbo_supported = ext && ext->isFrameBufferObjectSupported;// 详见RenderStage::runCameraSetUpbool using_multiple_render_targets = fbo_supported && _fbo->hasMultipleRenderingTargets();if (!using_multiple_render_targets){#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)if( getDrawBufferApplyMask() )state.glDrawBuffer(_drawBuffer);if( getReadBufferApplyMask() )state.glReadBuffer(_readBuffer);#endif}if (fbo_supported){ // ogl操作://创建一个新的fbo//遍历设置的_attachments,编译纹理//ext->glBindFramebuffer(READ_FRAMEBUFFER, fboID);//调用glDrawBuffers(GLsizei n, const GLenum *bufs);,指定在一个渲染操作中输出到多个颜色缓冲区的目标//遍历设置的_attachments,添加附件_fbo->apply(state);}// do the drawing itself.RenderBin::draw(renderInfo,previous);if(state.getCheckForGLErrors()!=osg::State::NEVER_CHECK_GL_ERRORS){if (state.checkGLErrors("after RenderBin::draw(..)")){if ( ext ){GLenum fbstatus = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);if ( fbstatus != GL_FRAMEBUFFER_COMPLETE_EXT ){OSG_NOTICE<<"RenderStage::drawInner(,) FBO status = 0x"<<std::hex<<fbstatus<<std::dec<<std::endl;}}}}// 以下是copy纹理,写image,生成mipmap等操作const FrameBufferObject* read_fbo = fbo_supported ? _fbo.get() : 0;bool apply_read_fbo = false;//glBlitFramebuffer用于在帧缓冲对象之间快速复制像素数据if (fbo_supported && _resolveFbo.valid() && ext->glBlitFramebuffer){GLbitfield blitMask = 0;bool needToBlitColorBuffers = false;//find which buffer types should be copiedfor (FrameBufferObject::AttachmentMap::const_iteratorit = _resolveFbo->getAttachmentMap().begin(),end =_resolveFbo->getAttachmentMap().end(); it != end; ++it){switch (it->first){case Camera::DEPTH_BUFFER:blitMask |= GL_DEPTH_BUFFER_BIT;break;case Camera::STENCIL_BUFFER:blitMask |= GL_STENCIL_BUFFER_BIT;break;case Camera::PACKED_DEPTH_STENCIL_BUFFER:blitMask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;break;case Camera::COLOR_BUFFER:blitMask |= GL_COLOR_BUFFER_BIT;break;default:needToBlitColorBuffers = true;break;}}// Bind the resolve framebuffer to blit into._fbo->apply(state, FrameBufferObject::READ_FRAMEBUFFER);_resolveFbo->apply(state, FrameBufferObject::DRAW_FRAMEBUFFER);// 如果不使用MSFBO则为0if (blitMask){// Blit to the resolve framebuffer.// Note that (with nvidia 175.16 windows drivers at least) if the read// framebuffer is multisampled then the dimension arguments are ignored// and the whole framebuffer is always copied.// 将READ_FRAMEBUFFER拷贝到DRAW_FRAMEBUFFERext->glBlitFramebuffer(static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),blitMask, GL_NEAREST);}#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE) && !defined(OSG_GLES3_AVAILABLE)// 拷贝多传输颜色附件if (needToBlitColorBuffers){for (FrameBufferObject::AttachmentMap::const_iteratorit = _resolveFbo->getAttachmentMap().begin(),end =_resolveFbo->getAttachmentMap().end(); it != end; ++it){osg::Camera::BufferComponent attachment = it->first;if (attachment >=osg::Camera::COLOR_BUFFER0){state.glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));state.glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));ext->glBlitFramebuffer(static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),static_cast<GLint>(_viewport->x() + _viewport->width()), static_cast<GLint>(_viewport->y() + _viewport->height()),GL_COLOR_BUFFER_BIT, GL_NEAREST);}}// reset the read and draw buffers? will comment out for now with the assumption that// the buffers will be set explicitly when needed elsewhere.// glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);// glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);}
#endifapply_read_fbo = true;read_fbo = _resolveFbo.get();using_multiple_render_targets = read_fbo->hasMultipleRenderingTargets();}// now copy the rendered image to attached texture.if (doCopyTexture){if (read_fbo) SubFunc::applyReadFBO(apply_read_fbo, read_fbo, state);copyTexture(renderInfo);}//如果有设置附件的image,则将附件读入image中for(std::map< osg::Camera::BufferComponent, Attachment>::const_iterator itr = _bufferAttachmentMap.begin();itr != _bufferAttachmentMap.end();++itr){if (itr->second._image.valid()){if (read_fbo) SubFunc::applyReadFBO(apply_read_fbo, read_fbo, state);#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)if (using_multiple_render_targets){int attachment=itr->first;if (attachment==osg::Camera::DEPTH_BUFFER || attachment==osg::Camera::STENCIL_BUFFER) {// assume first buffer rendered to is the one we wantglReadBuffer(read_fbo->getMultipleRenderingTargets()[0]);} else {glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + (attachment - osg::Camera::COLOR_BUFFER0));}} else {if (_readBuffer != GL_NONE){glReadBuffer(_readBuffer);}}#endifGLenum pixelFormat = itr->second._image->getPixelFormat();if (pixelFormat==0) pixelFormat = _imageReadPixelFormat;if (pixelFormat==0) pixelFormat = GL_RGB;GLenum dataType = itr->second._image->getDataType();if (dataType==0) dataType = _imageReadPixelDataType;if (dataType==0) dataType = GL_UNSIGNED_BYTE;itr->second._image->readPixels(static_cast<int>(_viewport->x()),static_cast<int>(_viewport->y()),static_cast<int>(_viewport->width()),static_cast<int>(_viewport->height()),pixelFormat, dataType);}}if (fbo_supported){// 是否需要解除绑定回复默认帧缓冲区if (getDisableFboAfterRender()){// switch off the frame buffer objectGLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);}doCopyTexture = true;}if (fbo_supported && _camera.valid()){// now generate mipmaps if they are required.const osg::Camera::BufferAttachmentMap& bufferAttachments = _camera->getBufferAttachmentMap();for(osg::Camera::BufferAttachmentMap::const_iterator itr = bufferAttachments.begin();itr != bufferAttachments.end();++itr){if (itr->second._texture.valid() && itr->second._mipMapGeneration){state.setActiveTextureUnit(0);//设置当前纹理单元state.applyTextureAttribute(0, itr->second._texture.get());//用于生成指定纹理的多级渐进纹理(Mipmap):void glGenerateMipmap(GLenum target);//target:GL_TEXTURE_2D,GL_TEXTURE_CUBE_MAP,GL_TEXTURE_3Dext->glGenerateMipmap(itr->second._texture->getTextureTarget());}}}
}
OSG渲染后台关系图


- 如果我们需要自己创建新的派生自Drawable的对象(就像osgText中所实现的),drawable几何体对象的具体实现在于drawImplementation函数。
- 如果想自己创建一种新的渲染属性(派生自StateAttribute),渲染属性的具现函数为StateAttribute::apply(State&),所有的渲染属性都重写了这一函数,以实现自己的功能。
- OSG渲染后台与用户层的接口是摄像机类(Camera)。场景中至少有一个主摄像机,它关联了一个图形设备(GraphicsContext,通常是窗口),以及一个渲染器(Renderer);我们可以在场景树中(或者别的视图View中,对于复合视景器而言)添加更多的摄像机,它们可以关联相同的或者其它的图形设备,但都会配有单独的渲染器,用以保存该摄像机的筛选设置、显示器设置等信息。
- 场景筛选和绘制的工作由渲染器来完成,而图形设备GraphicsContext则负责根据不同时机的选择,调用渲染器的相关函数。例如在单线程模式中,ViewerBase::renderingTraversals函数依次执行Renderer::cull和Renderer::draw函数(后者通过GraphicsContext::runOperations调用),而在多线程模型中调用者的关系将更加错综复杂。
- OSG渲染后台的调度中心是场景视图(SceneView),它负责保存和执行筛选访问器(CullVisitor)。CullVisitor负责遍历并裁减场景,同时在遍历过程中构建对于场景绘制至关重要的渲染树和状态树;生成的状态树以StateGraph为根节点和各级子节点(其中保存场景树的渲染状态StateSet数据),以RenderLeaf为末端叶节点的内容(其中保存场景树中的几何体Drawable对象);渲染树则以RenderStage为根节点,RenderBin为各级子节点,根据渲染顺序和方法的设定,状态树中的节点和渲染叶(RenderLeaf)被记录到RenderStage和各级RenderBin中;SceneView负责保存和维护状态树和渲染树。
- 绘制场景时,渲染树中的各级节点将取出保存的渲染叶数据,传递给OSG状态机(State),其中OSG状态机(State)是OpenGL状态机制的封装和实现,也是场景绘制的核心元件。状态机取得渲染叶中的几何数据之后,再向根部遍历状态树,取得该几何体绘制相关的所有渲染状态设置,并亲自或者交由StateAttribute派生类完成渲染状态的实际设定,以及场景元素的实际绘制工作。此时用到的就已经是我们耳熟能详的各种OpenGL函数了。
OSG的渲染流程
1、渲染树的作用是遍历各个渲染元(RenderBin),并按照指定的顺序执行其中各个渲染叶的渲染函数(RenderLeaf::render)。
2、状态树保存了从根节点到当前渲染叶的路径,遍历这条路径并收集所有的渲染属性数据,通过StateGraph::moveStateGraph关闭父节点所有状态,并打开当前节点所有状态,即可获得当前渲染叶渲染所需的所有OpenGL状态数据。
3、渲染叶的渲染函数(RenderLeaf::render)负责向状态机(osg::State)传递渲染状态数据,进而由渲染属性类本身完成参数在OpenGL中的注册和加载工作(StateAttribute::apply);渲染叶还负责调用几何体(Drawable)的绘制函数(drawImplementation),传递顶点和索引数据并完成场景的绘制工作。
RenderBin::draw(renderInfo,previous)
void RenderBin::draw(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
{renderInfo.pushRenderBin(this);if (_drawCallback.valid()){_drawCallback->drawImplementation(this,renderInfo,previous);}else drawImplementation(renderInfo,previous);renderInfo.popRenderBin();
}
RenderBin::drawImplementation
void RenderBin::drawImplementation(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
{osg::State& state = *renderInfo.getState();// OSG_NOTICE<<"begin RenderBin::drawImplementation "<<className()<<" sortMode "<<getSortMode()<<std::endl;unsigned int numToPop = (previous ? StateGraph::numToPop(previous->_parent) : 0);if (numToPop>1) --numToPop;unsigned int insertStateSetPosition = state.getStateSetStackSize() - numToPop;if (_stateset.valid()){state.insertStateSet(insertStateSetPosition, _stateset.get());}// 遍历所有的子渲染元(RenderBin::_bins),其中渲染顺序号小于0的渲染元将在这里执行它们的RenderBin::draw函数,// 由于draw函数内部调用了drawImplementation,因此这构成了一个递归调用,直至渲染树遍历至末端节点。// 在用户程序中,渲染顺序号的设置使用StateSet::setRenderBinDetails函数(RenderBinList的key)。// draw first set of draw bins.RenderBinList::iterator rbitr;for(rbitr = _bins.begin();rbitr!=_bins.end() && rbitr->first<0;++rbitr){rbitr->second->draw(renderInfo,previous);}// 遍历当前RenderBin所保存的所有渲染叶(RenderBin::_renderLeafList),执行RenderLeaf::render函数,实现场景的绘制。// 通常只有被设置为“DepthSortedBin”的渲染元会选择保存渲染叶而非状态节点(StateGraph),因为这样便于按照深度值排序对象。// draw fine grained ordering.for(RenderLeafList::iterator rlitr= _renderLeafList.begin();rlitr!= _renderLeafList.end();++rlitr){RenderLeaf* rl = *rlitr;rl->render(renderInfo,previous);previous = rl;}bool draw_forward = true; //(_sortMode!=SORT_BY_STATE) || (state.getFrameStamp()->getFrameNumber() % 2)==0;// 遍历当前RenderBin所保存的所有状态节点(RenderBin::_stateGraphList),// 获取其中保存的RenderLeaf对象(保存为StateGraph::_leaves),并执行其render函数。// draw coarse grained ordering.if (draw_forward){for(StateGraphList::iterator oitr=_stateGraphList.begin();oitr!=_stateGraphList.end();++oitr){for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();dw_itr != (*oitr)->_leaves.end();++dw_itr){RenderLeaf* rl = dw_itr->get();rl->render(renderInfo,previous);previous = rl;}}}else{for(StateGraphList::reverse_iterator oitr=_stateGraphList.rbegin();oitr!=_stateGraphList.rend();++oitr){for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();dw_itr != (*oitr)->_leaves.end();++dw_itr){RenderLeaf* rl = dw_itr->get();rl->render(renderInfo,previous);previous = rl;}}}//遍历所有的子渲染元(RenderBin::_bins),其中渲染顺序号大于0的渲染元此时才执行它们的RenderBin::draw函数。// draw post bins.for(;rbitr!=_bins.end();++rbitr){rbitr->second->draw(renderInfo,previous);}if (_stateset.valid()){state.removeStateSet(insertStateSetPosition);// state.apply();}// OSG_NOTICE<<"end RenderBin::drawImplementation "<<className()<<std::endl;
}
- 由此可知,渲染树中最先被绘制的将是那些顺序号小于0的末端RenderBin节点,其次则依次是顺序号等于0的末端节点,大于0的末端节点,小于0的倒数第二级节点……而作为渲染树根节点的RenderStage中保存的数据将最后被渲染。
- 渲染树同一层中不可能存在渲染顺序号相同的渲染元,因为使用setRenderBinDetails设置了相同数字参量的StateSet对象被构建成状态节点(StateGraph)之后,将插入到同一个RenderBin中,而不同name则是不同层级的renderbin。
RenderLeaf::render
- 渲染叶RenderLeaf是OSG渲染后台中几何体(Drawable)对象的唯一管理者。
- 而这里的render函数主要负责获取之前保存的Drawable指针,并将它们传递给负责渲染状态处理的State类,以及执行Drawable::draw函数。
void RenderLeaf::render(osg::RenderInfo& renderInfo,RenderLeaf* previous)
{osg::State& state = *renderInfo.getState();// don't draw this leaf if the abort中止 rendering flag has been set.if (state.getAbortRendering()){//cout << "early abort"<<endl;return;}if (previous){// apply matrices if required.state.applyProjectionMatrix(_projection.get());state.applyModelViewMatrix(_modelview.get());// 如果当前渲染叶与上一次处理的渲染叶父节点不同,则需要遍历状态树中相应的路径,// 并更新State状态机中保存的渲染状态数据(采用std::map类型,分别名为_modeMap和_attributeMap)。// apply state if required.StateGraph* prev_rg = previous->_parent;StateGraph* prev_rg_parent = prev_rg->_parent;StateGraph* rg = _parent;if (prev_rg_parent!=rg->_parent){// 它负责清除上一次使用的各种渲染状态,再沿着状态树中的路径,依次添加当前渲染叶所需的数据。// 最后执行函数State::apply(const StateSet*),由OSG状态机处理并执行相应的OpenGL指令。StateGraph::moveStateGraph(state,prev_rg_parent,rg->_parent);// send state changes and matrix changes to OpenGL.state.apply(rg->getStateSet());}else if (rg!=prev_rg){// send state changes and matrix changes to OpenGL.state.apply(rg->getStateSet());}// 设置着色器osg内置变量// if we are using osg::Program which requires OSG's generated uniforms to track// modelview and projection matrices then apply them now.if (state.getUseModelViewAndProjectionUniforms()) state.applyModelViewAndProjectionUniformsIfRequired();// 执行此渲染叶所保存的Drawable对象的draw函数,完成几何体的绘制。// Geometry对象将在这一函数中(实际上是Drawable::drawImplementation)向状态机传递顶点和索引数据,// 并交由状态机对象来完成几何数据的绘制。// draw the drawable_drawable->draw(renderInfo);}else{// apply matrices if required.state.applyProjectionMatrix(_projection.get());state.applyModelViewMatrix(_modelview.get());// apply state if required.StateGraph::moveStateGraph(state,NULL,_parent->_parent);state.apply(_parent->getStateSet());// if we are using osg::Program which requires OSG's generated uniforms to track// modelview and projection matrices then apply them now.if (state.getUseModelViewAndProjectionUniforms()) state.applyModelViewAndProjectionUniformsIfRequired();// draw the drawable_drawable->draw(renderInfo);}if (_dynamic){state.decrementDynamicObjectCount();}// OSG_NOTICE<<"RenderLeaf "<<_drawable->getName()<<" "<<_depth<<std::endl;
}
osg::State::apply(const StateSet*)
Drawable::draw(RenderInfo& renderInfo)
inline void Drawable::draw(RenderInfo& renderInfo) const
{State& state = *renderInfo.getState();bool useVertexArrayObject = state.useVertexArrayObject(_useVertexArrayObject);if (useVertexArrayObject){unsigned int contextID = renderInfo.getContextID();VertexArrayState* vas = _vertexArrayStateList[contextID].get();if (!vas){_vertexArrayStateList[contextID] = vas = createVertexArrayState(renderInfo);}else{// vas->setRequiresSetArrays(getDataVariance()==osg::Object::DYNAMIC);}State::SetCurrentVertexArrayStateProxy setVASProxy(state, vas);// 但凡是使用ogl核心模式,都要使用vaostate.bindVertexArrayObject(vas);drawInner(renderInfo);vas->setRequiresSetArrays(getDataVariance()==osg::Object::DYNAMIC);return;}// TODO, add check against whether VAO is active and supportedif (state.getCurrentVertexArrayState()){//OSG_NOTICE<<"state.getCurrentVertexArrayState()->getVertexArrayObject()="<< state.getCurrentVertexArrayState()->getVertexArrayObject()<<std::endl;state.bindVertexArrayObject(state.getCurrentVertexArrayState());}// 使用显示列表
#ifdef OSG_GL_DISPLAYLISTS_AVAILABLEif (!state.useVertexBufferObject(_supportsVertexBufferObjects && _useVertexBufferObjects) && _useDisplayList){// get the contextID (user defined ID of 0 upwards) for the// current OpenGL context.unsigned int contextID = renderInfo.getContextID();// get the globj for the current contextID.GLuint& globj = _globjList[contextID];if( globj == 0 ){// compile the display listglobj = generateDisplayList(contextID, getGLObjectSizeHint());glNewList( globj, GL_COMPILE );drawInner(renderInfo);glEndList();}// call the display listglCallList( globj);}else
#endif{// if state.previousVertexArrayState() is different than currentVertexArrayState bind current// OSG_NOTICE<<"Fallback drawInner()........................"<<std::endl;drawInner(renderInfo);}
}
#endif
Drawable::drawInner(RenderInfo& renderInfo)
inline void drawInner(RenderInfo& renderInfo) const{if (_drawCallback.valid())_drawCallback->drawImplementation(renderInfo,this);elsedrawImplementation(renderInfo);}
Drawable::drawImplementation
/** drawImplementation(RenderInfo&) is a pure virtual method for the actual implementation of OpenGL drawing calls, such as vertex arrays and primitives, that* must be implemented in concrete subclasses of the Drawable base class, examples include osg::Geometry and osg::ShapeDrawable.* drawImplementation(RenderInfo&) is called from the draw(RenderInfo&) method, with the draw method handling management of OpenGL display lists,* and drawImplementation(RenderInfo&) handling the actual drawing itself.* renderInfo : The osg::RenderInfo object that encapsulates the current rendering information including the osg::State OpenGL state for the current graphics context. */virtual void drawImplementation(RenderInfo& /*renderInfo*/) const {}
相关文章:
RenderStage::drawInner
文章目录 RenderStage::drawInnerOSG渲染后台关系图OSG的渲染流程RenderBin::draw(renderInfo,previous)RenderBin::drawImplementationRenderLeaf::renderosg::State::apply(const StateSet*)Drawable::draw(RenderInfo& renderInfo)Drawable::drawInner(RenderInfo& …...
C++初阶-类和对象(中)
目录 1.类的默认成员函数 2.构造函数(难度较高) 编辑 编辑 编辑 3.析构函数 4.拷贝构造函数 5.赋值运算符重载 5.1运算符重载 5.2赋值运算符重载 6.取地址运算符重载 6.1const成员函数 6.2取地址运算符重载 7.总结 1.类的默认成员函数…...
智谱开源新一代GLM模型,全面布局AI智能体生态
2024年4月15日,智谱在中关村论坛上正式发布了全球首个集深度研究与实际操作能力于一体的AI智能体——AutoGLM沉思。这一革命性技术的发布标志着智谱在AGI(通用人工智能)领域的又一次重要突破。智谱的最新模型不仅推动了AI智能体技术的升级&am…...
Vue3中provide和inject的用法示例
在 Vue3 中,provide 和 inject 用于实现跨层级组件通信。以下是一个简单的示例: 1. 父组件 (祖先组件) - 提供数据 javascript 复制 // ParentComponent.vue import { provide, ref, reactive } from vue;export default {setup() {// 提供静态数据p…...
分治-快排-75.颜色分类-力扣(LeetCode)
一、题目解析 给定一个数组将其元素按照0,1,,2三段式排序,并且在原地进行排序。 二、算法原理 解法:三指针 用cur遍历数组,left记录0的最左侧,right记录2的最右侧。 left初始值为-1,right的初…...
铅酸电池充电器方案EG1253+EG4321
参考: 基于EG1253EG4321铅酸电池(48V20AH)三段式充电器 屹晶微高性价比的电瓶车充电器方案——EG1253 电瓶电压 48V电瓶锂电池,其充满约为55V~56V,因此充电器输出电压为55V~56V; 若是48V铅酸电池,标称电压为48V&…...
Spring Boot 实现 Excel 导出功能(支持前端下载 + 文件流)
🧠 一、为什么用 EasyExcel? 在 Java 开发中,操作 Excel 的框架主要有: Apache POI(经典但慢、内存占用大) JXL(老旧不维护) Alibaba EasyExcel(阿里出品,…...
vue 中formatter
:formatter 是前端表格组件(如 Element UI、Vxe-Table 等)中用于 自定义单元格内容显示格式 的属性。它的核心作用是:将后端返回的原始数据(如编码、状态值等)转换为更友好、更易读的文本。 这段代码 :forma…...
协程?协程与线程的区别?Java是否支持协程?
一、前言 协程(Coroutine) 是一种轻量级的并发编程模型,允许在单线程内通过协作式多任务调度实现并发。由用户代码显式控制(用户态调度而非操作系统内核调度),避免了线程上下文切换的开销,适合…...
jsch(shell终端Java版)
学习笔记 Java SSH库使用简介:Apache sshd和JSch(Java Secure Channel) github - fork of the popular jsch library JSch学习笔记 web-shell - gitee代码 - 纯Java实现一个web shell登录Linux远程主机,技术选型 SpringBoot …...
Muduo网络库实现 [十六] - HttpServer模块
目录 设计思路 类的设计 模块的实现 公有接口 私有接口 疑问点 设计思路 本模块就是设计一个HttpServer模块,提供便携的搭建http协议的服务器的方法。那么这个模块需要如何设计呢? 这还需要从Http请求说起。 首先从http请求的请求行开始分析&…...
关于进程状态
目录 进程的各种状态 运行状态 阻塞状态 挂起状态 linux中的进程状态、 进程状态查看 S状态(浅睡眠) t 状态(追踪状态) T状态(暂停状态) 编辑 kill命令手册 D状态(深度睡眠&#…...
【MySQL】Read view存储的机制,记录可见分析
read view核心组成 1.1 事务id相关 creator_trx_id: 创建该read view的事务id 每开启一个事务都会生成一个 ReadView,而 creator_trx_id 就是这个开启的事务的 id。 m_ids: 创建read view时系统的活跃事务(未提交的事务)id集合 当前有哪些事…...
SQL注入 01
0x01 用户、脚本、数据库之间的关系 首先客户端发出了ID36的请求,脚本引擎收到后将ID36的请求先代入脚本的sql查询语句Select * from A where id 36 , 然后将此代入到数据库中进行查询,查到后将返回查询到的所有记录给脚本引擎,接…...
学习笔记:黑马程序员JavaWeb开发教程(2025.3.24)
11.2 案例-文件上传-简介 火狐浏览器可以看到文件上传传递的底层数据,而chrome对这一块数据进行了包装 在输出日志代码处打了一个断点,看服务端接收到的数据,在上传文件的保存地址中,可以看到,有三个临时文件&…...
计算机视觉cv2入门之视频处理
在我们进行计算机视觉任务时,经常会对视频中的图像进行操作,这里我来给大家分享一下,cv2对视频文件的操作方法。这里我们主要介绍cv2.VideoCapture函数的基本使用方法。 cv2.VideoCapture函数 当我们在使用cv2.VideoCapture函数时ÿ…...
【Linux】Rhcsa复习5
一、Linux文件系统权限 1、文件的一般权限 文件权限针对三类对象进行定义: owner 属主,缩写u group 属组, 缩写g other 其他,缩写o 每个文件针对每类访问者定义了三种主要权限: r:read 读 w&…...
FFmpeg:M3U8的AES加密
1、加密用的key,命令: openssl rand 16>enc.key 2、目的是生成一个enc.key文件 生成iv openssl rand -hex 16 生成后记录下来这个字符串 3、新建一个enc.keyinfo文件,内容有如下三行: key URIenc.key的路径,…...
VMware虚拟机走主机代理上网
🌐 VMware虚拟机走主机代理上网🔑 你是否也遇到过这样的困境?💡 在虚拟机中测试某个项目,却因为网络限制而寸步难行。今天,就让我们一起探索如何让VMware虚拟机轻松调用本机的代理上网工具,开启…...
百级Function架构集成DeepSeek实践:Go语言超大规模AI工具系统设计
一、百级Function系统的核心挑战 1.1 代码结构问题 代码膨胀现象:单个文件超过2000行代码路由逻辑复杂:巨型switch-case结构维护困难依赖管理失控:跨Function依赖难以追踪 // 传统实现方式的问题示例 switch functionName { case "fu…...
Cursor入门教程-JetBrains过度向
Cursor使用笔记 **前置:**之前博主使用的是JetBrains的IDE,VSCode使用比较少,所以会尽量朝着JetBrains的使用习惯及样式去调整。 一、设置语言为中文 如果刚上手Cursor,那么肯定对Cursor中的众多选项配置项不熟悉,这…...
【人工智能】Agent未来市场与技术潜力分析
Agent作为连接大模型与具体场景的桥梁,正在成为AI技术落地的核心载体。结合2025年的市场动态与技术趋势,其未来潜力可从以下多个维度展开分析: 一、市场前景:爆发式增长与多层级需求 市场规模与增速 全球AI Agent市场规模预计从2024年的51亿美元增至2030年的471亿美元(年复…...
计算机视觉与深度学习 | TensorFlow基本概念与应用场景:MNIST 手写数字识别(附代码)
TensorFlow 基本概念 TensorFlow 是一个开源的机器学习框架,由 Google 开发,核心概念包括: 张量(Tensor):多维数组,是数据的基本单位。计算图(Graph):早期版本中用于描述数据流和计算过程,2.x 默认启用即时执行(Eager Execution),兼顾灵活性和性能。层(Layers)…...
Mac OS系统下kernel_task占用大量CPU资源导致系统卡顿
CPU负载突然飙升,如截图: 根本原因,大家从各种博主上已知晓,现在提供自己的解决办法,亲测有效 一、设置开机自动禁用温度管理守护进程 1.创建脚本文件 mkdir -p ~/Scripts touch ~/Scripts/disable_thermald.sh …...
宝塔面板部署 Dify-latest 最新版本
一、本地部署Windows 版本宝塔面板 宝塔面板是一款简单容易上手使用的服务器管理软件,它可以帮助用户方便地管理服务器以及部署网站等。 (1)在宝塔面板官网的下载界面,选择 windows 版本下载。点此进入下载 (2&#x…...
《TCP/IP网络编程》学习笔记 | Chapter 24:制作 HTTP 服务器端
《TCP/IP网络编程》学习笔记 | Chapter 24:制作 HTTP 服务器端 《TCP/IP网络编程》学习笔记 | Chapter 24:制作 HTTP 服务器端HTTP 概要理解 Web 服务器端无状态的 Stateless 协议请求消息(Request Message)的结构响应消息&#x…...
MCP(2)架构篇:深入理解MCP的设计架构
前言 在上一篇《MCP系列之基础篇》中,我们初步了解了MCP(模型上下文协议)的基本概念和价值。本篇文章将深入探讨MCP的技术架构,帮助开发者和技术爱好者更全面地理解这一协议的内部工作机制。我们将剖析MCP的核心组件、通信模型和工作流程,解析Host、Client和Server三者之…...
Origin将双Y轴柱状图升级为双向分组柱状图
当变量同时存在两个数值时的可视化时,往往会想到用双Y轴柱状图来表达我们的数据。 双Y轴柱状图是一种在同一图表中使用左右两个Y轴的可视化形式,常用于展示两组量纲不同或数值范围差异较大的数据。 双向分组柱状图是一种结合了双向柱状图和分组柱状图的…...
Ubuntu 22.04 更换 Nvidia 显卡后启动无法进入桌面问题的解决
原显卡为 R7 240, 更换为 3060Ti 后, 开机进桌面时卡在了黑屏界面, 键盘有反应, 但是无法进入 shell. 解决方案为 https://askubuntu.com/questions/1538108/cant-install-rtx-4060-ti-on-ubuntu-22-04-lts 启动后在开机菜单中(如果没有开机菜单, 需要按shift键), 进入recove…...
JavaScript 笔记 --- part 4 --- Web API (part 2)
(webAPI part2) DOM 基本操作 事件流 定义: 指的是事件完整执行过程中的流动路径 捕获阶段: 事件从最外层的窗口对象开始,逐层向内传播到目标元素,并触发相应的事件处理程序。 冒泡阶段: 事件从目标元素开始,逐层向外传播到最外层的窗口对象…...
