Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance Enhancements for Web Viewer #1891

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 59 additions & 11 deletions javascript/MaterialXView/source/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ function fromMatrix(matrix, dimension)
* @param {mx.Uniforms} uniforms
* @param {THREE.textureLoader} textureLoader
*/
function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath, flipY)
function toThreeUniform(viewer, type, value, name, uniforms, textureLoader, searchPath, flipY)
{
let outValue;
let outValue = null;
switch (type)
{
case 'float':
Expand Down Expand Up @@ -117,18 +117,65 @@ function toThreeUniform(type, value, name, uniforms, textureLoader, searchPath,
case 'filename':
if (value)
{
let fullPath = searchPath + IMAGE_PATH_SEPARATOR + value;
const texture = textureLoader.load(fullPath);
// Set address & filtering mode
if (texture)
setTextureParameters(texture, name, uniforms, flipY);
outValue = texture;
// Cache / reuse texture to avoid reload overhead.
// Note: that data blobs and embedded data textures are not cached as they are transient data.
let checkCache = true;
let texturePath = searchPath + IMAGE_PATH_SEPARATOR + value;
if (value.startsWith('blob:'))
Copy link
Contributor Author

@kwokcb kwokcb Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blobs, embedded data and http references are not relative to a search path. This fixes it so users can use these texture URI specifications in their files.

{
texturePath = value;
console.log('Load blob URL:', texturePath);
checkCache = false;
}
else if (value.startsWith('http'))
{
texturePath = value;
console.log('Load HTTP URL:', texturePath);
}
else if (value.startsWith('data:'))
{
texturePath = value;
checkCache = false;
console.log('Load data URL:', texturePath);
}
const cachedTexture = checkCache && THREE.Cache.get(texturePath);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do proper cache checking.

if (cachedTexture)
{
// Get texture from cache
outValue = cachedTexture;
console.log('Use cached texture: ', texturePath, outValue);
}
else
{
outValue = textureLoader.load(
texturePath,
function (texture) {
console.log('Load new texture: ' + texturePath, texture);
outValue = texture;

// Add texture to ThreeJS cache
if (checkCache)
THREE.Cache.add(texturePath, texture);

viewer.scheduleUpdate();
},
undefined,
function (error) {
console.error('Error loading texture: ', error);
});

// Set address & filtering mode
if (outValue)
setTextureParameters(outValue, name, uniforms, flipY);
}
}
break;
case 'samplerCube':
case 'string':
default:
break;
default:
console.log('Value type not supported: ' + type);
outValue = null;
}

return outValue;
Expand Down Expand Up @@ -283,7 +330,7 @@ export function registerLights(mx, lights, genContext)
* @param {mx.shaderStage} shaderStage
* @param {THREE.TextureLoader} textureLoader
*/
export function getUniformValues(shaderStage, textureLoader, searchPath, flipY)
export function getUniformValues(viewer, shaderStage, textureLoader, searchPath, flipY)
{
let threeUniforms = {};

Expand All @@ -297,7 +344,8 @@ export function getUniformValues(shaderStage, textureLoader, searchPath, flipY)
const variable = uniforms.get(i);
const value = variable.getValue()?.getData();
const name = variable.getVariable();
threeUniforms[name] = new THREE.Uniform(toThreeUniform(variable.getType().getName(), value, name, uniforms,
//console.log('fill uniform, name:', name, ', value:', value);
threeUniforms[name] = new THREE.Uniform(toThreeUniform(viewer, variable.getType().getName(), value, name, uniforms,
textureLoader, searchPath, flipY));
}
}
Expand Down
26 changes: 23 additions & 3 deletions javascript/MaterialXView/source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function init()
orbitControls.addEventListener('change', () =>
{
viewer.getScene().setUpdateTransforms();
viewer.scheduleUpdate();
})

// Add hotkey 'f' to capture the current frame and save an image file.
Expand All @@ -91,6 +92,7 @@ function init()
if (event.key === 'f')
{
captureRequested = true;
viewer.scheduleUpdate();
}
});

Expand Down Expand Up @@ -129,6 +131,7 @@ function init()

}).then(() =>
{
viewer.scheduleUpdate();
animate();
}).catch(err =>
{
Expand All @@ -146,6 +149,7 @@ function init()
viewer.getMaterial().loadMaterials(viewer, materialFilename);
viewer.getEditor().updateProperties(0.9);
viewer.getScene().setUpdateTransforms();
viewer.scheduleUpdate();
});

