响应式设计
1.使用css使canvas填充页面
- 调整画布大小
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
- 如果尺寸没变最好不要设置相同大小。
- render.setSize第三个参数传入false,可以看下面的代码,内部默认会设置canvas的css属性。
if ( updateStyle !== false ) {
_canvas.style.width = width + 'px';
_canvas.style.height = height + 'px';
}
- HD-DPI显示器
renderer.setPixelRatio(window.devicePixelRatio);
解决方法1调用setPixelRatio设置设备像素比。通常用于避免HiDPI设备上绘图模糊。
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const pixelRatio = window.devicePixelRatio;
const width = canvas.clientWidth * pixelRatio | 0;
const height = canvas.clientHeight * pixelRatio | 0;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
解决方法2自己处理。
第二种方式更好,因为可以知道绘图缓冲区的确切尺寸。
图元
-
Geometry
和BufferGeometry
对比
基于BufferGeometry
的图元是面向性能的类型。几何体的顶点是直接生成为一个高效的类型数组形式,可以被上传到GPU进行渲染。意味着更快的启动,占用更少的内存。但如果想修改数据就需要复杂的编程。
基于Geometry
的图元更灵活、更易修改。 它们根据 JavaScript 的类而来。它们需要更多的内存,在被渲染前,Three.js 会将它们转换成相应的BufferGeometry
。
import * as THREE from "../three";
const canvas = document.querySelector("#canvas");
const renderer = new THREE.WebGLRenderer({ canvas });
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xaaaaaa);
const fov = 40;
const aspect = 2;
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 120;
{
const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
{
const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(1, -2, -4);
scene.add(light);
}
const objects = [];
const spread = 15;
function addObject(x, y, obj) {
obj.position.x = x * spread;
obj.position.y = y * spread;
scene.add(obj);
objects.push(obj);
}
function createMaterial() {
const material = new THREE.MeshPhongMaterial({
side: THREE.DoubleSide,
});
// 0-1 红色0 绿色.33 蓝色.66
const hue = Math.random();
// 0-1 没有颜色0 饱和度最高1
const saturation = 1;
// 0-1 黑色0 白色1 最大数量颜色0.5
// luminance 从0到0.5 表示颜色从黑到hue,从0.5到1.0表示颜色从hue到白。
const luminance = 0.5;
material.color.setHSL(hue, saturation, luminance);
return material;
}
function addSolidGeometry(x, y, geometry) {
const mesh = new THREE.Mesh(geometry, createMaterial());
addObject(x, y, mesh);
}
function addLineGeometry(x, y, geometry) {
const material = new THREE.LineBasicMaterial({ color: 0x000000 });
const mesh = new THREE.LineSegments(geometry, material);
addObject(x, y, mesh);
}
{
const width = 8;
const height = 8;
const depth = 8;
addSolidGeometry(-2, 2, new THREE.BoxGeometry(width, height, depth));
}
{
const radius = 7;
const segments = 24;
addSolidGeometry(-1, 2, new THREE.CircleGeometry(radius, segments));
}
{
const radius = 6;
const height = 8;
const segments = 16;
addSolidGeometry(0, 2, new THREE.ConeGeometry(radius, height, segments));
}
{
const radiusTop = 4;
const radiusBottom = 4;
const height = 8;
const radialSegments = 12;
addSolidGeometry(
1,
2,
new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radialSegments)
);
}
{
const radius = 7;
addSolidGeometry(2, 2, new THREE.DodecahedronGeometry(radius));
}
{
const shape = new THREE.Shape();
const x = -2.5;
const y = -5;
shape.moveTo(x + 2.5, y + 2.5);
shape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
const extrudeSettings = {
steps: 2,
depth: 2,
bevelEnabled: true,
bevelThickness: 1,
bevelSize: 1,
bevelSegments: 2,
};
addSolidGeometry(-2, 1, new THREE.ExtrudeGeometry(shape, extrudeSettings));
}
{
const radius = 7;
addSolidGeometry(-1, 1, new THREE.IcosahedronGeometry(radius));
}
{
const points = [];
for (let i = 0; i < 10; ++i) {
points.push(new THREE.Vector2(Math.sin(i * 0.2) * 3 + 3, (i - 5) * 0.8));
}
addSolidGeometry(0, 1, new THREE.LatheGeometry(points));
}
{
const radius = 7;
addSolidGeometry(1, 1, new THREE.OctahedronGeometry(radius));
}
{
function klein(v, u, target) {
u *= Math.PI;
v *= 2 * Math.PI;
u = u * 2;
let x;
let z;
if (u < Math.PI) {
x =
3 * Math.cos(u) * (1 + Math.sin(u)) +
2 * (1 - Math.cos(u) / 2) * Math.cos(u) * Math.cos(v);
z =
-8 * Math.sin(u) -
2 * (1 - Math.cos(u) / 2) * Math.sin(u) * Math.cos(v);
} else {
x =
3 * Math.cos(u) * (1 + Math.sin(u)) +
2 * (1 - Math.cos(u) / 2) * Math.cos(v + Math.PI);
z = -8 * Math.sin(u);
}
const y = -2 * (1 - Math.cos(u) / 2) * Math.sin(v);
target.set(x, y, z).multiplyScalar(0.75);
}
const slices = 25;
const stacks = 25;
addSolidGeometry(2, 1, new THREE.ParametricGeometry(klein, slices, stacks));
}
{
const width = 9;
const height = 9;
const widthSegments = 2;
const heightSegments = 2;
addSolidGeometry(
-2,
0,
new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)
);
}
{
const verticesOfCube = [
-1,
-1,
-1,
1,
-1,
-1,
1,
1,
-1,
-1,
1,
-1,
-1,
-1,
1,
1,
-1,
1,
1,
1,
1,
-1,
1,
1,
];
const indicesOfFaces = [
2,
1,
0,
0,
3,
2,
0,
4,
7,
7,
3,
0,
0,
1,
5,
5,
4,
0,
1,
2,
6,
6,
5,
1,
2,
3,
7,
7,
6,
2,
4,
5,
6,
6,
7,
4,
];
const radius = 7;
const detail = 2;
addSolidGeometry(
-1,
0,
new THREE.PolyhedronGeometry(verticesOfCube, indicesOfFaces, radius, detail)
);
}
{
const innerRadius = 2;
const outerRadius = 7;
const segments = 18;
addSolidGeometry(
0,
0,
new THREE.RingGeometry(innerRadius, outerRadius, segments)
);
}
{
const shape = new THREE.Shape();
const x = -2.5;
const y = -5;
shape.moveTo(x + 2.5, y + 2.5);
shape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
addSolidGeometry(1, 0, new THREE.ShapeGeometry(shape));
}
{
const radius = 7;
const widthSegments = 12;
const heightSegments = 8;
addSolidGeometry(
2,
0,
new THREE.SphereGeometry(radius, widthSegments, heightSegments)
);
}
{
const radius = 7;
addSolidGeometry(-2, -1, new THREE.TetrahedronGeometry(radius));
}
{
const radius = 5;
const tubeRadius = 2;
const radialSegments = 8;
const tubularSegments = 24;
addSolidGeometry(
0,
-1,
new THREE.TorusGeometry(radius, tubeRadius, radialSegments, tubularSegments)
);
}
{
const radius = 3.5;
const tube = 1.5;
const radialSegments = 8;
const tubularSegments = 64;
const p = 2;
const q = 3;
addSolidGeometry(
1,
-1,
new THREE.TorusKnotGeometry(
radius,
tube,
tubularSegments,
radialSegments,
p,
q
)
);
}
{
class CustomSinCurve extends THREE.Curve {
constructor(scale) {
super();
this.scale = scale;
}
getPoint(t) {
const tx = t * 3 - 1.5;
const ty = Math.sin(2 * Math.PI * t);
const tz = 0;
return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
}
}
const path = new CustomSinCurve(4);
const tubularSegments = 20;
const radius = 1;
const radialSegments = 8;
const closed = false;
addSolidGeometry(
2,
-1,
new THREE.TubeGeometry(
path,
tubularSegments,
radius,
radialSegments,
closed
)
);
}
{
const width = 8;
const height = 8;
const depth = 8;
const thresholdAngle = 15;
addLineGeometry(
-1,
-2,
new THREE.EdgesGeometry(
new THREE.BoxGeometry(width, height, depth),
thresholdAngle
)
);
}
{
const width = 8;
const height = 8;
const depth = 8;
addLineGeometry(
1,
-2,
new THREE.WireframeGeometry(new THREE.BoxGeometry(width, height, depth))
);
}
{
const radius = 7;
const widthSegments = 12;
const heightSegments = 8;
const geometry = new THREE.SphereGeometry(
radius,
widthSegments,
heightSegments
);
const material = new THREE.PointsMaterial({
color: "red",
size: 0.2, // in world units
});
const points = new THREE.Points(geometry, material);
scene.add(points);
points.position.set(-15, -15, 0);
objects.push(points);
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj, index) => {
const speed = 0.1 + index * 0.05;
const rot = time * speed;
obj.rotation.x = rot;
obj.rotation.y = rot;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);