生成圆锥内的均匀分布的单位向量(Generating uniform unit random vectors in a cone)

本文详细介绍了如何生成单位圆锥内均匀分布的随机单位向量,首先回顾了向量基础知识,然后阐述了计算思路,包括角度坐标系统与笛卡尔坐标系统之间的转换。接着,通过数学公式推导出在给定圆锥侧角条件下的随机方向向量,并提供了Three.js的JavaScript实现代码。文章还讨论了如何使用旋转矩阵将向量对齐到圆锥方向。最后,附上了相关代码和参考资料。
摘要由CSDN通过智能技术生成

特别感谢:@我们家的橙酱GitHub)对本文的帮助哒

0. 向量复习

因为本节涉及基本的向量芝士,如果大家对向量不是很熟悉,请见:向量复习(一)。已经很熟悉的童鞋,可以跳过这部分内容。

1.背景介绍

生成一个单位向量非常的简单,但是如果我们要求这个单位向量是在单位球或单位圆锥里面呢(单位圆内的均匀分布的单位向量,请见randomDirection)。而且随机生成均匀分布的单位向量,应该怎们做呢?这点非常重要哦,因为我们在粒子系统中,需要这个技术来模拟流星效果,或者爆炸效果,也就是说粒子的方向向量是在单位圆锥里面的均匀分布的随机单位向量,比如下面的流星效果:Blibli演示视频链接

粒子系统(Particle System)演示

2. 生成圆锥内的均匀分布的单位向量

计算思路先要用到角度坐标系统,如果对它不是很熟悉的童鞋,可以看看下面角度坐标系统和笛卡尔坐标系统的转化关系12
请添加图片描述
在这里插入图片描述

也就是说,我们先用角度坐标计算在圆锥里面的单位方向向量,然后用上面的公式转化到一般坐标系里面。所以接下来就是计算在角度坐标系中,球上的坐标3

在这里插入图片描述

没有太多数学基础的童鞋不用着急额,这里的公式和概念先混个眼熟,后面我们直接用到计算,不太明白也没有关系哦。接下来,我们现在有一个圆锥(Cone),圆心(Origin)为P,其方向向量(Direction)为D,边角(Side angle)为的ψ。我们以P = [ 0, 0, 0 ],D = [ 0, 0, 1 ], ψ = Π / 4为例,就能得到下图中的圆锥3

在这里插入图片描述

现在我们只考虑三维的情况,且P = [ 0, 0 ,0 ](如果P不在原点,我们只需要把整个圆锥平移到P就行,即:[ 0, 0, 0 ] + P),我们有如下的Cone( D, ψ ),计算在圆锥内的均匀分布的方向向量的公式为3

在这里插入图片描述

其中,θ为[ 0, 2Π ]中均匀分布取值,同样z为[ cosΦ, 1 ]中均匀分布取值,而Φ就是我们给定圆锥的Side Angle(ψ),这样就可以计算这个圆锥里面的随机向量。注意,教材上面计算Φ可通过圆锥方向向量D中Z值来求得3

在这里插入图片描述

但笔者实在无法理解这样的做法,这里给大家提一下,有兴趣的童鞋可以研究一下,如果有结果麻烦告知一下啦~

到这里,我们得到了圆锥里面的向量,但是注意这里的向量都是以Z轴(圆锥的本地坐标)为中心轴的向量(上图圆锥中的向量),所以我们想要根据圆锥的方向向量D进行旋转对齐

接下来,我们将进入到代码解析当中,看看如何用Three.js了进行实现。

3. 代码解析

在理解了计算原理之后,那就该来实现它啦哒,这里我们用Javascript来进行代码讲解。之前我们计算圆锥内的向量是需要用到三个变量:P(圆点),D(方向)和ψ(边角角度),但是我们现在需要生成在单位圆锥内均匀分布的随机方向向量,那么P永远就是原点(因为向量可以随意平移),我们只需要指定其他两个变量就能进行计算圆锥内的单位方向向量:

