利用OpenGL点精灵实现云模拟(Cloud Simulation Using OpenGL PointSprite)

本教程介绍如何使用OpenGL点精灵(PointSprite)技术模拟云朵。通过构造不同大小的球体并将其组合成云的形状,再抽取包围盒内球体区域的体素作为点精灵的位置,最终实现逼真的云朵渲染效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 [教学视频]计算机图形学基础 在线学习教程  

*原创文章,转载请注明出处*

 

利用OpenGL点精灵实现云模拟

 Cloud Simulation Using OpenGL PointSprite

 

 

这篇教程介绍一种利用OpenGL点精灵,也就是PointSprite来实现云的模拟。在网上找了一些资料和论文,都是模拟真实的云和光照,且都比较复杂。后来看到一篇文章,介绍了一篇相对简单但效果比较好的方法。首先建立好云的轮廓模型,可以使用3DMax或其他的建模工具,然后创建该模型的包围体,将包围体中属于云的部分抽取出来,最后对抽取出来的部分进行三角化,然后贴图,最后加上光照。受到该方法的启发,这里我介绍一种更为简单的方法来实现对云的模拟。

 

和从文件读取云模型相比,用代码生成云的轮廓要快的多。云的轮廓我们可以用球来模拟,使用多个不同大小的球可以组成不同形状的云。图Fig1中显示了利用三个半径不同的球组成的云的形状。当然你也可以使用更多不同大小的球来组成更逼真,更复杂的云。

 

 

 

 

Fig1. 不同大小的球组成的云的形状

 

描述这样三个球只需用几个结构体即可。

 

      struct VECTOR3

      {

           float x,y,z;

           VECTOR3(){}

           VECTOR3(float _x, float _y, float _z)

           {

                 x = _x; y = _y; z = _z;

           }

      };

 

结构体VECTOR3是一个三维向量结构体,用来表示球的圆心。再加上半径R我们就可以描述球的几何性质了。于是球的结构体可以定义为

 

      struct Sphere

      {

           VECTOR3 C;

           float   R;

           Sphere(){}

           Sphere(VECTOR3 c, float r)

           {

                 C.x = c.x; C.y = c.y; C.z = c.z;

                 R = r;

           }

      };

 

接下来就要得到整个云的包围盒,包围盒可以用包围盒立方体对角线上的两个顶点来描述,这里使用顶点坐标全为负和全为正的两个点。包围盒机构体可以定义为

 

      struct BoundingBox

      {

           VECTOR3 origin;

           VECTOR3 MinPt;

           VECTOR3 MaxPt;

           Line Boundaries[12];

      };

 

在上面的结构体中,origin表示包围盒的中心坐标,MinPt表示全为负的顶点,MaxPt表示全为正的顶点。利用球心所在位置和球半径就可以决定包围盒的大小。用每一个球的球心位置减去该球的半径,然后比较这个值,最小的就是MinPt的值。同样用每一个球的球心位置加上该球的半径,其中最大的就是MaxPt的值。为了方便后面绘制该包围球,该结构体中还有一个Line结构体,该结构体表示包围盒的边的信息,定义如下

 

struct Line

      {

           VECTOR3 origin;

           VECTOR3 end;

      };

 

 

很明显Line结构体中originend分别表示包围体一条边的起点和终点。Fig2显示了Fig1中云形状的包围盒。

 

(a)

(b)

 

 Fig2. 云的包围盒

 

 

为了用PointSprite来模型云,我们需知道每个PointSprite在三维空间中的位置。而这些位置就是由云的形状来决定的。只要能找到每个球内的PointSprite,那么就能利用PointSprite来模拟云的形状了。这里用的方法有点体渲染(Volume Rendering)的味道。先将包围盒分成一个一个的体素(voxel)voxel的多少由voxel的大小来决定。现在要做的就是抽取出所有球内的voxel

抽取的过程很简单,只要判断当前voxel和球的位置关系即可。将voxel的坐标带入球的方程(已知球心和半径),判断和半径的关系,只要小于等于半径的平方,那么该voxel就在球内。

 

(x-a)2+(y-b)2+(z-c)2 R2

 

