提交 cab0a0f7 编写于 作者: A alteredq

Added support for compressed textures.

Thanks to @toji for blog post and DDS utilities.

Fixes #2348

TODO: example textures for alpha formats (DXT3, DXT5).
上级 74d5e31b
因为 它太大了无法显示 source diff 。你可以改为 查看blob
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - materials - compressed textures</title>
<meta charset="utf-8">
<style>
body {
margin: 0px;
background-color: #050505;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script>
var camera, scene, renderer;
var mesh1, mesh2;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 800;
scene = new THREE.Scene();
geometry = new THREE.CubeGeometry( 200, 200, 200 );
var map1 = THREE.ImageUtils.loadCompressedTexture( 'textures/compressed/disturb_dxt1_nomip.dds' );
map1.minFilter = map1.magFilter = THREE.LinearFilter;
map1.anisotropy = 4;
var map2 = THREE.ImageUtils.loadCompressedTexture( 'textures/compressed/disturb_dxt1_mip.dds' );
map2.anisotropy = 4;
var material1 = new THREE.MeshBasicMaterial( { map: map1 } );
var material2 = new THREE.MeshBasicMaterial( { map: map2 } );
mesh1 = new THREE.Mesh( geometry, material1 );
mesh1.position.x = -200;
scene.add( mesh1 );
mesh2 = new THREE.Mesh( geometry, material2 );
mesh2.position.x = 200;
scene.add( mesh2 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
var time = Date.now() * 0.001;
mesh1.rotation.x = time;
mesh1.rotation.y = time;
mesh2.rotation.x = time;
mesh2.rotation.y = time;
renderer.render( scene, camera );
}
</script>
</body>
</html>
......@@ -181,3 +181,18 @@ THREE.RGBFormat = 1020;
THREE.RGBAFormat = 1021;
THREE.LuminanceFormat = 1022;
THREE.LuminanceAlphaFormat = 1023;
// Compressed texture formats
THREE.RGB_S3TC_DXT1_Format = 2001;
THREE.RGBA_S3TC_DXT1_Format = 2002;
THREE.RGBA_S3TC_DXT3_Format = 2003;
THREE.RGBA_S3TC_DXT5_Format = 2004;
/*
// Potential future PVRTC compressed texture formats
THREE.RGB_PVRTC_4BPPV1_Format = 2100;
THREE.RGB_PVRTC_2BPPV1_Format = 2101;
THREE.RGBA_PVRTC_4BPPV1_Format = 2102;
THREE.RGBA_PVRTC_2BPPV1_Format = 2103;
*/
......@@ -70,6 +70,211 @@ THREE.ImageUtils = {
},
loadCompressedTexture: function ( url, mapping, onLoad, onError ) {
var texture = new THREE.CompressedTexture();
texture.mapping = mapping;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var buffer = xhr.response;
var dds = THREE.ImageUtils.parseDDS( buffer, true );
texture.format = dds.format;
texture.mipmaps = dds.mipmaps;
texture.image.width = dds.width;
texture.image.height = dds.height;
// gl.generateMipmap fails for compressed textures
// mipmaps must be embedded in the DDS file
// or texture filters must not use mipmapping
texture.generateMipmaps = false;
texture.needsUpdate = true;
if ( onLoad ) onLoad( texture );
}
xhr.onerror = onError;
xhr.open( 'GET', url, true );
xhr.responseType = "arraybuffer";
xhr.send( null );
return texture;
},
parseDDS: function ( buffer, loadMipmaps ) {
var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 };
// Adapted from @toji's DDS utils
// https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js
// All values and structures referenced from:
// http://msdn.microsoft.com/en-us/library/bb943991.aspx/
var DDS_MAGIC = 0x20534444;
var DDSD_CAPS = 0x1,
DDSD_HEIGHT = 0x2,
DDSD_WIDTH = 0x4,
DDSD_PITCH = 0x8,
DDSD_PIXELFORMAT = 0x1000,
DDSD_MIPMAPCOUNT = 0x20000,
DDSD_LINEARSIZE = 0x80000,
DDSD_DEPTH = 0x800000;
var DDSCAPS_COMPLEX = 0x8,
DDSCAPS_MIPMAP = 0x400000,
DDSCAPS_TEXTURE = 0x1000;
var DDSCAPS2_CUBEMAP = 0x200,
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
DDSCAPS2_VOLUME = 0x200000;
var DDPF_ALPHAPIXELS = 0x1,
DDPF_ALPHA = 0x2,
DDPF_FOURCC = 0x4,
DDPF_RGB = 0x40,
DDPF_YUV = 0x200,
DDPF_LUMINANCE = 0x20000;
function fourCCToInt32( value ) {
return value.charCodeAt(0) +
(value.charCodeAt(1) << 8) +
(value.charCodeAt(2) << 16) +
(value.charCodeAt(3) << 24);
}
function int32ToFourCC( value ) {
return String.fromCharCode(
value & 0xff,
(value >> 8) & 0xff,
(value >> 16) & 0xff,
(value >> 24) & 0xff
);
}
var FOURCC_DXT1 = fourCCToInt32("DXT1");
var FOURCC_DXT3 = fourCCToInt32("DXT3");
var FOURCC_DXT5 = fourCCToInt32("DXT5");
var headerLengthInt = 31; // The header length in 32 bit ints
// Offsets into the header array
var off_magic = 0;
var off_size = 1;
var off_flags = 2;
var off_height = 3;
var off_width = 4;
var off_mipmapCount = 7;
var off_pfFlags = 20;
var off_pfFourCC = 21;
// Parse header
var header = new Int32Array( buffer, 0, headerLengthInt );
if ( header[ off_magic ] !== DDS_MAGIC ) {
console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" );
return dds;
}
if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {
console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" );
return dds;
}
var blockBytes;
var fourCC = header[ off_pfFourCC ];
switch ( fourCC ) {
case FOURCC_DXT1:
blockBytes = 8;
dds.format = THREE.RGB_S3TC_DXT1_Format;
break;
case FOURCC_DXT3:
blockBytes = 16;
dds.format = THREE.RGBA_S3TC_DXT3_Format;
break;
case FOURCC_DXT5:
blockBytes = 16;
dds.format = THREE.RGBA_S3TC_DXT5_Format;
break;
default:
console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) );
return dds;
}
dds.mipmapCount = 1;
if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {
dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );
}
dds.width = header[ off_width ];
dds.height = header[ off_height ];
var dataOffset = header[ off_size ] + 4;
// Extract mipmaps buffers
var width = dds.width;
var height = dds.height;
for ( var i = 0; i < dds.mipmapCount; i ++ ) {
var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
var mipmap = { "data": byteArray, "width": width, "height": height };
dds.mipmaps.push( mipmap );
dataOffset += dataLength;
width *= 0.5;
height *= 0.5;
}
return dds;
},
getNormalMap: function ( image, depth ) {
// Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
......
......@@ -176,6 +176,7 @@ THREE.WebGLRenderer = function ( parameters ) {
var _glExtensionTextureFloat;
var _glExtensionStandardDerivatives;
var _glExtensionTextureFilterAnisotropic;
var _glExtensionCompressedTextureS3TC;
initGL();
......@@ -195,6 +196,8 @@ THREE.WebGLRenderer = function ( parameters ) {
var _supportsVertexTextures = ( _maxVertexTextures > 0 );
var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
// API
this.getContext = function () {
......@@ -6243,7 +6246,18 @@ THREE.WebGLRenderer = function ( parameters ) {
setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
if ( texture instanceof THREE.DataTexture ) {
if ( texture instanceof THREE.CompressedTexture ) {
var mipmap, mipmaps = texture.mipmaps;
for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
}
} else if ( texture instanceof THREE.DataTexture ) {
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
......@@ -6607,6 +6621,15 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
if ( _glExtensionCompressedTextureS3TC !== undefined ) {
if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
return 0;
};
......@@ -6739,6 +6762,10 @@ THREE.WebGLRenderer = function ( parameters ) {
_gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
_glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) ||
_gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) ||
_gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
if ( ! _glExtensionTextureFloat ) {
console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
......@@ -6757,6 +6784,12 @@ THREE.WebGLRenderer = function ( parameters ) {
}
if ( ! _glExtensionCompressedTextureS3TC ) {
console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
}
};
function setDefaultGLState () {
......
......@@ -52,6 +52,7 @@
"../src/materials/ParticleDOMMaterial.js",
"../src/materials/ShaderMaterial.js",
"../src/textures/Texture.js",
"../src/textures/CompressedTexture.js",
"../src/textures/DataTexture.js",
"../src/objects/Particle.js",
"../src/objects/ParticleSystem.js",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册