D3D Frustum六个裁剪平面生成原理

视锥体剔除(Frustum Culling)算法详解-透视投影矩阵直接推导 本文章介绍了如何从投影矩阵(ProjectionMatrix)推导,得到视锥体(Frustum)的六个面的面方程,并且判断一个**点(point)是否在视锥体范围内,或者包围球(Bound ing Sphere)**是否与视锥体相交。 当然,我们也可以通过ViewMatrix,将平面萃取到摄像机坐标系空间;或者通过叠加WorldModelMatrix,将平面萃取到世界坐标系空间。 阅读详情

概念介绍

Frustum裁剪是CLOD中很重要的一个算法,很多文章都是一句话就过去,或者直接给出代码。但是数学推导很少给出,本文章的目的就是解释大家看这些代码中的疑问。
透视投影是将相机空间中的点从视锥体(view frustum)变换到规则观察体(Canonical View Volume,CCV)中,即是世界空间的视锥体(view frustum)中的任何一个点,如果经过投影矩阵变换后,它必定规则观察体(Canonical View Volume,CCV)中,也即是在(-1,-1,0) ~ (1,1,1)之间的值如图1所示
这里 我们定义
P0=(-1,-1,0)
P1=(1,-1,0)
P2=(1,-1,1)
P3=(-1,-1,1)
P4=(-1,1,0)
P5=(1,1,0)
P6=(1,1,1)
P7=(-1,1,1)
我们通过这8个点构建6个面,通过3点共面,假设面是Pos0,pos1,pos2构成,u=Pos1-Pos0,v=Pos2-Pos0,那么法向量n=u×v。则d=-(n×Pos0)。得到每个平面的平面公式n,d,从而得到A,B,C,D,(n的xn,yn,zn,d,就是a,b,c,d)。这里要注意构造面试后P点的顺序,d3D是按顺时针来构造面。法线都是由frustum里到外。
Near: (P0,P4,P5) n=(0,0,-1),d=0 0x+0y-1z+0=0
Far: (P2,P6,P7) n=(0,0,1),d=-1 0x+0y+1z-1=0
Left: (P0,P3,P7) n=(-1,0,0),d=-1 -1x+0y+0z-1=0
Right: (P1,P5,P6) n=(1,0,0),d=-1 1x+0y+0z-1=0
Top: (P4,P7,P6) n=(0,1,0),d=-1 0x+1y+0z-1=0
Bottom: (P0,P1,P2) n=(0,-1,0),d=-1 0x-1y+0z-1=0
我们假设这六个平面中某个平面上存在一个点P’(x’,y’,c’,1),那它的平面方程为A’x’ + B’y’+ C’z’+ D’= 0,在进行投影变换之前的坐标为P(x,y,z,1),在世界空间中的平面方程Ax + By + Cz + D = 0,如果P‘点在CVV中,那点P(x,y,z,1)必定在view Frustum中。
原理一
1.推理
由介绍我们可以得到下面的等式
                  |A’|                      |A|
(x’,y’,c’,1) × |B’| = 0 (x,y,z,1) × |B| = 0
                  |C’|                      |C|
                  |D’|                      |D|
同时(x,y,c,1) × Tvproj= (x‘,y’,z‘,1)
注意Tviewproj矩阵=Tview×Tproj(即是摄像机矩阵和投影矩阵相乘。是将世界坐标转换到视平面的变化矩阵)
结合着3个等式我们可以得到
 |A|                     |A’|
 |B| =Tviewproj × |B’|  (等式1)
 |C|                    |C’|
 |D|                    |D’|
