浏览代码

Added support for texture rotation

WestLangley 8 年之前
父节点
当前提交
ae1193294c

+ 18 - 1
docs/api/math/Matrix3.html

@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+	<!DOCTYPE html>
 <html lang="en">
 <html lang="en">
 	<head>
 	<head>
 		<meta charset="utf-8" />
 		<meta charset="utf-8" />
@@ -169,6 +169,23 @@ m.elements = [ 11, 21, 31,
 		<h3>[method:Matrix3 setFromMatrix4]( [page:Matrix4 m] )</h3>
 		<h3>[method:Matrix3 setFromMatrix4]( [page:Matrix4 m] )</h3>
 		<div>Set this matrx to the upper 3x3 matrix of the Matrix4 [page:Matrix4 m].</div>
 		<div>Set this matrx to the upper 3x3 matrix of the Matrix4 [page:Matrix4 m].</div>
 
 
+		<h3>
+			[method:Matrix3 setUvTransform](
+			[page:Float tx], [page:Float ty], [page:Float sx], [page:Float sy],
+			[page:Float rotation], [page:Float cx], [page:Float cy] )
+		</h3>
+		<div>
+		[page:Float tx] - translation x<br />
+		[page:Float ty] - translation y<br />
+		[page:Float sx] - scale x<br />
+		[page:Float sy] - scale y<br />
+		[page:Float rotation] - rotation (in radians)<br />
+		[page:Float cx] - center x of rotation<br />
+		[page:Float cy] - center y of rotation<br /><br />
+
+		Sets the UV transform matrix from the texture properties offset (translate), repeat (scale), rotation, and center.
+		</div>
+
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		<div>
 		[page:Array array] - (optional) array to store the resulting vector in. If not given a new array will be created.<br />
 		[page:Array array] - (optional) array to store the resulting vector in. If not given a new array will be created.<br />

+ 11 - 0
docs/api/textures/Texture.html

@@ -147,6 +147,17 @@
 		assigned to achieve the desired repetiton.
 		assigned to achieve the desired repetiton.
 		</div>
 		</div>
 
 
+		<h3>[property:number rotation]</h3>
+		<div>
+		How much the texture is rotated, in radians. Postive values are counter-clockwise. Default is *0*.
+		</div>
+
+		<h3>[property:Vector2 center]</h3>
+		<div>
+		The center point of the texture -- used for both rotation and scaling. The range for each component is *0.0* to *1.0*. The default is [ *0*, *0* ],
+		which corresponds to the lower-left corner of the texture.
+		</div>
+
 		<h3>[property:boolean generateMipmaps]</h3>
 		<h3>[property:boolean generateMipmaps]</h3>
 		<div>
 		<div>
 		Whether to generate mipmaps (if possible) for a texture. True by default. Set this to false if you are
 		Whether to generate mipmaps (if possible) for a texture. True by default. Set this to false if you are

+ 158 - 0
examples/webgl_materials_texture_rotation.html

@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - materials - texture - rotation</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				margin: 0px;
+				background-color: #050505;
+				color: #fff;
+				overflow: hidden;
+			}
+
+			a { color: #e00 }
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				color: #ffffff;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				text-align: center;
+			}
+
+		</style>
+	</head>
+
+	<body>
+
+		<div id="info">
+			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl - texture rotation
+		</div>
+
+		<script src="../build/three.js"></script>
+
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script src="js/Detector.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var mesh, renderer, scene, camera;
+
+			var gui;
+
+			var API = {
+				translateX: 0,
+				translateY: 0,
+				scaleX: 0.25,
+				scaleY: 0.25,
+				rotation: Math.PI / 4, // positive is counter-clockwise
+				centerX: 0.5,
+				centerY: 0.5
+			};
+
+			init();
+			render();
+
+
+			function init() {
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( 10, 15, 25 );
+				scene.add( camera );
+
+				var controls = new THREE.OrbitControls( camera, renderer.domElement );
+				controls.addEventListener( 'change', render );
+				controls.minDistance = 20;
+				controls.maxDistance = 50;
+				controls.maxPolarAngle = Math.PI / 2;
+
+				var geometry = new THREE.BoxGeometry( 10, 10, 10 );
+
+				var loader = new THREE.TextureLoader();
+				var texture = loader.load( 'textures/UV_Grid_Sm.jpg', render );
+				texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+
+				var material = new THREE.MeshBasicMaterial( { map: texture } );
+
+				mesh = new THREE.Mesh( geometry, material );
+				scene.add( mesh );
+
+				updateTextureParams();
+
+				initGui();
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				render();
+
+			}
+
+			function updateTextureParams() {
+
+				var map = mesh.material.map;
+
+				map.offset.x = API.translateX;
+				map.offset.y = API.translateY;
+				map.repeat.x = API.scaleX;
+				map.repeat.y = API.scaleY;
+				map.rotation = API.rotation;
+				map.center.x = API.centerX;
+				map.center.y = API.centerY;
+
+				render();
+
+			}
+
+			function initGui() {
+
+				var drop;
+
+				gui = new dat.GUI();
+
+				gui.add( API, 'translateX', 0.0, 1.0 ).name( 'offset.x' ).onChange( updateTextureParams );
+				gui.add( API, 'translateY', 0.0, 1.0 ).name( 'offset.y' ).onChange( updateTextureParams );
+				gui.add( API, 'scaleX', 0.25, 2.0 ).name( 'repeat.x' ).onChange( updateTextureParams );
+				gui.add( API, 'scaleY', 0.25, 2.0 ).name( 'repeat.y' ).onChange( updateTextureParams );
+				gui.add( API, 'rotation', - 2.0, 2.0 ).name( 'rotation' ).onChange( updateTextureParams );
+				gui.add( API, 'centerX', 0.0, 1.0 ).name( 'center.x' ).onChange( updateTextureParams );
+				gui.add( API, 'centerY', 0.0, 1.0 ).name( 'center.y' ).onChange( updateTextureParams );
+
+			}
+
+		</script>
+
+	</body>
+
+</html>