/**
 * get random Unit Vector3 bounded by the Cone.
 * This is defined by the direction of the cone and its side angle, a.k.a., emission angle
 *
 * Reference resource:
 * Generating uniform unit random vectors in Rn, UMONS, Belgium, Andersen Ang
 *
 * @param {Vector3} center  center of the cone
 * @param {Vector3} direction  direction of the cone
 * @param {Number} sideAngle  in degrees
 */

static randomUnitVector3InCone( center, direction, sideAngle ) {
    let theta = Math.random() * 360;

    // side angle of the cone is sideAngle degrees
    let cosPhi = Math.cos( MyMath.radians( sideAngle ) );
    let z = MyMath.randomInRange( cosPhi, 1 );

    console.assert( MyMath.doubleCompare( 1 - z * z, 0 ) >= 0, 1 - z * z );
    let sinPhi = Math.sqrt( 1 - z * z );
    let x = sinPhi * Math.cos( MyMath.radians( theta ) );
    let y = sinPhi * Math.sin( MyMath.radians( theta ) );

    // hit it with a rotation matrix to get it aligned with the direction of the cone
    let rotation = new THREE.Matrix4().lookAt( center, direction.clone(), Dynamics.zAxis.clone() );
    let directionV = new THREE.Vector3( x, y, z ).clone().transformDirection( rotation );
    // console.log( MyMath.degrees( direction.angleTo( directionV ) ), direction.length() );
    return directionV;
}

代码基本就是上面计算思路的直接实现,因为我们需要用到cosΦ,所以直接计算cosΦ,不用计算Φ。

MyMath.randomInRange( cosPhi, 1 );

这一步我们就计算在这个给定Cone里面的均匀分布的随机方向向量,边角角度范围为[ 0, Φ ],Φ即为圆锥的Side Angle。

接下来,我们就一步步套公式进行计算,最后得到一个随机单位向量,这个向量在以Z轴为方向轴,SideAngle为Φ的单位圆锥内:

let sinPhi = Math.sqrt( 1 - z * z );
let x = sinPhi * Math.cos( MyMath.radians( theta ) );
let y = sinPhi * Math.sin( MyMath.radians( theta ) );

之后,我们需要用原来的圆锥方向轴对生成的方向向量进行对齐,这里我们用到Three.js提供的两个方法:lookAttransformDirection

.lookAt ( eye : Vector3, center : Vector3, up : Vector3, ) : this

Constructs a rotation matrix, looking from eye towards center oriented by the up vector.

创建一个旋转矩阵,这个矩阵从eye的位置看向center,并且由up控制

这里的eye是圆锥的圆心P,center是圆锥的方向向量D,up是Z轴(注意在WebGL中Z轴正对屏幕,并非垂直向上)

.transformDirection ( m : Matrix4 ) : this

Transforms the direction of this vector by a matrix (the upper left 3 x 3 subset of a m) and then normalizes the result.

用一个矩阵(用到的部分是左上的3x3的矩阵进行旋转)旋转当前向量,并且对其进行单位化(模为1)

写出来的代码为:

// hit it with a rotation matrix to get it aligned with the direction of the cone
let rotation = new THREE.Matrix4().lookAt( center, direction.clone(), Dynamics.zAxis.clone() );
let directionV = new THREE.Vector3( x, y, z ).clone().transformDirection( rotation );

4. 附录:代码

  1. randomUnitVector3InCone
  2. Particle System
  3. Particle System Programs

5.参考资料

  1. Generating uniform unit random vectors in R_n, Andersen Ang
  2. Vector3 in three.js
  3. Spherical Coordinates
  4. Polar coordinate system

6. 免责声明

※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;


在这里插入图片描述


  1. Polar coordinate system ↩︎

  2. Spherical Coordinates ↩︎

  3. Generating uniform unit random vectors in R_n, Andersen Ang ↩︎ ↩︎ ↩︎ ↩︎

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值