如何解决ThreeJs:无法在顶部和底部加载不同的图像
我试图在 Threejs 中使用纹理在顶部和底部放置不同的图像。 但我在底部和顶部得到相同的图像。 下面是我正在使用的代码。我的需求是在 ThreeJs 中使用纹理在两侧显示不同的图像。
注意: 1. 在我的代码中,我使用了 ThreeJs 版本(r125),这是必要的我不能使用旧版本。
<html lang="en">
<head>
<title>three.js webgl - geometry - shapes</title>
<Meta charset="utf-8">
<Meta name="viewport" content="width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
background-color: #f0f0f0;
color: #444;
}
</style>
</head>
<body>
<div id="info">texture on shapes</div>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r125/build/three.module.js';
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r125/examples/jsm/controls/OrbitControls.js";
let container;
let camera,scene,renderer;
let group;
let windowHalfX = window.innerWidth / 2;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xbbbbbb);
camera = new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,1,1000);
camera.position.set(0,-150,-300);
scene.add(camera);
const light = new THREE.PointLight(0xffffff,0.8);
camera.add(light);
group = new THREE.Group();
group.rotation.y = Math.PI;
scene.add(group);
const helper = new THREE.GridHelper(500,10);
helper.rotation.x = Math.PI / 2;
group.add(helper);
const rectWidth = 120;
const rectHeight = 200;
const rectangleShape = new THREE.Shape()
.moveto(0,0)
.lineto(0,rectHeight)
.lineto(rectWidth,0);
const extrudeSettings = { depth: 10,bevelEnabled: true,bevelSegments: 2,steps: 1,bevelSize: 1,bevelThickness: 1 };
const geometry = new THREE.ExtrudeGeometry(rectangleShape,extrudeSettings);
var textureLoader1 = new THREE.TextureLoader();
var topTexture = textureLoader1.load("https://threejsfundamentals.org/threejs/resources/images/tree-01.png"); // Top side Image
topTexture.repeat.set(1 / rectWidth,1 / rectHeight);
var textureLoader2 = new THREE.TextureLoader();
var bottomTexture = textureLoader2.load("https://threejsfundamentals.org/threejs/resources/images/tree-02.png"); // Bottom side Image
bottomTexture.repeat.set(1 / rectWidth,1 / rectHeight);
var frontMaterial = new THREE.MeshphongMaterial({ map: topTexture,side: THREE.FrontSide });
var backMaterial = new THREE.MeshphongMaterial({ map: bottomTexture,side: THREE.BackSide });
var sideMaterial = new THREE.MeshphongMaterial({ color: 0xD9D934 });
var materials = [frontMaterial,sideMaterial,backMaterial];
var material = new THREE.MeshFaceMaterial(materials);
let mesh = new THREE.Mesh(geometry,material);
mesh.position.set(-60,-100,0);
// Edited but faces not found
for (var face in mesh.geometry.faces) {
if (mesh.geometry.faces[face].normal.z < -0.9) {
mesh.geometry.faces[face].materialIndex = 5;
}
}
group.add(mesh);
renderer = new THREE.Webglrenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth,window.innerHeight);
container.appendChild(renderer.domElement);
const controls = new OrbitControls(camera,renderer.domElement);
controls.target.set(0,0);
controls.update();
window.addEventListener('resize',onWindowResize);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene,camera);
}
</script>
</body>
</html>
解决方法
ExtrudeGeometry 上的材料无法按照您期望的方式工作。引用 documentation for ExtrudeGeometry
在使用此几何体创建网格时,如果您希望将单独的材料用于其面和挤出的侧面,您可以使用一系列材料。第一种材料将应用于面部;第二种材料将应用于两侧。
如果需要,您可以添加第三种材质,然后通过手动更改该面的材质索引将其设置在其中一个面上。但据我所知,没有办法通过构造函数自动执行此操作。
编辑:更正我自己,我相信您不能再这样做(更改单个面的材质索引),因为 ExtrudeGeometry 的实现方式发生了变化。相反,我相信您现在必须使用单个纹理并创建 UV 贴图。
您的代码已更新为使用 UV 贴图,该贴图使用一张图像的上半部分作为 ExtrudeGeometry 顶面的纹理,将下半部分用作底面。这是通过定义自定义 UV 生成器并将其添加到传递给 ExtrudeGeometry 的配置来完成的。 UV 生成器提供两种方法:generateTopUV() 和 generateSideWallUV()。后者与 THREE 提供的默认值相同。另一种是对几何体的顶部和底部进行 UV 映射。
请注意,这是一个非常不可移植的 kludge,针对这个特定问题的几何进行了硬编码。
<html lang="en">
<head>
<title>three.js webgl - geometry - shapes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
background-color: #f0f0f0;
color: #444;
}
</style>
</head>
<body>
<div id="info">texture on shapes</div>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r125/build/three.module.js';
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r125/examples/jsm/controls/OrbitControls.js";
let container;
let camera,scene,renderer;
let group;
let windowHalfX = window.innerWidth / 2;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xbbbbbb);
camera = new THREE.PerspectiveCamera(50,window.innerWidth / window.innerHeight,1,1000);
camera.position.set(0,-150,-300);
scene.add(camera);
const light = new THREE.PointLight(0xffffff,0.8);
camera.add(light);
group = new THREE.Group();
group.rotation.y = Math.PI;
scene.add(group);
const helper = new THREE.GridHelper(500,10);
helper.rotation.x = Math.PI / 2;
group.add(helper);
const rectWidth = 120;
const rectHeight = 200;
const rectangleShape = new THREE.Shape()
.moveTo(0,0)
.lineTo(0,rectHeight)
.lineTo(rectWidth,0);
const uvGenerator = {
generateTopUV: function(geometry,vertices,indexA,indexB,indexC) {
const ax = vertices[indexA * 3];
const ay = vertices[indexA * 3 + 1];
const az = vertices[indexA * 3 + 2];
const bx = vertices[indexB * 3];
const by = vertices[indexB * 3 + 1];
const bz = vertices[indexB * 3 + 2];
const cx = vertices[indexC * 3];
const cy = vertices[indexC * 3 + 1];
const cz = vertices[indexC * 3 + 2];
if(indexA > 3) {
return([
new THREE.Vector2(ax,ay / 2),new THREE.Vector2(bx,by / 2),new THREE.Vector2(cx,cy / 2),]);
} else {
return([
new THREE.Vector2(ax,(ay / 2) + rectHeight / 2),(by / 2) + rectHeight / 2),(cy / 2) + rectHeight / 2),]);
}
},generateSideWallUV: function(geometry,indexC,indexD) {
const ax = vertices[indexA * 3];
const ay = vertices[indexA * 3 + 1];
const az = vertices[indexA * 3 + 2];
const bx = vertices[indexB * 3];
const by = vertices[indexB * 3 + 1];
const bz = vertices[indexB * 3 + 2];
const cx = vertices[indexC * 3];
const cy = vertices[indexC * 3 + 1];
const cz = vertices[indexC * 3 + 2];
const dx = vertices[indexD * 3];
const dy = vertices[indexD * 3 + 1];
const dz = vertices[indexD * 3 + 2];
if(Math.abs(ay - by) < 0.01) {
return([
new THREE.Vector2(ax,1 - az),1 - bz),1 - cz),new THREE.Vector2(dx,1 - dz),]);
} else {
return([
new THREE.Vector2(ay,new THREE.Vector2(by,new THREE.Vector2(cy,new THREE.Vector2(dy,};
const extrudeSettings = { depth: 10,bevelEnabled: true,bevelSegments: 2,steps: 1,bevelSize: 1,bevelThickness: 1,UVGenerator: uvGenerator };
const geometry = new THREE.ExtrudeGeometry(rectangleShape,extrudeSettings);
var textureLoader1 = new THREE.TextureLoader();
var topTexture = textureLoader1.load("https://threejsfundamentals.org/threejs/resources/images/tree-01.png"); // Top side Image
topTexture.repeat.set(1 / rectWidth,1 / rectHeight);
var frontMaterial = new THREE.MeshPhongMaterial({ map: topTexture,side: THREE.FrontSide });
var sideMaterial = new THREE.MeshPhongMaterial({ color: 0xD9D934 });
var materials = [frontMaterial,sideMaterial];
var material = new THREE.MeshFaceMaterial(materials);
let mesh = new THREE.Mesh(geometry,material);
mesh.position.set(-60,-100,0);
group.add(mesh);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth,window.innerHeight);
container.appendChild(renderer.domElement);
const controls = new OrbitControls(camera,renderer.domElement);
controls.target.set(0,0);
controls.update();
window.addEventListener('resize',onWindowResize);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene,camera);
}
</script>
</body>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。