上式中(a,b,c)为球心,R为半径。

 

 

(a)

(b)

(c)

(d)

 
 

Fig3 从包围盒中抽取云轮廓内的体素

 

Fig3中可以看到,(a)中显示了包围盒的所有体素,(b)中抽取出了在云形状内部的部分体素。(c)中可以清楚的看到云内部体素的形状,而(d)则是将云内部每个体素的位置加上一定随机扰动的结果。

 

有了云内部voxel,就可以将每个voxel当作一个PointSprite,适当的调节PointSprite的大小和体素的大小,然后给PointSprite贴上带alpha通道的纹理即可,如Fig4

 

 

(a)

(b)

  Fig4 PointSprite模拟的云

 

整个云模拟的过程中,重要的部分就是将包围盒中用于模拟云的球内部的体素抽取出来。只要正确的抽取出云内部的体素,那么云的形状也就得到了。具体的内容是实现方法可以参考该教程的源代码。如果OpenGL版本不支持PointSprite,请更新OpenGL驱动,并下载高版本的OpenGL库。

 

 

下载该教程和源代码 

 

 

*原创文章,转载请注明出处*

robot@robot-virtual-machine:~/桌面/final_homework$ source install/setup.bash robot@robot-virtual-machine:~/桌面/final_homework$ ros2 launch fishbot_description display_robot.launch.py [INFO] [launch]: All log files can be found below /home/robot/.ros/log/2025-06-24-00-11-46-081731-robot-virtual-machine-7490 [INFO] [launch]: Default logging verbosity is set to INFO [INFO] [gazebo-1]: process started with pid [7491] [INFO] [ros2-2]: process started with pid [7493] [INFO] [robot_state_publisher-3]: process started with pid [7495] [INFO] [joint_state_publisher_gui-4]: process started with pid [7497] [INFO] [rviz2-5]: process started with pid [7499] [rviz2-5] qt.qpa.plugin: Could not find the Qt platform plugin "wayland" in "" [robot_state_publisher-3] [WARN] [1750695106.292463264] [robot_state_publisher]: No robot_description parameter, but command-line argument available. Assuming argument is name of URDF file. This backwards compatibility fallback will be removed in the future. [robot_state_publisher-3] [WARN] [1750695106.302384420] [kdl_parser]: The root link base_link has an inertia specified in the URDF, but KDL does not support a root link with an inertia. As a workaround, you can add an extra dummy link to your URDF. [robot_state_publisher-3] [INFO] [1750695106.302610250] [robot_state_publisher]: got segment base_link [robot_state_publisher-3] [INFO] [1750695106.302689782] [robot_state_publisher]: got segment imu_link [robot_state_publisher-3] [INFO] [1750695106.302710901] [robot_state_publisher]: got segment lidar_link [joint_state_publisher_gui-4] qt.qpa.plugin: Could not find the Qt platform plugin "wayland" in "" [gazebo-1] Gazebo multi-robot simulator, version 11.10.2 [gazebo-1] Copyright (C) 2012 Open Source Robotics Foundation. [gazebo-1] Released under the Apache 2 License. [gazebo-1] http://gazebosim.org [gazebo-1] [rviz2-5] [INFO] [1750695107.130130445] [rviz2]: Stereo is NOT SUPPORTED [rviz2-5] [INFO] [1750695107.130604125] [rviz2]: OpenGl version: 4.1 (GLSL 4.1) [gazebo-1] Gazebo multi-robot simulator, version 11.10.2 [gazebo-1] Copyright (C) 2012 Open Source Robotics Foundation. [gazebo-1] Released under the Apache 2 License. [gazebo-1] http://gazebosim.org [gazebo-1] [rviz2-5] [INFO] [1750695107.218685070] [rviz2]: Stereo is NOT SUPPORTED [joint_state_publisher_gui-4] [INFO] [1750695107.423622348] [joint_state_publisher_gui]: Waiting for robot_description to be published on the robot_description topic... [rviz2-5] [ERROR] [1750695107.426237025] [rviz2]: PluginlibFactory: The plugin for class 'rviz_default_plugins/Imu' failed to load. Error: According to the loaded plugin descriptions the class rviz_default_plugins/Imu with base class type rviz_common::Display does not exist. Declared types are nav2_rviz_plugins/ParticleCloud rviz_default_plugins/AccelStamped rviz_default_plugins/Axes rviz_default_plugins/Camera rviz_default_plugins/DepthCloud rviz_default_plugins/Effort rviz_default_plugins/FluidPressure rviz_default_plugins/Grid rviz_default_plugins/GridCells rviz_default_plugins/Illuminance rviz_default_plugins/Image rviz_default_plugins/InteractiveMarkers rviz_default_plugins/LaserScan rviz_default_plugins/Map rviz_default_plugins/Marker rviz_default_plugins/MarkerArray rviz_default_plugins/Odometry rviz_default_plugins/Path rviz_default_plugins/PointCloud rviz_default_plugins/PointCloud2 rviz_default_plugins/PointStamped rviz_default_plugins/Polygon rviz_default_plugins/Pose rviz_default_plugins/PoseArray rviz_default_plugins/PoseWithCovariance rviz_default_plugins/Range rviz_default_plugins/RelativeHumidity rviz_default_plugins/RobotModel rviz_default_plugins/TF rviz_default_plugins/Temperature rviz_default_plugins/TwistStamped rviz_default_plugins/Wrench [joint_state_publisher_gui-4] [INFO] [1750695107.461749461] [joint_state_publisher_gui]: Centering [gazebo-1] [Wrn] [gazebo_ros_init.cpp:178] [gazebo-1] # # ####### ####### ### ##### ####### [gazebo-1] ## # # # # # # # # [gazebo-1] # # # # # # # # # [gazebo-1] # # # # # # # # ##### [gazebo-1] # # # # # # # # # [gazebo-1] # ## # # # # # # # [gazebo-1] # # ####### # ### ##### ####### [gazebo-1] [gazebo-1] This version of Gazebo, now called Gazebo classic, reaches end-of-life [gazebo-1] in January 2025. Users are highly encouraged to migrate to the new Gazebo [gazebo-1] using our migration guides (https://gazebosim.org/docs/latest/gazebo_classic_migration?utm_source=gazebo_ros_pkgs&utm_medium=cli) [gazebo-1] [gazebo-1] [joint_state_publisher_gui-4] [INFO] [1750695107.837611111] [joint_state_publisher_gui]: Centering [ros2-2] [INFO] [1750695107.897855160] [spawn_entity]: Spawn Entity started [ros2-2] [INFO] [1750695107.900047566] [spawn_entity]: Loading entity XML from file /home/robot/桌面/final_homework/install/fishbot_description/share/fishbot_description/urdf/first_robot.urdf [ros2-2] [INFO] [1750695107.902118423] [spawn_entity]: Waiting for service /spawn_entity, timeout = 30 [ros2-2] [INFO] [1750695107.905140588] [spawn_entity]: Waiting for service /spawn_entity [gazebo-1] [Msg] Waiting for master. [gazebo-1] [Msg] Connected to gazebo master @ http://127.0.0.1:11345 [gazebo-1] [Msg] Publicized address: 192.168.150.128 [gazebo-1] [Wrn] [GuiIface.cc:120] Could not find the Qt platform plugin "wayland" in "" [gazebo-1] [Err] [InsertModelWidget.cc:403] Missing model.config for model "/home/robot/.gazebo/models/wpr_simulation2" [gazebo-1] context mismatch in svga_surface_destroy [gazebo-1] context mismatch in svga_surface_destroy [ros2-2] [ERROR] [1750695138.117988219] [spawn_entity]: Service /spawn_entity unavailable. Was Gazebo started with GazeboRosFactory? [ros2-2] [ERROR] [1750695138.119174800] [spawn_entity]: Spawn service failed. Exiting. [ros2-2] [ros2run]: Process exited with failure 1 [ERROR] [ros2-2]: process has died [pid 7493, exit code 1, cmd 'ros2 run gazebo_ros spawn_entity.py -entity first_robot -file /home/robot/桌面/final_homework/install/fishbot_description/share/fishbot_description/urdf/first_robot.urdf'].
最新发布
06-24
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张赐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值