通过等式1,我们可以求出6个面在世界坐标系下的平面方程Ax + By + Cz + D = 0
2代码
void CFrustum::InitFrustum1(const D3DXMATRIX& aoViewMatrix,const D3DXMATRIX& aoProjMatrix)
{
D3DXMATRIX loComboMatrix;
D3DXMATRIX loInvComboMatrix;
D3DXMatrixMultiply(&loComboMatrix,&aoViewMatrix,&aoProjMatrix);
// 求得view * proj的逆矩阵.
D3DXMatrixInverse(&loInvComboMatrix, NULL, &loComboMatrix );
// 如果经过投影矩阵,所有的三维世界坐标的点都变为(-1,-1,0) ~ (1,1,1)之间的值.
// 将同次空间的临界值填入moCVVPos.
moCVVPos[0].x = -1.0f; moCVVPos[0].y = -1.0f; moCVVPos[0].z = 0.0f;
moCVVPos[1].x = 1.0f; moCVVPos[1].y = -1.0f; moCVVPos[1].z = 0.0f;
moCVVPos[2].x = 1.0f; moCVVPos[2].y = -1.0f; moCVVPos[2].z = 1.0f;
moCVVPos[3].x = -1.0f; moCVVPos[3].y = -1.0f; moCVVPos[3].z = 1.0f;
moCVVPos[4].x = -1.0f; moCVVPos[4].y = 1.0f; moCVVPos[4].z = 0.0f;
moCVVPos[5].x = 1.0f; moCVVPos[5].y = 1.0f; moCVVPos[5].z = 0.0f;
moCVVPos[6].x = 1.0f; moCVVPos[6].y = 1.0f; moCVVPos[6].z = 1.0f;
moCVVPos[7].x = -1.0f; moCVVPos[7].y = 1.0f; moCVVPos[7].z = 1.0f;
//将cvv坐标转换回世界坐标
for(int i = 0; i < 8; i++ )
D3DXVec3TransformCoord( &moCVVPos[i], &moCVVPos[i], &loInvComboMatrix );
// 通过得到的世界坐标制作平截头体平面.
// 向量由平截头体内部指向外部的平面.
D3DXPlaneFromPoints(&moFrustumPlane[FRUSTUM_PLANE_FRONT], moCVVPos , moCVVPos+4, moCVVPos+5); // 近平面(near)
D3DXPlaneFromPoints(&moFrustumPlane[FRUSTUM_PLANE_BACK], moCVVPos+2, moCVVPos+6, moCVVPos+7); // 远平面(far)
D3DXPlaneFromPoints(&moFrustumPlane[FRUSTUM_PLANE_LEFT], moCVVPos , moCVVPos+3, moCVVPos+7); // 左平面(left)
D3DXPlaneFromPoints(&moFrustumPlane[FRUSTUM_PLANE_RIGHT], moCVVPos+1, moCVVPos+5, moCVVPos+6); // 右平面(right)
D3DXPlaneFromPoints(&moFrustumPlane[FRUSTUM_PLANE_TOP], moCVVPos+4, moCVVPos+7, moCVVPos+6); // 上平面(top)
D3DXPlaneFromPoints(&moFrustumPlane[FRUSTUM_PLANE_BOTTOM], moCVVPos , moCVVPos+1, moCVVPos+2); // 下平面(bottom)
}
上面的代码很容易理解,完全按原理来实现,但是当我们每次调用这个函数,我们每次都要求Tvproj矩阵的逆矩阵,同时还要重新用点来构造每个frustum平面,并且调用的是D3DXPlaneFromPoints函数。我们还有更好的方法吗?下面我们接着优化我们的代码,优化之前我们接着分析
原理二
1.推理
我们知道在P(x,y,z,1) 经过Tviewproj矩阵变换后得到点P’(x’,y’,z’,w’),这个点在前面的推导过程中,保证是在frustum的某个平面上的.这个时候我们知道如果对P的每个分量都除以w’就可以把P’归一化到一个长方体的空间,即x’/w’, y’/w’在[-1,1]区间,z’/w’在[0,1]区间,所以如果有一个投影转换后的点P1’,它的x1’,y1’在[-w’,w’]区间,z1’在[0,w’]区间,这个点肯定就在视锥体内.
                                             |a11,a12,a13,a14|
假设Tviewproj = [v0,v1,v2,v3] = |a21,a22,a23,a24|
                                             |a31,a32,a33,a34|
                                             |a41,a42,a43,a44|
