用Threejs画一个完美的圆环。参考Threejs Demo里 webgl_geometry_shapes.html 的代码写了测试程序 如下
const arcShape = new THREE.Shape()
.moveTo( 0, 0 )
.absarc( 0, 0, 40, 0, Math.PI * 2, false );
const holePath = new THREE.Path()
.moveTo( 0, 0 )
.absarc( 0, 0, 30, 0, Math.PI * 2, true );
arcShape.holes.push( holePath );
let geometry = new THREE.ShapeGeometry( arcShape );
let mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, color: '#00ff00' } ) );
scene.add( mesh );
圆环是有了,可惜圆环有明显的棱角,不太完美啊。很自然的想到absarc函数是否有类似CircleGeometry类构造时的segments参数把圆多分点三角形出来那不就圆滑了吗。
可惜Curve→CurvePath→Path→Shape 看了个遍都没找到类似的函数,不过看到Shape类extractPoints函数有个divisions参数。感觉找点了什么。赶紧测试代码写起来······
let arr = new THREE.Shape().absarc( 0, 0, 40, 0, Math.PI * 2 ).extractPoints(360),
arrh = new THREE.Shape().absarc( 0, 0, 30, 0, Math.PI * 2 ).extractPoints(360),
sp = new THREE.Shape( arr.shape ),
ph = new THREE.Path( arrh.shape );
sp.holes.push( ph );
let geometry = new THREE.ShapeGeometry( sp );
let mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, color: '#00ff00' } ) );
scene.add( mesh );
运行后结果
结果,感觉挺完美了。
完整代码
demo.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>canvas</title>
<style>
html, body {
width:100%;
height:100%;
}
body {
overflow:hidden;
padding:0px;
margin:0px;
}
</style>
<script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script>
<script type="importmap">
{
"imports": {
"three": "/js/threejs/build/three.module.js",
"three/addons/": "/js/threejs/examples/jsm/"
}
}
</script>
<script type="module">
import * as Initer from '/js/InitThree.module.js';
import * as THREE from 'three';
$(document).ready(function() {
Initer.Init( {
Stats : true,
AxesHelper : 0,
orbitCtrl : true,
cameraX : 0,
cameraY : 0,
cameraZ : 300
} );
let arr = new THREE.Shape().absarc( 0, 0, 40, 0, Math.PI * 2 ).extractPoints(360),
arrh = new THREE.Shape().absarc( 0, 0, 30, 0, Math.PI * 2 ).extractPoints(360),
sp = new THREE.Shape( arr.shape ),
ph = new THREE.Path( arrh.shape );
sp.holes.push( ph );
let geometry = new THREE.ShapeGeometry( sp );
let mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { side: THREE.DoubleSide, color: '#00ff00' } ) );
scene.add( mesh );
});
</script>
</head>
<body>
</body>
</html>
InitThree.module.js
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
let scene, camera, renderer, light, axes, updateFnc, deltaT=0, stats = null, obctrl = null;
function animate( timestamp ) {
if( deltaT == 0 ) {
deltaT = timestamp;
}
if( updateFnc ) {
updateFnc( timestamp - deltaT );
deltaT = timestamp;
}
renderer.render( scene, camera );
if( stats ) {
stats.update();
}
requestAnimationFrame( animate );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function Init( _params ) {
let Params = _params || {};
Params.alphaValue = Params.alphaValue || 1;
Params.bgColor = typeof( Params.bgColor ) != 'undefined' ? Params.bgColor : 0x333;
Params.cameraX = typeof( Params.cameraX ) != 'undefined' ? Params.cameraX : 100;
Params.cameraY = typeof( Params.cameraY ) != 'undefined' ? Params.cameraY : 100;
Params.cameraZ = typeof( Params.cameraZ ) != 'undefined' ? Params.cameraZ : 100;
Params.Stats = Params.Stats || false;
Params.AxesHelper = Params.AxesHelper || false;
updateFnc = _params.updateFnc || null;
Params.orbitCtrl = _params.orbitCtrl || null;
if( typeof( updateFnc ) != "function" ) {
updateFnc = null;
}
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 10000);
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer:true,
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearAlpha( Params.alphaValue );
renderer.setClearColor( Params.bgColor );
document.body.appendChild(renderer.domElement);
light = new THREE.AmbientLight(0xFFFFFF, 1.5);
scene.add(light);
if( Params.AxesHelper ) {
axes = new THREE.AxesHelper(1000);
axes.setColors( new THREE.Color( 0xff0000 ),
new THREE.Color( 0xffff00 ),
new THREE.Color( 0x0000ff ) );
scene.add(axes);
}
if( Params.Stats ) {
stats = new Stats();
document.body.appendChild( stats.dom );
}
window.addEventListener( 'resize', onWindowResize );
if( Params.orbitCtrl ) {
obctrl = new OrbitControls( camera, renderer.domElement );
}
camera.position.x = Params.cameraX;
camera.position.y = Params.cameraY;
camera.position.z = Params.cameraZ;
window.scene = scene;
window.camera = camera;
requestAnimationFrame( animate );
}
export { Init }