Skip to content

Commit

Permalink
Rendering refactor for anti-aliasing (google#880)
Browse files Browse the repository at this point in the history
* removed normalmap blur

* added roughnessmipmapper

* need to change strategies

* roughness shader runs

* changing roughness mips, but not saving the texture properly

* texture saving working, but seems to have a race condition

* commented out debugging

* roughness mipmapper sort of working but may have a race

* working better now; equation needs work

* mipmapping and saving work, equation should be tweaked

* merging master

* roughness mipmapper working

* cleanup

* added vertex normal antialiasing

* fixed skybox

* disaligned blur axes to remove pole artifact

* added uniform mip level

* moved geometry antialiasing up to affect main roughness value

* using two roughness values

* moved debugging function

* fixed black PMREM corner pixels

* added directional light fidelity test

* remapped roughness

* best yet

* first cleanup

* second cleanup

* more cleanup

* fixed unlit model bug

* reverting index

* bumped threejs version

* cleanup

* cleaning spaces

* added docs, shader improvement

* updated goldens

* slight update of PMREM parameters to match analysis

* updated goldens

* addressing feedback

* renderer -> threeRenderer

* moved debug to utilities

* added comma
  • Loading branch information
elalish authored Nov 19, 2019
1 parent 58db473 commit 3fb2fc3
Show file tree
Hide file tree
Showing 142 changed files with 567 additions and 254 deletions.
Binary file added examples/assets/spot1Lux.hdr
Binary file not shown.
12 changes: 9 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"@types/puppeteer": "^1.11.1",
"@types/resize-observer-browser": "^0.1.2",
"@types/three": "^0.93.12",
"@types/webgl2": "^0.0.5",
"@webcomponents/webcomponentsjs": "~2.1.3",
"chai": "^4.1.2",
"chokidar-cli": "^1.2.1",
Expand Down Expand Up @@ -112,7 +113,7 @@
},
"dependencies": {
"lit-element": "^2.2.0",
"three": "^0.108.0"
"three": "^0.110.0"
},
"publishConfig": {
"access": "public"
Expand Down
4 changes: 2 additions & 2 deletions src/features/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ export const AnimationMixin = <T extends Constructor<ModelViewerElementBase>>(
}

this[$paused] = true;
this[$renderer].renderer.shadowMap.autoUpdate = false;
this[$renderer].threeRenderer.shadowMap.autoUpdate = false;
this.dispatchEvent(new CustomEvent('pause'));
}

