据我所知,ECMAscript 6类语法只是先前使用的原型继承模式的语法糖,但是我对如何扩展Three.js Mesh对象与类语法一起使用感到困惑。
此刻,我有一个基于原型模式的工作类:
function GFAElement(params) {
//
var p = params.split("-");
var userData = {
type: "GFA",
flights: parseInt(p[0]),
pitch: parseInt(p[1]),
length: parseInt(p[2])
};
var shape = getProfile();
var extrudeSettings = {
steps: 5*userData.length,
depth: userData.length,
bevelEnabled: false
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
} );
THREE.Mesh.call( this, geometry, material );
this.geometry.vertices.forEach( vertex => {
var angle = 2*Math.PI/userData.flights*vertex.z/userData.pitch;
var updateX = vertex.x * Math.cos(angle) - vertex.y * Math.sin(angle);
var updateY = vertex.y * Math.cos(angle) + vertex.x * Math.sin(angle);
vertex.x = updateX;
vertex.y = updateY;
});
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
this.type = 'GFAElement';
this.userData = userData;
}
GFAElement.prototype = Object.create( THREE.Mesh.prototype );
GFAElement.prototype.constructor = GFAElement;
我已经尝试将其转换为类语法:
class GFAElement extends THREE.Mesh {
constructor(params){
super();
this.type = 'GFAElement';
var p = params.split("-");
this.userData.type = "GFA",
this.userData.flights = parseInt(p[0]);
this.userData.pitch = parseInt(p[1]);
this.userData.length = parseInt(p[2]);
this.generate();
}
generate(){
var shape = getProfile();
var extrudeSettings = {
steps: 5*this.userData.length,
depth: this.userData.length,
bevelEnabled: false
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
} );
THREE.Mesh.call( this, geometry, material );
this.geometry.vertices.forEach( vertex => {
var angle = 2*Math.PI/this.userData.flights*vertex.z/this.userData.pitch;
var updateX = vertex.x * Math.cos(angle) - vertex.y * Math.sin(angle);
var updateY = vertex.y * Math.cos(angle) + vertex.x * Math.sin(angle);
vertex.x = updateX;
vertex.y = updateY;
});
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
}
这给我一个错误:
three.min.js:11 Uncaught TypeError: Cannot redefine property: id
我认为这是extends THREE.Mesh
和THREE.Mesh.call( this, geometry, material );
不兼容的结果,但是我无法纠正这种不兼容。
这使我有一个主要问题,我该如何将上述原型模式转换为类语法?
'use strict';
var container;
var camera, scene, renderer, controls;
var screw, mirror;
// Screw parameters
var P = 2; // number of flights
var D = 50, // outer diameter
Dr = D/1.66, // root diameter
Cl = (Dr+D)/2, // centerline distance
αi = 2*Math.acos(Cl/D),
Ih = D*Math.sin(αi/2)/2,
H = D-Cl;
var αf = αi,
αt = Math.PI/P - αf,
αr = αt;
//console.log(D, Dr, Cl, Ih, H);
//console.log(αi, αf, αt, αr);
function getFlankParams(α1, D1, α2, D2, ctr){
// flanks are arcs with origin (xc, yc) of radius Cl passing through (x1, y1) and (x2, y2):
// (x1-xc)^2 + (y1-yc)^2 = Cl^2
// (x2-xc)^2 + (y2-yc)^2 = Cl^2
var x1 = D1*Math.cos(α1),
y1 = D1*Math.sin(α1),
x2 = D2*Math.cos(α2),
y2 = D2*Math.sin(α2);
// Solving system of equations yields linear eq:
// y1-yc = beta - alpha*(x1-xc)
var alpha = (x1-x2)/(y1-y2),
beta = (y1-y2)*(1+Math.pow(alpha,2))/2;
// Substitution and applying quadratic equation:
var xc = x1 - alpha*beta/(1+Math.pow(alpha,2))*(1+Math.pow(-1,ctr)*Math.sqrt(1-(1-Math.pow(Cl/beta,2))*(1+1/Math.pow(alpha,2)))),
yc = y1 + alpha*(x1-xc) - beta;
// Following from law of consines, the angle the flank extends wrt its own origin:
var asq = Math.pow(Dr/2,2)+Math.pow(D/2,2)-2*(Dr/2)*(D/2)*Math.cos(αf),
af = Math.acos(1-asq/Math.pow(Cl, 2)/2);
var params = {xc: xc, yc: yc, af: af};
return params;
}
function getProfile() {
var shape = new THREE.Shape();
var angle = 0, ctr = 0;
// loop over number of flights
for (var p=0; p<P; p++){
// tip
shape.absarc(0, 0, D/2, angle, angle+αt);
angle += αt;
// flank
var params = getFlankParams(angle, D/2, angle+αf, Dr/2, ctr++);
shape.absarc(params.xc, params.yc, Cl, angle+αf-params.af, angle+αf, false);
angle += αf;
// root
shape.absarc(0, 0, Dr/2, angle, angle+αr);
angle += αr;
// flank
params = getFlankParams(angle, Dr/2, angle+αf, D/2, ctr++);
shape.absarc(params.xc, params.yc, Cl, angle, angle+αf-params.af, false);
angle += αf;
}
return shape;
}
function GFAElement(params) {
//
var p = params.split("-");
var userData = {
type: "GFA",
flights: parseInt(p[0]),
pitch: parseInt(p[1]),
length: parseInt(p[2])
};
var shape = getProfile();
var extrudeSettings = {
steps: 5*userData.length,
depth: userData.length,
bevelEnabled: false
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
} );
THREE.Mesh.call( this, geometry, material );
this.geometry.vertices.forEach( vertex => {
var angle = 2*Math.PI/userData.flights*vertex.z/userData.pitch;
var updateX = vertex.x * Math.cos(angle) - vertex.y * Math.sin(angle);
var updateY = vertex.y * Math.cos(angle) + vertex.x * Math.sin(angle);
vertex.x = updateX;
vertex.y = updateY;
});
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
this.type = 'GFAElement';
this.userData = userData;
}
GFAElement.prototype = Object.create( THREE.Mesh.prototype );
GFAElement.prototype.constructor = GFAElement;
//GFAElement.prototype.getMesh = function() {return this.mesh;}
class NewGFAElement extends THREE.Mesh {
constructor(params){
super();
this.type = 'GFAElement';
var p = params.split("-");
this.userData.type = "GFA",
this.userData.flights = parseInt(p[0]);
this.userData.pitch = parseInt(p[1]);
this.userData.length = parseInt(p[2]);
this.generate();
}
generate(){
var shape = getProfile();
var extrudeSettings = {
steps: 5*this.userData.length,
depth: this.userData.length,
bevelEnabled: false
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
} );
THREE.Mesh.call( this, geometry, material );
this.geometry.vertices.forEach( vertex => {
var angle = 2*Math.PI/this.userData.flights*vertex.z/this.userData.pitch;
var updateX = vertex.x * Math.cos(angle) - vertex.y * Math.sin(angle);
var updateY = vertex.y * Math.cos(angle) + vertex.x * Math.sin(angle);
vertex.x = updateX;
vertex.y = updateY;
});
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
}
class KBElement extends THREE.Group {
//
constructor(params){
super();
this.type = 'KBElement';
var p = params.split("-");
this.userData.type = "KB";
this.userData.thickness = parseInt(p[0]);
this.userData.flights = parseInt(p[1]);
this.userData.length = parseInt(p[2]);
this.userData.stagAngle = parseInt(p[3]);
this.generate();
}
generate(){
var shape = getProfile();
var extrudeSettings = {
depth: this.userData.thickness,
bevelEnabled: false
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
} );
var mesh = new THREE.Mesh( geometry, material );
super.add( mesh );
for (var n=1, nt = this.userData.length/this.userData.thickness; n<nt; n++){
mesh = mesh.clone();
mesh.position.z += this.userData.thickness;
mesh.rotation.z += this.userData.stagAngle;
super.add( mesh );
}
}
}
class Screw extends THREE.Group {
//
constructor(){
super();
}
add(desc){
var elem;
var params = desc.split(" ");
if (params[0] == "GFA") {
elem = new NewGFAElement(params[1]);
} else
if (params[0] == "KB") {
elem = new KBElement(params[1]);
}
super.add(elem);
}
}
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
//renderer.gammaInput = true;
//renderer.gammaOutput = true;
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x222222 );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 200, 200, 200 );
scene.add( camera );
var light = new THREE.PointLight( 0xffffff );
camera.add( light );
controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.minDistance = 100;
controls.maxDistance = 500;
screw = new Screw();
screw.add('GFA 2-40-90');
//screw.add('KB 5-2-30-90');
//var mirror = screw.mirror();
//scene.add(screw, mirror);
scene.add(screw);
console.log(screw);
}
function animate() {
//group.rotation.z -= 2*Math.PI/100;
//mirror.rotation.z -= 2*Math.PI/100;
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}
init();
animate();
body {
font-family: Monospace;
background-color: #222;
margin: 0px;
overflow: hidden;
}
a {
color: #f80;
}
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
答案 0 :(得分:1)
在访问super()
的构造函数中的this
引用之前,必须确保调用GFAElement
。因此,首先创建几何图形和材料,然后像这样调用super
:
super( geometry, material );
以下小提琴在基于您的代码的完整示例中展示了该方法: