代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html lang="en">
<head>
<title>Verge3D webgl - geometry - spline extrusion</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
background-color: #f0f0f0;
color: #444;
}
a {
color: #08f;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="https://www.soft8soft.com/verge3d" target="_blank" rel="noopener">Verge3D</a> - spline extrusion examples<br/>
by <a href="http://www.lab4games.net/zz85/blog" target="_blank" rel="noopener">zz85</a>
</div>
<script type="module">
import * as v3d from '../build/v3d.module.js';
import Stats from './jsm/libs/stats.module.js';
import { GUI } from './jsm/libs/dat.gui.module.js';
import { Curves } from './jsm/curves/CurveExtras.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
let container, stats;
let camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
const direction = new v3d.Vector3();
const binormal = new v3d.Vector3();
const normal = new v3d.Vector3();
const position = new v3d.Vector3();
const lookAt = new v3d.Vector3();
const pipeSpline = new v3d.CatmullRomCurve3([
new v3d.Vector3(0, 10, - 10), new v3d.Vector3(10, 0, - 10),
new v3d.Vector3(20, 0, 0), new v3d.Vector3(30, 0, 10),
new v3d.Vector3(30, 0, 20), new v3d.Vector3(20, 0, 30),
new v3d.Vector3(10, 0, 30), new v3d.Vector3(0, 0, 30),
new v3d.Vector3(- 10, 10, 30), new v3d.Vector3(- 10, 20, 30),
new v3d.Vector3(0, 30, 30), new v3d.Vector3(10, 30, 30),
new v3d.Vector3(20, 30, 15), new v3d.Vector3(10, 30, 10),
new v3d.Vector3(0, 30, 10), new v3d.Vector3(- 10, 20, 10),
new v3d.Vector3(- 10, 10, 10), new v3d.Vector3(0, 0, 10),
new v3d.Vector3(10, - 10, 10), new v3d.Vector3(20, - 15, 10),
new v3d.Vector3(30, - 15, 10), new v3d.Vector3(40, - 15, 10),
new v3d.Vector3(50, - 15, 10), new v3d.Vector3(60, 0, 10),
new v3d.Vector3(70, 0, 0), new v3d.Vector3(80, 0, 0),
new v3d.Vector3(90, 0, 0), new v3d.Vector3(100, 0, 0)
]);
const sampleClosedSpline = new v3d.CatmullRomCurve3([
new v3d.Vector3(0, - 40, - 40),
new v3d.Vector3(0, 40, - 40),
new v3d.Vector3(0, 140, - 40),
new v3d.Vector3(0, 40, 40),
new v3d.Vector3(0, - 40, 40)
]);
sampleClosedSpline.curveType = 'catmullrom';
sampleClosedSpline.closed = true;
// Keep a dictionary of Curve instances
const splines = {
GrannyKnot: new Curves.GrannyKnot(),
HeartCurve: new Curves.HeartCurve(3.5),
VivianiCurve: new Curves.VivianiCurve(70),
KnotCurve: new Curves.KnotCurve(),
HelixCurve: new Curves.HelixCurve(),
TrefoilKnot: new Curves.TrefoilKnot(),
TorusKnot: new Curves.TorusKnot(20),
CinquefoilKnot: new Curves.CinquefoilKnot(20),
TrefoilPolynomialKnot: new Curves.TrefoilPolynomialKnot(14),
FigureEightPolynomialKnot: new Curves.FigureEightPolynomialKnot(),
DecoratedTorusKnot4a: new Curves.DecoratedTorusKnot4a(),
DecoratedTorusKnot4b: new Curves.DecoratedTorusKnot4b(),
DecoratedTorusKnot5a: new Curves.DecoratedTorusKnot5a(),
DecoratedTorusKnot5c: new Curves.DecoratedTorusKnot5c(),
PipeSpline: pipeSpline,
SampleClosedSpline: sampleClosedSpline
};
let parent, tubeGeometry, mesh;
const params = {
spline: 'GrannyKnot',
scale: 4,
extrusionSegments: 100,
radiusSegments: 3,
closed: true,
animationView: false,
lookAhead: false,
cameraHelper: false,
};
const material = new v3d.MeshLambertMaterial({ color: 0xff00ff });
const wireframeMaterial = new v3d.MeshBasicMaterial({ color: 0x000000, opacity: 0.3, wireframe: true, transparent: true });
function addTube() {
if (mesh !== undefined) {
parent.remove(mesh);
mesh.geometry.dispose();
}
const extrudePath = splines[params.spline];
tubeGeometry = new v3d.TubeBufferGeometry(extrudePath, params.extrusionSegments, 2, params.radiusSegments, params.closed);
addGeometry(tubeGeometry);
setScale();
}
function setScale() {
mesh.scale.set(params.scale, params.scale, params.scale);
}
function addGeometry(geometry) {
// 3D shape
mesh = new v3d.Mesh(geometry, material);
const wireframe = new v3d.Mesh(geometry, wireframeMaterial);
mesh.add(wireframe);
parent.add(mesh);
}
function animateCamera() {
cameraHelper.visible = params.cameraHelper;
cameraEye.visible = params.cameraHelper;
}
init();
animate();
function init() {
container = document.getElementById('container');
// camera
camera = new v3d.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10000);
camera.position.set(0, 50, 500);
// scene
scene = new v3d.Scene();
scene.background = new v3d.Color(0xf0f0f0);
// light
const light = new v3d.DirectionalLight(0xffffff);
light.position.set(0, 0, 1);
scene.add(light);
// tube
parent = new v3d.Object3D();
scene.add(parent);
splineCamera = new v3d.PerspectiveCamera(84, window.innerWidth / window.innerHeight, 0.01, 1000);
parent.add(splineCamera);
cameraHelper = new v3d.CameraHelper(splineCamera);
scene.add(cameraHelper);
addTube();
// debug camera
cameraEye = new v3d.Mesh(new v3d.SphereBufferGeometry(5), new v3d.MeshBasicMaterial({ color: 0xdddddd }));
parent.add(cameraEye);
cameraHelper.visible = params.cameraHelper;
cameraEye.visible = params.cameraHelper;
// renderer
renderer = new v3d.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
// stats
stats = new Stats();
container.appendChild(stats.dom);
// dat.GUI
const gui = new GUI({ width: 300 });
const folderGeometry = gui.addFolder('Geometry');
folderGeometry.add(params, 'spline', Object.keys(splines)).onChange(function() {
addTube();
});
folderGeometry.add(params, 'scale', 2, 10).step(2).onChange(function() {
setScale();
});
folderGeometry.add(params, 'extrusionSegments', 50, 500).step(50).onChange(function() {
addTube();
});
folderGeometry.add(params, 'radiusSegments', 2, 12).step(1).onChange(function() {
addTube();
});
folderGeometry.add(params, 'closed').onChange(function() {
addTube();
});
folderGeometry.open();
const folderCamera = gui.addFolder('Camera');
folderCamera.add(params, 'animationView').onChange(function() {
animateCamera();
});
folderCamera.add(params, 'lookAhead').onChange(function() {
animateCamera();
});
folderCamera.add(params, 'cameraHelper').onChange(function() {
animateCamera();
});
folderCamera.open();
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 100;
controls.maxDistance = 2000;
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
// animate camera along spline
const time = Date.now();
const looptime = 20 * 1000;
const t = (time % looptime) / looptime;
tubeGeometry.parameters.path.getPointAt(t, position);
position.multiplyScalar(params.scale);
// interpolation
const segments = tubeGeometry.tangents.length;
const pickt = t * segments;
const pick = Math.floor(pickt);
const pickNext = (pick + 1) % segments;
binormal.subVectors(tubeGeometry.binormals[pickNext], tubeGeometry.binormals[pick]);
binormal.multiplyScalar(pickt - pick).add(tubeGeometry.binormals[pick]);
tubeGeometry.parameters.path.getTangentAt(t, direction);
const offset = 15;
normal.copy(binormal).cross(direction);
// we move on a offset on its binormal
position.add(normal.clone().multiplyScalar(offset));
splineCamera.position.copy(position);
cameraEye.position.copy(position);
// using arclength for stablization in look ahead
tubeGeometry.parameters.path.getPointAt((t + 30 / tubeGeometry.parameters.path.getLength()) % 1, lookAt);
lookAt.multiplyScalar(params.scale);
// camera orientation 2 - up orientation via normal
if (!params.lookAhead) lookAt.copy(position).add(direction);
splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
splineCamera.quaternion.setFromRotationMatrix(splineCamera.matrix);
cameraHelper.update();
renderer.render(scene, params.animationView === true ? splineCamera : camera);
}
</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。