我想知道,是否有任何方法可以使用3D模型在three.js中发生粒子碰撞,但是我已经尝试过了,但是并没有保持我想要的状态。我还想创建一个弹性碰撞,使每个粒子都与指针相反的角度
https://codepen.io/AlainBarrios/pen/YoNooV?editors=0010
const s = {
vs: `
uniform float scale;
uniform vec3 mouse;
varying vec2 vUv;
void main(){
vUv = uv;
vec3 newpos = position;
float d = length(newpos - mouse);
float maxRadius = 5.;
if(d < maxRadius){
float koef = d / maxRadius;
newpos *= vec3(2., 2., 1.);
newpos = mix(position, newpos, koef);
}
vec4 mvPosition = modelViewMatrix * vec4(newpos, 1.0);
gl_PointSize = 100. * (1. / - mvPosition.z);
gl_Position = projectionMatrix * mvPosition;
}
`,
fs: `
varying vec2 vUv;
void main(){
vec2 uv = vUv;
gl_FragColor = vec4(1., 1., 1., 1.);
}
`
};
// Carga modelos 3D externos o texturas dependiendo de la opcion
const loaderFiles = {
gltf: new THREE.GLTFLoader(),
texture: new THREE.TextureLoader()
};
class WebGL {
constructor() {
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.camera = new THREE.PerspectiveCamera(
45,
innerWidth / innerHeight,
0.1,
1000
);
this.scene = new THREE.Scene();
this.group = new THREE.Group();
this.clock = new THREE.Clock();
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();
this.helper = new Helper(this.scene);
this.loader = loaderFiles.gltf;
this.update = this.update.bind(this);
this.onResize = this.onResize.bind(this);
}
// Coloca el objeto renderer dentro del DOM
// Instaciamos la clase OrbitControls para mover la camara
// Agrega la camara y el objeto group dentro de la escena
init() {
const _contentCanvas = document.querySelector("#content-canvas");
this.renderer.setSize(innerWidth, innerHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.scene.add(this.camera);
this.scene.add(this.group);
this.scene.background = new THREE.Color(0x140000);
this.controls = new THREE.OrbitControls(this.camera);
this.camera.position.set(0, 10, 60);
this.camera.lookAt(this.scene.position);
this.helper.axes(100);
_contentCanvas.appendChild(this.renderer.domElement);
this.loadModel();
window.addEventListener("resize", this.onResize);
window.addEventListener("mousemove", ev => this.onMousemove(ev));
}
// Inicia todos los metodos que serviran para crear nuestro espacio y objetos
loadModel() {
this.loader.load(
"https://rawcdn.githack.com/AlainBarrios/3d-models/694ea0751aab59c235390f61e81ee1d37f328d5a/knight_girl.glb?raw=true",
gltf => {
this.mat = new THREE.ShaderMaterial({
uniforms: {
time: {
type: "f",
value: 0
},
resolution: {
type: "v2",
value: new THREE.Vector2(innerWidth, innerHeight)
},
mouse: {
type: "v3",
value: new THREE.Vector2(0, 0, 0)
},
scale: {
type: "f",
value: innerHeight / 2
}
},
vertexShader: s.vs,
fragmentShader: s.fs
});
//const mat = new THREE.PointsMaterial({ color: 0xFFFFFF, size: 0.25 })
const positions = this.combineBuffer(gltf, "position");
const geo = new THREE.BufferGeometry();
geo.addAttribute("position", positions);
geo.addAttribute("initialPosition", positions);
geo.computeBoundingBox();
geo.attributes.position.setDynamic(true);
this._modelMesh = new THREE.Points(geo, this.mat);
this._modelMesh.position.set(0, -10, 0);
this.scene.add(this._modelMesh);
const planeGeo = new THREE.PlaneBufferGeometry(15, 50, 1, 1);
this.planeMesh = new THREE.Mesh(
planeGeo,
new THREE.MeshBasicMaterial({ color: 0x000, visible: false })
);
this.planeMesh.position.set(0, 15, 0)
this.scene.add(this.planeMesh);
this._modelMesh.rotation.x = -Math.PI / 2;
this._modelMesh.rotation.z = -Math.PI;
this.update();
}
);
}
combineBuffer(model, bufferName) {
let count = 0;
model.scene.traverse(child => {
if (child.isMesh) {
const buffer = child.geometry.attributes[bufferName];
count += buffer.array.length;
}
});
const combined = new Float32Array(count);
let offset = 0;
model.scene.traverse(child => {
if (child.isMesh) {
const buffer = child.geometry.attributes[bufferName];
combined.set(buffer.array, offset);
offset += buffer.array.length;
}
});
return new THREE.BufferAttribute(combined, 3);
}
onMousemove(ev) {
this.mouse.x = 1 - ev.clientX / innerWidth * 2;
this.mouse.y = (ev.clientY / innerHeight) * 2 - 1;
console.log(this.mouse)
}
// Actualiza cualquier cambio, para luego representarlo en el canvas
update() {
//this._modelMesh.rotation.z += .01;
this.detectIntersection();
this.render();
requestAnimationFrame(this.update);
}
detectIntersection() {
this.raycaster.setFromCamera(this.mouse, this.camera);
// calculate objects intersecting the picking ray
this.intersects = this.raycaster.intersectObjects([this.planeMesh]);
if (this.intersects.length > 0) {
this.mat.uniforms.mouse.value = this.intersects[0].point;
console.log(this.intersects[0].uv)
}
}
// Rescala el canvas y escenario
onResize() {
const _w = innerWidth;
const _h = innerHeight;
this.renderer.setSize(_w, _h);
this.camera.aspect = _w / _h;
this.mat.uniforms.scale.value = domElement.height / 2;
/*if (_w / _h > 1) {
this.mesh.scale.x = this.mesh.scale.y = this.mesh.scale.z = 1.05 * w / h;
}*/
this.camera.updateProjectionMatrix();
}
// Renderiza nuestro escenario
render() {
this.renderer.render(this.scene, this.camera);
}
}
const webgl = new WebGL();
webgl.init();
这是我唯一能做的,我希望找到解决问题的方法。