three.js:自定义几何体不会被纹理化 [英] three.js: custom geometry wont be textured
问题描述
我制作了两个自定义几何图形: Box2Geometry
和 StaticTestPentagonPlaneGeometry
。
第一个将纹理化很好,这可以在
从StaticTestPentagonPlaneGeometry渲染输出小提琴:
< img src =https://i.stack.imgur.com/2Q1bY.pngalt =从StaticTestPentagonPlaneGeometry渲染小提琴>
来自Box2Geometry小提琴的表现良好的代码:
use strict; // make DOM elements:var container = document.createElement('div'); document.body.appendChild(container); var info = document.createElement('div'); container.appendChild(info); // create scene:var scene = new THREE.Scene (); //制作'Box2'几何体及其相应的纹理和网格:var loader = new THREE.TextureLoader(); loader.crossOrigin =; loader.load(http://mrdoob.github.io /three.js/examples/textures/crate.gif,function(texture){var myBox2geom = new THREE.Box2Geometry(100,100,100,10,10,10); // args:x,y,z-维度和段的宽度texture.minFilter = THREE.NearestFilter; var material = new THREE.MeshLambertMaterial({map:texture,side:THREE.DoubleSide}); var myBox2mesh = new THREE.Mesh(myBox2geom,material); scene.add(myBox2mesh); },function(){},// onProgress函数函数(错误){console.log(错误)} //没有记录错误); // make light:var light = new THREE.PointLight(0xffffff); light。 position.set(0,0,300); light.lookAt(new THREE.Vector3(0,0,0)); scene.add(light); // make camera:var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight,1,10000); camera.position.set(0,0,300); camera.lookAt(new THREE.Vector3(0,0,0)); scene.add(camera); // make renderer:var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth,window.innerHeight); container.appendChild(renderer.domElement); // aaaand render,continuous!function animate(){requestAnimationFrame (动画); renderer.render(scene,camera);} animate(); THREE.Box2Geometry = function(width,height,depth,widthSegments,heightSegments,depthSegments){THREE.Geometry.call(this); this.parameters = {width:width,height:height,depth:depth,widthSegments:widthSegments,heightSegments:heightSegments,depthSegments:depthSegments}; this.widthSegments = widthSegments || 1; this.heightSegments = heightSegments || 1; this.depthSegments = depthSegments || 1; var constructee = this; // constructee =当前由Box2Geometry构造函数构造的实例var width_half = width / 2; // width =绝对3D空间中沿x的距离var height_half = height / 2; // height =绝对3D空间中沿y的距离var depth_half = depth / 2; // depth =绝对三维空间buildPlane中沿z的距离('z','y', - 1,-1,depth,height,width_half,0); // px buildPlane('z','y',1,-1,depth,height,-width_half,1); // nx buildPlane('x','z',1,1,width,depth,height_half,2); // py buildPlane('x','z',1,-1,width,depth,-height_half,3); // ny buildPlane('x','y',1,-1,width,height,depth_half,4); // pz buildPlane('x','y', - 1,-1,width,height,-depth_half,5); // nz function buildPlane(u,v,uDir,vDir,uDist,vDist,wDist_half,materialIndex){var w,iu,iv,segU = constructee.widthSegments,//沿着你的段数// width = x segV = constructee.heightSegments,//沿v //高度的段数= y uDist_half = uDist / 2,//沿着u的平面范围除以2 vDist_half = vDist / 2,//平面沿v的范围,除以两个offset = constructee.vertices.length; if((u ==='x'&& v ==='y')||(u ==='y'&& v ==='x')){w ='z ; } else if((u ==='x'&& v ==='z')||(u ==='z'&& v ==='x')){w = 'Y'; segV = constructee.depthSegments; } else if((u ==='z'&& v ==='y')||(u ==='y'&& v ==='z')){w = 'X'; segU = constructee.depthSegments; } var segUi = segU + 1,// i = inc =递增(乘1)segVi = segV + 1,// i = inc =递增(乘1)segmentDist_u = uDist / segU,segmentDist_v = vDist / segV,normal =新的THREE.Vector3(); normal [w] = wDist_half> 0? 1:-1; for(iv = 0; iv< segVi; iv ++){for(iu = 0; iu< segUi; iu ++){var vertex = new THREE.Vector3(); vertex [u] =(iu * segmentDist_u - uDist_half)* uDir; vertex [v] =(iv * segmentDist_v - vDist_half)* vDir; vertex [w] = wDist_half; constructee.vertices.push(vertex); for(iv = 0; iv< segV; iv ++){for(iu = 0; iu< segU; iu ++){var a = iu + segUi * iv; var b = iu + segUi *(iv + 1); var c =(iu + 1)+ segUi *(iv + 1); var d =(iu + 1)+ segUi * iv; var uva = new THREE.Vector2(iu / segU,1 - iv / segV); var uvb = new THREE.Vector2(iu / segU,1 - (iv + 1)/ segV); var uvc = new THREE.Vector2((iu + 1)/ segU,1 - (iv + 1)/ segV); var uvd = new THREE.Vector2((iu + 1)/ segU,1 - iv / segV); var face1 = new THREE.Face3(a + offset,b + offset,d + offset); face1.normal.copy(normal); face1.vertexNormals.push(normal.clone(),normal.clone(),normal.clone()); face1.materialIndex = materialIndex; constructee.faces.push(face1); constructee.faceVertexUvs [0] .push([uva,uvb,uvd]); var face2 = new THREE.Face3(b + offset,c + offset,d + offset); face2.normal.copy(normal); face2.vertexNormals.push(normal.clone(),normal.clone(),normal.clone()); face2.materialIndex = materialIndex; constructee.faces.push(face2); constructee.faceVertexUvs [0] .push([uvb.clone(),uvc,uvd.clone()]); this.mergeVertices();}; THREE.Box2Geometry.prototype = Object.create(THREE.Geometry.prototype);
<!doctype html>< html> < HEAD> < meta charset =utf-8> < meta name =viewportcontent =width = device-width,initial-scale = 1,user-scalable = no> < /头> <身体GT; < script src =https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js>< / script> < script src =main.js>< / script> < / body>< / html>
StaticTestPentagonPlaneGeometry中的功能失调代码小提琴:
use strict ; // make DOM elements:var container = document.createElement('div'); document.body.appendChild(container); var info = document.createElement('div'); container.appendChild(info); //创建场景:var scene = new THREE.Scene(); //制作'PentagonPlane'几何体及其相应的纹理和网格:var loader = new THREE.TextureLoader(); loader.crossOrigin =; loader.load( http://mrdoob.github.io/three.js/examples/textures/crate.gif,函数(纹理){var myStaticTestPentagonPlane_geometry = new THREE.StaticTestPentagonPlaneGeometry(); texture.minFilter = THREE.NearestFilter; var material = NE w THREE.MeshLambertMaterial({map:texture,side:THREE.DoubleSide,emissive:0xffffff}); //删除'emissive'并不能解决问题var myStaticTestPentagonPlane_mesh = new THREE.Mesh(myStaticTestPentagonPlane_geometry,material); scene.add(myStaticTestPentagonPlane_mesh); },function(){},// onProgress函数函数(错误){console.log(错误)} //没有记录错误); // make light:var light = new THREE.PointLight(0xffffff); light。 position.set(0,0,300); light.lookAt(new THREE.Vector3(0,0,0)); scene.add(light); // make camera:var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight,1,10000); camera.position.set(0,0,300); camera.lookAt(new THREE.Vector3(0,0,0)); scene.add(camera); // make renderer:var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth,window.innerHeight); container.appendChild(renderer.domElement); // aaaand render,continuous!function animate(){requestAnimationFrame (动画); renderer.render(scene,camera);} animate(); THREE.StaticTestPentagonPlaneGeometry = function(){THREE.Geometry.call(this); var quintuplet = // PentagonPlaneGeometry的静态顶点[new THREE.Vector3(-50,-50,51),new THREE.Vector3(-50,50,51),new THREE.Vector3(50,50,51),新的THREE.Vector3(70,0,51),新的THREE.Vector3(50,-50,51)]; var constructee = this; // constructee =当前由StaticTestPentagonPlaneGeometry构造函数构造的实例//必须始终按顺序排序顶点,从quadPlane var q = quintuplet外部看; //填充顶点数组:constructee.vertices.push(q [0]); constructee.vertices.push(Q [1]); constructee.vertices.push(Q [2]); constructee.vertices.push(Q [3]); constructee.vertices.push(Q [4]); //先前计算过,并且自手动粘贴后,faceVertexUvs:var uv0 = new THREE.Vector2(0,0); var uv1 = new THREE.Vector2(0,0.8333333333333334); var uv2 = new THREE.Vector2(0.8333333333333334,0.8333333333333334); var uv3 = new THREE.Vector2(1,0.4166666666666667); var uv4 = new THREE.Vector2(0.8333333333333334,0.8333333333333334); //构造面:var q0 = 0,q1 = 1,q2 = 2,q3 = 3,q4 = 4; //使平面正常:var planeVec1 = q [0] .clone()。sub(q [1]); var planeVec2 = q [0] .clone()。sub(q [2]); var normal = planeVec1.cross(planeVec2).normalize(); //创建面孔:var face1 = new THREE.Face3(q0,q4,q3); constructee.faceVertexUvs [0] .push([uv0,uv4,uv3]); // alt:a d e face1.normal.copy(normal); face1.vertexNormals.push(normal.clone(),normal.clone(),normal.clone(),normal.clone(),normal.clone()); var face2 = new THREE.Face3(q0,q3,q1); constructee.faceVertexUvs [0] .push([uv0.clone(),uv3.clone(),uv1]); face2.normal.copy(normal); face2.vertexNormals.push(normal.clone(),normal.clone(),normal.clone(),normal.clone(),normal.clone()); var face3 = new THREE.Face3(q1,q3,q2); constructee.faceVertexUvs [0] .push([uv1.clone(uv1),uv3.clone(),uv2]); face3.normal.copy(normal); face3.vertexNormals.push(normal.clone(),normal.clone(),normal.clone(),normal.clone(),normal.clone()); constructee.faces.push(面1); constructee.faces.push(face2); constructee.faces.push(face3); this.mergeVertices();}; THREE.StaticTestPentagonPlaneGeometry.prototype = Object.create(THREE.Geometry.prototype);
<!doctype html>< html> < HEAD> < meta charset =utf-8> < meta name =viewportcontent =width = device-width,initial-scale = 1,user-scalable = no> < /头> <身体GT; < script src =https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js>< / script> <! - < script src =three.js>< / script> - > < script src =main.js>< / script> < / body>< / html>
你的面法线指向错误的方向(0,0,-1)。所以你可以像这样更正正常的
计算:
normal.z * = -1;
或者作为更通用的解决方案,您可以交换的参数。交叉
函数调用。此代码:
var normal = planeVec1.cross(planeVec2).normalize();
然后变为:
var normal = planeVec2.cross(planeVec1).normalize();
最后,你可以简单地让three.js为你计算面部法线:
constructee.computeFaceNormals();
您需要删除自发光组件才能使其正常工作。
I made two custom geometries: Box2Geometry
and StaticTestPentagonPlaneGeometry
.
The first will texturize just fine, as can be seen in this Box2Geometry JSFiddle.
The second won't texturize, as can be seen in this StaticTestPentagonPlaneGeometry JSFiddle
(do note that the fiddles load a bit slowly).
The two fiddles are basically identical, except for the different geometries. The material for the StaticTestPentagonPlaneGeometry
has been given emissive: 0xffffff
as argument, but removing this property doesn't solve the problem.
For completeness sake, I've also made a third fiddle, with the intention of demonstrating both geometries in action simultaneously. However, this fiddle fails to render anything, and I think the computing gods are surely laughing right now.
Rendering output from the Box2Geometry fiddle:
Rendering output from the StaticTestPentagonPlaneGeometry fiddle:
The well behaved code from the Box2Geometry fiddle:
"use strict";
// make DOM elements:
var container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
container.appendChild( info );
// create scene:
var scene = new THREE.Scene();
// make the 'Box2' geometry, and its corresponding texture and mesh:
var loader = new THREE.TextureLoader();
loader.crossOrigin = "";
loader.load("http://mrdoob.github.io/three.js/examples/textures/crate.gif",
function ( texture ) {
var myBox2geom = new THREE.Box2Geometry( 100, 100, 100, 10, 10, 10 ); // args: x,y,z-dimensions and width of their segments
texture.minFilter = THREE.NearestFilter;
var material = new THREE.MeshLambertMaterial( { map: texture, side: THREE.DoubleSide } );
var myBox2mesh = new THREE.Mesh(myBox2geom, material);
scene.add( myBox2mesh );
},
function () {}, // onProgress function
function ( error ) { console.log( error ) } // no error gets logged
);
// make light:
var light = new THREE.PointLight( 0xffffff );
light.position.set(0, 0, 300);
light.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( light );
// make camera:
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set(0, 0, 300);
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( camera );
// make renderer:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// aaaand render, continuously!
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
THREE.Box2Geometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
THREE.Geometry.call( this );
this.parameters = {
width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments
};
this.widthSegments = widthSegments || 1;
this.heightSegments = heightSegments || 1;
this.depthSegments = depthSegments || 1;
var constructee = this; // constructee = the instance currently being constructed by the Box2Geometry constructor
var width_half = width / 2; // width = the distance along x in the absolute 3D space
var height_half = height / 2; // height = the distance along y in the absolute 3D space
var depth_half = depth / 2; // depth = the distance along z in the absolute 3D space
buildPlane( 'z', 'y', -1, -1, depth, height, width_half, 0 ); // px
buildPlane( 'z', 'y', 1, -1, depth, height, -width_half, 1 ); // nx
buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py
buildPlane( 'x', 'z', 1, -1, width, depth, -height_half, 3 ); // ny
buildPlane( 'x', 'y', 1, -1, width, height, depth_half, 4 ); // pz
buildPlane( 'x', 'y', -1, -1, width, height, -depth_half, 5 ); // nz
function buildPlane( u, v, uDir, vDir, uDist, vDist, wDist_half, materialIndex ) {
var w, iu, iv,
segU = constructee.widthSegments, // number of segments along u // width = x
segV = constructee.heightSegments, // number of segments along v // height = y
uDist_half = uDist / 2, // the extent of the plane along u, divided by two
vDist_half = vDist / 2, // the extent of the plane along v, divided by two
offset = constructee.vertices.length;
if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) {
w = 'z';
} else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) {
w = 'y';
segV = constructee.depthSegments;
} else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {
w = 'x';
segU = constructee.depthSegments;
}
var segUi = segU + 1, // i = inc = incremented (by one)
segVi = segV + 1, // i = inc = incremented (by one)
segmentDist_u = uDist / segU,
segmentDist_v = vDist / segV,
normal = new THREE.Vector3();
normal[ w ] = wDist_half > 0 ? 1 : -1;
for ( iv = 0; iv < segVi; iv++ ) {
for ( iu = 0; iu < segUi; iu++ ) {
var vertex = new THREE.Vector3();
vertex[ u ] = ( iu * segmentDist_u - uDist_half ) * uDir;
vertex[ v ] = ( iv * segmentDist_v - vDist_half ) * vDir;
vertex[ w ] = wDist_half;
constructee.vertices.push( vertex );
}
}
for ( iv = 0; iv < segV; iv++ ) {
for ( iu = 0; iu < segU; iu++ ) {
var a = iu + segUi * iv;
var b = iu + segUi * ( iv + 1 );
var c = ( iu + 1 ) + segUi * ( iv + 1 );
var d = ( iu + 1 ) + segUi * iv;
var uva = new THREE.Vector2( iu / segU, 1 - iv / segV );
var uvb = new THREE.Vector2( iu / segU, 1 - ( iv + 1 ) / segV );
var uvc = new THREE.Vector2( ( iu + 1 ) / segU, 1 - ( iv + 1 ) / segV );
var uvd = new THREE.Vector2( ( iu + 1 ) / segU, 1 - iv / segV );
var face1 = new THREE.Face3( a + offset, b + offset, d + offset );
face1.normal.copy( normal );
face1.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
face1.materialIndex = materialIndex;
constructee.faces.push( face1 );
constructee.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
var face2 = new THREE.Face3( b + offset, c + offset, d + offset );
face2.normal.copy( normal );
face2.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
face2.materialIndex = materialIndex;
constructee.faces.push( face2 );
constructee.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
}
}
}
this.mergeVertices();
};
THREE.Box2Geometry.prototype = Object.create( THREE.Geometry.prototype );
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script>
<script src="main.js"></script>
</body>
</html>
The dysfunctional code from the StaticTestPentagonPlaneGeometry fiddle:
"use strict";
// make DOM elements:
var container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
container.appendChild( info );
// create scene:
var scene = new THREE.Scene();
// make the 'PentagonPlane' geometry, and its corresponding texture and mesh:
var loader = new THREE.TextureLoader();
loader.crossOrigin = "";
loader.load("http://mrdoob.github.io/three.js/examples/textures/crate.gif",
function ( texture ) {
var myStaticTestPentagonPlane_geometry = new THREE.StaticTestPentagonPlaneGeometry();
texture.minFilter = THREE.NearestFilter;
var material = new THREE.MeshLambertMaterial( { map: texture, side: THREE.DoubleSide, emissive: 0xffffff } ); // removing 'emissive' doesn't solve the problem
var myStaticTestPentagonPlane_mesh = new THREE.Mesh(myStaticTestPentagonPlane_geometry, material);
scene.add( myStaticTestPentagonPlane_mesh );
},
function () {}, // onProgress function
function ( error ) { console.log( error ) } // no error gets logged
);
// make light:
var light = new THREE.PointLight( 0xffffff );
light.position.set(0, 0, 300);
light.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( light );
// make camera:
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set(0, 0, 300);
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( camera );
// make renderer:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// aaaand render, continuously!
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
THREE.StaticTestPentagonPlaneGeometry = function () {
THREE.Geometry.call(this);
var quintuplet = // static vertices of the PentagonPlaneGeometry
[
new THREE.Vector3(-50, -50, 51 ),
new THREE.Vector3(-50, 50, 51 ),
new THREE.Vector3( 50, 50, 51 ),
new THREE.Vector3( 70, 0, 51 ),
new THREE.Vector3( 50, -50, 51 )
];
var constructee = this; // constructee = the instance currently being constructed by the StaticTestPentagonPlaneGeometry constructor
// Vertices must always be ordered clockwise, seen from outside the quadPlane
var q = quintuplet;
// populate the vertex array:
constructee.vertices.push(q[0]);
constructee.vertices.push(q[1]);
constructee.vertices.push(q[2]);
constructee.vertices.push(q[3]);
constructee.vertices.push(q[4]);
// previously calculated, and since manually pasted, faceVertexUvs:
var uv0 = new THREE.Vector2(0, 0);
var uv1 = new THREE.Vector2(0, 0.8333333333333334);
var uv2 = new THREE.Vector2(0.8333333333333334, 0.8333333333333334);
var uv3 = new THREE.Vector2(1, 0.4166666666666667);
var uv4 = new THREE.Vector2(0.8333333333333334, 0.8333333333333334);
// construct faces:
var q0 = 0, q1 = 1, q2 = 2, q3 = 3, q4 = 4;
// make plane normal:
var planeVec1 = q[0].clone().sub(q[1]);
var planeVec2 = q[0].clone().sub(q[2]);
var normal = planeVec1.cross(planeVec2).normalize();
// create faces:
var face1 = new THREE.Face3(q0, q4, q3);
constructee.faceVertexUvs[ 0 ].push([ uv0, uv4, uv3 ]); // alt: a d e
face1.normal.copy( normal );
face1.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone(), normal.clone() );
var face2 = new THREE.Face3(q0, q3, q1);
constructee.faceVertexUvs[ 0 ].push([ uv0.clone(), uv3.clone(), uv1 ]);
face2.normal.copy( normal );
face2.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone(), normal.clone() );
var face3 = new THREE.Face3(q1, q3, q2);
constructee.faceVertexUvs[ 0 ].push([ uv1.clone(uv1), uv3.clone(), uv2 ]);
face3.normal.copy( normal );
face3.vertexNormals.push( normal.clone(), normal.clone(), normal.clone(), normal.clone(), normal.clone() );
constructee.faces.push(face1);
constructee.faces.push(face2);
constructee.faces.push(face3);
this.mergeVertices();
};
THREE.StaticTestPentagonPlaneGeometry.prototype = Object.create(THREE.Geometry.prototype);
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script>
<!-- <script src="three.js"></script> -->
<script src="main.js"></script>
</body>
</html>
Your face normals point to wrong direction (0, 0, -1). So you can correct the normal
calculation like this:
normal.z *= -1;
or as a more general solution, you can interchange the arguments for the .cross
function call. This code:
var normal = planeVec1.cross(planeVec2).normalize();
then becomes this:
var normal = planeVec2.cross(planeVec1).normalize();
Finally, you could simply ask three.js to calculate face normals for you:
constructee.computeFaceNormals ();
You need to remove emissive component to make it work.
这篇关于three.js:自定义几何体不会被纹理化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!