Basis compression

Hi,
I’m so xcite about the basis format ! - I am updating a scene with this format and in latest repo version 106.
I’m using this post https://medium.com/samsung-internet-dev/using-basis-textures-in-three-js-6eb7e104447d and the three.js example

The textures load fine according to console, but I’m getting a white mesh with the errors below, whereas it would have worked just fine MeshStandardMaterial and pngs in three.js version 104.
THREE.Material: ‘map’ parameter is undefined.
THREE.Material: ‘normalMap’ parameter is undefined.
THREE.Material: ‘aoMap’ parameter is undefined.

This is a snippet:

//
const basisLoader = new BasisTextureLoader(textureManager);
basisLoader.setTranscoderPath( ‘js/libs/basis/’ );
basisLoader.detectSupport( renderer );

			// Make a new instance of the loader
			
			var albedoM = basisLoader.load( "Photog_Vase1/albedoBasis.basis");
			var normalMap = basisLoader.load( "Photog_Vase1/normalBasis.basis");
			var aoMap = basisLoader.load( "Photog_Vase1/aoBasis.basis");	
			var roughMap = basisLoader.load( "Photog_Vase1/roughnessBasis.basis");

			textureManager.onLoad=function	() {
				
				vaseMeshMaterial = new THREE.MeshStandardMaterial( { 
					roughness: roughMap,
					metalness: settings.metalness,
					roughness: settings.roughness,
					map: albedoM,
					normalMap: normalMap,
					normalScale: new THREE.Vector2( 1, -1 ),
					aoMap: aoMap,
					aoMapIntensity: 1,
					flatShading: false,
					//envMap: reflectionCube,
					//envMapIntensity: settings.envMapIntensity,
					side: THREE.DoubleSide
				});

Can someone please share some guidance where i may have gone wrong pls?
Here’s the scene if that could help https://drive.google.com/drive/folders/1riXdJE6j62cbmejsxPGnjHlj2sliOmNu?usp=sharing

Thanks a bunch!

BasisTextureLoader.load is (currently) asynchronous – it doesn’t return a Texture object immediately. Try something like this:

Promise.all([
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/albedoBasis.basis", resolve, undefined, reject ) ),
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/normalBasis.basis", resolve, undefined, reject ) ),
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/aoBasis.basis", resolve, undefined, reject ) ),
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/roughnessBasis.basis", resolve, undefined, reject ) ),
]).then(([map, normalMap, aoMap, roughnessMap]) => {
	vaseMeshMaterial = new THREE.MeshStandardMaterial({map: map, ... });
});
1 Like

Thanks a ton @donmccurdy , I couldn’t have guessed !

In running it I get this console error:
THREE.WebGLProgram: gl.getProgramInfoLog() C:\fakepath(818,16-119): warning X3571: pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them
THREE.WebGLRenderer: WEBGL_compressed_texture_pvrtc extension not supported.

Only the Albedo map renders but incomplete, UVs out of place.

I can run and render just fine the basis example https://threejs.org/examples/?q=basis#webgl_loader_texture_basis
But cannot render the pvrtc example: https://threejs.org/examples/?q=pvr#webgl_loader_texture_pvrtc

I’m on up to date chrome (Version 75.0.3770.100 (Official Build) (64-bit) and uptodate firefox, windows 10.
snapshot2

Any further thoughts I can chase please?

Here the code changed in case it helps, scene updated here: https://drive.google.com/drive/folders/1riXdJE6j62cbmejsxPGnjHlj2sliOmNu?usp=sharing

const basisLoader = new BasisTextureLoader();
				basisLoader.setTranscoderPath( 'js/libs/basis/' );
				basisLoader.detectSupport( renderer );
				myObjectLoader = new OBJLoader( meshManager);

Promise.all([
					new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/albedoBasis.basis", resolve, undefined, reject ) ),
					new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/normalBasis.basis", resolve, undefined, reject ) ),
					new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/aoBasis.basis", resolve, undefined, reject ) ),
					new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/roughnessBasis.basis", resolve, undefined, reject ) ),
				]).then(([albedoM, normalMap, aoMap, roughMap]) => {
					vaseMeshMaterial = new THREE.MeshStandardMaterial({
						roughness: roughMap,
						metalness: settings.metalness,
						roughness: settings.roughness,
						map: albedoM,
						normalMap: normalMap,
						normalScale: new THREE.Vector2( 1, -1 ),
						aoMap: aoMap,
						aoMapIntensity: 1,
						flatShading: false,
						//envMap: reflectionCube,
						//envMapIntensity: settings.envMapIntensity,
						side: THREE.DoubleSide
					});

myObjectLoader.load( "Photog_Vase1/LowPoly_repos.obj", function ( group ) {
						var geometry = group.children[ 0 ].geometry;
						geometry.attributes.uv2 = geometry.attributes.uv;
						geometry.center();

						vaseMesh = new THREE.Mesh( geometry, vaseMeshMaterial );
						vaseMeshMaterial.normalScale.x = -1;
						vaseMesh.castShadow = true;
						vaseMesh.receiveShadow = true;
						vaseMesh.position.set(0,0,0);
					} , onProgress,onError);
				});

try to ad

  albedoM.encoding = THREE.sRGBEncoding;
  albedoM.wrapS = THREE.RepeatWrapping;
  albedoM.wrapT = THREE.RepeatWrapping;
  albedoM.repeat.x = 10;
  albedoM.repeat.y = 10; 

to all your maps

Thank you for the suggestion @arpu , can I get some further guidance please?

Where do I now define the maps so I can add these properties? This didn’t work for me:
Uncaught TypeError: Cannot create property ‘encoding’ on string ‘Photog_Vase1/albedoBasis.basis’

Thanks a bunch for your help, Sergio

//declare maps
var albedoM = “Photog_Vase1/albedoBasis.basis”;
var normalMap = “Photog_Vase1/normalBasis.basis”;
var aoMap = “Photog_Vase1/aoBasis.basis”;
var roughMap = “Photog_Vase1/roughnessBasis.basis”;

//Add properties to maps
albedoM.encoding = THREE.sRGBEncoding;

albedoM.wrapS = THREE.RepeatWrapping;

albedoM.wrapT = THREE.RepeatWrapping;

albedoM.repeat.x = 10;

albedoM.repeat.y = 10;

//Adding promise
Promise.all([
new Promise((resolve, reject) => basisLoader.load( albedoM, resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( normalMap, resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( aoMap, resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( roughMap, resolve, undefined, reject ) ),
]).then(([albedoM, normalMap, aoMap, roughMap]) => {
vaseMeshMaterial = new THREE.MeshStandardMaterial({
roughness: roughMap,
metalness: settings.metalness,
roughness: settings.roughness,
map: albedoM,
normalMap: normalMap,
//normalScale: new THREE.Vector2( 1, -1 ),
aoMap: aoMap,
aoMapIntensity: 1,
flatShading: false,
//envMap: reflectionCube,
//envMapIntensity: settings.envMapIntensity,
side: THREE.DoubleSide
});

Then wh

Promise.all([
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/albedoBasis.basis", resolve, undefined, reject ) ),
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/normalBasis.basis", resolve, undefined, reject ) ),
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/aoBasis.basis", resolve, undefined, reject ) ),
	new Promise((resolve, reject) => basisLoader.load( "Photog_Vase1/roughnessBasis.basis", resolve, undefined, reject ) ),
]).then(([map, normalMap, aoMap, roughnessMap]) => {
      map.encoding = THREE.sRGBEncoding;
      map.wrapS = THREE.RepeatWrapping;
      map.wrapT = THREE.RepeatWrapping;
      map.repeat.x = 10;
      map.repeat.y = 10;
      normalMap.encoding = THREE.sRGBEncoding;
      normalMap.wrapS = THREE.RepeatWrapping;
      normalMap.wrapT = THREE.RepeatWrapping;
      normalMap.repeat.x = 10;
      normalMap.repeat.y = 10;
     // ... same for all other maps 
	vaseMeshMaterial = new THREE.MeshStandardMaterial({map: map, ... });
});
2 Likes

^You’ll only want to use sRGB encoding for textures that contain color data. In this case that would just be .map. Other texture types are linear.

2 Likes

Thanks a bunch for your help @arpu @donmccurdy

the suggested code worked but resulted in smaller shells.
I also tested leaving in/out sRGBenconding for the other maps but didn’t help for this tiling issue.

Changing the repeat param only made the shells even smaller. I note the model’s UV is 1-1:

I followed these steps to create the basis files and had no errors: https://medium.com/samsung-internet-dev/using-basis-textures-in-three-js-6eb7e104447d

This is the result of the pre-basis conversion of textures in Unity:

Any other tips appreciated please !
Here’re the probject files incl the textures before converting these to basis: https://drive.google.com/drive/folders/1ORxEtvCeg-OcchWxIXtXk6ZrPLPwZdLE?usp=sharing

Cheers!

looks like you don’t need these:
map.repeat.x = 10;
map.repeat.y = 10;

normalMap.repeat.x = 10;
normalMap.repeat.y = 10;

or set repeat.x/y to 1

when original .png textures are used your mesh renders fine, but with .basis its upside down.
this should be easily fixed with setting flipY property to true when .basis is used, unfortunately it doesn’t
do anything when flipY is changed… which seems to be a bug in .basis texture implementation i guess.
so the solution to your problem is to manually flip .png files before converting them to .basis
and you need to set those repeats (x/y) to 1

1 Like

Try:

texture.flipY = true;
texture.needsUpdate = true;
1 Like

I did. It doesn’t work with .basis. It works fine with .png textures.

1 Like

Oops, my mistake. The flipY flag does not work with compressed textures. I believe that’s a fundamental WebGL-level thing. See THREE.CompressedTexture docs.

1 Like

That’s good to know! Thanks.

Hey all, I tried your suggestions but didn’t get very far unfortunately

I tried with repeat.x/y for each map and also only for albedoM like below
albedoM.repeat.x/y = 1;
but gave me error and removed it
Uncaught ReferenceError: Invalid left-hand side in assignment

I tried with and without repeat.x = 1; and repeat.y = 1; for every map but the result was the same.

I’ve re-uploaded the files with the flipped basis maps (meaning I rotated the map 180 degrees and then converted to basis) https://drive.google.com/drive/folders/1B-cE-YJc_vm92gyLZqcQUFsphaj-uD84?usp=sharing
Thanks a bunch for your help !

Just in case, here’s the output converting albedo map to basis
Basis Universal GPU Texture Compressor Reference Encoder v1.08.00, Copyright © 2019 Binomial LLC, All rights reserved
Processing 1 total files
Read source image “VaseFiles/FlippedYalbedo.png”, 4096x4096
Total basis file slices: 1
Slice: 0, alpha: 0, orig width/height: 4096x4096, width/height: 4096x4096, first_block: 0, image_index: 0, mip_level: 0, iframe: 0
Wrote output .basis file “FlippedYalbedo.basis”
Compression succeeded to file “FlippedYalbedo.basis” in 53.900 secs

You don’t rotate texture, you need to flip it vertically.
Also, you don’t really have to flip the original texture yourself as
basis compression tool has “-y_flip” option.
So you just need to call:

basisu originalTexture.png -y_flip

you need to set those repeats (x/y) to 1” means:
tex.repeat.x = 1;
tex.repeat.y = 1;

2 Likes

@Alright could you create either a live demo, or a version of this code that can be run without any changes? The HTML in your folder seems to reference a lot of files that aren’t there.

I don’t think that repeat.x or repeat.y are related to the problem here, they should probably be left at 1.

1 Like

Hi @vujadin @donmccurdy
Apologies for the late reply, I was travelling this weekend.

The flip command on basisu without manually flipping the textures worked great, as well as keeping repeat.x and repeat.y =1 :slight_smile:

Unfortunately I’m sorry I can’t host for demo but I’ve cleaned up the files and folders. Please save the contents (not the folder “VaseBasis”) in the three.js examples folder and should work straight away, any probs please let me know :):smiley:

https://drive.google.com/drive/folders/1QiC-LEfdPjrr0Daoijljsb79uUFMKByD?usp=sharing

Thanks a bunch for your help !