Threejs如何在形状的脸上使用不同的纹理?

时间:2019-02-19 05:54:06

标签: javascript three.js

正在寻找有关如何正确执行此操作的指导: 我正在尝试创建一个“平坦”的测地线形状,以便为每个面显示不同的纹理。

这是我要创建的形状(轮廓)(尽管该形状具有“圆形”线,但我认为这对我来说没什么大不了的,只要三角形的比例是好的):

Here is the shape (outline) I'd like to create:

我想做的是动态选择不同的面孔并为其添加纹理。我计划使用THREE.Texture(canvas)来从其他画布元素上渲染的内容中获取纹理。

所以结果看起来像这样:

enter image description here

在这里,每种颜色都代表我要放入的画布纹理。动态部分是我要控制哪个纹理显示在哪里,并且还可能混合和匹配不同组的三角形(或单个三角形)关联不同的纹理。最终,我也希望画布图像也可以制作动画。

这是到目前为止我尝试过的代码的结果:

enter image description here

我尝试绘制一个多面体(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);
  1. 正在寻找有关是否能正确解决此问题的一般反馈,如果不能正确解决,我可以做些什么来改进。

  2. 我可以正确绘制此形状吗? (具体来说,是绘制3d对象并指向摄像机,使其像我到目前为止所做的最好的方式那样看起来像2d一样。)

  3. 我如何有效地管理选择要纹理化的正确三角形面,以及如何在多个面上使用一个纹理(不重复纹理)?正在使用3d形状渲染2d图像,我不需要在此形状的背面绘制纹理,如何避免这种情况?

  4. 奖金:我希望能够变形基础的几何体,例如,更改复杂性或细分面等。到目前为止,我可以将几何体从一帧更改为下一帧,但不确定如何将它们与动画“融合”。

  5. 最后,如果我以良好的fps为场景设置动画,关于如何使该表演者有什么建议?

0 个答案:

没有答案