Kaynağa Gözat

TextureUtils: Add `contain()`, `cover()` and `fill()`. (#28713)

* TextureUtils: Add `contain()`, `cover()` and `fill()`.

* WebGLTextures: Improve tree shaking.

* Update TextureUtils.js

Clean up.

* Update webgl_test_wide_gamut.html

Simplify example.
Michael Herzog 1 yıl önce
ebeveyn
işleme
3ea97b9007

+ 15 - 0
docs/api/en/extras/TextureUtils.html

@@ -13,6 +13,21 @@
 
 		<h2>Methods</h2>
 
+		<h3>[method:Texture contain]( [param:Texture texture], [param:Number aspect] )</h3>
+		<p>
+			Scales the texture as large as possible within its surface without cropping or stretching the texture. The method preserves the original aspect ratio of the texture. Akin to CSS `object-fit: contain`.
+		</p>
+
+		<h3>[method:Texture cover]( [param:Texture texture], [param:Number aspect] )</h3>
+		<p>
+			Scales the texture to the smallest possible size to fill the surface, leaving no empty space. The method preserves the original aspect ratio of the texture. Akin to CSS `object-fit: cover`.
+		</p>
+
+		<h3>[method:Texture fill]( [param:Texture texture] )</h3>
+		<p>
+			Configures the texture to the default transformation. Akin to CSS `object-fit: fill`.
+		</p>
+
 		<h3>[method:Number getByteLength]( [param:Number width], [param:Number height], [param:Number format], [param:Number type] )</h3>
 		<p>
 			Given the width, height, format, and type of a texture. Determines how

+ 2 - 1
docs/list.json

@@ -103,7 +103,8 @@
 				"Earcut": "api/en/extras/Earcut",
 				"ImageUtils": "api/en/extras/ImageUtils",
 				"PMREMGenerator": "api/en/extras/PMREMGenerator",
-				"ShapeUtils": "api/en/extras/ShapeUtils"
+				"ShapeUtils": "api/en/extras/ShapeUtils",
+				"TextureUtils": "api/en/extras/TextureUtils"
 			},
 
 			"Extras / Core": {

+ 4 - 28
examples/webgl_test_wide_gamut.html

@@ -128,8 +128,8 @@
 				textureL.colorSpace = THREE.SRGBColorSpace;
 				textureR.colorSpace = THREE.DisplayP3ColorSpace;
 
-				sceneL.background = containTexture( window.innerWidth / window.innerHeight, textureL );
-				sceneR.background = containTexture( window.innerWidth / window.innerHeight, textureR );
+				sceneL.background = THREE.TextureUtils.contain( textureL, window.innerWidth / window.innerHeight );
+				sceneR.background = THREE.TextureUtils.contain( textureR, window.innerWidth / window.innerHeight );
 
 			}
 
@@ -175,8 +175,8 @@
 
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
-				containTexture( window.innerWidth / window.innerHeight, sceneL.background );
-				containTexture( window.innerWidth / window.innerHeight, sceneR.background );
+				THREE.TextureUtils.contain( sceneL.background, window.innerWidth / window.innerHeight );
+				THREE.TextureUtils.contain( sceneR.background, window.innerWidth / window.innerHeight );
 
 			}
 
@@ -189,30 +189,6 @@
 
 			}
 
-			function containTexture( aspect, target ) {
-
-				// Sets the matrix uv transform so the texture image is contained in a region having the specified aspect ratio,
-				// and does so without distortion. Akin to CSS object-fit: contain.
-				// Source: https://github.com/mrdoob/three.js/pull/17199
-
-				var imageAspect = ( target.image && target.image.width ) ? target.image.width / target.image.height : 1;
-
-				if ( aspect > imageAspect ) {
-
-					target.matrix.setUvTransform( 0, 0, aspect / imageAspect, 1, 0, 0.5, 0.5 );
-
-				} else {
-
-					target.matrix.setUvTransform( 0, 0, 1, imageAspect / aspect, 0, 0.5, 0.5 );
-
-				}
-
-				target.matrixAutoUpdate = false;
-
-				return target;
-
-			}
-
 			function animate() {
 
 				renderer.setScissor( 0, 0, sliderPos, window.innerHeight );

+ 71 - 2
src/extras/TextureUtils.js

@@ -1,5 +1,71 @@
 import { AlphaFormat, LuminanceFormat, LuminanceAlphaFormat, RedFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBAFormat, RGBAIntegerFormat, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, UnsignedByteType, ByteType, UnsignedShortType, ShortType, HalfFloatType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedIntType, IntType, FloatType, UnsignedInt5999Type } from '../constants.js';
 
+function contain( texture, aspect ) {
+
+	const imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;
+
+	if ( imageAspect > aspect ) {
+
+		texture.repeat.x = 1;
+		texture.repeat.y = imageAspect / aspect;
+
+		texture.offset.x = 0;
+		texture.offset.y = ( 1 - texture.repeat.y ) / 2;
+
+	} else {
+
+		texture.repeat.x = aspect / imageAspect;
+		texture.repeat.y = 1;
+
+		texture.offset.x = ( 1 - texture.repeat.x ) / 2;
+		texture.offset.y = 0;
+
+	}
+
+	return texture;
+
+}
+
+function cover( texture, aspect ) {
+
+	const imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;
+
+	if ( imageAspect > aspect ) {
+
+		texture.repeat.x = aspect / imageAspect;
+		texture.repeat.y = 1;
+
+		texture.offset.x = ( 1 - texture.repeat.x ) / 2;
+		texture.offset.y = 0;
+
+	} else {
+
+		texture.repeat.x = 1;
+		texture.repeat.y = imageAspect / aspect;
+
+		texture.offset.x = 0;
+		texture.offset.y = ( 1 - texture.repeat.y ) / 2;
+
+	}
+
+	return texture;
+
+}
+
+function fill( texture ) {
+
+	texture.repeat.x = 1;
+	texture.repeat.y = 1;
+
+	texture.offset.x = 0;
+	texture.offset.y = 0;
+
+	return texture;
+
+}
+
+
+
 /**
  * Given the width, height, format, and type of a texture. Determines how many
  * bytes must be used to represent the texture.
@@ -135,7 +201,10 @@ function getTextureTypeByteLength( type ) {
 }
 
 const TextureUtils = {
-	getByteLength,
+	contain,
+	cover,
+	fill,
+	getByteLength
 };
 
-export { getByteLength, TextureUtils };
+export { contain, cover, fill, getByteLength, TextureUtils };

+ 3 - 3
src/renderers/webgl/WebGLTextures.js

@@ -2,7 +2,7 @@ import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Near
 import { createElementNS } from '../../utils.js';
 import { ColorManagement } from '../../math/ColorManagement.js';
 import { Vector2 } from '../../math/Vector2.js';
-import { TextureUtils } from '../../extras/TextureUtils.js';
+import { getByteLength } from '../../extras/TextureUtils.js';
 
 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
 
@@ -855,7 +855,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 										if ( texture.layerUpdates.size > 0 ) {
 
-											const layerByteLength = TextureUtils.getByteLength( mipmap.width, mipmap.height, texture.format, texture.type );
+											const layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format, texture.type );
 
 											for ( const layerIndex of texture.layerUpdates ) {
 
@@ -981,7 +981,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 						if ( texture.layerUpdates.size > 0 ) {
 
-							const layerByteLength = TextureUtils.getByteLength( image.width, image.height, texture.format, texture.type );
+							const layerByteLength = getByteLength( image.width, image.height, texture.format, texture.type );
 
 							for ( const layerIndex of texture.layerUpdates ) {