billboard 的OpenGL实现&&OpenGL多线程创建纹理

http://hi.baidu.com/atyuwen/blog/item/5355f17370ef9b1b8701b098.html

虚拟现实技术与算法的大作业需要用到billboard技术,写了这样一个类来实现。很简单的一个类,完整的代码如下:

//-------------------------------------------------------
// CBillBoard: a virtual class to draw BillBoard rect
// By: atyuwen.     Date: 2008.11.12
//-------------------------------------------------------
class CBillBoard  
{
public:
     CBillBoard(){};
     virtual ~CBillBoard() = 0;

     // Clear the rotate elements
     static inline void BeginBillBoard()
     {
         float mat[ 16];
         glGetFloatv(GL_MODELVIEW_MATRIX, mat);

         // Identify the 3*3 sub matrix in Top-left corner
         mat[ 1] = mat[ 2] = mat[ 6] = 0;
         mat[ 4] = mat[ 8] = mat[ 9] = 0;
         mat[ 0] = mat[ 5] = mat[ 10] = 1;
        
         glLoadMatrixf(mat);
     }

     // Draw rect
     static inline void DrawBillBoard( float *pos, float w, float h)
     {
         glPushMatrix();
    
         glTranslatef(pos[ 0], pos[ 1], pos[ 2]);
         BeginBillBoard();

         // Draw a Quad
         glBegin(GL_QUADS);
         glTexCoord2i( 0, 0); glVertex2f(-w/ 2, -h/ 2);    // Bottom-left
         glTexCoord2i( 1, 0); glVertex2f( w/ 2, -h/ 2);    // Bottom-right
         glTexCoord2i( 1, 1); glVertex2f( w/ 2,   h/ 2);    // Top-right
         glTexCoord2i( 0, 1); glVertex2f(-w/ 2,   h/ 2);    // Top-left
         glEnd();

         glPopMatrix();
     }
};


http://hi.baidu.com/co_olwind/blog/item/9f33cb3734060042251f142c.html

关于这个问题以前只知道多个线程不能同时使用一个RC,结果为了能动态加载,当初还做了一个通过拆分主线程的工作来模拟多线程加载的伪多线程程序,今天突然很想把这个问题彻底搞明白,结果从百度到google.com最后才在终于找到这么一篇讲解详细的英文文章,可怜我4级都没过的英语啊...

这是英文原文地址:http://veelck.wordpress.com/2008/11/28/multithread-texture-loading-in-opengl/

老外写东西一般废话会比较多,为了节省技术人员的宝贵时间就不逐句翻译了,提取一下要点吧,如下:

首先使用同一个DC创建两个RC,并且使用wglShareLists共享两个RC的资源。建议不要给这三个函数之间加其他向RC中添加东西的GL函数。

HGLRC hRC1 = wglCreateContext(hDC);

HGLRC hRC2 = wglCreateContext(hDC);

wglShareLists(hRC2, hRC1);

注意:wglShareLists的第一个参数中的RC是分享别人资源的,第二个参数中的RC是奉献资源供别人分享的。

//这是一个用来渲染场景的线程(也可用主线程来渲染)

renderingThread()

{

   //...

   wglMakeCurrent(hDC, hRC1);

   //...

}

理论上来讲,可以在多创建几个RC,然后用多线程同时渲染。但是据说这样做是可行但却无益的。因为OpenGL会进行一些频繁的切换,导致产生高昂的开销。

//这是一个用来加载资源的线程,可以加载图片,并使用创建纹理,设置纹理参数等。

loadingThread()

{

   //...

   wglMakeCurrent(hDC, hRC2);

   //...

}

注意,加载工作也可以写在多个线程中,例如使用多个线程从硬盘中读取图片文件(在多核机器上用双核读图片会比单核快一些),然后使用一个专门的线程调用GL的函数来创建纹理。但是,如果使用一些开源的图像库来读取图片的话就要注意了,有些开源的图像库不支持多线程,如DevIL。(FreeImage记得也存在这个问题)

最后别忘了在各个线程结束时调用wglMakeCurrent(NULL, NULL);取消DC与RC的关联。

还有要删除RC

wglDeleteContext(hRC2);

wglDeleteContext(hRC1);

最后要发一下牢骚。网上三维图形方面的资料相比其他计算机技术而言实在是不多,而且大多数还没有用。国内更是少的可怜,可能高人们都在忙着为买房子而奋斗导致没时间上网了。以下是该英文文章作者的感言,深有同感啊,向这种有国际主义精神的高人致敬。

It was quite a struggle to find anything useful in the web, only some minor things at few forums and mailing groups. But using that with some thinking and reading between lines I finally found the solution I’d like to share, as it can save (in my opinion) much time of searching and experimenting for others.

