mirror of
https://github.com/visgl/luma.gl.git
synced 2026-02-01 14:33:49 +00:00
glTF Snapshot Tests (#913)
This commit is contained in:
parent
f4b50f877b
commit
050f58f2be
@ -3,7 +3,7 @@ import {AnimationLoop, setParameters, clear, GLTFInstantiator, log} from 'luma.g
|
||||
import {Matrix4, radians} from 'math.gl';
|
||||
import document from 'global/document';
|
||||
|
||||
const GLTF_BASE_URL = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/";
|
||||
export const GLTF_BASE_URL = "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/";
|
||||
|
||||
const INFO_HTML = `
|
||||
<p><b>glTF</b> rendering.</p>
|
||||
@ -75,14 +75,19 @@ const INFO_HTML = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
function loadGLTF(urlOrPromise, gl) {
|
||||
const DEFAULT_OPTIONS = {
|
||||
pbrDebug: true,
|
||||
pbrIbl: true
|
||||
};
|
||||
|
||||
function loadGLTF(urlOrPromise, gl, options = DEFAULT_OPTIONS) {
|
||||
const promise = urlOrPromise instanceof Promise ? urlOrPromise : window.fetch(urlOrPromise).then(res => res.arrayBuffer());
|
||||
|
||||
return promise.then(data => {
|
||||
const gltfParser = new GLTFParser();
|
||||
const gltf = gltfParser.parse(data);
|
||||
|
||||
const instantiator = new GLTFInstantiator(gl, {pbrDebug: true});
|
||||
const instantiator = new GLTFInstantiator(gl, options);
|
||||
const scenes = instantiator.instantiate(gltf);
|
||||
|
||||
log.info(4, "gltfParser: ", gltfParser)();
|
||||
@ -96,11 +101,11 @@ function loadGLTF(urlOrPromise, gl) {
|
||||
});
|
||||
}
|
||||
|
||||
class DemoApp {
|
||||
constructor() {
|
||||
export class DemoApp {
|
||||
constructor({modelFile = null, initialZoom = 2} = {}) {
|
||||
this.scenes = [];
|
||||
this.gl = null;
|
||||
this.loadedModelUrl = null;
|
||||
this.modelFile = modelFile;
|
||||
|
||||
this.glOptions = {
|
||||
// Use to test gltf with webgl 1.0 and 2.0
|
||||
@ -112,7 +117,7 @@ class DemoApp {
|
||||
lastY: 0
|
||||
};
|
||||
|
||||
this.translate = 2;
|
||||
this.translate = initialZoom;
|
||||
this.rotation = [0, 0];
|
||||
this.rotationStart = [0, 0];
|
||||
|
||||
@ -177,19 +182,30 @@ class DemoApp {
|
||||
});
|
||||
|
||||
this.gl = gl;
|
||||
const modelSelector = document.getElementById("modelSelector");
|
||||
loadGLTF(GLTF_BASE_URL + modelSelector.value, this.gl).then(scenes => (this.scenes = scenes));
|
||||
|
||||
modelSelector.onchange = event => {
|
||||
if (this.modelFile) {
|
||||
// options for unit testing
|
||||
const options = {
|
||||
pbrDebug: false,
|
||||
pbrIbl: false
|
||||
};
|
||||
loadGLTF(this.modelFile, this.gl, options).then(scenes => (this.scenes = scenes));
|
||||
} else {
|
||||
const modelSelector = document.getElementById("modelSelector");
|
||||
loadGLTF(GLTF_BASE_URL + modelSelector.value, this.gl).then(scenes => (this.scenes = scenes));
|
||||
};
|
||||
|
||||
modelSelector.onchange = event => {
|
||||
loadGLTF(GLTF_BASE_URL + modelSelector.value, this.gl).then(scenes => (this.scenes = scenes));
|
||||
};
|
||||
}
|
||||
|
||||
const showSelector = document.getElementById("showSelector");
|
||||
showSelector.onchange = event => {
|
||||
const value = showSelector.value.split(" ").map(x => parseFloat(x));
|
||||
this.u_ScaleDiffBaseMR = value.slice(0, 4);
|
||||
this.u_ScaleFGDSpec = value.slice(4);
|
||||
};
|
||||
if (showSelector) {
|
||||
showSelector.onchange = event => {
|
||||
const value = showSelector.value.split(" ").map(x => parseFloat(x));
|
||||
this.u_ScaleDiffBaseMR = value.slice(0, 4);
|
||||
this.u_ScaleFGDSpec = value.slice(4);
|
||||
};
|
||||
}
|
||||
|
||||
this.initalizeEventHandling(canvas);
|
||||
}
|
||||
@ -212,12 +228,14 @@ class DemoApp {
|
||||
|
||||
const uProjection = new Matrix4().perspective({fov: radians(40), aspect, near: 0.1, far: 9000});
|
||||
|
||||
if (!this.scenes.length) return;
|
||||
if (!this.scenes.length) return false;
|
||||
|
||||
let success = true;
|
||||
|
||||
this.scenes[0].traverse((model, {worldMatrix}) => {
|
||||
// In glTF, meshes and primitives do no have their own matrix.
|
||||
const u_MVPMatrix = new Matrix4(uProjection).multiplyRight(uView).multiplyRight(worldMatrix);
|
||||
model.draw({
|
||||
success = success && model.draw({
|
||||
uniforms: {
|
||||
u_Camera: cameraPos,
|
||||
u_MVPMatrix,
|
||||
@ -229,6 +247,8 @@ class DemoApp {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,7 +18,8 @@ const ATTRIBUTE_TYPE_TO_COMPONENTS = {
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
modelOptions: {},
|
||||
pbrDebug: false
|
||||
pbrDebug: false,
|
||||
pbrIbl: null
|
||||
};
|
||||
|
||||
// GLTF instantiator for luma.gl
|
||||
@ -113,7 +114,8 @@ export default class GLTFInstantiator {
|
||||
attributes: this.createAttributes(gltfPrimitive.attributes, gltfPrimitive.indices),
|
||||
material: gltfPrimitive.material,
|
||||
modelOptions: this.options.modelOptions,
|
||||
debug: this.options.pbrDebug
|
||||
debug: this.options.pbrDebug,
|
||||
ibl: this.options.pbrIbl
|
||||
});
|
||||
|
||||
return model;
|
||||
|
||||
@ -137,12 +137,10 @@ class GLTFEnv {
|
||||
}
|
||||
|
||||
class GLTFMaterialParser {
|
||||
constructor(gl, {attributes, material, debug}) {
|
||||
constructor(gl, {attributes, material, debug, ibl}) {
|
||||
this.gl = gl;
|
||||
this.env = new GLTFEnv(gl);
|
||||
|
||||
this.defines = {
|
||||
USE_IBL: 1,
|
||||
USE_TEX_LOD: 1,
|
||||
|
||||
// TODO: Use EXT_sRGB if available (Standard in WebGL 2.0)
|
||||
@ -157,14 +155,16 @@ class GLTFMaterialParser {
|
||||
u_LightDirection: [0.0, 0.5, 0.5],
|
||||
u_LightColor: [1.0, 1.0, 1.0],
|
||||
|
||||
u_MetallicRoughnessValues: [1, 1], // Default is 1 and 1
|
||||
u_MetallicRoughnessValues: [1, 1] // Default is 1 and 1
|
||||
};
|
||||
|
||||
// IBL
|
||||
if (ibl) {
|
||||
this.env = new GLTFEnv(gl);
|
||||
// u_DiffuseEnvSampler: this.env.getDiffuseEnvSampler(),
|
||||
// u_SpecularEnvSampler: this.env.getSpecularEnvSampler(),
|
||||
u_brdfLUT: this.env.getBrdfTex(),
|
||||
u_ScaleIBLAmbient: [1, 1]
|
||||
};
|
||||
this.uniforms.u_brdfLUT = this.env.getBrdfTex();
|
||||
this.uniforms.u_ScaleIBLAmbient = [1, 1];
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
// Override final color for reference app visualization
|
||||
@ -177,6 +177,7 @@ class GLTFMaterialParser {
|
||||
this.defineIfPresent(attributes.TANGENT, 'HAS_TANGENTS');
|
||||
this.defineIfPresent(attributes.TEXCOORD_0, 'HAS_UV');
|
||||
|
||||
this.defineIfPresent(ibl, 'USE_IBL');
|
||||
this.defineIfPresent(debug, 'PBR_DEBUG');
|
||||
|
||||
if (material) {
|
||||
@ -264,9 +265,9 @@ function addVersionToShader(gl, source) {
|
||||
|
||||
export function createGLTFModel(
|
||||
gl,
|
||||
{id, drawMode, vertexCount, attributes, material, modelOptions, debug = false}
|
||||
{id, drawMode, vertexCount, attributes, material, modelOptions, debug, ibl}
|
||||
) {
|
||||
const materialParser = new GLTFMaterialParser(gl, {attributes, material, debug});
|
||||
const materialParser = new GLTFMaterialParser(gl, {attributes, material, debug, ibl});
|
||||
|
||||
log.info(4, 'createGLTFModel defines: ', materialParser.defines)();
|
||||
|
||||
@ -289,17 +290,19 @@ export function createGLTFModel(
|
||||
model.setProps({attributes});
|
||||
model.setUniforms(materialParser.uniforms);
|
||||
|
||||
materialParser.env.getDiffuseEnvSampler().then(cubeTex => {
|
||||
model.setUniforms({
|
||||
u_DiffuseEnvSampler: cubeTex
|
||||
if (ibl) {
|
||||
materialParser.env.getDiffuseEnvSampler().then(cubeTex => {
|
||||
model.setUniforms({
|
||||
u_DiffuseEnvSampler: cubeTex
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
materialParser.env.getSpecularEnvSampler().then(cubeTex => {
|
||||
model.setUniforms({
|
||||
u_SpecularEnvSampler: cubeTex
|
||||
materialParser.env.getSpecularEnvSampler().then(cubeTex => {
|
||||
model.setUniforms({
|
||||
u_SpecularEnvSampler: cubeTex
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@ -56,13 +56,14 @@
|
||||
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/register": "^7.0.0",
|
||||
"@loaders.gl/gltf": "^0.6.2",
|
||||
"@probe.gl/test-utils": "^3.0.0-alpha.4",
|
||||
"babel-eslint": "^9.0.0",
|
||||
"babel-loader": "^8.0.0",
|
||||
"babel-plugin-istanbul": "^5.0.0",
|
||||
"babel-plugin-version-inline": "^1.0.0",
|
||||
"babel-plugin-inline-webgl-constants": "^1.0.0",
|
||||
"babel-plugin-istanbul": "^5.0.0",
|
||||
"babel-plugin-remove-glsl-comments": "^1.0.0",
|
||||
"babel-plugin-version-inline": "^1.0.0",
|
||||
"codecov": "^3.1.0",
|
||||
"coveralls": "^2.13.0",
|
||||
"eslint": "4.13.1",
|
||||
|
||||
38
test/render/gltf-test-cases.js
Normal file
38
test/render/gltf-test-cases.js
Normal file
@ -0,0 +1,38 @@
|
||||
import {AnimationLoop} from '@luma.gl/core';
|
||||
import {DemoApp, GLTF_BASE_URL} from '../../examples/gltf/app';
|
||||
|
||||
const examples = {
|
||||
damagedHelmet: {
|
||||
modelFile: `${GLTF_BASE_URL}DamagedHelmet/glTF-Binary/DamagedHelmet.glb`,
|
||||
initialZoom: 5
|
||||
},
|
||||
duck: {
|
||||
modelFile: `${GLTF_BASE_URL}Duck/glTF-Binary/Duck.glb`,
|
||||
initialZoom: 8
|
||||
},
|
||||
monster: {
|
||||
modelFile: `${GLTF_BASE_URL}Monster/glTF-Binary/Monster.glb`,
|
||||
initialZoom: 120
|
||||
}
|
||||
};
|
||||
|
||||
export default Object.keys(examples).map(name => {
|
||||
const app = new DemoApp(examples[name]);
|
||||
const animationLoop = new AnimationLoop(app);
|
||||
|
||||
return {
|
||||
name,
|
||||
onInitialize: params => {
|
||||
return animationLoop.onInitialize(params);
|
||||
},
|
||||
onRender: params => {
|
||||
const result = animationLoop.onRender(params);
|
||||
if (result !== false) {
|
||||
params.done();
|
||||
}
|
||||
},
|
||||
timeout: 5000,
|
||||
onFinalize: animationLoop.onFinalize.bind(animationLoop),
|
||||
goldenImage: `./test/render/golden-images/${name}.png`
|
||||
};
|
||||
});
|
||||
BIN
test/render/golden-images/damagedHelmet.png
Normal file
BIN
test/render/golden-images/damagedHelmet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
test/render/golden-images/duck.png
Normal file
BIN
test/render/golden-images/duck.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
test/render/golden-images/monster.png
Normal file
BIN
test/render/golden-images/monster.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@ -2,6 +2,7 @@ import test from 'tape-catch';
|
||||
import {SnapshotTestRunner} from '@luma.gl/test-utils';
|
||||
|
||||
import EXAMPLE_TEST_CASES from './example-test-cases';
|
||||
import GLTF_TEST_CASES from './gltf-test-cases';
|
||||
|
||||
const renderTestCaseCount = EXAMPLE_TEST_CASES.length;
|
||||
|
||||
@ -11,6 +12,7 @@ test('RenderTest', t => {
|
||||
|
||||
new SnapshotTestRunner({width: 600, height: 400})
|
||||
.add(EXAMPLE_TEST_CASES)
|
||||
.add(GLTF_TEST_CASES)
|
||||
.run({
|
||||
onTestStart: testCase => t.comment(testCase.name),
|
||||
onTestPass: (testCase, result) => t.pass(`match: ${result.matchPercentage}`),
|
||||
|
||||
19
yarn.lock
19
yarn.lock
@ -720,6 +720,20 @@
|
||||
lodash "^4.17.10"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@loaders.gl/core@^0.6.2":
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@loaders.gl/core/-/core-0.6.2.tgz#d4260e27c367e4c41ea7ba69a2d9525ee608511b"
|
||||
integrity sha512-dG8mTy+c+xqgkYKe/We6mgLfesCy3ITlEdfWccKjWupIa6iKPBnf/CgDQE8+C4IOzKR5njDCMMKKOM0kZIdDQw==
|
||||
dependencies:
|
||||
text-encoding "^0.6.4"
|
||||
|
||||
"@loaders.gl/gltf@^0.6.2":
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@loaders.gl/gltf/-/gltf-0.6.2.tgz#03f4546840d0bf6c2e64cb0c08c3723af3106a6f"
|
||||
integrity sha512-vZZV029K0ZOg/7lOJ/FF7mu5a1UZg0OTNrDMBpUFLlyX7gEheErGOpLD3WlDA+SxBdsdb4RLA7rCdpRLN5yyAQ==
|
||||
dependencies:
|
||||
"@loaders.gl/core" "^0.6.2"
|
||||
|
||||
"@luma.gl/glfx@^6.3.0-alpha.2":
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@luma.gl/glfx/-/glfx-6.3.0.tgz#08929e3488b58ddf339c6df0627282543d78c66a"
|
||||
@ -7557,6 +7571,11 @@ test-exclude@^5.0.0:
|
||||
read-pkg-up "^4.0.0"
|
||||
require-main-filename "^1.0.1"
|
||||
|
||||
text-encoding@^0.6.4:
|
||||
version "0.6.4"
|
||||
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
|
||||
integrity sha1-45mpgiV6J22uQou5KEXLcb3CbRk=
|
||||
|
||||
text-extensions@^1.0.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.8.0.tgz#6f343c62268843019b21a616a003557bdb952d2b"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user