其中其中V0,v1,v2,v3是四个列向量.
P ’= P×Tviewproj = (P?v0, P?v1, P?v2, P?v3 ) = (x’,y’,z’,w’)
根据上面的x的范围我们有:
-w’ <= x’ 就是 -p’?v3 <= p’?v0 就是 p’?v0 + p’?v3 <= 0 得到 P’?(v0+v3) <= 0
把列向量换成矩阵的元素有
(x,y,z,1).(m_11 + m_14, m12 + m24, m13 + m34, m14 + m44 ) <= 0
就是
(m_11+m_14)*x + (m_12 + m_24)*y + (m_13 + m_34)*z + (m_14 + m_44)*1 <=0
简单地看这是一个 A*x + B*y + C*z + D*1 <= 0 描述了一个半空间,就是平面A*x + B*y + C*z + D*1 = 0右边的空间
所以我们知道是锥体的左裁减面为
(m_11+m_14)*x + (m_12 + m_24)*y + (m_13 + m_34)*z + (m_14 + m_44)*1= 0.
相应地可以计算出 6个裁减面
Left= (v0 + v3).
Right =(v3 - v0)
Bottom =(v3 + v1)
Top = (v3 - v1 )
Near = (v2)
Far = (v3 - v2)
裁减的时候把点带入公式Ax+By+Cz+Dw看大与0还是小与0就可以知道在平面的里面还是外面,在实际计算中需要对A,B,C,D进行归一化。因为我们在处理坐标的时候,点几乎都是经过归一化的。
2.代码
void CFrustum::InitFrustum(const D3DXMATRIX& aoViewMatrix,const D3DXMATRIX& aoProjMatrix)
{
D3DXMATRIX loComboMatrix;
D3DXMatrixMultiply(&loComboMatrix,&aoViewMatrix,&aoProjMatrix);
// calculate the planes
// Near
D3DXPLANE* lpPlane = &moFrustumPlane[FRUSTUM_PLANE_NEAR];
lpPlane->a = loComboMatrix._14 + loComboMatrix._13;
lpPlane->b = loComboMatrix._24 + loComboMatrix._23;
lpPlane->c = loComboMatrix._34 + loComboMatrix._33;
lpPlane->d = loComboMatrix._44 + loComboMatrix._43;
D3DXPlaneNormalize(lpPlane,lpPlane);
// Far
lpPlane = &moFrustumPlane[FRUSTUM_PLANE_FAR];
lpPlane->a = loComboMatrix._14 - loComboMatrix._13;
lpPlane->b = loComboMatrix._24 - loComboMatrix._23;
lpPlane->c = loComboMatrix._34 - loComboMatrix._33;
lpPlane->d = loComboMatrix._44 - loComboMatrix._43;
D3DXPlaneNormalize(lpPlane,lpPlane);
//Left
lpPlane = &moFrustumPlane[FRUSTUM_PLANE_LEFT];
lpPlane->a = loComboMatrix._14 + loComboMatrix._11; // Left
lpPlane->b = loComboMatrix._24 + loComboMatrix._21;
lpPlane->c = loComboMatrix._34 + loComboMatrix._31;
lpPlane->d = loComboMatrix._44 + loComboMatrix._41;
D3DXPlaneNormalize(lpPlane,lpPlane);
// Right
lpPlane = &moFrustumPlane[FRUSTUM_PLANE_RIGHT];
lpPlane->a = loComboMatrix._14 - loComboMatrix._11;
lpPlane->b = loComboMatrix._24 - loComboMatrix._21;
lpPlane->c = loComboMatrix._34 - loComboMatrix._31;
lpPlane->d = loComboMatrix._44 - loComboMatrix._41;
D3DXPlaneNormalize(lpPlane,lpPlane);
// Top
lpPlane = &moFrustumPlane[FRUSTUM_PLANE_TOP];
lpPlane->a = loComboMatrix._14 - loComboMatrix._12;
lpPlane->b = loComboMatrix._24 - loComboMatrix._22;
lpPlane->c = loComboMatrix._34 - loComboMatrix._32;
lpPlane->d = loComboMatrix._44 - loComboMatrix._42;
D3DXPlaneNormalize(lpPlane,lpPlane);
// Bottom
lpPlane = &moFrustumPlane[FRUSTUM_PLANE_BOTTOM];
lpPlane->a = loComboMatrix._14 + loComboMatrix._12; // Bottom
lpPlane->b = loComboMatrix._24 + loComboMatrix._22;
lpPlane->c = loComboMatrix._34 + loComboMatrix._32;
lpPlane->d = loComboMatrix._44 + loComboMatrix._42;
D3DXPlaneNormalize(lpPlane,lpPlane);
}
第2种方法在没有看见之间,先看见的是代码 http://www.racer.nl/reference/vfc_markmorley.htm ,自己想了好久都没考虑清楚。最后看见解释,鄙视自己的数学逻辑推理。3d看来困难的就在于思考方式,同样的代码处理,第二种方式明显快很多。
判断裁剪
我们已经有了裁剪体的方程,当我们需要裁剪一个顶点的时候,这六个方程已经足够了。但是我们要判断一个区域的可见性时,我们进行一些额外的计算。如图2所示,一个物体和投影体的关系大致可以分为:包围、被包围、相交和相离四种情况。图中最大的浅蓝色的矩形包围了整个投影体。深绿色的小矩形则完全被投影体包围。浅绿色的矩形和投影体相交。这三种情况下物体都是可以被看到的。剩下红色的矩形则和投影体相离、只有它完全不可见
图2
当处理节点的可见性的时候,由于节点的不规则性。我们还需要引入包围体的概念。所谓的包围体,就是用一个比较简单的几何体去度量另外一个比较复杂的几何体,让它刚好能包围另外一个几何体。比较合适的包围体外形有矩形、正方形和球体。其中球体处理最为简单,但是近似度也最差。我们为每一个节点都建立一个包围体,只要测试这个包围体,我们就可以决定一个节点的可见性,由于包围体肯定大于这个节点,因此我们可以保证不会有任何可见的节点被裁剪在投影体之外
BOOL CFrustum::PointInFrustum( float afX, float afY, float afZ )
{
// A*x+B*y+C*z+D = 0 is in plane,
for(int i = 0; i < FRUSTUM_PLANE_COUNT; i++ )
{
D3DXPLANE &loPlane = moFrustumPlane[i];
//减少函数调用
//if(D3DXPlaneDotCoord(&moFrustumPlane[i], &D3DXVECTOR3(afX, afY, afZ)) < 0.0f)
if(loPlane.a * afX + loPlane.b * afY + loPlane.c * afZ + loPlane.d < 0.0f)
return FALSE;
}
return TRUE;
}
BOOL CFrustum::SphereInFrustum( float afX, float afY, float afZ, float AfRadius )
{
// A*x+B*y+C*z+D = -radius is in plane,
for(int i = 0; i < FRUSTUM_PLANE_COUNT; i++ )
{
D3DXPLANE &loPlane = moFrustumPlane[i];
//减少函数调用,直接用公式运算
//if(D3DXPlaneDotCoord(&moFrustumPlane[i], &D3DXVECTOR3(afX, afY, afZ)) < -AfRadius)
if( loPlane.a * afX + loPlane.b * afY + loPlane.c * afZ + loPlane.d <= -AfRadius )
{
return false;
}
}
return TRUE;
}
BOOL CFrustum::CubeInFrustum( float afX, float afY, float afZ, float aiSize,BOOL & abIsCompletelyContained )
{
float lfAlfaX = afX + aiSize;
float lfDeltaX = afX - aiSize;
float lfAlfaY = afY + aiSize;
float lfDeltaY = afY - aiSize;
float lfAlfaZ = afZ + aiSize;
float lfDeltaZ = afZ - aiSize;
DWORD ldwNumPointInFrustum = 0;
for(int i = 0; i < FRUSTUM_PLANE_COUNT; i++ )
{
int j = 8;
BOOL lbIsInAllPlanes = TRUE;
D3DXPLANE &loPlane = moFrustumPlane[i];
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfDeltaX,lfDeltaY, lfDeltaZ)) < 0.0f)
if(loPlane.a * lfDeltaX + loPlane.b * lfDeltaY + loPlane.c * lfDeltaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfAlfaX,lfDeltaY, lfDeltaZ)) < 0.0f)
if(loPlane.a * lfAlfaX + loPlane.b * lfDeltaY + loPlane.c * lfDeltaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfDeltaX,lfAlfaY, lfDeltaZ)) < 0.0f)
if(loPlane.a * lfDeltaX + loPlane.b * lfAlfaY + loPlane.c * lfDeltaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfAlfaX,lfAlfaY, lfAlfaZ)) < 0.0f)
if(loPlane.a * lfAlfaX + loPlane.b * lfAlfaY + loPlane.c * lfDeltaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfDeltaX,lfDeltaY, lfAlfaZ)) < 0.0f)
if(loPlane.a * lfDeltaX + loPlane.b * lfDeltaY + loPlane.c * lfAlfaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfAlfaX,lfDeltaY, lfAlfaZ)) < 0.0f)
if(loPlane.a * lfAlfaX + loPlane.b * lfDeltaY + loPlane.c * lfAlfaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfDeltaX,lfDeltaY, lfAlfaZ)) < 0.0f)
if(loPlane.a * lfDeltaX + loPlane.b * lfDeltaY + loPlane.c * lfAlfaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
//if(D3DXPlaneDotCoord(&loPlane[i], &D3DXVECTOR3(lfAlfaX,lfAlfaY, lfAlfaZ)) < 0.0f)
if(loPlane.a * lfAlfaX + loPlane.b * lfAlfaY + loPlane.c * lfAlfaZ + loPlane.d < 0.0f)
{
lbIsInAllPlanes = FALSE;
j--;
}
// if none contained, return FALSE.
if(0 == j)
return FALSE;
// update counter if they were all in front of plane.
if(lbIsInAllPlanes)
++ldwNumPointInFrustum;
}
abIsCompletelyContained = (BOOL)(ldwNumPointInFrustum == FRUSTUM_PLANE_COUNT);
return TRUE;
}
详解D3D/OpenGL光栅化(2) 上一篇讨论了D3D/OGL如何将Shader输出的图元顶点坐标及属性转化为其所覆盖像素和像素的属性。本篇将继续地讨论光栅化其他步骤相关的细节。包括Face Cull,Fill Mode, Clipping, 透视矫正等。 阅读详情

