使用 Three.js,我尝试在挤压屋顶面上正确对齐木瓦纹理。对于每个屋顶面,我都有一个平面上的 Vector3 位置列表。我将位置捕捉到平面并将位置转换为 Vector2。然后,我构建一个 Shape 并使用 ExtrudeGeometry 为屋顶面提供一定的深度。然后我使用这个拉伸几何体创建一个网格。然后我重新定位网格以匹配原始 Vector3 位置。然后我将木瓦纹理应用到挤压网格上。不幸的是,木瓦纹理未对齐。它应该与地面水平对齐(就像屋顶上的实际木瓦一样)。相反,纹理在每个拉伸网格上似乎具有不同的对齐方式。如何纠正纹理的对齐方式?另外,有没有更简单的方法来完成这一切?
这是我的代码:
import * as THREE from "https://threejs.org/build/three.module.js";
import { OrbitControls } from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
// Initialize variables.
var camera, scene, renderer;
// Construct a first facet.
const facetA = {
constant: 91.61580281251129,
normal: new THREE.Vector3(0.295196273024157, -0.7734475261474146, 0.5609260955679382),
positions: [
new THREE.Vector3(-0.43264564724512017, 0.39861787856381, -10.811021142221584),
new THREE.Vector3(-0.3603916879324139, 0.62325788852944, -10.672222577778967),
new THREE.Vector3(-3.438495501227518, 3.90763891140433, -4.443674443873537),
new THREE.Vector3(-4.468878632744621, 3.4661899184247, -4.521952858193468),
new THREE.Vector3(-6.261958684067886, 3.4661899184247, -3.5885344644729096),
new THREE.Vector3(-11.501336764455012, 0.39861787856381, -5.0490252538672)
]
};
// Construct a second facet.
const facetB = {
constant: 102.2695562384374,
normal: new THREE.Vector3(0.47299246405089335, -0.8710230296599417, 0.13265372498758107),
positions: [
new THREE.Vector3(-11.501336764455012, 0.39861787856381, -5.0490252538672),
new THREE.Vector3(-6.261958684067886, 3.4661899184247, -3.5885344644729096),
new THREE.Vector3(-11.90307662122538, 0.39861787856381, -3.616574527141971)
]
};
// Construct a facet list.
const facets = [facetA, facetB];
// Initialize the scene.
init();
// Begin the animation.
animate();
// Initializes the scene.
function init() {
// Construct a scene.
scene = new THREE.Scene();
// Construct a camera.
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(-20, 5, -5);
scene.add(camera);
// Construct an axes helper.
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// Construct facet meshes.
const count = facets.length;
for(var index = 0; index < count; index++) {
const facet = facets[index];
const mesh = getMesh(facet);
scene.add(mesh);
}
// Construct a renderer.
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Construct orbit controls.
const controls = new OrbitControls( camera, renderer.domElement );
controls.update();
}
// Animates the scene.
function animate() {
// Request an animation frame.
requestAnimationFrame(animate);
// Render the scene.
render();
}
// Renders the scene.
function render() {
// Render the scene.
renderer.render(scene, camera);
}
// Gets a mesh representing a facet.
function getMesh(facet) {
// Get the facet's constant.
const constant = facet.constant;
// Get the facet's normal.
const normal = facet.normal;
// Get the facet's plane.
const plane = new THREE.Plane(normal, constant);
// Get the facet's positions.
const positions = facet.positions;
// Load a texture.
//const texture = new THREE.TextureLoader().load("https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/uv_grid_opengl.jpg");
const texture = new THREE.TextureLoader().load("https://dl.dropboxusercontent.com/s/nckrp8ydlaietr8/shingles.jpg");
// Scale the texture.
texture.repeat.set(0.2, 0.2);
// Wrap the texture.
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
// Construct a material.
const material = new THREE.MeshBasicMaterial({map: texture});
// Get an extruded mesh.
const mesh = getExtrudedMesh(plane, positions, material);
// Return the mesh.
return mesh;
}
// Gets an extruded mesh.
function getExtrudedMesh(plane, positions, material) {
// Get a shape representing the facet.
const shape = getShape(plane, positions);
// Construct geometry.
const geometry = new THREE.ExtrudeGeometry(shape, {depth: 0.2, bevelEnabled: false});
// Construct an origin.
const origin = new THREE.Vector3(0, 0, 0);
// Get the plane's normal.
const normal = plane.normal;
// Construct an x-axis vector.
const axisX = new THREE.Vector3(1, 0, 0);
// Construct an orientation matrix to offset pivot.
const orientation = new THREE.Matrix4();
// Construct a matrix to fix the pivot rotation.
const offsetRotation = new THREE.Matrix4();
// Construct a matrix to fix the pivot position.
const offsetPosition = new THREE.Matrix4();
// Look at the destination.
orientation.lookAt(origin, normal, axisX);
// Rotate 90 degrees around z axis.
offsetRotation.makeRotationZ(Math.PI / 2);
// Combine orientation and rotation.
orientation.multiply(offsetRotation);
// Rotate the geometry.
geometry.applyMatrix4(orientation);
// Construct a mesh.
const mesh = new THREE.Mesh(geometry, material);
// Get the first position.
const firstPosition = positions[0];
// Position the mesh.
mesh.position.set(firstPosition.x, firstPosition.y, firstPosition.z);
// Return the mesh.
return mesh;
}
// Snaps 3D points to a plane and returns the resulting 2D shape.
function getShape(plane, inputPositions) {
// Construct a shape.
const shape = new THREE.Shape();
// Convert the positions to 2D.
const outputPositions = toVector2(plane, inputPositions);
// Count the positions.
const count = outputPositions.length;
// For each position...
for(var index = 0; index < count; index++) {
// Get the current position.
const outputPosition = outputPositions[index];
// Get the position's coordinates.
const x = outputPosition.x;
const y = outputPosition.y;
// Add the position to the shape
shape.lineTo(x, y);
}
// Return the shape.
return shape;
}
// Snaps 3D points to a plane and returns the resulting 2D points.
function toVector2(plane, inputPositions) {
// Get the first position.
const positionA = inputPositions[0];
// Construct a second position above the first.
const positionB = positionA.clone();
positionB.x += 1;
// Snap the positions to the plane.
const p1 = new THREE.Vector3();
const p2 = new THREE.Vector3();
plane.projectPoint(positionA, p1);
plane.projectPoint(positionB, p2);
// Get normal vector to plane.
const normal = plane.normal;
// Get new x-axis in the plane.
const axisX = (new THREE.Vector3().subVectors(p2, p1)).normalize();
// Get the new z-axis.
const axisZ = normal;
// Get new y-axis in the plane.
const axisY = (new THREE.Vector3().crossVectors(axisX, axisZ)).normalize();
// Get new origin in the plane.
const origin = p1;
// Initialize an output position list.
const outputPositions = new Array();
// Count the positions.
const positionCount = inputPositions.length;
// For each position...
for(var positionIndex = 0; positionIndex < positionCount; positionIndex++) {
// Get the current input position.
const inputPosition = inputPositions[positionIndex];
// Construct an output position.
const outputPosition = new THREE.Vector2();
// Set the output position's coordinates.
outputPosition.x = (new THREE.Vector3().subVectors(inputPosition, origin)).dot(axisX);
outputPosition.y = (new THREE.Vector3().subVectors(inputPosition, origin)).dot(axisY);
// Add the output position to the list.
outputPositions.push(outputPosition);
}
// Return the output positions.
return outputPositions;
}
这是一个 JSFiddle:
https://jsfiddle.net/rmibert/2aw47Lj1/41/
这是显示两个屋顶面上未对齐的木瓦的屏幕截图:
这个问题你解决了吗?是怎么解决的