【问题标题】:apply two textures on a plane in Three.js在 Three.js 中的平面上应用两个纹理
【发布时间】:2019-10-09 09:59:41
【问题描述】:

是否可以在一个平面上同时添加两个纹理?还是立方体?

我想在平面的上半部分应用一种纹理,在下半部分应用不同的纹理。

类似这样的:

这是我目前设置的

var geometry = new THREE.PlaneGeometry( 2, 2 );
var loader = new THREE.TextureLoader();
var texture = loader.load( 'textures/stone.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 4, 4 );
var material = new THREE.MeshBasicMaterial( { map: texture } );
var mesh = new THREE.Mesh(geometry, material);

scene.add(mesh);

【问题讨论】:

  • 到目前为止您尝试过什么?你的飞机是怎么定义的?
  • @TheJim01 更新问题

标签: three.js


【解决方案1】:

您需要分割几何体,并使用多种材质。

这意味着您将使用PlaneGeometrywidthSegmentsheightSegments 参数来定义一个具有两个以上面的平面。这是必要的,因为每个面只能有一种材质(除非您正在做一些非常花哨的混合)。

一旦有了分段平面,就可以将每个面的materialIndex 指定为指向单独的材质。

您还将使用一组材质来定义您的网格,而不仅仅是一个 - 每个面的 materialIndex 引用材质数组中的一个索引。

我将留给你做的最后一件事是调整面部 UV 和纹理重复/包裹以达到你想要的效果。

如果您对此主题还有其他问题,请发表评论,我会尽力解决。

// https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js
// https://threejs.org/examples/js/controls/TrackballControls.js

/**********************/
/*   Initialization   */
/**********************/

var renderer = new THREE.WebGLRenderer( {
	canvas: document.getElementById( "view" ),
	antialias: true,
  alpha: true
} );

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera( 28, 1, 1, 1000 );
camera.position.z = 50;

camera.add( new THREE.PointLight( 0xffffff, 1, Infinity ) );

scene.add( camera );

var controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.addEventListener( "change", render );

/**********************/
/* Populate the Scene */
/**********************/

var texLoader = new THREE.TextureLoader();

var tex1 = texLoader.load( "https://upload.wikimedia.org/wikipedia/commons/2/2b/WallRGB.png", render ); // bricks
var tex2 = texLoader.load( "https://upload.wikimedia.org/wikipedia/commons/6/6f/NGC772_-_SDSS_DR14.png", render ); // space

var mat1 = new THREE.MeshLambertMaterial( { map: tex1 } );
var mat2 = new THREE.MeshLambertMaterial( { map: tex2 } );

// First, segment your geometry however you need it.
// This one is segmented into 1 horizontal segment with 2 vertical segments.
var planeGeo = new THREE.PlaneGeometry( 10, 10, 1, 2 );

// Next you need to set up your faces to use specific materials.
planeGeo.faces[ 0 ].materialIndex = 0;
planeGeo.faces[ 1 ].materialIndex = 0;
planeGeo.faces[ 2 ].materialIndex = 1;
planeGeo.faces[ 3 ].materialIndex = 1;

// You can create a mesh using an array of materials, referenced by materialIndex.
var mesh = new THREE.Mesh( planeGeo, [ mat1, mat2 ] );

scene.add( mesh );

/**********************/
/*   Render Function  */
/**********************/

function render () {
	renderer.render( scene, camera );
}
render();

/**********************/
/*   Animation Loop   */
/**********************/

function animate () {
	requestAnimationFrame( animate );
	controls.update();
}
animate();
<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="chrome=1,IE=edge">
	<title>TEST</title>

	<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script>
	<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>

</head>

<body>
	
  <canvas id="view" width="500" height="500" style="border: 1px black solid;"></canvas>

	<script src="test.js"></script>

</body>

</html>

【讨论】:

  • 谢谢!!正是我想要的
  • 能问你点别的吗?这些图块是 75x75 像素。如果我想在较大的瓷砖之间(跨越红线)放置第三个 75x10 像素(相同但短得多)的瓷砖怎么办。这可能吗?
  • @MatíasCánepa 首先,您不能将其视为“像素”。 GL 测量是无单位的,尽管它们都使用相同的单位。最后,您可以计算像素大小,但最好不要这样想。
  • @MatíasCánepa 关于添加第三个“行”,PlaneGeometry 将其行/列均匀细分。这意味着在 3 路拆分中,每行将是总高度的 33%。您可以深入了解planeGeo.vertices 并更改它们的位置以更好地适应您想要的效果,但请记住无单位性质。如果tex1 的高度为 100px,tex2 的高度为 75px,则tex2 行的面应组成为tex1 行面高度的 75%。这有意义吗?
  • @pailhead 你的观点是正确的,因为三个网格在概念上比操纵几何更容易。不过,它可能不符合马蒂亚斯的想法。我想不出任何理由将这个概念分成多个网格,但我没有假设,而是从表面上看待这个问题。
【解决方案2】:

补充@TheJim01 的回答,下面的代码将调整地板几何体上的 UV 坐标,以便它们平铺:

var tileSize = 24;
var textureSize = 256;
var floorScale = tileSize/textureSize;
floorGeometry.faceVertexUvs.forEach(layer => layer.forEach((face, i) => {
    const base = layer[i % 2];
    if (i % 2) {
        face[0].x = 0;
        face[0].y = floorScale;
        face[1].x = floorScale;
        face[1].y = floorScale;
        face[2].x = floorScale;
        face[2].y = 0;  
    } else {
        face[0].x = 0;
        face[0].y = 0;          
        face[1].x = 0;
        face[1].y = floorScale;
        face[2].x = floorScale;
        face[2].y = 0;
    }
}));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 2014-04-02
    • 2017-05-17
    • 2014-11-15
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多