+ 13 - 0
src/math/Matrix3.js

@@ -273,6 +273,19 @@ Object.assign( Matrix3.prototype, {
 
 
 	},
 	},
 
 
+	setUvTransform: function ( tx, ty, sx, sy, rotation, cx, cy ) {
+
+		var c = Math.cos( rotation );
+		var s = Math.sin( rotation );
+
+		this.set(
+			sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
+			- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
+			0, 0, 0
+		);
+
+	},
+
 	equals: function ( matrix ) {
 	equals: function ( matrix ) {
 
 
 		var te = this.elements;
 		var te = this.elements;

+ 6 - 2
src/renderers/WebGLRenderer.js

@@ -1984,8 +1984,10 @@ function WebGLRenderer( parameters ) {
 
 
 			var offset = uvScaleMap.offset;
 			var offset = uvScaleMap.offset;
 			var repeat = uvScaleMap.repeat;
 			var repeat = uvScaleMap.repeat;
+			var rotation = uvScaleMap.rotation;
+			var center = uvScaleMap.center;
 
 
-			uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
+			uniforms.uvTransform.value.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y );
 
 
 		}
 		}
 
 
@@ -2019,8 +2021,10 @@ function WebGLRenderer( parameters ) {
 
 
 			var offset = material.map.offset;
 			var offset = material.map.offset;
 			var repeat = material.map.repeat;
 			var repeat = material.map.repeat;
+			var rotation = material.map.rotation;
+			var center = material.map.center;
 
 
-			uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
+			uniforms.uvTransform.value.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y );
 
 
 		}
 		}
 
 

+ 2 - 1
src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl

@@ -1,6 +1,7 @@
 #ifdef USE_MAP
 #ifdef USE_MAP
 
 
-	vec4 mapTexel = texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );
+	vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;
+	vec4 mapTexel = texture2D( map, uv );
 	diffuseColor *= mapTexelToLinear( mapTexel );
 	diffuseColor *= mapTexelToLinear( mapTexel );
 
 
 #endif
 #endif

+ 1 - 1
src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl

@@ -1,6 +1,6 @@
 #ifdef USE_MAP
 #ifdef USE_MAP
 
 