setSceneLoadingCallback(file =>
Expand All @@ -154,6 +158,7 @@ function init()
console.log('Drop geometry to:', glbFileName);
scene.setGeometryURL(glbFileName);
scene.loadGeometry(viewer, orbitControls);
viewer.scheduleUpdate();
});

// enable three.js Cache so that dropped files can reference each other
Expand All @@ -165,10 +170,12 @@ function onWindowResize()
viewer.getScene().updateCamera();
viewer.getScene().setUpdateTransforms();
renderer.setSize(window.innerWidth, window.innerHeight);
console.log('resize refresh....');
viewer.scheduleUpdate();
}

function animate()
{
{
requestAnimationFrame(animate);

if (turntableEnabled)
Expand All @@ -179,8 +186,19 @@ function animate()
viewer.getScene().setUpdateTransforms();
}

renderer.render(viewer.getScene().getScene(), viewer.getScene().getCamera());
viewer.getScene().updateTransforms();
// Only re-render when an update request was made
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-render gated by requirement to refresh. All the schedulUpdate() calls triggers the requirment.

if (viewer.needUpdate() || turntableEnabled)
{
renderer.render(viewer.getScene().getScene(), viewer.getScene().getCamera());

if (viewer.getScene().getUpdateTransforms())
{
viewer.getScene().updateTransforms();
viewer.getScene().setUpdateTransforms(false);
}

viewer.finishUpdate();
}

if (captureRequested)
{
Expand All @@ -197,9 +215,11 @@ function handleKeyEvents(event)
if (event.keyCode == V_KEY)
{
viewer.getScene().toggleBackgroundTexture();
viewer.scheduleUpdate();
}
else if (event.keyCode == P_KEY)
{
turntableEnabled = !turntableEnabled;
viewer.scheduleUpdate();
}
}
76 changes: 69 additions & 7 deletions javascript/MaterialXView/source/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,14 @@ export class Scene
orbitControls.update();
}

setUpdateTransforms()
setUpdateTransforms(val=true)
{
this.#_updateTransforms = true;
this.#_updateTransforms = val;
}

getUpdateTransforms()
{
return this.#_updateTransforms;
}

updateTransforms()
Expand All @@ -235,7 +240,7 @@ export class Scene
{
return;
}
this.#_updateTransforms = false;
this.setUpdateTransforms(false);

const scene = this.getScene();
const camera = this.getCamera();
Expand Down Expand Up @@ -622,7 +627,12 @@ export class Material

// Load material
if (mtlxMaterial)
await mx.readFromXmlString(doc, mtlxMaterial, searchPath);
try {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small fix. Would "crash" sometimes on invalid files.

await mx.readFromXmlString(doc, mtlxMaterial, searchPath);
}
catch (error) {
console.log('Error loading material file: ', error);
}
else
Material.createFallbackMaterial(doc);

Expand Down Expand Up @@ -847,12 +857,14 @@ export class Material
assigned += viewer.getScene().updateMaterial(matassign);
matassign.setGeometry(temp);
assignedSolo = true;
viewer.scheduleUpdate();
break
}
}
else
{
assigned += viewer.getScene().updateMaterial(matassign);
viewer.scheduleUpdate();
}
}
}
Expand All @@ -861,6 +873,7 @@ export class Material
this._defaultMaterial = new MaterialAssign(this._materials[0].getMaterial(), ALL_GEOMETRY_SPECIFIER);
this._defaultMaterial.setShader(this._materials[0].getShader());
viewer.getScene().updateMaterial(this._defaultMaterial);
viewer.scheduleUpdate();
}

