three.js:自定义几何体不会被纹理化

时间:2015-12-30 16:05:33

标签: javascript three.js

我制作了两个自定义几何图形:Box2GeometryStaticTestPentagonPlaneGeometry

第一个会纹理化很好,这可以在Box2Geometry JSFiddle中看到。 第二个不会纹理化,这可以在StaticTestPentagonPlaneGeometry JSFiddle中看到 (请注意,小提琴加载有点慢)。 除了不同的几何形状外,两个小提琴基本相同。 StaticTestPentagonPlaneGeometry的材料已被赋予emissive: 0xffffff作为参数,但删除此属性并不能解决问题。

为了完整起见,我还制作了third fiddle,目的是同时展示两种几何形状。然而,这个小提琴无法呈现任何东西,我认为计算之神现在肯定会笑。

从Box2Geometry小提琴渲染输出:

Output of Box2 fiddle

从StaticTestPentagonPlaneGeometry小提琴渲染输出:

Rendering from StaticTestPentagonPlaneGeometry fiddle

来自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();

// 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 );
&#13;
<!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>
&#13;
&#13;
&#13;

来自StaticTestPentagonPlaneGeometry的功能失调的代码:

&#13;
&#13;
"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);
&#13;
<!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>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

你的脸部法线指向错误的方向(0,0,-1)。因此,您可以像这样更正normal计算:

normal.z *= -1;

或作为更通用的解决方案,您可以交换.cross函数调用的参数。这段代码:

var normal    = planeVec1.cross(planeVec2).normalize();

然后变成这个:

var normal    = planeVec2.cross(planeVec1).normalize();

最后,您可以简单地让three.js为您计算面部法线:

constructee.computeFaceNormals ();

您需要删除自发光组件才能使其正常工作。