相关推荐

Unity底层揭秘:ICall如何实现C#与C++的极速通信

① 它只做一件事:★ 把"C# 方法名"和"C++ 函数地址"记进一个哈希表。不编译、不检查、不验证。② 真正连上是在第一次调用时:★ JIT 去查表 → 查到地址 → 写死进机器码 → 以后不再查。所以必须在第一次调用之前注册完。③ 它省掉了所有安全检查换速度:★ 参数类型、返回类型全靠你手写对。写错了不报错,只会崩溃或给你错误的数据。本身简单到只有一行插入操作。难的从来不是调用它,而是——保证你 C# 那边的方法签名,和 C++ 这边的函数签名,一个字节都不差。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 17

OpenGL中frustum投影矩阵的推导

OpenGL中,有一个函数叫frustum,字面的意思是截锥体,也就是一个去掉头部的锥体,如下图所示, 看了一下《计算机图形学》(英文名Computer Graphics with OpenGL)的透视投影推导过程,比较全面,各种情况都有描述。不过最近又参考了网上的一些资料,发现这里【1】的推导过程比较单纯直接。我们看一下, 注意到上面这个图,观察者的位置相对于(0,0,0)这个点是在...

tanmx219的博客 8618

Unity 视锥体:摄像机可见空间的 6 面切割

