正在寻找有关如何正确执行此操作的指导: 我正在尝试创建一个“平坦”的测地线形状,以便为每个面显示不同的纹理。
这是我要创建的形状(轮廓)(尽管该形状具有“圆形”线,但我认为这对我来说没什么大不了的,只要三角形的比例是好的):
我想做的是动态选择不同的面孔并为其添加纹理。我计划使用THREE.Texture(canvas)
来从其他画布元素上渲染的内容中获取纹理。
所以结果看起来像这样:
在这里,每种颜色都代表我要放入的画布纹理。动态部分是我要控制哪个纹理显示在哪里,并且还可能混合和匹配不同组的三角形(或单个三角形)关联不同的纹理。最终,我也希望画布图像也可以制作动画。
这是到目前为止我尝试过的代码的结果:
我尝试绘制一个多面体(THREE.IcosahedronGeometry
)并使用THREE.OrthographicCamera
进行查看。然后,我遍历这些面并将THREE.MeshBasicMaterial
映射到每个面,并为每个面的材质的color
值应用随机颜色。 (也已经能够渲染画布,但不确定如何控制方向或画布需要显示的哪一部分,该部分暂时被注释掉了)。
这是我的代码:
import * as THREE from 'three';
import * as dat from 'dat.gui';
// Controls using dat.gui
const Settings = function() {
this.z = 0;
this.rotation = 0;
this.viewSize = 900;
};
const gui = new dat.GUI();
const settings = new Settings();
// Control for z position of camera, currently doesn't work
gui.add(settings, 'z', -100, 100).onChange(value => {
camera.position.z = value;
});
// Control for rotation of object
gui.add(settings, 'rotation', 0, 360).onChange(value => {
element.rotation.set(THREE.Math.degToRad(value), 0, 0);
});
// Control for view size, currenly not sure how to update this once value is changed
gui.add(settings, 'viewSize', 0, 2000);
// Container for renderer
const container = document.querySelector('#container');
// Renderer
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(container.clientWidth, container.clientHeight);
const viewSize = 300;
const aspectRatio = container.clientWidth / container.clientHeight;
// Not very confident if I'm setting this camera up 100%, but seems ok
// Camera
const camera = new THREE.OrthographicCamera(
(-aspectRatio * viewSize) / 2, // Camera frustum left plane
(aspectRatio * viewSize) / 2, // Camera frustum right plane
viewSize / 2, // Camera frustum top plane
-viewSize / 2, // Camera frustum bottom plane
-1000, // Camera frustum near plane
1000 // Camera frustum far plane
);
// Scene
const scene = new THREE.Scene();
// Add the camera to the scene
scene.add(camera);
// Append renderer to dom
container.appendChild(renderer.domElement);
// Camera
camera.position.z = settings.z;
// Create a random rgb value
function random_rgb() {
const o = Math.round,
r = Math.random,
s = 255;
return `rgb(${o(r() * s)},${o(r() * s)},${o(r() * s)})`;
}
// Create a texture
const getTexture = i => {
// Canvas
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 100;
const context = canvas.getContext('2d');
// set background color (placeholder where here we'd be drawing something)
context.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
// draws rectangle with background color...
// really should take into account the size and shape of face?
context.fillRect(0, 0, 100, 100);
// Create texture from canvas
const texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
return texture;
};
// Create the icosahedron
const geometry = new THREE.IcosahedronGeometry(viewSize / 2, 2);
// get the UV mapping for each face?
const faceVertexUvs = geometry.faceVertexUvs[0];
// Create a material for each face
const createFaceMaterial = i =>
new THREE.MeshBasicMaterial({
color: new THREE.Color(random_rgb(i)), // just test with a color instead of texture
//map: getTexture(i), // here we'd add the texture from canvas instead of color
wireframe: false,
wireframeLinewidth: 1
});
// Map the materials to each face
let materials = faceVertexUvs.map((vertex, i) => {
geometry.faces[i].materialIndex = i;
return createFaceMaterial(i);
});
/*
Alternate way to map, by using geometry.faces.length
var materials = [];
for (var i = 0; i < geometry.faces.length; i++) {
geometry.faces[i].materialIndex = i;
materials.push(
new THREE.MeshBasicMaterial({
color: new THREE.Color(random_rgb()),
wireframe: false,
wireframeLinewidth: 1
})
);
}
*/
// Create the 3D element (mesh)
const element = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
// Add the element to the scene
scene.add(element);
// Draw!
renderer.render(scene, camera);
// Update/Animate
function update() {
// Draw!
renderer.render(scene, camera);
// Schedule the next frame.
requestAnimationFrame(update);
}
// Schedule the first frame.
requestAnimationFrame(update);
正在寻找有关是否能正确解决此问题的一般反馈,如果不能正确解决,我可以做些什么来改进。
我可以正确绘制此形状吗? (具体来说,是绘制3d对象并指向摄像机,使其像我到目前为止所做的最好的方式那样看起来像2d一样。)
我如何有效地管理选择要纹理化的正确三角形面,以及如何在多个面上使用一个纹理(不重复纹理)?正在使用3d形状渲染2d图像,我不需要在此形状的背面绘制纹理,如何避免这种情况?
奖金:我希望能够变形基础的几何体,例如,更改复杂性或细分面等。到目前为止,我可以将几何体从一帧更改为下一帧,但不确定如何将它们与动画“融合”。
最后,如果我以良好的fps为场景设置动画,关于如何使该表演者有什么建议?