Add IBL to jsbinding and testwasm.

This commit is contained in:
Philip Rideout
2018-10-17 16:13:53 -07:00
parent f5319f2492
commit d3e7f40398
4 changed files with 187 additions and 56 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ class App {
}
}
Filament.init(['bakedColor.filamat'], () => { Window.app = new App() } );
Filament.init(['bakedColor.filamat'], () => { window.app = new App() } );
```
The two calls to `bind()` allow us to pass instance methods as callbacks for animation and resize
+85 -2
View File
@@ -35,12 +35,14 @@
#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/IndirectLight.h>
#include <filament/LightManager.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/SwapChain.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
@@ -88,8 +90,10 @@ namespace emscripten {
BIND(TransformManager)
BIND(VertexBuffer)
BIND(IndexBuffer)
BIND(IndirectLight)
BIND(Material)
BIND(MaterialInstance)
BIND(Skybox)
BIND(Texture)
BIND(utils::Entity)
BIND(utils::EntityManager)
@@ -107,6 +111,8 @@ using IndexBuilder = IndexBuffer::Builder;
using MatBuilder = Material::Builder;
using TexBuilder = Texture::Builder;
using LightBuilder = LightManager::Builder;
using IblBuilder = IndirectLight::Builder;
using SkyBuilder = Skybox::Builder;
// We avoid directly exposing driver::BufferDescriptor because embind does not support move
// semantics and void* doesn't make sense to JavaScript anyway. This little wrapper class is exposed
@@ -207,6 +213,16 @@ value_array<flatmat4>("mat4")
.element(index< 8>()).element(index< 9>()).element(index<10>()).element(index<11>())
.element(index<12>()).element(index<13>()).element(index<14>()).element(index<15>());
struct flatmat3 {
math::mat3f m;
float& operator[](int i) { return m[i / 3][i % 3]; }
};
value_array<flatmat3>("mat3")
.element(index<0>()).element(index<1>()).element(index<2>())
.element(index<3>()).element(index<4>()).element(index<5>())
.element(index<6>()).element(index<7>()).element(index<8>());
// CORE FILAMENT CLASSES
// ---------------------
@@ -283,7 +299,12 @@ class_<View>("View")
.function("setPostProcessingEnabled", &View::setPostProcessingEnabled);
class_<Scene>("Scene")
.function("addEntity", &Scene::addEntity);
.function("addEntity", &Scene::addEntity)
.function("remove", &Scene::remove)
.function("setSkybox", &Scene::setSkybox, allow_raw_pointers())
.function("setIndirectLight", &Scene::setIndirectLight, allow_raw_pointers())
.function("getRenderableCount", &Scene::getRenderableCount)
.function("getLightCount", &Scene::getLightCount);
class_<Camera>("Camera")
.function("setProjection", EMBIND_LAMBDA(void, (Camera* self, Camera::Projection projection,
@@ -441,6 +462,18 @@ class_<Texture>("Texture")
.function("setImage", EMBIND_LAMBDA(void, (Texture* self,
Engine* engine, uint8_t level, PixelBufferDescriptor pbd), {
self->setImage(*engine, level, std::move(*pbd.pbd));
}), allow_raw_pointers())
.function("setImageCube", EMBIND_LAMBDA(void, (Texture* self,
Engine* engine, uint8_t level, PixelBufferDescriptor pbd), {
uint32_t faceSize = pbd.pbd->size / 6;
Texture::FaceOffsets offsets;
offsets.px = faceSize * 0;
offsets.nx = faceSize * 1;
offsets.py = faceSize * 2;
offsets.ny = faceSize * 3;
offsets.pz = faceSize * 4;
offsets.nz = faceSize * 5;
self->setImage(*engine, level, std::move(*pbd.pbd), offsets);
}), allow_raw_pointers());
class_<TexBuilder>("Texture$Builder")
@@ -464,6 +497,47 @@ class_<TexBuilder>("Texture$Builder")
.BUILDER_FUNCTION("rgbm", TexBuilder, (TexBuilder* builder, bool rgbm), {
return &builder->rgbm(rgbm); });
class_<IndirectLight>("IndirectLight")
.class_function("Builder", (IblBuilder (*)()) [] { return IblBuilder(); })
.function("setIntensity", &IndirectLight::setIntensity);
class_<IblBuilder>("IndirectLight$Builder")
.function("build", EMBIND_LAMBDA(IndirectLight*, (IblBuilder* builder, Engine* engine), {
return builder->build(*engine);
}), allow_raw_pointers())
.BUILDER_FUNCTION("reflections", IblBuilder, (IblBuilder* builder, Texture const* cubemap), {
return &builder->reflections(cubemap); })
.BUILDER_FUNCTION("irradianceTex", IblBuilder, (IblBuilder* builder, Texture const* cubemap), {
return &builder->irradiance(cubemap); })
.BUILDER_FUNCTION("irradianceSh", IblBuilder, (IblBuilder* builder, uint8_t nbands, val ta), {
// This is not efficient but consuming a BufferDescriptor would be overkill.
size_t nfloats = ta["length"].as<size_t>();
if (nfloats != nbands * nbands * 3) {
printf("Received %zu floats for spherical harmonics, expected %d.", nfloats, nbands);
return builder;
}
std::vector<float> floats(nfloats);
for (size_t i = 0; i < nfloats; i++) {
floats[i] = ta[i].as<float>();
}
return &builder->irradiance(nbands, (math::float3 const*) floats.data()); })
.BUILDER_FUNCTION("intensity", IblBuilder, (IblBuilder* builder, float value), {
return &builder->intensity(value); })
.BUILDER_FUNCTION("rotation", IblBuilder, (IblBuilder* builder, flatmat3 value), {
return &builder->rotation(value.m); });
class_<Skybox>("Skybox")
.class_function("Builder", (SkyBuilder (*)()) [] { return SkyBuilder(); });
class_<SkyBuilder>("Skybox$Builder")
.function("build", EMBIND_LAMBDA(Skybox*, (SkyBuilder* builder, Engine* engine), {
return builder->build(*engine);
}), allow_raw_pointers())
.BUILDER_FUNCTION("environment", SkyBuilder, (SkyBuilder* builder, Texture* cubemap), {
return &builder->environment(cubemap); })
.BUILDER_FUNCTION("showSun", SkyBuilder, (SkyBuilder* builder, bool show), {
return &builder->showSun(show); });
// UTILS TYPES
// -----------
@@ -502,7 +576,16 @@ class_<KtxBundle>("KtxBundle")
self->getBlob(index, &data, &size);
return BufferDescriptor(data, size);
}), allow_raw_pointers())
.function("info", &KtxBundle::info);
.function("getCubeBlob", EMBIND_LAMBDA(BufferDescriptor, (KtxBundle* self, uint32_t miplevel), {
uint8_t* data;
uint32_t size;
self->getBlob({miplevel}, &data, &size);
return BufferDescriptor(data, size * 6);
}), allow_raw_pointers())
.function("info", &KtxBundle::info)
.function("getMetadata", EMBIND_LAMBDA(std::string, (KtxBundle* self, std::string key), {
return std::string(self->getMetadata(key.c_str()));
}), allow_raw_pointers());
class_<KtxInfo>("KtxInfo")
.property("endianness", &KtxInfo::endianness)
+2 -1
View File
@@ -13,11 +13,12 @@ SERVE_DIR = BUILD_DIR + "/libs/filamentjs"
GLMATRIX_DIR = ROOT_DIR + "/third_party/gl-matrix"
PORT = 8000
# Copy assets used for testing into the server folder.
# Copy test assets into the server folder.
src_assets = (
glob.glob(BUILD_DIR + "/samples/web/public/material/*") +
glob.glob(BUILD_DIR + "/samples/web/public/monkey/*") +
glob.glob(BUILD_DIR + "/samples/web/public/pillars_2k/*") +
glob.glob(GLMATRIX_DIR + "/*.js") +
glob.glob(SCRIPT_DIR + "/testwasm.*"))
+99 -52
View File
@@ -1,21 +1,35 @@
// Extend gl-matrix.
Filament.loadMathExtensions();
var Fov, VertexAttribute, AttributeType, PrimitiveType, IndexType, LightType;
Filament.init([
'bakedColor.filamat',
'sandboxLit.filamat',
'texturedLit.filamat',
'albedo.ktx',
'pillars_2k_ibl.ktx',
'pillars_2k_skybox.ktx',
], () => {
// Declare convenient aliases to Filament enums at global scope.
window.VertexAttribute = Filament.VertexAttribute;
window.AttributeType = Filament.VertexBuffer$AttributeType;
window.PrimitiveType = Filament.RenderableManager$PrimitiveType;
window.IndexType = Filament.IndexBuffer$IndexType;
window.Fov = Filament.Camera$Fov;
window.LightType = Filament.LightManager$Type;
// Create the app and store its instance in the global scope to aid debugging.
window.app = new App();
});
class App {
constructor() {
VertexAttribute = Filament.VertexAttribute;
AttributeType = Filament.VertexBuffer$AttributeType;
PrimitiveType = Filament.RenderableManager$PrimitiveType;
IndexType = Filament.IndexBuffer$IndexType;
Fov = Filament.Camera$Fov;
LightType = Filament.LightManager$Type;
const BAKED_COLOR_PACKAGE = Filament.Buffer(Filament.assets['bakedColor.filamat']);
const SANDBOX_LIT_PACKAGE = Filament.Buffer(Filament.assets['sandboxLit.filamat']);
const TEXTURED_LIT_PACKAGE = Filament.Buffer(Filament.assets['texturedLit.filamat']);
const ALBEDO_KTX = Filament.Buffer(Filament.assets['albedo.ktx']);
const IBL_KTX = Filament.Buffer(Filament.assets['pillars_2k_ibl.ktx']);
const SKYBOX_KTX = Filament.Buffer(Filament.assets['pillars_2k_skybox.ktx']);
const TRIANGLE_POSITIONS = Filament.Buffer(new Float32Array([ 1, 0, -.5, .86, -.5, -.86 ]));
const TRIANGLE_COLORS = Filament.Buffer(new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]));
@@ -97,68 +111,108 @@ class App {
.build(engine, sunlight);
this.scene.addEntity(sunlight);
const albedo = [158 / 255.0, 118 / 255.0, 74 / 255.0];
sandboxMatInstance.setColorParameter("baseColor", Filament.RgbType.sRGB, albedo);
sandboxMatInstance.setFloatParameter("roughness", 0.6);
sandboxMatInstance.setColorParameter("baseColor", Filament.RgbType.sRGB, [0.8, 0.0, 0.0]);
sandboxMatInstance.setFloatParameter("roughness", 0.5);
sandboxMatInstance.setFloatParameter("metallic", 0.0);
sandboxMatInstance.setFloatParameter("reflectance", 0.5);
sandboxMatInstance.setFloatParameter("reflectance", 0.3);
sandboxMatInstance.setFloatParameter("clearCoat", 0.7);
sandboxMatInstance.setFloatParameter("clearCoatRoughness", 0.0);
sandboxMatInstance.setFloatParameter("clearCoatRoughness", 0.3);
sandboxMatInstance.setFloatParameter("anisotropy", 0.0);
////////////////////////////////////////////////////////////////////////////////////////////////
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
this.camera = engine.createCamera();
this.view = engine.createView();
this.view.setCamera(this.camera);
this.view.setScene(this.scene);
this.view.setClearColor([0.1, 0.2, 0.3, 1.0]);
this.resize();
this.render = this.render.bind(this);
this.resize = this.resize.bind(this);
window.addEventListener("resize", this.resize);
window.requestAnimationFrame(this.render);
////////////////////////////////////////////////////////////////////////////////////////////////
const sandboxInstance = sandboxMaterial.createInstance();
sandboxInstance.setFloatParameter("metallic", 1.0)
sandboxInstance.setFloat3Parameter("baseColor", [1.0, 2.0, 3.0]);
const ktx = Window.ktx = new Filament.KtxBundle(ALBEDO_KTX)
const nmips = ktx.getNumMipLevels();
console.assert(11 == nmips);
console.assert(1024 == ktx.info().pixelWidth)
console.assert(1024 == ktx.info().pixelHeight)
const tex = Filament.Texture.Builder()
.width(ktx.info().pixelWidth)
.height(ktx.info().pixelHeight)
.levels(nmips)
.sampler(Filament.Texture$Sampler.SAMPLER_2D)
.format(Filament.Texture$InternalFormat.SRGB8)
.build(engine);
const format = Filament.PixelDataFormat.RGB;
const format = Filament.PixelDataFormat.RGBM;
const dtype = Filament.PixelDataType.UBYTE;
for (let level = 0; level < nmips; ++level) {
const ta = ktx.getBlob([level, 0, 0]).getBytes();
const pbd = Filament.PixelBuffer(ta, format, dtype);
tex.setImage(engine, level, pbd)
}
const texturedMaterial = engine.createMaterial(TEXTURED_LIT_PACKAGE);
const texturedInstance = texturedMaterial.createInstance();
const sampler = new Filament.TextureSampler(Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
Filament.MagFilter.LINEAR, Filament.WrapMode.REPEAT);
texturedInstance.setTextureParameter("albedo", tex, sampler);
const iblktx = new Filament.KtxBundle(IBL_KTX);
const iblnmips = iblktx.getNumMipLevels();
const ibltex = Filament.Texture.Builder()
.width(iblktx.info().pixelWidth)
.height(iblktx.info().pixelHeight)
.levels(iblnmips)
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
.format(Filament.Texture$InternalFormat.RGBA8)
.rgbm(true)
.build(engine);
for (let level = 0; level < iblnmips; ++level) {
const ta = iblktx.getCubeBlob(level).getBytes();
ibltex.setImageCube(engine, level, Filament.PixelBuffer(ta, format, dtype));
}
const shstring = iblktx.getMetadata("sh");
const shfloats = shstring.split(/\s/, 9 * 3).map(parseFloat);
const indirectLight = Filament.IndirectLight.Builder()
.reflections(ibltex)
.irradianceSh(3, shfloats)
.intensity(30000.0)
.build(engine);
indirectLight.setIntensity(50000);
this.scene.setIndirectLight(indirectLight);
const skyktx = new Filament.KtxBundle(SKYBOX_KTX);
const skytex = Filament.Texture.Builder()
.width(skyktx.info().pixelWidth)
.height(skyktx.info().pixelHeight)
.levels(1)
.sampler(Filament.Texture$Sampler.SAMPLER_CUBEMAP)
.format(Filament.Texture$InternalFormat.RGBA8)
.rgbm(true)
.build(engine);
const skyta = skyktx.getCubeBlob(0).getBytes();
skytex.setImageCube(engine, 0, Filament.PixelBuffer(skyta, format, dtype));
const skybox = Filament.Skybox.Builder()
.environment(skytex)
.build(engine);
this.scene.setSkybox(skybox);
// Test normal 2D textures.
(() => {
const ktx = new Filament.KtxBundle(ALBEDO_KTX);
const nmips = ktx.getNumMipLevels();
console.assert(11 == nmips);
console.assert(1024 == ktx.info().pixelWidth)
console.assert(1024 == ktx.info().pixelHeight)
const tex = Filament.Texture.Builder()
.width(ktx.info().pixelWidth)
.height(ktx.info().pixelHeight)
.levels(nmips)
.sampler(Filament.Texture$Sampler.SAMPLER_2D)
.format(Filament.Texture$InternalFormat.SRGB8)
.build(engine);
const format = Filament.PixelDataFormat.RGB;
const dtype = Filament.PixelDataType.UBYTE;
for (let level = 0; level < nmips; ++level) {
const ta = ktx.getBlob([level, 0, 0]).getBytes();
const pbd = Filament.PixelBuffer(ta, format, dtype);
tex.setImage(engine, level, pbd);
}
const texturedMaterial = engine.createMaterial(TEXTURED_LIT_PACKAGE);
const texturedInstance = texturedMaterial.createInstance();
const sampler = new Filament.TextureSampler(Filament.MinFilter.LINEAR_MIPMAP_LINEAR,
Filament.MagFilter.LINEAR, Filament.WrapMode.REPEAT);
texturedInstance.setTextureParameter("albedo", tex, sampler);
})();
}
render() {
// Test setting transforms.
const transform = mat4.fromTranslation(mat4.create(), [0, 0, -5]);
const transform = mat4.fromTranslation(mat4.create(), [0, 0, -4]);
const tcm = this.engine.getTransformManager();
tcm.setTransform(tcm.getInstance(this.sphereEntity), transform);
@@ -180,13 +234,6 @@ class App {
const eye = [0, 0, 0], center = [0, 0, -1], up = [0, 1, 0];
this.camera.lookAt(eye, center, up);
const aspect = width / height;
this.camera.setProjectionFov(45, aspect, 0.1, 50.0, aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL);
this.camera.setProjectionFov(45, aspect, 1.0, 10.0, aspect < 1 ? Fov.HORIZONTAL : Fov.VERTICAL);
}
}
Filament.init([
'bakedColor.filamat',
'sandboxLit.filamat',
'texturedLit.filamat',
'albedo.ktx',
], () => { Window.app = new App() });