解析 Unity 视锥体的构成与剔除机制:六个裁剪平面如何围合摄像机可见空间,包围盒与视锥体的相交判定如何决定物体是否进入渲染队列。文章同时厘清视锥体剔除与遮挡剔除的职责边界,帮助定位 DrawCall 与帧率问题。

游戏人生 13

Direct3D Frustum裁剪原理

本文原创版权归 百度 laizhishen 所有,如有转载,请按如下方式显式标明原创作者及原文出处,以示尊重!! 作者:laizhishen 原文:http://hi.baidu.com/laizhishen/blog/item/3d206d209cca9c54ac34de4

优秀技术文章收录 3316

View Frustum Culling Tutorial

介绍视锥体裁剪的一篇比较全面的文章 The view frustum is the volume that contains everything that is potentially (there may be occlusions) visible on the screen. This volume is defined according to the camera's settings, and when using a perspective projection takes the shape of a truncated pyramid.

Spring Authorization Server自定义密码模式:突破标准OAuth2限制,实现MFA与复杂业务集成

OAuth 2.0授权框架是构建现代应用安全体系的基石,其密码模式(Resource Owner Password Credentials Grant)提供了一种直接的资源所有者凭证交换令牌的机制。该模式的核心原理是客户端收集用户密码并直接向授权服务器请求访问令牌,适用于受信任的客户端场景。在技术价值上,它简化了某些传统应用的OAuth集成流程。然而,标准实现往往难以满足复杂的现实业务需求,例如需要集成多因素认证(MFA)、对接外部LDAP目录服务或执行自定义密码加密校验等场景。Spring Authori