### 回答1: 可以使用 Cesium 的 `BillboardCollection` 类来实现在 Vue 框架中点击创建 billboard 的功能。 首先,在 Vue 组件的 data 中定义一个变量来存储 billboard 集合: ``` data() { return { billboardCollection: new Cesium.BillboardCollection() } } ``` 然后,在组件的 mounted 钩子函数中,将 billboard 集合添加到场景中: ``` mounted() { this.viewer.scene.primitives.add(this.billboardCollection); } ``` 接着,在组件的 template 中绑定点击事件,在事件处理函数中添加新的 billboard: ``` <template> <div @click="addBillboard">Click to add a billboard</div> </template> <script> export default { methods: { addBillboard() { // 获取鼠标点击的位置 let pickedObject = this.viewer.scene.pick(this.viewer.camera.getPickRay(this.viewer.canvas.clientWidth / 2, this.viewer.canvas.clientHeight / 2)); if (Cesium.defined(pickedObject)) { let position = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(pickedObject.position); // 创建新的 billboard let billboard = this.billboardCollection.add({ position: Cesium.Cartesian3.fromRadians(position.longitude, position.latitude, position.height + 100), image: 'path/to/image.png' }); } } } } </script> ``` 在这个例子中,我们使用了 Cesium 的 `pick` 方法来获取鼠标点击的位置,然后使用 `Cartesian3.fromRadians` 将经纬度坐标转换为笛卡尔坐标,最后使用 `BillboardCollection.add` 方法添加新的 billboard。 希望这些信息能帮助您实现在 Vue 框架中使用 Cesium 创建 billboard 的功能。 ### 回答2: 在Vue框架中实现点击创建billboard功能,可以按照以下步骤进行: 1. 首先,在Vue项目中引入Cesium库,可以通过npm安装或直接引入Cesium.js文件。 2. 在Vue组件中,可以在`mounted`钩子函数中创建Cesium的Viewer对象,并将其初始化为指定DOM元素的父元素,如: ``` mounted() { this.viewer = new Cesium.Viewer(this.$refs.mapContainer); } ``` 其中`$refs.mapContainer`是在模板中定义的一个ref,用于获取地图容器的DOM元素。 3. 在模板中定义一个按钮,并绑定一个点击事件,如: ```vue <template> <div> <button @click="createBillboard">创建Billboard</button> <div class="map-container" ref="mapContainer"></div> </div> </template> ``` 4. 在Vue组件的methods选项中定义`createBillboard`方法,用于创建billboard。在该方法中,可以使用Cesium的`Cesium.Cartesian3`类创建一个位置,然后通过`Cesium.BillboardCollection`类创建一个billboard,并设置其属性,最后将billboard添加到scene中。代码示例如下: ```vue methods: { createBillboard() { // 创建位置 var position = Cesium.Cartesian3.fromDegrees(103, 30); // 创建BillboardCollection并设置属性 var billboard = this.viewer.scene.primitives.add( new Cesium.BillboardCollection() ); billboard.add({ position: position, image: "path/to/billboard-image.png", scale: 1.0, }); }, } ``` 其中,`Cesium.Cartesian3.fromDegrees`根据经纬度创建一个位置,`Cesium.BillboardCollection`用于存储和渲染多个billboard,`image`属性指定billboard的图片路径,`scale`属性用于设置billboard的大小。 5. 最后,通过点击按钮,调用`createBillboard`方法即可在地图上创建一个billboard。 这样,就在Vue框架中实现了点击创建billboard功能。 ### 回答3: 在Vue框架中实现点击创建Billboard功能,可以按照以下步骤实现: 1. 首先,将Cesium集成到Vue项目中。可以通过npm安装Cesium,然后在Vue组件中引入Cesium相关的库文件。 2. 在Vue组件的data选项中添加一个数组billboards,用于存储所有的Billboard对象信息。在初始状态下,该数组为空。 3. 在Vue组件的template中添加一个Cesium的Canvas元素,用于渲染Cesium场景。可以将该Canvas元素的id设为"cesiumContainer"。 4. 在Vue组件的methods选项中添加一个方法handleClick,用于处理点击事件。在该方法内,获取点击事件的坐标,在3D场景中添加一个Billboard对象,并将其位置设为点击坐标。然后,将该Billboard对象的信息添加到billboards数组中保存。 5. 在Vue组件的mounted钩子函数中,通过Cesium的Viewer对象初始化3D场景,并将Canvas元素绑定到该Viewer对象上。同时,监听Canvas元素的点击事件,当点击事件发生时,调用handleClick方法。 6. 在Vue组件的template中,使用v-for指令循环遍历billboards数组,并根据每个Billboard对象的信息,在Canvas中显示对应的Billboard元素。 通过以上步骤,就可以在Vue框架中实现点击创建Billboard功能。当用户在Canvas中点击时,会在点击位置创建一个Billboard,并在屏幕上显示出来。同时,Billboard对象的信息也会保存在billboards数组中,以便后续的操作和管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值