1.图像去锯齿
利用{antialias: true}
能有效缓解
this.renderer = new this.THREE.WebGLRenderer({
antialias: true})
2.引用路径不当
引用路径不当会导致一些奇怪的错误,在threejs中所有的加载的引用都要用绝对路径,资源放在静态文件夹下。
3.缩放问题
缩放scale
注意不能是0。
如下的函数相当于Math.floor()
,但是该函数在~~(0.5)
返回的就是0,需要注意。
rand:function(min,max){
return ~~(Math.random()*(max-min+1)+min)
}
4.材料颜色问题
通常我们使用的是Hex
的颜色,但是我想要很多个粉红的爱心,但是爱心的颜色又要有不同,这样我们最好是用HSL
,我们这里只需要改变一些l
的值就可以得到很多类似的颜色。
// svg是利用爱心svg图像拉伸而成的Three.Mesh对象
// this.heartNum是指爱心的数量
for (let i = 0; i < this.heartNum; i++) {
let heart = svg.clone()
let svgMaterial = new this.THREE.MeshPhongMaterial({
shininess:60
});
heart.material = svgMaterial
let color = new this.THREE.Color(0xFFBBFF) // 粉色
let hsl= {
}
color.getHSL(hsl)
heart.material.color.setHSL(hsl.h,hsl.s,this.rand(0.6,1)*hsl.l)
this.scene.add(heart)
}
说明:threejs
中的网格物体对材质的是引用传递,不是值传递,如果material
被 mesh1
和mesh2
用到了,改变 mesh1.material.color
,则mesh2
的材质颜色也改了,所以这里我们给每一个mesh
一个material
效果
3.transformSVGPathExposed以及ThreeBSP对应的js文件
transformSVGPathExposed
将svg图像转化成three.shape
对象
ThreeBSP
图像的一些处理
其中用到了coffee语法,将其转化成js可以参考,http://coffee-script.org/
(一)transformSVGPathExposed涉及的js文件
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
var THREE = require('three')
var transformSVGPathExposed;
var applySVGTransformExposed;
function d3threeD(exports) {
const DEGS_TO_RADS = Math.PI / 180,
UNIT_SIZE = 1;
const DIGIT_0 = 48,
DIGIT_9 = 57,
COMMA = 44,
SPACE = 32,
PERIOD = 46,
MINUS = 45;
function transformSVGPath(pathStr) {
var paths = [];
var path = new THREE.Shape();
var idx = 1,
len = pathStr.length,
activeCmd,
x = 0,
y = 0,
nx = 0,
ny = 0,
firstX = null,
firstY = null,
x1 = 0,
x2 = 0,
y1 = 0,
y2 = 0,
rx = 0,
ry = 0,
xar = 0,
laf = 0,
sf = 0,
cx, cy;
function eatNum() {
var sidx, c, isFloat = false,
s;
// eat delims
while (idx < len) {
c = pathStr.charCodeAt(idx);
if (c !== COMMA && c !== SPACE)
break;
idx++;
}
if (c === MINUS)
sidx = idx++;
else
sidx = idx;
// eat number
while (idx < len) {
c = pathStr.charCodeAt(idx);
if (DIGIT_0 <= c && c <= DIGIT_9) {
idx++;
continue;
} else if (c === PERIOD) {
idx++;
isFloat = true;
continue;
}
s = pathStr.substring(sidx, idx);
return isFloat ? parseFloat(s) : parseInt(s);
}
s = pathStr.substring(sidx);
return isFloat ? parseFloat(s) : parseInt(s);
}
function nextIsNum() {
var c;
// do permanently eat any delims...
while (idx < len) {
c = pathStr.charCodeAt(idx);
if (c !== COMMA && c !== SPACE)
break;
idx++;
}
c = pathStr.charCodeAt(idx);
return (c === MINUS || (DIGIT_0 <= c && c <= DIGIT_9));
}
var canRepeat;
var enteredSub = false;
var zSeen = false;
activeCmd = pathStr[0];
while (idx <= len) {
canRepeat = true;
switch (activeCmd) {
// moveto commands, become lineto's if repeated
case 'M':
enteredSub = false;
x = eatNum();
y = eatNum();
path.moveTo(x, y);
activeCmd = 'L';
break;
case 'm':
x += eatNum();
y += eatNum();
path.moveTo(x, y);
activeCmd = 'l';
break;
case 'Z':
case 'z':
// z is a special case. This ends a segment and starts
// a new path. Since the three.js path is continuous
// we should start a new path here. This also draws a
// line from the current location to the start location.
canRepeat = false;
if (x !== firstX || y !== firstY)
path.lineTo(firstX, firstY);
paths.push(path);
// reset the elements
firstX = null;
firstY = null;
// avoid x,y being set incorrectly
enteredSub = true;
path = new THREE.Shape();
zSeen = true;
break;
// - lines!
case 'L':
case 'H':
case 'V':
nx = (activeCmd === 'V') ? x : eatNum();
ny = (activeCmd === 'H') ? y : eatNum();
path.lineTo(nx, ny);
x = nx;
y = ny;
break;
case 'l':
case 'h':
case 'v':
nx = (activeCmd === 'v') ? x : (x + eatNum());
ny = (activeCmd === 'h') ? y : (y + eatNum());
path.lineTo(nx, ny);
x = nx;
y = ny;
break;
// - cubic bezier
case 'C':
x1 = eatNum();
y1 = eatNum();
case 'S':
if (activeCmd === 'S') {
x1 = 2 * x - x2;
y1 = 2 * y - y2;
}
x2 = eatNum();
y2 = eatNum();
nx = eatNum();
ny = eatNum();
path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
x = nx;
y = ny;
break;
case 'c':
x1 = x + eatNum();
y1 = y + eatNum();
case 's':
if (activeCmd === 's') {
x1 = 2 * x - x2;
y1 = 2 * y - y2;
}
x2 = x + eatNum();
y2 = y + eatNum();
nx = x + eatNum();
ny = y + eatNum();
path.bezierCurveTo(x1, y1, x2, y2, nx, ny);
x = nx;
y = ny;
break;
// - quadratic bezier
case 'Q':
x1 = eatNum();
y1 = eatNum();
case 'T':
if (activeCmd === 'T') {
x1 = 2 * x - x1;
y1 = 2 * y - y1;
}
nx = eatNum();
ny = eatNum();
path.quadraticCurveTo(x1, y1, nx, ny);
x = nx;
y = ny;
break;
case 'q':
x1 = x + eatNum();
y1 = y + eatNum();
case 't':
if (activeCmd === 't') {
x1 = 2 * x - x1;
y1 = 2 * y - y1;
}
nx = x + eatNum();
ny = y + eatNum();
path.quadraticCurveTo(x1, y1, nx, ny);
x = nx;
y = ny;
break;
// - elliptical arc
case 'A':
rx = eatNum();
ry = eatNum();
xar = eatNum() * DEGS_TO_RADS;
laf = eatNum();
sf = eatNum();
nx = eatNum();
ny = eatNum();
if (rx !== ry) {
console.warn("Forcing elliptical arc to be a circular one :(",
rx, ry);
}
// SVG implementation notes does all the math for us! woo!
// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
// step1, using x1 as x1'
x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2;
y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2;
// step 2, using x2 as cx'
var norm = Math.sqrt(
(rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) /
(rx * rx * y1 * y1 + ry * ry * x1 * x1));
if (laf === sf)
norm = -norm;
x2 = norm * rx * y1 / ry;
y2 = norm * -ry * x1 / rx;
// step 3
cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2;
cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2;
var u = new THREE.Vector2(1, 0),
v = new THREE.Vector2((x1 - x2) / rx,
(y1 - y2) / ry);
var startAng = Math.acos(u.dot(v) / u.length() / v.length());
if (u.x * v.y - u.y * v.x < 0)
startAng = -startAng;
// we can reuse 'v' from start angle as our 'u' for delta angle
u.x = (-x1 - x2) / rx;
u.y = (-y1 - y2) / ry;
var deltaAng = Math.acos(v.dot(u) / v.length() / u.length());
// This normalization ends up making our curves fail to triangulate...
if (v.x * u.y - v.y * u.x < 0)
deltaAng = -deltaAng;
if (!sf && deltaAng > 0)
deltaAng -= Math.PI * 2;
if (sf && deltaAng < 0)
deltaAng += Math.PI * 2;
path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf);
x = nx;
y = ny;
break;
case ' ':
// if it's an empty space, just skip it, and see if we can find a real command
break;
default:
break;
}
if (firstX === null && !enteredSub) {
firstX = x;
firstY = y;
}
// just reissue the command
if (canRepeat && nextIsNum())
continue;
activeCmd = pathStr[idx++];
}
if (zSeen) {
return paths;
} else {
paths.push(path);
return paths;
}
}
transformSVGPathExposed = transformSVGPath;
function applySVGTransform(obj, tstr) {
var idx = tstr.indexOf('('),
len = tstr.length,
cmd = tstr.substring(0, idx++);
function eatNum() {
var sidx, c, isFloat = false,
s;
// eat delims
while (idx < len) {
c = tstr