weixin_34302561的博客 437

视锥裁剪

背景 视锥体(frustum),是指场景中摄像机的可见的一个锥体范围。它有上、下、左、右、近、远,共6个面组成。在视锥体内的景物可见,反之则不可见。为提高性能,只对其中与视锥体有交集的对象进行绘制。 我们计算出视锥体六个面的空间平面方程,将点坐标分别代入六个面的平面方程做比较,则可以判断点是否在视锥体内。 空间平面方程可表示为: Ax+By+Cz=0 对于点

Gypsyy的专栏 5924

IPD(集成产品开发)管理之道

IPD,是集成产品开发(Integrated Product Development)的缩写,它是集成了众多管理模型和理论、众多企业最佳管理实践的一整套体系,可以帮助企业快速响应市场变化、缩短产品上市时间、减少资源浪费、提高生产力,最终取得商业成功。IPD的思想最早来源于美国PRTM公司出版的《产品及生命周期优化法》一书中,该书详细描述了IPD模式所包含的各个方面。但IPD在中国的普及,源于IBM和华为的推行使用。IPD作为一套先进的产品研发管理模式,其成功的基础是功能部门和各团队之间的密切配合。

钢镚·真的博客 2713

OpenGL投影变换:视景体及glFrustum、gluPerspective 与glOrtho、gluOrtho2D

一.            视景体视景体是指成像景物所在空间的集合。它是一个空间集合体。         注意视景体指的是一个空间集合。一般来说,集合中的每个空间都是个立方体。然后所有的这些空间堆在一起,在外侧取一个最大的外接立方体,就是可显示的区域,该可显示区域也是一个视景体。在这个可显示区域内,放置着可以显示的物体。注意,可以显示的物体仅仅是拥有显示权限,但是不一定显示,这取决于相机等其他因素...

超频化石鱼的博客 5388

AI Agent在智能投研中的实战:多智能体信息整合与策略生成

本文将带你从0到1完整搭建一套基于LangChain和AutoGen的多智能体AI投研系统首先,我们会一起梳理智能投研的核心痛点、金融数据的独特性,以及为什么传统AI Agent,尤其是多智能体协同架构,是破局的唯一最优解;RAG检索增强生成(但这次是金融领域定制化的,包括向量检索+时序数据检索+知识图谱检索的“三元检索增强”)、AutoGen多智能体协同框架。

软件工程实践的博客 381

Testbench编写:激励生成、响应监控、仿真时间控制

本文介绍了Verilog/VHDL Testbench的核心技术,重点阐述了激励生成、响应监控和仿真时间控制三大关键环节。通过时钟生成、复位信号生成等具体代码示例,展示了如何有效构建测试平台。文章还总结了波形输出、自动检查等验证方法,并提出了模块化设计、自动化检查等最佳实践,帮助开发者提升FPGA仿真效率和验证质量。这些技术要点为数字电路设计的正确性验证提供了系统化的解决方案。

2301_79143213的博客 111

D3D Frustum裁剪原理

概念介绍 Frustum裁剪原理" alt="D3D Frustum裁剪原理" src="http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif" style="padding-bottom:0px; border-right-width:0px; list-style-type:none; margin:0px; padd

痞子龙3D编程 2885

C# 与华中数控设备通信:数控机床自动化控制与实时监测系统

华中数控系统与C#通信开发指南 核心要点 通信基础 支持串口(RS232/RS485)和以太网两种连接方式 协议选择:通用Modbus协议或华中自定义HNC协议 关键数据映射表明确各参数对应的寄存器地址和功能码 系统架构 四层架构:设备层→通信层→业务层→应用层 包含实时数据采集、指令下发、状态监控、异常处理全流程 支持Modbus和HNC协议动态切换 代码实现 串口通信使用NModbus库简化开发 提供连接管理、数据读取、指令下发完整示例 包含异常处理和超时重连机制 应用价值 实现数控机床远程监控和自动化

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 2018

Frustum PointNets完全解析:从RGB-D数据到3D目标检测的革命性突破

Frustum PointNets是一个基于深度学习的3D目标检测框架,专门用于从RGB-D数据中精确识别和定位三维物体。该项目通过创新的视锥体(Frustum)区域裁剪技术,结合PointNets网络架构,实现了从2D图像检测到3D空间定位的端到端解决方案,为自动驾驶、机器人导航等领域提供了强大的技术支持。 ## 🚀 核心技术原理:从2D到3D的跨越 Frustum PointNets的核

gitblog_00916的博客 544

全覆盖路径规划开源项目Clean-robot-turtlebot3关键函数解析(上)

本系列文章主要介绍全覆盖路径规划开源项目Clean-robot-turtlebot3的相关内容,包含如下四篇文章,分别介绍了开源项目Clean-robot-turtlebot3流程的概括总结、ROS坐标系常用坐标及其变换、Clean-robot-turtlebot3关键函数解析等内容。

慕羽★的博客 2778

【Python LeetCode 专题】面试经典 150 题

面试经典 150 题

一杯水果茶!足矣~ 1173

KITTI数据集实战:使用Frustum PointNets训练3D目标检测模型完整流程

Frustum PointNets是一种基于RGB-D数据的3D目标检测模型,能够从图像和点云数据中精准识别三维物体。本文将详细介绍如何利用KITTI数据集训练Frustum PointNets模型,从环境准备到模型评估,帮助你快速掌握3D目标检测的核心流程。 ## 准备工作:环境与数据集 ### 1. 克隆项目代码库 首先需要获取Frustum PointNets的源代码,执行以下命令克隆仓

gitblog_00247的博客 930

YOLO26涨点改进 | 检测头Head创新改进篇 | 利用DynamicConv高效动态卷积改进YOLO26检测头,DyHead通过增强检测头操作,轻量化改进、提高模型目标检测的精度

YOLO26作为新一代轻量化目标检测模型的代表,凭借精简的Backbone架构、高效的特征融合 Neck 设计,在实时检测场景(如嵌入式设备、边缘计算)中展现出优异的性能,成为工业落地与科研入门的优选模型。但在实际应用中,YOLO26原生检测头仍存在核心瓶颈:采用固定参数卷积核,无法根据输入特征的目标尺度、纹理差异动态调整卷积权重,导致多尺度目标适配不足、复杂背景下特征利用率低,且传统改进方案往往难以平衡“精度提升”与“轻量化”,要么精度提升有限,要么大幅增加参数量、拖累推理速度。

qq_36130719的博客 370

从数据准备到模型部署:Frustum PointNets全流程开发指南

Frustum PointNets是一个基于RGB-D数据的3D目标检测项目,它通过结合2D图像检测与3D点云处理技术,实现了高效准确的三维目标识别。本指南将带你完整了解从环境搭建、数据准备到模型训练与评估的全流程,帮助你快速上手这一强大的3D检测框架。 ## 📋 环境准备与项目搭建 ### 1. 快速克隆项目仓库 首先需要获取项目源码,通过以下命令克隆仓库: ```bash git c

