three.js:自定义几何体不会被纹理化 [英] three.js: custom geometry wont be textured

查看:59
本文介绍了three.js:自定义几何体不会被纹理化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了两个自定义几何图形: 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