将平面版本移植到Three.JS。在上一段代码中仍无法为粒子设置它。蓝色和绿色的粒子应与两个洋红色粒子的位置相同。
我有要在诸如Shadertoy素描https://www.shadertoy.com/view/wtd3Wn之类的粒子之间进行元球运动转换的代码,>
所以,最后,我需要这样的东西:
为此,我创建了另一个着色器[Joint],其宽度/高度等于粒子之间的距离,并且已经确定了它们的位置,因此如果您调用,则>]
gl_FragColor = vec4(1.0-circle(fragCoord,startPos,16.0)* circle(fragCoord,endPos,16.0));
它将在其位置上画圆。
但是当我尝试绘制元球时,我一无所有。
非常确定我在执行fragCoord初始化时出错,或者必须调整这些参数:
const float threshold = 3.0; const float density = 1000.0; const float norm = 2.0;
和
balls[0] = setMetaball(vec2(0.0, 0.0), 0.2, vec3(0.0, 0.0, 1.0)); balls[1] = setMetaball(startPos, 0.05, vec3(0.0, 0.0, 1.0)); balls[2] = setMetaball(endPos, 0.1, vec3(0.0, 1.0, 0.0)); balls[3] = setMetaball(endPos, 0.05, vec3(0.0, 1.0, 0.0));
位置和半径
THREE.TOUCH = {}; var circularPoint = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="128px" height="128px"><circle cx="64" cy="64" r="62" fill="white" /></svg>'; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(35, innerWidth / innerHeight, 1, 1000); camera.position.set(0, 0, 20); var renderer = new THREE.WebGLRenderer(); renderer.setSize(innerWidth, innerHeight); renderer.setPixelRatio(window.devicePixelRatio); renderer.setClearColor(0xEEEEEE, 1.0); document.body.appendChild(renderer.domElement); var controls = new THREE.OrbitControls(camera, renderer.domElement); var N = 4, verts = [], colors = [], radius = []; verts = [ new THREE.Vector3(0.0, 0.0, -4.0), new THREE.Vector3(-4.0, 0.0, 0.0), new THREE.Vector3(4.0, 0.0, 0.0), new THREE.Vector3(0.0, 0.0, 4.0) ]; colors.push(1.0, 0., 1.0); colors.push(1.0, 0., 1.0); colors.push(0.847, 0.332, 0.347); colors.push(0.457, 0.695, 0.675); for (var i = 0; i < N; i++) { radius.push(0.5); } var pointsGeometry = new THREE.BufferGeometry().setFromPoints(verts); pointsGeometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3)); pointsGeometry.addAttribute("radius", new THREE.BufferAttribute(new Float32Array(radius), 1)); var pointsMaterial = new THREE.ShaderMaterial({ uniforms: { viewport: { value: window.innerHeight * window.devicePixelRatio }, texture: { value: new THREE.TextureLoader().load(circularPoint) }, resolution: { value: [innerWidth * 2, innerHeight * 2] } }, vertexShader: document.getElementById("vertexParticle").textContent, fragmentShader: document.getElementById("fragmentParticle").textContent, transparent: true }) var verts2 = [], colors2 = [], radius2 = []; var dist = new THREE.Vector3(-4.0, 0.0, 0.0).distanceTo(new THREE.Vector3(0.0, 0.0, -4.0)); for (var i = 0; i < 1; i++) { for (var j = i + 1; j < 2; j++) { var dist = verts[i].distanceTo(verts[j]); var nv = new THREE.Vector3(verts[i].x, verts[i].y, verts[i].z); verts2.push(nv.lerp(verts[j], 0.5)); radius2.push(dist / 2.0 + 0.5); } } var jointsGeometry = new THREE.BufferGeometry().setFromPoints(verts2); jointsGeometry.addAttribute("radius", new THREE.BufferAttribute(new Float32Array(radius2), 1)); var jointsMaterial = new THREE.ShaderMaterial({ uniforms: { viewport: { value: innerHeight * devicePixelRatio }, texture: { value: new THREE.TextureLoader().load(circularPoint) }, start: { value: verts[0] }, end: { value: verts[1] }, resolution: { value: [innerWidth * 2, innerHeight * 2] } }, vertexShader: document.getElementById("vertexJoint").textContent, fragmentShader: document.getElementById("fragmentJoint").textContent, transparent: true }) jointsMaterial.extensions.derivatives = true; jointsMaterial.extensions.fragDepth = true; jointsMaterial.extensions.drawBuffers = true; var points = new THREE.Points(pointsGeometry, pointsMaterial); scene.add(points); var joints = new THREE.Points(jointsGeometry, jointsMaterial); scene.add(joints); renderer.setAnimationLoop(function() { renderer.render(scene, camera) });
body { overflow: hidden; margin: 0; }
<html> <head> <meta charset="utf-8"> <title>THREE.JS METABALLS</title> <meta name="description" content="Ehno based on D3.JS | THREE.JS stack."> <meta name="keywords" content="HTML,CSS,CSV,JavaScript,D3.JS,THREE.JS"> <meta name="author" content="Vladimir V. KUCHINOV"> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.min.js"></script> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script> <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> <script type="x-shader/x-vertex" id="vertexParticle"> #define PI 3.141592 attribute float radius; attribute vec3 color; uniform float viewport; varying vec3 vColor; void main() { vColor = color; vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); gl_PointSize = viewport * radius * PI / -mvPosition.z; gl_Position = projectionMatrix * mvPosition; } </script> <script type="x-shader/x-fragment" id="fragmentParticle"> varying vec3 vColor; uniform sampler2D texture; uniform vec2 resolution; void main() { gl_FragColor = vec4(vColor, 1.) * texture2D(texture, gl_PointCoord); if (gl_FragColor.a < 0.1) discard; } </script> <script type="x-shader/x-vertex" id="vertexJoint"> #define PI 3.141592 attribute float radius; uniform float viewport; uniform vec2 resolution; uniform vec3 start; uniform vec3 end; varying vec2 outStart; varying vec2 outEnd; varying vec2 vUv; vec2 projectWorldCoordinates(vec3 in_){ vec4 p = projectionMatrix * modelViewMatrix * vec4(in_.xy, in_.z, 1.0); return p.xy / p.w; } void main() { vUv = uv; outStart = projectWorldCoordinates(start); outEnd = projectWorldCoordinates(end); vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); gl_PointSize = viewport * radius * PI / -mvPosition.z; gl_Position = projectionMatrix * mvPosition; } </script> <script type="x-shader/x-fragment" id="fragmentJoint"> uniform vec2 resolution; varying vec2 outStart; varying vec2 outEnd; varying vec2 vUv; const float threshold = 3.0; const float density = 1000.0; const float norm = 2.0; vec2 startPos; vec2 endPos; float pixelPower; vec2 fragCoord; vec4 mixColor; struct Metaball{ vec2 position; float radius; vec3 color; float power; }; Metaball balls[4]; float Norm(float num_) { return pow(num_, norm); } Metaball setMetaball(vec2 position_, float radius_, vec3 color_){ Metaball m; m.position = position_; m.radius = radius_; m.color = color_; vec2 pixelPosition = fragCoord.xy / resolution.xy; pixelPosition.x = pixelPosition.x * resolution.x / resolution.y; vec2 distanceVector = pixelPosition - position_; distanceVector = vec2(abs(distanceVector.x), abs(distanceVector.y)); float normDistance = Norm(distanceVector.x) + Norm(distanceVector.y); m.power = Norm(radius_) / normDistance; return m; } vec4 drawMetaballs(){ vec4 color = vec4(0.); vec3 val; int powerMeta = 0; float maxPower = 0.0; balls[0] = setMetaball(vec2(0.0, 0.0), 0.2, vec3(0.0, 0.0, 1.0)); balls[1] = setMetaball(startPos, 0.05, vec3(0.0, 0.0, 1.0)); balls[2] = setMetaball(endPos, 0.1, vec3(0.0, 1.0, 0.0)); balls[3] = setMetaball(endPos, 0.05, vec3(0.0, 1.0, 0.0)); for(int i = 0; i < 4; i++){ pixelPower += balls[i].power; if(maxPower < balls[i].power){ maxPower = balls[i].power; powerMeta = i; } balls[i].power *= balls[i].radius; } val = vec3(0.); for(int i = 0; i < 4; i++){ vec2 pixelPosition = fragCoord / resolution.xy; pixelPosition.x = pixelPosition.x * resolution.x / resolution.y; vec2 distanceVector = pixelPosition - balls[i].position; distanceVector = vec2(abs(distanceVector.x), abs(distanceVector.y)); float normDistance = Norm(distanceVector.x) + Norm(distanceVector.y); balls[i].power = Norm(balls[i].radius) / normDistance; val += balls[i].color * (balls[i].power / maxPower); } if(pixelPower < threshold || pixelPower > threshold + Norm(density)) { val = vec3(0.0); } color = vec4(val, 1.0); return color; } float circle( vec2 _st, vec2 _center, float _radius ){ const float thickness = 8.0; float dist = length(_st - _center); return smoothstep(0.0, thickness / 2.0, abs(_radius - dist)); } void main() { vec2 fragCoord = vec2(gl_FragCoord.x, gl_FragCoord.y); vec2 uv = (fragCoord * 2.0 - resolution.xy) / resolution.y; startPos = (outStart.xy * 0.5 + 0.5) * resolution.xy; endPos = (outEnd.xy * 0.5 + 0.5) * resolution.xy; vec4 mb = drawMetaballs(); gl_FragColor = mb; //vec4(1.0 - circle(fragCoord, startPos, 16.0 ) * circle(fragCoord, endPos, 16.0 ) ); } </script> </body> </html>
我有代码试图在诸如Shadertoy草图https://www.shadertoy.com/view/wtd3Wn之类的粒子之间进行元球运动过渡,因此,最后,我需要这样的东西:...] >
将平面版本移植到Three.JS。在上一段代码中仍无法为粒子设置它。蓝色和绿色的粒子应与两个洋红色粒子的位置相同。
<html>
<head>
<meta charset="utf-8">
<title>THREE.JS METABALLS</title>
<meta name="description" content="Ehno based on D3.JS | THREE.JS stack.">
<meta name="keywords" content="HTML,CSS,CSV,JavaScript,D3.JS,THREE.JS">
<meta name="author" content="Vladimir V. KUCHINOV">
<style>
body { overflow: hidden; margin: 0; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<!--
<script src="LineMaterial.js"></script>
<script src="LineSegments2.js"></script>
<script src="LineSegmentsGeometry.js"></script>
<script src="LineGeometry.js"></script>
<script src="Line2.js"></script>
-->
<script type="x-shader/x-vertex" id="vertexParticle">
#define PI 3.141592
attribute float radius;
attribute vec3 color;
uniform float viewport;
varying vec3 vColor;
void main() {
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = viewport * radius * PI / -mvPosition.z;
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentParticle">
varying vec3 vColor;
uniform sampler2D texture;
uniform vec2 resolution;
void main() {
gl_FragColor = vec4(vColor, 1.) * texture2D(texture, gl_PointCoord);
if (gl_FragColor.a < 0.1) discard;
}
</script>
<script type="x-shader/x-vertex" id="vertexJoint">
#define PI 3.141592
attribute float radius;
uniform float viewport;
uniform vec2 resolution;
uniform vec3 start;
uniform vec3 end;
varying vec2 outStart;
varying vec2 outEnd;
varying vec2 vUv;
vec2 projectWorldCoordinates(vec3 in_){
vec4 p = projectionMatrix * modelViewMatrix * vec4(in_.xy, in_.z, 1.0);
return p.xy / p.w;
}
void main() {
vUv = uv;
outStart = projectWorldCoordinates(start);
outEnd = projectWorldCoordinates(end);
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = viewport * radius * PI / -mvPosition.z;
gl_Position = projectionMatrix * mvPosition;
}
</script>
<script type="x-shader/x-fragment" id="fragmentJoint">
uniform vec2 resolution;
uniform float time;
varying vec2 outStart;
varying vec2 outEnd;
varying vec2 vUv;
const float threshold = 3.0;
const float density = 1000.0;
const float norm = 2.0;
vec2 startPos;
vec2 endPos;
float pixelPower;
vec2 fragCoord;
vec4 mixColor;
struct Metaball{
vec2 position;
float radius;
vec4 color;
float power;
};
Metaball balls[4];
float Norm(float num_) { return pow(num_, norm); }
Metaball setMetaball(vec2 position_, float radius_, vec4 color_){
Metaball m;
m.position = position_;
m.radius = radius_;
m.color = color_;
vec2 distanceVector = fragCoord - position_;
distanceVector = vec2(abs(distanceVector.x), abs(distanceVector.y));
float normDistance = Norm(distanceVector.x) + Norm(distanceVector.y);
m.power = Norm(radius_) / normDistance;
return m;
}
vec4 drawMetaballs(){
vec4 val;
int powerMeta = 0;
float maxPower = 0.0;
vec2 p0 = outStart;
vec2 p1 = outEnd;
vec2 d0 = mix(p0, p1, -(sin(time) - 1.0) / 4.);
vec2 d1 = mix(p1, p0, -(sin(time) - 1.0) / 4.);
balls[0] = setMetaball(p0, 0.225, vec4(0.0, 0.0, 1.0, 1.0));
balls[1] = setMetaball(d0, 0.10, vec4(0.0, 0.0, 1.0, 1.0));
balls[2] = setMetaball(p1, 0.225, vec4(0.0, 1.0, 0.0, 1.0));
balls[3] = setMetaball(d1, 0.10, vec4(0.0, 1.0, 0.0, 1.0));
for(int i = 0; i < 4; i++){
pixelPower += balls[i].power;
if(maxPower < balls[i].power){
maxPower = balls[i].power;
powerMeta = i;
}
balls[i].power *= balls[i].radius;
}
val = vec4(0.);
for(int i = 0; i < 4; i++){
vec2 distanceVector = fragCoord - balls[i].position;
distanceVector = vec2(abs(distanceVector.x), abs(distanceVector.y));
float normDistance = Norm(distanceVector.x) + Norm(distanceVector.y);
balls[i].power = Norm(balls[i].radius) / normDistance;
val += balls[i].color * (balls[i].power / maxPower);
}
if(pixelPower < threshold || pixelPower > threshold + Norm(density))
{
val = vec4(0.0);
}
return vec4(val);
}
float circle( vec2 _st, vec2 _center, float _radius ){
const float thickness = 1.0;
float dist = length(_st - _center);
return smoothstep(0.0, thickness / 2.0, abs(_radius - dist));
}
void main() {
fragCoord = -1.0 + 2.0 * gl_PointCoord;
gl_FragColor = vec4(drawMetaballs());
}
</script>
<script>
THREE.TOUCH = {};
var joints, uniforms;
var circularPoint = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="128px" height="128px"><circle cx="64" cy="64" r="62" fill="white" /></svg>';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 200);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0xEEEEEE, 1.0);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var N = 4,
verts = [],
colors = [],
radius = [];
verts = [
new THREE.Vector3(0.0, 0.0, -4.0),
new THREE.Vector3(-4.0, 0.0, 0.0),
new THREE.Vector3(4.0, 0.0, 0.0),
new THREE.Vector3(0.0, 0.0, 4.0)
];
colors.push(1.0, 0., 1.0);
colors.push(1.0, 0., 1.0);
colors.push(0.847, 0.332, 0.347);
colors.push(0.457, 0.695, 0.675);
for (var i = 0; i < N; i++) {
radius.push(0.5);
}
var pointsGeometry = new THREE.BufferGeometry().setFromPoints(verts);
pointsGeometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3));
pointsGeometry.addAttribute("radius", new THREE.BufferAttribute(new Float32Array(radius), 1));
var pointsMaterial = new THREE.ShaderMaterial({
uniforms: {
viewport: {
value: window.innerHeight * window.devicePixelRatio
},
texture: {
value: new THREE.TextureLoader().load(circularPoint)
},
resolution: {
value: [innerWidth * 2, innerHeight * 2]
}
},
vertexShader: document.getElementById("vertexParticle").textContent,
fragmentShader: document.getElementById("fragmentParticle").textContent,
transparent: true
})
var verts2 = [],
colors2 = [],
radius2 = [];
var dist = new THREE.Vector3(-4.0, 0.0, 0.0).distanceTo(new THREE.Vector3(0.0, 0.0, -4.0));
for (var i = 0; i < 1; i++) {
for (var j = i + 1; j < 2; j++) {
var dist = verts[i].distanceTo(verts[j]);
var nv = new THREE.Vector3(verts[i].x, verts[i].y, verts[i].z);
verts2.push(nv.lerp(verts[j], 0.5));
radius2.push(dist / 2.0 + 0.5);
}
}
var jointsGeometry = new THREE.BufferGeometry().setFromPoints(verts2);
jointsGeometry.addAttribute("radius", new THREE.BufferAttribute(new Float32Array(radius2), 1));
uniforms = {
viewport: {
value: innerHeight * devicePixelRatio
},
texture: {
value: new THREE.TextureLoader().load(circularPoint)
},
time: { value: 0.0 },
start: {
value: verts[0]
},
end: {
value: verts[1]
},
resolution: {
value: new THREE.Vector2(window.innerWidth * 2, window.innerHeight * 2)
}
};
var jointsMaterial = new THREE.ShaderMaterial({
uniforms,
vertexShader: document.getElementById("vertexJoint").textContent,
fragmentShader: document.getElementById("fragmentJoint").textContent,
transparent: true
})
jointsMaterial.extensions.derivatives = true;
jointsMaterial.extensions.fragDepth = true;
jointsMaterial.extensions.drawBuffers = true;
var points = new THREE.Points(pointsGeometry, pointsMaterial);
scene.add(points);
joints = new THREE.Points(jointsGeometry, jointsMaterial);
scene.add(joints);
renderer.setAnimationLoop(function(timestamp) {
uniforms[ "time" ].value = timestamp / 1000;
renderer.render(scene, camera)
});
</script>
</body>
</html>
将平面版本移植到Three.JS。在上一段代码中仍无法为粒子设置它。蓝色和绿色的粒子应与两个洋红色粒子的位置相同。