if (assigned > 0)
Expand Down Expand Up @@ -916,8 +929,8 @@ export class Material
let theScene = viewer.getScene();
let flipV = theScene.getFlipGeometryV();
let uniforms = {
...getUniformValues(shader.getStage('vertex'), textureLoader, searchPath, flipV),
...getUniformValues(shader.getStage('pixel'), textureLoader, searchPath, flipV),
...getUniformValues(viewer, shader.getStage('vertex'), textureLoader, searchPath, flipV),
...getUniformValues(viewer, shader.getStage('pixel'), textureLoader, searchPath, flipV),
}

Object.assign(uniforms, {
Expand Down Expand Up @@ -953,6 +966,7 @@ export class Material
if (logDetailedTime)
console.log("- Per material generate time: ", performance.now() - startGenerateMat, "ms");

viewer.scheduleUpdate();
return newMaterial;
}

Expand Down Expand Up @@ -1009,6 +1023,7 @@ export class Material
}
viewer.getMaterial().updateMaterialAssignments(viewer, this._soloMaterial);
viewer.getScene().setUpdateTransforms();
viewer.scheduleUpdate();
}

//
Expand Down Expand Up @@ -1231,6 +1246,10 @@ export class Material
}
const w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);
w.domElement.classList.add('peditoritem');
w.onChange(function (value)
{
viewer.scheduleUpdate();
});
}
break;

Expand Down Expand Up @@ -1294,6 +1313,10 @@ export class Material
{
let w = currentFolder.add(material.uniforms[name], 'value', minValue, maxValue, step).name(path);
w.domElement.classList.add('peditoritem');
w.onChange(function (value)
{
viewer.scheduleUpdate();
});
}
else
{
Expand All @@ -1319,6 +1342,7 @@ export class Material
{
material.uniforms[name].value = value;
}
viewer.scheduleUpdate();
}
const defaultOption = enumList[value]; // Set the default selected option
const dropdownController = currentFolder.add(enumeration, defaultOption, enumeration).name(path);
Expand All @@ -1334,6 +1358,11 @@ export class Material
{
let w = currentFolder.add(material.uniforms[name], 'value').name(path);
w.domElement.classList.add('peditoritem');
w.onChange(function (value)
{
viewer.scheduleUpdate();
});

}
break;

Expand Down Expand Up @@ -1377,6 +1406,10 @@ export class Material
let w = vecFolder.add(material.uniforms[name].value,
key, minValue[key], maxValue[key], step[key]).name(keyString[key]);
w.domElement.classList.add('peditoritem');
w.onChange(function (value)
{
viewer.scheduleUpdate();
});
})
}
break;
Expand All @@ -1398,6 +1431,7 @@ export class Material
{
const color3 = new THREE.Color(value);
material.uniforms[name].value.set(color3.toArray());
viewer.scheduleUpdate();
});
w.domElement.classList.add('peditoritem');
}
Expand All @@ -1421,7 +1455,11 @@ export class Material
let item = currentFolder.add(dummy, 'thevalue');
item.name(path);
item.disable(true);
item.domElement.classList.add('peditoritem');
let w = item.domElement.classList.add('peditoritem');
w.onChange(function (value)
{
viewer.scheduleUpdate();
});
}
break;
default:
Expand Down Expand Up @@ -1465,6 +1503,30 @@ export class Viewer

this.fileLoader = new THREE.FileLoader();
this.hdrLoader = new RGBELoader();

this.updates = 0
}

scheduleUpdate()
{
this.updates++;
//console.log('Schedule update: ', this.updates)
}

finishUpdate()
{
if (this.updates > 0)
{
this.updates--;
//console.log('Finish update: ', this.updates)
}
}

needUpdate()
{
//if (this.updates > 0)
// console.log('Need update: ', this.updates > 0)
return this.updates > 0;
}

//
Expand Down
Binary file added resources/Geometry/sphere.glb
Binary file not shown.