-	uniform vec4 offsetRepeat;
+	uniform mat3 uvTransform;
 	uniform sampler2D map;
 	uniform sampler2D map;
 
 
 #endif
 #endif

+ 1 - 1
src/renderers/shaders/ShaderChunk/uv_pars_vertex.glsl

@@ -1,6 +1,6 @@
 #if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 #if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 
 
 	varying vec2 vUv;
 	varying vec2 vUv;
-	uniform vec4 offsetRepeat;
+	uniform mat3 uvTransform;
 
 
 #endif
 #endif

+ 1 - 1
src/renderers/shaders/ShaderChunk/uv_vertex.glsl

@@ -1,5 +1,5 @@
 #if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 #if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )
 
 
-	vUv = uv * offsetRepeat.zw + offsetRepeat.xy;
+	vUv = ( uvTransform * vec3( uv, 1 ) ).xy;
 
 
 #endif
 #endif

+ 3 - 2
src/renderers/shaders/UniformsLib.js

@@ -1,6 +1,7 @@
 import { Vector4 } from '../../math/Vector4';
 import { Vector4 } from '../../math/Vector4';
 import { Color } from '../../math/Color';
 import { Color } from '../../math/Color';
 import { Vector2 } from '../../math/Vector2';
 import { Vector2 } from '../../math/Vector2';
+import { Matrix3 } from '../../math/Matrix3';
 import { DataTexture } from '../../textures/DataTexture';
 import { DataTexture } from '../../textures/DataTexture';
 
 
 /**
 /**
@@ -15,7 +16,7 @@ var UniformsLib = {
 		opacity: { value: 1.0 },
 		opacity: { value: 1.0 },
 
 
 		map: { value: null },
 		map: { value: null },
-		offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) },
+		uvTransform: { value: new Matrix3() },
 
 
 		alphaMap: { value: null },
 		alphaMap: { value: null },
 
 
@@ -180,7 +181,7 @@ var UniformsLib = {
 		size: { value: 1.0 },
 		size: { value: 1.0 },
 		scale: { value: 1.0 },
 		scale: { value: 1.0 },
 		map: { value: null },
 		map: { value: null },
-		offsetRepeat: { value: new Vector4( 0, 0, 1, 1 ) }
+		uvTransform: { value: new Matrix3() }
 
 
 	}
 	}
 
 

+ 6 - 0
src/textures/Texture.js

@@ -38,6 +38,8 @@ function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, ty
 
 
 	this.offset = new Vector2( 0, 0 );
 	this.offset = new Vector2( 0, 0 );
 	this.repeat = new Vector2( 1, 1 );
 	this.repeat = new Vector2( 1, 1 );
+	this.rotation = 0;
+	this.center = new Vector2( 0, 0 );
 
 
 	this.generateMipmaps = true;
 	this.generateMipmaps = true;
 	this.premultiplyAlpha = false;
 	this.premultiplyAlpha = false;
@@ -102,6 +104,8 @@ Object.assign( Texture.prototype, EventDispatcher.prototype, {
 
 
 		this.offset.copy( source.offset );
 		this.offset.copy( source.offset );
 		this.repeat.copy( source.repeat );
 		this.repeat.copy( source.repeat );
+		this.rotation = source.rotation;
+		this.center.copy( source.center );
 
 
 		this.generateMipmaps = source.generateMipmaps;
 		this.generateMipmaps = source.generateMipmaps;
 		this.premultiplyAlpha = source.premultiplyAlpha;
 		this.premultiplyAlpha = source.premultiplyAlpha;
@@ -175,6 +179,8 @@ Object.assign( Texture.prototype, EventDispatcher.prototype, {
 
 
 			repeat: [ this.repeat.x, this.repeat.y ],
 			repeat: [ this.repeat.x, this.repeat.y ],
 			offset: [ this.offset.x, this.offset.y ],
 			offset: [ this.offset.x, this.offset.y ],
+			rotation: this.rotation,
+			center: [ this.center.x, this.center.y ],
 			wrap: [ this.wrapS, this.wrapT ],
 			wrap: [ this.wrapS, this.wrapT ],
 
 
 			minFilter: this.minFilter,
 			minFilter: this.minFilter,