[THREE.JS Metaballs动画在片段着色器处

问题描述 投票:1回答:1

我有要在诸如Shadertoy素描https://www.shadertoy.com/view/wtd3Wn之类的粒子之间进行元球运动转换的代码,>

所以,最后,我需要这样的东西:

enter image description here最终,还必须对其进行动画处理。

为此,我创建了另一个着色器[Joint],其宽度/高度等于粒子之间的距离,并且已经确定了它们的位置,因此如果您调用,则>]

gl_FragColor = vec4(1.0-circle(fragCoord,startPos,16.0)* circle(fragCoord,endPos,16.0));

它将在其位置上画圆。

enter image description here

但是当我尝试绘制元球时,我一无所有。

enter image description here

非常确定我在执行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 glsl shader fragment-shader
1个回答
1
投票

将平面版本移植到Three.JS。在上一段代码中仍无法为粒子设置它。蓝色和绿色的粒子应与两个洋红色粒子的位置相同。

© www.soinside.com 2019 - 2024. All rights reserved.