gitblog_00251的博客 368

STM32G474_board_STM32G474开发板

板载资源板载DAP下载器,无需连接外部下载器,单板可实现调试SWD接口引出,可以断开板载DAP下载器,方便外置下载器下载程序板载PD模块,参考ST官方的PD设计,适用于开发PD接口QSPI-Flash模块,可以焊接W25Q64/128/80/32等型号Flash一颗红色LED,一颗绿色LED,一颗用户按键IO接口全部引出(QSPI、USB、SWD通过功能接口引出)

USCAR-49 Performance Specification for Miniature Automotive

USCAR-49 Performance Specification for Miniature Automotive Coaxial Connectors

视锥体六面推导——由摄像机视图投影矩阵直达平面方程的原理与工程实践

定义摄像机位置C,正前方向f,上方向u,右方向r。Near(近平面)、Far(远平面)Left、Right、Top、Bottom 四个侧面六个平面整体描述一个有效空间体积。Nearest plane: 近平距d_near,中心点为 C + f * d_nearFurthest plane: 远平距d_far,中心点为 C + f * d_far上下左右则根据视场角、宽高比可推导法线而真实的平面系数和实际渲染体系会涉及矩阵四元、空间坐标变换。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1120

HP-Socket是一套通用的高性能TCP/UDP/HTTP通信框架,包含服务端组件、客户端组件和Agent组件,广泛适用于各种不同应用场景的TCP/UDP/HTTP通信系统,提供C+等编程语言接口

HP-Socket是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件、客户端组件和Agent组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/C++、C#、Delphi、E(易语言)、Java、Python 等编程语言接口。HP-Socket 对通信层实现完全封装,应用程序不必关注通信层的任何细节;HP-Socket 提供基于事件通知模型的 API 接口,能非常简单高效地整合到新旧应用程序中。Server 基于IOCP / EPOLL通信模型,并结合缓存池、私有堆等技术实现高效内存管理,支持超大规模、高并发通信场景。Agent Agent组件实质上是Multi-Client组件,与Server组件采用相同的技术架构。一个Agent组件对象可同时建立和高效处理大规模Socket连接。Client 基于Event Select / POLL通信模型,每个组件对象创建一个通信线程并管理一个Socket连接,适用于小规模客户端场景。

3D游戏技术 - 大型3D地图优化渲染技术

技术简介: 如果需要渲染一个大型3D地图,由于数据量,需要渲染的东西非常多,所以尤其一些慢一点的机器就会变得非常卡。 如下面这些会造成帧率(FPS)下降的图: 这样的图: 还有这样的魔兽世界的图: 到底暴雪是如何让这些场景流畅地渲染的呢? 那就必须想办法提高渲染速度,也就是帧率(FPS)要提高,才能使得游戏流畅。 会用到的相关技术会有: 1 地图分块剔除 2 kd树 3 BSP树 4 LOD技术 等等,最后把场景优化到极致,才能创造出伟大的游戏。每一种技术都需要挺长篇幅介绍的,本文就分

靖空间 1万+

有源二阶低通滤波电路实验电路multisim源文件

有源二阶低通滤波电路实验电路multisim源文件,multisim10及以上版本可以正常打开仿真,是教材上的电路,可以直接仿真,方便大家学习。

汇总!多模态3D目标检测发展路线,涉及决策、特征、点、体素融合等

点击上方“3D视觉工坊”,选择“星标”干货第一时间送达作者丨柒柒来源丨自动驾驶之心点击进入—>3D视觉工坊学习交流群什么是多模态3D目标检测?多模态3D目标检测是当前3D目标检测研究热点之一,主要是指利用跨模态数据提升模型的检测精度。一般而言,多模态数据包含:图像数据、激光雷达数据、毫米波雷达数据、双目深度数据等,本文主要关注于当前研究较多的RGB+LiDAR融合3D目标检测模型进行汇总和总...

3D视觉工坊 2261
上一篇: Qt移动开发的一些网站和链接
下一篇: 碰撞检测基本完成,方法小结,以备后忘!
SprintfWater
博客等级 码龄15年 242粉丝 139原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值