javascript - 如何将粒子系统初始化为球形帽?
问题描述
我的 Three.js 项目包括在一个经典的圣诞雪球(一个 sphereGeometry)内制作雪(带有一些粒子)。我已经创建了粒子,THREE.BufferGeometry()
并初始化了它们,为每个参数(x,y,z)提供了一个 initial_position。
有没有办法让它们只在球体内可见?我解决了给球体外部的粒子与背景颜色相同的问题,但它不能完美地工作。
有没有办法让球体外的粒子不可见?也许让它们变得透明。
否则我怎么能将粒子初始化为球形帽?谢谢!
这就是我初始化粒子位置的方式(作为平行六面体):
for(i=0; i<n; i++){
init_pos_y[i] = 50 + (Math.random()-0.5)*20;
init_pos_x[i] = (Math.random()-0.5)*100;
init_pos_z[i] = (Math.random()-0.5)*100;
acceleration[i] = Math.random()*1;
在顶点着色器中,这就是我如何使粒子下落并赋予它们颜色(并根据其在球体内或球外的位置改变其不透明度):
void main(){
vec3 p = position;
p.x = initial_position_x;
p.z = initial_position_z;
if (initial_position_y - time * acceleration > -32.8 + min_level){
p.y = initial_position_y - time * acceleration;
}
else{
p.y = -33.8 + min_level;
}
float opacity;
if (p.x*p.x + p.y*p.y + p.z*p.z > 2490.0){
opacity = 0.40;
vColor = vec4( customColor, opacity );
}
else{
opacity = 1.0;
vColor = vec4( customColor2, opacity );
}
gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
vUv = projectionMatrix * vec4(p, 1.0);
gl_PointSize = 3.0*acceleration;
}
解决方案
首先,您需要将您的点放在一个圆柱体中(在一个圆圈内随机,在高度上随机)。为此,请参阅功能setInCircle()
。
然后需要修改shader的代码。我更喜欢用 来做.onBeforeCompile()
,因此你可以修改必要的部分,保留材料的所有其他功能。
在着色器中,您通过添加距离(时间 * 速度)将 y 值除以 10(mod()
函数)来更改 y 值,因此您将其置于一个循环中,在 5 到 -5 的范围内从上到下移动。
最后一件事是检查给定变换向量的长度是否小于或等于给定半径,将结果传递给片段着色器,如果结果小于 0.5,则丢弃一个像素。
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.setScalar(10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var pts = [];
var radius = 5;
var pointsCount = 5000;
for (i = 0; i < pointsCount; i++) {
let v2 = setInCircle().multiplyScalar(radius);
let v3 = new THREE.Vector3(v2.x, THREE.Math.randFloat(-radius, radius), v2.y);
pts.push(v3);
}
var geom = new THREE.BufferGeometry().setFromPoints(pts);
var uniforms = {
speed: {
value: 1
},
time: {
value: 0
},
radius: {
value: radius
}
}
var mat = new THREE.PointsMaterial({
color: "magenta",
size: 0.05
});
mat.onBeforeCompile = shader => {
shader.uniforms.speed = uniforms.speed;
shader.uniforms.time = uniforms.time;
shader.uniforms.radius = uniforms.radius;
shader.vertexShader = `
uniform float speed;
uniform float time;
uniform float radius;
varying float vVisible;
` + shader.vertexShader;
//console.log(shader.vertexShader);
shader.vertexShader = shader.vertexShader.replace(
`#include <begin_vertex>`,
`#include <begin_vertex>
transformed.y = mod((transformed.y - speed * time) - 5., 10.) - 5.;
vVisible = length(transformed) <= radius ? 1.: 0.;
`
);
shader.fragmentShader = `
varying float vVisible;
` + shader.fragmentShader;
console.log(shader.fragmentShader);
shader.fragmentShader = shader.fragmentShader.replace(
`void main() {`,
`void main() {
if (vVisible < 0.5) discard;
`
);
}
var points = new THREE.Points(geom, mat);
scene.add(points);
function setInCircle() {
let v = new THREE.Vector2();
v.set(
THREE.Math.randFloat(-1, 1),
THREE.Math.randFloat(-1, 1)
)
return v.length() <= 1 ? v : setInCircle();
}
var clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
uniforms.time.value = clock.getElapsedTime();
renderer.render(scene, camera)
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
推荐阅读
- java - 在对象名称之间检索
- python-3.7 - 在 Python 中使用辛普森法则
- typescript - 捆绑的 Typescript 编译器 API
- javascript - 为什么我的 jQuery 过滤器函数中的测试没有按预期工作?
- encryption - 解密签名和加密的 SMIME 消息时 Openssl 错误的内容类型
- javascript - Javascript比较内存中的对象大小
- laravel - 我的 Laravel 其他页面出现图表 Js 错误问题?
- javascript - 当按回车键时仅打开下拉菜单
- css - 如何在表格中添加标题?
- python - Flask url 重定向给出了意外的关键字参数异常