最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Simulate air flowing through a pipe in Three.js - Stack Overflow

programmeradmin1浏览0评论

I'm trying to make the direction flow and air flow like this example: /

As I can see there's only the texture is moving

I don't understand how to make the air flowing to correct direction on the pipe and surface like that.

Any idea is much appreciated!

(I'm thinking they might use some uv unwrap technique bine with animate the UV offset of texture)

I'm trying to make the direction flow and air flow like this example: https://animagraffs./supercharger-vs-turbo/

As I can see there's only the texture is moving

I don't understand how to make the air flowing to correct direction on the pipe and surface like that.

Any idea is much appreciated!

(I'm thinking they might use some uv unwrap technique bine with animate the UV offset of texture)

Share Improve this question edited Apr 16, 2017 at 3:19 user128511 asked Apr 15, 2017 at 23:32 Ben MackBen Mack 4992 gold badges7 silver badges32 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 10

It looks like you can just adjust a texture's UV offset

texture.offset.x = someAnimatedValue;
texture.offset.y = someAnimatedValue;

As for making the pipe itself, pretty much any 3d modeling package (blender, maya, 3d studio max, etc...) will let you extrude a line along a path. So to make the pipe you make a circle and then extrude it along the path. Similarly you can put a wall/fence down the center of a pipe by extruding a line down the same curve. The default UV coordinates will be correct for scrolling.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);

const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);

// make a texture with an arrow
const ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = 64;
ctx.canvas.height = 64;

ctx.fillStyle = "rgba(0,0,255,0.5)";
ctx.fillRect(0, 0, 64, 64);

ctx.translate(32, 32);
ctx.rotate(Math.PI * .5);
ctx.fillStyle = "rgb(0,255,255)";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "48px sans-serif";
ctx.fillText("➡︎", 0, 0);

const texture = new THREE.CanvasTexture(ctx.canvas);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.x = 4;
texture.repeat.y = 9;

const radiusTop = 1;
const radiusBottom = 1;
const height = 5;
const radiusSegments = 20;
const heightSegments = 2;
const openEnded = true;
const geometry = new THREE.CylinderBufferGeometry( 
  radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded);
const material = new THREE.MeshBasicMaterial({
   map: texture,
   side: THREE.DoubleSide,
   depthWrite: false,
   depthTest: false,
   transparent: true,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
mesh.rotation.z = Math.PI * .5;

function render(time) {
  time *= 0.001;
  
  resize();
  
  const cameraSpeed = time * 0.3;
  const cameraRadius = 5;
  camera.position.x = Math.cos(cameraSpeed) * cameraRadius;
  camera.position.y = 1;
  camera.position.z = Math.sin(cameraSpeed) * cameraRadius;
  camera.lookAt(mesh.position);
	
  texture.offset.y = (time * 3 % 1);
  
  renderer.render(scene, camera);
	requestAnimationFrame(render);
}
requestAnimationFrame(render);

function resize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare./ajax/libs/three.js/84/three.min.js"></script>

Note that looking at the original diagram I'd stay they aren't animating a pipe, they are animating a strip that's inside the pipe at has an arrow texture being scrolled on it. So, in you modeling package, after creating the pipes extrude a line down the path.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);

const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);

// make a texture with an arrow
const ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = 64;
ctx.canvas.height = 64;

ctx.translate(32, 32);
ctx.rotate(Math.PI * .5);
ctx.fillStyle = "rgb(0,255,255)";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "48px sans-serif";
ctx.fillText("➡︎", 0, 0);

const texture = new THREE.CanvasTexture(ctx.canvas);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.x = 1;
texture.repeat.y = 5;

const radiusTop = 1;
const radiusBottom = 1;
const height = 5;
const radiusSegments = 20;
const heightSegments = 2;
const openEnded = true;
const geometry = new THREE.CylinderBufferGeometry( 
  radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded);
const material = new THREE.MeshBasicMaterial({
   color: 0x4040FF,
   opacity: 0.5,
   side: THREE.DoubleSide,
   depthWrite: false,
   depthTest: false,
   transparent: true,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
mesh.rotation.z = Math.PI * .5;

const stripGeo = new THREE.PlaneBufferGeometry(radiusTop * 1.7, height);
const stripMat = new THREE.MeshBasicMaterial({
   map: texture,
   opacity: 0.5,
   side: THREE.DoubleSide,
   depthWrite: false,
   depthTest: false,
   transparent: true,
});
const stripMesh = new THREE.Mesh(stripGeo, stripMat);
scene.add(stripMesh);
stripMesh.rotation.z = Math.PI * .5;

function render(time) {
  time *= 0.001;
  
  resize();
  
  const cameraSpeed = time * 0.3;
  const cameraRadius = 5;
  camera.position.x = Math.cos(cameraSpeed) * cameraRadius;
  camera.position.y = 1;
  camera.position.z = Math.sin(cameraSpeed) * cameraRadius;
  camera.lookAt(mesh.position);
	
  texture.offset.y = (time * 3 % 1);
  
  renderer.render(scene, camera);
	requestAnimationFrame(render);
}
requestAnimationFrame(render);

function resize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://cdnjs.cloudflare./ajax/libs/three.js/84/three.min.js"></script>

PS: I'm too lazy to deal with the sorting issues but dealing with that should be a separate quesiton

发布评论

评论列表(0)

  1. 暂无评论