play() {
if (this[$paused] && this.availableAnimations.length > 0) {
this[$paused] = false;
this[$renderer].renderer.shadowMap.autoUpdate = true;
this[$renderer].threeRenderer.shadowMap.autoUpdate = true;

if (!this[$scene].model.hasActiveAnimation) {
this[$changeAnimation]();
Expand Down
21 changes: 9 additions & 12 deletions src/model-viewer-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ import {HAS_INTERSECTION_OBSERVER, HAS_RESIZE_OBSERVER} from './constants.js';
import {makeTemplate} from './template.js';
import {$evictionPolicy, CachingGLTFLoader} from './three-components/CachingGLTFLoader.js';
import {ModelScene} from './three-components/ModelScene.js';
import {ContextLostEvent, Renderer} from './three-components/Renderer.js';
import {debounce, deserializeUrl, isDebugMode, resolveDpr} from './utilities.js';
import {ContextLostEvent, renderer} from './three-components/Renderer.js';
import {debounce, deserializeUrl, resolveDpr} from './utilities.js';
import {dataUrlToBlob} from './utilities/data-conversion.js';
import {ProgressTracker} from './utilities/progress-tracker.js';

let renderer = new Renderer({debug: isDebugMode()});

const CLEAR_MODEL_TIMEOUT_MS = 1000;
const FALLBACK_SIZE_UPDATE_THRESHOLD_MS = 50;
const UNSIZED_MEDIA_WIDTH = 300;
Expand All @@ -46,7 +44,6 @@ const $onContextLost = Symbol('onContextLost');
const $contextLostHandler = Symbol('contextLostHandler');

export const $isInRenderTree = Symbol('isInRenderTree');
export const $resetRenderer = Symbol('resetRenderer');
export const $ariaLabel = Symbol('ariaLabel');
export const $loadedTime = Symbol('loadedTime');
export const $updateSource = Symbol('updateSource');
Expand Down Expand Up @@ -74,11 +71,6 @@ interface ToBlobOptions {
export default class ModelViewerElementBase extends UpdatingElement {
protected static[$template]: HTMLTemplateElement|void;

static[$resetRenderer]() {
renderer.dispose();
renderer = new Renderer();
}

static get is() {
return 'model-viewer';
}
Expand Down Expand Up @@ -185,8 +177,13 @@ export default class ModelViewerElementBase extends UpdatingElement {
}

// Create the underlying ModelScene.
this[$scene] = new ModelScene(
{canvas: this[$canvas], element: this, width, height, renderer});
this[$scene] = new ModelScene({
canvas: this[$canvas],
element: this,
width,
height,
renderer: renderer
});

this[$scene].addEventListener('model-load', (event) => {
this[$markLoaded]();
Expand Down
1 change: 0 additions & 1 deletion src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ canvas.show {
.slot.poster.show {
opacity: 1;
transition: none;
background-color: inherit;
}
.slot.poster > * {
Expand Down
12 changes: 3 additions & 9 deletions src/test/features/environment-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {Color, Material, Mesh, Scene} from 'three';
import {MeshStandardMaterial} from 'three';

import {EnvironmentInterface, EnvironmentMixin} from '../../features/environment.js';
import ModelViewerElementBase, {$resetRenderer, $scene} from '../../model-viewer-base.js';
import ModelViewerElementBase, {$scene} from '../../model-viewer-base.js';
import Model from '../../three-components/Model.js';
import {ModelScene} from '../../three-components/ModelScene.js';
import {assetPath, rafPasses, textureMatchesMeta, timePasses, waitForEvent} from '../helpers.js';
Expand Down Expand Up @@ -119,12 +119,6 @@ const waitForLoadAndEnvMap =
};

suite('ModelViewerElementBase with EnvironmentMixin', () => {
suiteTeardown(() => {
// Reset the renderer once at the end of this spec, to clear out all
// of the heavy cached image buffers:
ModelViewerElementBase[$resetRenderer]();
});

let nextId = 0;
let tagName: string;
let ModelViewerElement:
Expand Down Expand Up @@ -338,13 +332,13 @@ suite('ModelViewerElementBase with EnvironmentMixin', () => {

test('changes the tone mapping exposure of the renderer', async () => {
const originalToneMappingExposure =
scene.renderer.renderer.toneMappingExposure;
scene.renderer.threeRenderer.toneMappingExposure;
element.exposure = 2.0;
await timePasses();
scene.renderer.render(performance.now());

const newToneMappingExposure =
scene.renderer.renderer.toneMappingExposure;
scene.renderer.threeRenderer.toneMappingExposure;

expect(newToneMappingExposure)
.to.be.greaterThan(originalToneMappingExposure);
Expand Down
23 changes: 19 additions & 4 deletions src/test/fidelity/components/renderers/filament-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,25 @@ export class FilamentViewer extends LitElement {

await fetchFilamentAssets([modelUrl, iblUrl, skyboxUrl]);

this[$ibl] = this[$engine].createIblFromKtx(iblUrl);
this[$scene].setIndirectLight(this[$ibl]);
this[$ibl].setIntensity(1.0);
this[$ibl].setRotation([0, 0, -1, 0, 1, 0, 1, 0, 0]); // 90 degrees
// This special case is for the DirectionalLightTest, where we compare the
// <model-viewer> IBL to the Filament directional light by using a special
// environment map with a single bright pixel that represents a 1 lux
// directional light.
if (lightingBaseName === 'spot1Lux') {
const light = self.Filament.EntityManager.get().create();
self.Filament.LightManager
.Builder(self.Filament.LightManager$Type.DIRECTIONAL)
.color([1, 1, 1])
.intensity(1)
.direction([-1, 0, 0])
.build(this[$engine], light);
this[$scene].addEntity(light);
} else {
this[$ibl] = this[$engine].createIblFromKtx(iblUrl);
this[$scene].setIndirectLight(this[$ibl]);
this[$ibl].setIntensity(1.0);
this[$ibl].setRotation([0, 0, -1, 0, 1, 0, 1, 0, 0]); // 90 degrees
}

this[$skybox] = this[$engine].createSkyFromKtx(skyboxUrl);
this[$scene].setSkybox(this[$skybox]);
Expand Down
2 changes: 1 addition & 1 deletion src/test/model-viewer-base-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ suite('ModelViewerElementBase', () => {
});

test('dispatches a related error event', async () => {
const renderer = element[$renderer].renderer;
const renderer = element[$renderer].threeRenderer;
const errorEventDispatches = waitForEvent(element, 'error');
// We make a best effor to simulate the real scenario here, but
// for some cases like headless Chrome WebGL might be disabled,
Expand Down
4 changes: 2 additions & 2 deletions src/test/three-components/Renderer-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ suite('Renderer', () => {

test('updates effective DPR', async () => {
const {element} = scene;
const initialDpr = renderer.renderer.getPixelRatio();
const initialDpr = renderer.threeRenderer.getPixelRatio();
const {width, height} = scene.getSize();

element[$onResize]({width, height});
Expand All @@ -141,7 +141,7 @@ suite('Renderer', () => {

await new Promise(resolve => requestAnimationFrame(resolve));

const newDpr = renderer.renderer.getPixelRatio();
const newDpr = renderer.threeRenderer.getPixelRatio();

expect(newDpr).to.be.equal(initialDpr + 1);
});
Expand Down
18 changes: 9 additions & 9 deletions src/test/three-components/TextureUtils-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,27 @@ const EQUI_URL = assetPath('spruit_sunrise_1k_LDR.jpg');
const HDR_EQUI_URL = assetPath('spruit_sunrise_1k_HDR.hdr');

suite('TextureUtils', () => {
let renderer: WebGLRenderer;
let threeRenderer: WebGLRenderer;

suiteSetup(() => {
// The renderer can retain state, so these tests have the possibility of
// getting different results in different orders. However, our use of the
// renderer *should* always return its state to what it was before to avoid
// this kind of problem (and many other headaches).
renderer = new WebGLRenderer({canvas});
renderer.debug.checkShaderErrors = true;
// The threeRenderer can retain state, so these tests have the possibility
// of getting different results in different orders. However, our use of the
// threeRenderer *should* always return its state to what it was before to
// avoid this kind of problem (and many other headaches).
threeRenderer = new WebGLRenderer({canvas});
threeRenderer.debug.checkShaderErrors = true;
});

suiteTeardown(() => {
// Ensure we free up memory from loading large environment maps:
Cache.clear();
renderer.dispose();
threeRenderer.dispose();
});

let textureUtils: TextureUtils;

setup(() => {
textureUtils = new TextureUtils(renderer);
textureUtils = new TextureUtils(threeRenderer);
});

teardown(async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/three-components/ARRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ARRenderer extends EventDispatcher {

// this.renderer is a three.js WebGLRenderer, it is shared with the parent
// Renderer.
this.renderer = parentRenderer.renderer;
this.renderer = parentRenderer.threeRenderer;

this.inputContext = inputContext;

Expand Down
17 changes: 16 additions & 1 deletion src/three-components/CachingGLTFLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
* limitations under the License.
*/

import {Mesh, Object3D, Scene} from 'three';
import {Mesh, MeshStandardMaterial, Object3D, Scene} from 'three';
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';

import {CacheEvictionPolicy} from '../utilities/cache-eviction-policy.js';

import {cloneGltf, Gltf} from './ModelUtils.js';
import {RoughnessMipmapper} from './RoughnessMipmapper.js';

export type ProgressCallback = (progress: number) => void;

Expand Down Expand Up @@ -126,6 +127,8 @@ export class CachingGLTFLoader {
preloaded.set(url, true);
}

protected roughnessMipmapper = new RoughnessMipmapper();

/**
* Loads a glTF from the specified url and resolves a unique clone of the
* glTF. If the glTF has already been loaded, makes a clone of the cached
Expand All @@ -150,6 +153,18 @@ export class CachingGLTFLoader {
if (!node.name) {
node.name = node.uuid;
}
if (!(node as Mesh).isMesh) {
return;
}
const mesh = node as Mesh;
const materials =
Array.isArray(mesh.material) ? mesh.material : [mesh.material];
materials.forEach(material => {
if ((material as any).isMeshStandardMaterial) {
this.roughnessMipmapper.generateMipmaps(
material as MeshStandardMaterial);
}
});
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/three-components/Debugger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface ModelViewerSceneDetails {
export class Debugger {
constructor(renderer: Renderer) {
// Force WebGL shader debugging on:
renderer.renderer.debug = {checkShaderErrors: true};
renderer.threeRenderer.debug = {checkShaderErrors: true};
// Announce debug details at microtask timing to give the `Renderer`
// constructor time to complete its initialization, just to be on the safe
// side:
Expand Down
13 changes: 1 addition & 12 deletions src/three-components/ModelScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export class ModelScene extends Scene {
if (this.shadow == null) {
this.shadow = new Shadow(this.model, this.pivot, this.shadowSoftness);
this.pivot.add(this.shadow);
// this.showShadowHelper();
// showShadowHelper(this);
}
this.shadow.setIntensity(shadowIntensity);
}
Expand All @@ -263,17 +263,6 @@ export class ModelScene extends Scene {
}
}

/**
* Renders a box representing the shadow camera, which is helpful in
* debugging.
*/
// showShadowHelper() {
// if (this.shadow != null) {
// const helper = new CameraHelper(this.shadow.shadow.camera);
// this.add(helper);
// }
// }

createSkyboxMesh(): Mesh {
const geometry = new BoxBufferGeometry(1, 1, 1);
geometry.removeAttribute('normal');
Expand Down
14 changes: 7 additions & 7 deletions src/three-components/ModelUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {Camera, Material, Object3D, Scene, Shader, Vector3} from 'three';
import {SkeletonUtils} from 'three/examples/jsm/utils/SkeletonUtils.js';

import {cubeUVChunk} from './shader-chunk/cube_uv_reflection_fragment.glsl.js';
import {normalmapChunk} from './shader-chunk/normalmap_pars_fragment.glsl.js';
import {lightsChunk} from './shader-chunk/lights_physical_fragment.glsl.js';

// NOTE(cdata): What follows is a TypeScript-ified version of:
// https://gist.github.com/cdata/f2d7a6ccdec071839bc1954c32595e87
Expand All @@ -40,11 +40,9 @@ const updateShader = (shader: Shader) => {
shader.fragmentShader =
shader.fragmentShader
.replace('#include <cube_uv_reflection_fragment>', cubeUVChunk)
.replace('#include <normalmap_pars_fragment>', normalmapChunk);
.replace('#include <lights_physical_fragment>', lightsChunk);
};



/**
* Fully clones a parsed GLTF, including correct cloning of any SkinnedMesh
* objects.
Expand Down Expand Up @@ -74,9 +72,11 @@ export const cloneGltf = (gltf: Gltf): Gltf => {
specularGlossiness.cloneMaterial(material) :
material.clone();
clone.onBeforeCompile = updateShader;
// TODO(elalish): remove this when we upgrade three.js to a version with
// this fix: mrdoob/three.js#17795
clone.vertexTangents = material.vertexTangents;
// This is a fix for NormalTangentMirrorTest. Remove when
// https://github.com/mrdoob/three.js/issues/11438 is solved.
if (!clone.vertexTangents && clone.normalScale) {
clone.normalScale.y *= -1;
}
return clone;
};

Expand Down
Loading

0 comments on commit 3fb2fc3

Please sign in to comment.