【发布时间】:2018-06-19 00:51:45
【问题描述】:
我为我的应用程序重新创建了一个包模型并将其作为 .obj 导出到 ThreeJs:
我已经为模型几何中的每个面分配了不同的颜色,如下所示:
var geometry = new THREE.Geometry().fromBufferGeometry( bagMesh.children[0].geometry );
for (var i = 0; i < geometry.faces.length; i ++ ) {
var face = geometry.faces[i];
// 7 & 8 = front side
// can we flip its normal?
if(i === 7 || i === 8) {
face.color.setHex( 0xff0000 );
} else {
face.color.setHex( Math.random() * 0xffffff );
}
}
geometry.translate( 0, -1, 0.75);
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors, side: THREE.DoubleSide }) );
scene.add(mesh);
我已经在 faces 数组的索引 7 和 8 处识别出正面的面,并将它们变为红色。
问题是当我看包里面时也可以看到这种颜色:
我意识到这是因为我已将对象设置为 THREE.DoubleSide,但如果我将其更改为 THREE.FrontSide,则侧面仅部分可见。
所以我的问题是如何为每一面分配不同的独特颜色(全部 11 种,也包括内部),而该颜色不会出现在相对的那一边?
我试图通过仅使用颜色而不是将图像映射到其上来使事情变得简单,这是我最终想要实现的。
注意 - 我之前的模型通过将每一面视为单独的网格解决了这个问题,但这会导致其他问题,例如 z 隐藏和闪烁问题。
谢谢
编辑
@WestLangley 我设置了一个小提琴来演示您在评论中添加的内容。假设我做对了它并没有达到预期的效果:
(function onLoad() {
var canvasElement;
var width, height;
var scene, camera;
var renderer;
var controls;
var pivot;
var bagMesh;
var planeMesh;
const objLoader = new THREE.OBJLoader2();
const fileLoader = new THREE.FileLoader();
init();
function init() {
container = document.getElementById('container');
initScene();
addGridHelper();
addCamera();
addLighting();
addRenderer();
addOrbitControls();
loadPlaneObj();
// Logic
var update = function() {};
// Draw scene
var render = function() {
renderer.render(scene, camera);
};
// Run game logic (update, render, repeat)
var gameLoop = function() {
requestAnimationFrame(gameLoop);
update();
render();
};
gameLoop();
}
/**** Basic Scene Setup ****/
function initScene() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xd3d3d3);
var axis = new THREE.AxesHelper();
scene.add(axis);
}
function addCamera() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(3,3,3);
scene.add(camera);
}
function addGridHelper() {
var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
planeGeometry.rotateX(-Math.PI / 2);
var planeMaterial = new THREE.ShadowMaterial({
opacity: 0.2
});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.y = -200;
plane.receiveShadow = true;
scene.add(plane);
var helper = new THREE.GridHelper(2000, 100);
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper();
scene.add(axis);
}
// *********** Lighting settings **********************
function addLighting() {
var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
scene.add(light);
}
// ************** Material settings **************
function setMaterial(materialName) {
// get the object from the scene
var bagMesh = scene.getObjectByName('bag');
var material;
if (!materialName) {
materialName = materials.material;
}
if (bagMesh) {
var colour = parseInt(materials.colour);
switch (materialName) {
case 'MeshBasicMaterial':
material = new THREE.MeshBasicMaterial({
color: colour
});
break;
case 'MeshDepthMaterial':
material = new THREE.MeshDepthMaterial();
break;
case 'MeshLambertMaterial':
material = new THREE.MeshLambertMaterial({
color: colour
});
break;
case 'MeshNormalMaterial':
material = new THREE.MeshNormalMaterial();
break;
case 'MeshPhongMaterial':
material = new THREE.MeshPhongMaterial({
color: colour
});
break;
case 'MeshPhysicalMaterial':
material = new THREE.MeshPhysicalMaterial({
color: colour
});
break;
case 'MeshStandardMaterial':
material = new THREE.MeshStandardMaterial({
color: colour
});
break;
case 'MeshToonMaterial':
material = new THREE.MeshToonMaterial({
color: colour
});
break;
}
bagMesh.children.forEach(function(c) {
c.material = material;
});
}
}
function setMaterialColour(colour) {
materials.colour = colour;
setMaterial(null);
}
// ************** End of materials ***************
function addRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
}
function addOrbitControls() {
var controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function addPivot() {
var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
var cubeMat = new THREE.MeshBasicMaterial();
pivot = new THREE.Mesh(cubeGeo, cubeMat);
bagMesh.position.x -= 15;
bagMesh.position.z -= 55;
pivot.add(bagMesh);
pivot.add(handle);
scene.add(pivot);
}
function loadPlaneObj() {
loadObj('Plane', 'https://rawgit.com/Katana24/threejs-experimentation/master/models/Plane.obj', 'https://rawgit.com/Katana24/threejs-experimentation/master/models/Plane.mtl', addPlaneToSceneSOAnswer);
}
function loadObj(objName, objUrl, mtlUrl, onLoadFunc) {
var onLoadMtl = function(materials) {
objLoader.setModelName(objName);
objLoader.setMaterials(materials);
fileLoader.setPath('');
fileLoader.setResponseType('arraybuffer');
fileLoader.load(objUrl,
function(onLoadContent) {
var mesh = objLoader.parse(onLoadContent);
onLoadFunc(mesh);
},
function(inProgress) {},
function(error) {
throw new Error('Couldnt load the model: ', error);
});
};
objLoader.loadMtl(mtlUrl, objName+'.mtl', onLoadMtl);
}
function addPlaneToSceneSOAnswer(mesh) {
var frontMaterial = new THREE.MeshBasicMaterial( { color : 0xff0000, side: THREE.FrontSide } );
var backMaterial = new THREE.MeshBasicMaterial( { color : 0x00ff00, side: THREE.BackSide } );
var geometry = new THREE.Geometry().fromBufferGeometry( mesh.children[0].geometry );
var length = geometry.faces.length;
geometry.faces.splice(14, 1);
for (var i = 0; i < geometry.faces.length; i ++ ) {
var face = geometry.faces[i];
face.color.setHex(Math.random() * 0xffffff);
}
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors, side: THREE.DoubleSide }) );
mesh.material.side = THREE.FrontSide;
var mesh2 = new THREE.Mesh( geometry, mesh.material.clone() );
mesh2.material.side = THREE.BackSide;
// mesh2.material.vertexColors = THREE.NoColors;
mesh2.material.vertexColors = [new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color(0x0000ff)];
mesh.add( mesh2 );
scene.add(mesh);
}
})();
body {
background: transparent;
padding: 0;
margin: 0;
font-family: sans-serif;
}
#canvas {
margin: 10px auto;
width: 800px;
height: 350px;
margin-top: -44px;
}
<body>
<div id="container"></div>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>
</body>
我在这里错过了什么?
【问题讨论】:
-
在您之前将每一面视为单独网格的方法中,您是否在一个上使用 THREE.FrontSide 而在另一个上使用 THREE.BackSide?我不认为你在这里使用的面部颜色不会在不复制网格的情况下工作......使用图像(一个网格上有两种材料)是另一种选择。
-
您能否详细说明一下使用两种材料制作一个网格是什么意思以及如何区分两侧?
-
mesh.material.side = THREE.FrontSide; var mesh2 = new THREE.Mesh( geometry, material.clone() ); mesh2.material.side = THREE.BackSide; mesh2.material.vertexColors = THREE.NoColors; mesh.add( mesh2 ); -
@WestLangley 我已经用您的评论编辑了我的答案。你能详细说明一下吗?
-
如果您希望内部为纯色,我发布的内容将起作用。如果您希望内部具有顶点颜色,那么您也需要克隆几何体 (
geometry.clone()),并在克隆的几何体上设置所需的内部顶点颜色。
标签: three.js