Add IBL to jsbinding and testwasm.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.*"))
|
||||
|
||||
|
||||
@@ -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() });
|
||||
|
||||
Reference in New Issue
Block a user