env probe bounces

This commit is contained in:
Mikulas Florek 2019-09-23 23:33:43 +02:00
parent 1a0a12bad0
commit d74f1148ff
10 changed files with 136 additions and 125 deletions

View file

@ -2256,7 +2256,12 @@ public:
while (lua_next(L, -2) != 0)
{
const char* parameter_name = luaL_checkstring(L, -2);
if (equalStrings(parameter_name, "position"))
if (equalStrings(parameter_name, "name"))
{
const char* name = LuaWrapper::toType<const char*>(L, -1);
editor.setEntityName(e, name);
}
else if (equalStrings(parameter_name, "position"))
{
const DVec3 pos = LuaWrapper::toType<DVec3>(L, -1);
editor.setEntitiesPositions(&e, &pos, 1);

View file

@ -282,6 +282,13 @@ namespace Lumix
}
}
Span<Key> keys() const {
Span<Key> res;
res.m_begin = m_keys;
res.m_end = m_keys + m_size;
return res;
}
private:
template <typename T> void callDestructors(T* ptr, int count)
{

View file

@ -162,24 +162,6 @@ float Vec4::length() const
const Quat Quat::IDENTITY = { 0, 0, 0, 1 };
Quat::AxisAngle Quat::getAxisAngle() const
{
AxisAngle ret;
if (fabs(1 - w*w) < 0.00001f)
{
ret.angle = 0;
ret.axis.set(0, 1, 0);
}
else
{
ret.angle = 2 * acosf(w);
float tmp = 1 / sqrt(1 - w*w);
ret.axis.set(x * tmp, y * tmp, z * tmp);
}
return ret;
}
Quat::Quat(const Vec3& axis, float angle)
{
float half_angle = angle * 0.5f;

View file

@ -600,19 +600,12 @@ inline Vec2 lerp(const Vec2& op1, const Vec2& op2, float t)
struct LUMIX_ENGINE_API Quat
{
struct AxisAngle
{
Vec3 axis;
float angle;
};
Quat() {}
Quat(const Vec3& axis, float angle);
Quat(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
void fromEuler(const Vec3& euler);
Vec3 toEuler() const;
AxisAngle getAxisAngle() const;
void set(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
void conjugate();
Quat conjugated() const;
@ -712,28 +705,6 @@ struct LUMIX_ENGINE_API RigidTransform
return{ DVec3(rot.rotate(rhs.pos)) + pos, rot * rhs.rot };
}
/*
Vec3 transform(const Vec3& value) const
{
return pos + rot.rotate(value);
}
RigidTransform interpolate(const RigidTransform& rhs, float t)
{
RigidTransform ret;
lerp(pos, rhs.pos, &ret.pos, t);
nlerp(rot, rhs.rot, &ret.rot, t);
return ret;
}
inline Transform toScaled(float scale) const;
Matrix toMatrix() const;
*/
Quat rot;
DVec3 pos;
};

View file

@ -109,7 +109,6 @@ static bool saveAsDDS(const char* path, const u8* data, int w, int h) {
}
struct FontPlugin final : public AssetBrowser::IPlugin, AssetCompiler::IPlugin
{
FontPlugin(StudioApp& app)
@ -1665,6 +1664,7 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
explicit EnvironmentProbePlugin(StudioApp& app)
: m_app(app)
, m_data(app.getWorldEditor().getAllocator())
, m_probes(app.getWorldEditor().getAllocator())
{
WorldEditor& world_editor = app.getWorldEditor();
Engine& engine = world_editor.getEngine();
@ -1697,7 +1697,7 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
if (!OS::makePath(path) && !OS::dirExists(path)) {
logError("Editor") << "Failed to create " << path;
}
path << "/probes/";
path << "/probes_tmp/";
if (!OS::makePath(path) && !OS::dirExists(path)) {
logError("Editor") << "Failed to create " << path;
}
@ -1774,15 +1774,32 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
}
void generateCubemap(ComponentUID cmp)
{
ASSERT(cmp.isValid());
void generateCubemaps(bool bounce) {
ASSERT(!m_in_progress);
m_in_progress = true;
MT::memoryBarrier();
ASSERT(m_probes.empty());
const EntityRef entity = (EntityRef)cmp.entity;
// TODO block user interaction
Universe* universe = m_app.getWorldEditor().getUniverse();
if (universe->getName()[0] == '\0') {
logError("Editor") << "Universe must be saved before environment probe can be generated.";
return;
}
// TODO handle in .pln
m_pipeline->define("PROBE_BOUNCE", bounce);
auto* scene = static_cast<RenderScene*>(universe->getScene(ENVIRONMENT_PROBE_TYPE));
const Span<EntityRef> probes = scene->getAllEnvironmentProbes();
m_probes.reserve(probes.length());
for (const EntityRef& p : probes) {
m_probes.push(p);
}
}
void generateCubemap(EntityRef entity)
{
ASSERT(!m_in_progress);
Universe* universe = m_app.getWorldEditor().getUniverse();
if (universe->getName()[0] == '\0') {
@ -1790,18 +1807,22 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
return;
}
m_in_progress = true;
MT::memoryBarrier();
WorldEditor& world_editor = m_app.getWorldEditor();
Engine& engine = world_editor.getEngine();
auto& plugin_manager = engine.getPluginManager();
IAllocator& allocator = engine.getAllocator();
const DVec3 probe_position = universe->getPosition((EntityRef)cmp.entity);
auto* scene = static_cast<RenderScene*>(universe->getScene(CAMERA_TYPE));
const EnvironmentProbe& probe = scene->getEnvironmentProbe(entity);
const DVec3 probe_position = universe->getPosition(entity);
Viewport viewport;
viewport.is_ortho = false;
viewport.fov = degreesToRadians(90.f);
viewport.near = 0.1f;
viewport.far = 10000.f;
viewport.far = probe.radius;
viewport.w = TEXTURE_SIZE;
viewport.h = TEXTURE_SIZE;
@ -1815,9 +1836,8 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
m_data.resize(6 * TEXTURE_SIZE * TEXTURE_SIZE * 4);
renderer->startCapture();
const bool ndc_bottom_left = ffr::isOriginBottomLeft();
for (int i = 0; i < 6; ++i) {
const bool ndc_bottom_left = ffr::isOriginBottomLeft();
Vec3 side = crossProduct(ndc_bottom_left ? ups_opengl[i] : ups[i], dirs[i]);
Matrix mtx = Matrix::IDENTITY;
mtx.setZVector(dirs[i]);
@ -1831,35 +1851,35 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
const ffr::TextureHandle res = m_pipeline->getOutput();
ASSERT(res.isValid());
renderer->getTextureImage(res, TEXTURE_SIZE * TEXTURE_SIZE * 4, &m_data[i * TEXTURE_SIZE * TEXTURE_SIZE * 4]);
}
if (ndc_bottom_left) continue;
renderer->frame();
renderer->frame();
u32* tmp = (u32*)&m_data[i * TEXTURE_SIZE * TEXTURE_SIZE * 4];
if (i == 2 || i == 3)
{
flipY(tmp, TEXTURE_SIZE);
}
else
{
flipX(tmp, TEXTURE_SIZE);
if (!ndc_bottom_left) {
for (int i = 0; i < 6; ++i) {
u32* tmp = (u32*)&m_data[i * TEXTURE_SIZE * TEXTURE_SIZE * 4];
if (i == 2 || i == 3) {
flipY(tmp, TEXTURE_SIZE);
}
else {
flipX(tmp, TEXTURE_SIZE);
}
}
}
renderer->stopCapture();
renderer->frame();
renderer->frame();
m_irradiance_size = 32;
m_radiance_size = 128;
m_reflection_size = TEXTURE_SIZE;
if (scene->isEnvironmentProbeCustomSize(entity)) {
m_irradiance_size = scene->getEnvironmentProbe(entity).irradiance_size;
m_radiance_size = scene->getEnvironmentProbe(entity).radiance_size;
m_reflection_size = scene->getEnvironmentProbeReflectionSize(entity);
if (probe.flags.isSet(EnvironmentProbe::OVERRIDE_GLOBAL_SIZE)) {
m_irradiance_size = probe.irradiance_size;
m_radiance_size = probe.radiance_size;
// TODO the size of m_data should be m_reflection_size^2 instead of TEXTURE_SIZE^2
m_reflection_size = probe.reflection_size;
}
m_save_reflection = scene->isEnvironmentProbeReflectionEnabled(entity);
m_probe_guid = scene->getEnvironmentProbeGUID(entity);
m_reload_probe = entity;
m_save_reflection = probe.flags.isSet(EnvironmentProbe::REFLECTION);
m_probe_guid = probe.guid;
JobSystem::run(this, [](void* ptr) {
((EnvironmentProbePlugin*)ptr)->processData();
@ -1869,15 +1889,35 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
void update() override
{
if (m_reload_probe.isValid() && !m_in_progress) {
if (m_reload_probes && !m_in_progress) {
m_reload_probes = false;
Universe* universe = m_app.getWorldEditor().getUniverse();
auto* scene = static_cast<RenderScene*>(universe->getScene(CAMERA_TYPE));
if(universe->hasEntity((EntityRef)m_reload_probe)
&& universe->hasComponent((EntityRef)m_reload_probe, ENVIRONMENT_PROBE_TYPE))
{
scene->reloadEnvironmentProbe((EntityRef)m_reload_probe);
const char* universe_name = universe->getName();
auto* scene = static_cast<RenderScene*>(universe->getScene(ENVIRONMENT_PROBE_TYPE));
const Span<EntityRef> probes = scene->getAllEnvironmentProbes();
auto move = [universe_name](u64 guid, const char* postfix){
const StaticString<MAX_PATH_LENGTH> tmp_path("universes/", universe_name, "/probes_tmp/", guid, postfix, ".dds");
const StaticString<MAX_PATH_LENGTH> path("universes/", universe_name, "/probes/", guid, postfix, ".dds");
if (!OS::fileExists(tmp_path)) return;
if (!OS::moveFile(tmp_path, path)) {
logError("Editor") << "Failed to move file " << tmp_path;
}
};
for (EntityRef e : probes) {
const EnvironmentProbe& probe = scene->getEnvironmentProbe(e);
move(probe.guid, "");
move(probe.guid, "_radiance");
move(probe.guid, "_irradiance");
}
m_reload_probe = INVALID_ENTITY;
}
else if (!m_probes.empty() && !m_in_progress) {
const EntityRef e = m_probes.back();
m_probes.pop();
generateCubemap(e);
if (m_probes.empty()) m_reload_probes = true;
}
}
@ -1953,7 +1993,10 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
if (ImGui::Button("View radiance")) m_app.getAssetBrowser().selectResource(texture->getPath(), true, false);
}
if (m_in_progress) ImGui::Text("Generating...");
else if (ImGui::Button("Generate")) generateCubemap(cmp);
else {
if (ImGui::Button("Generate")) generateCubemaps(false);
if (ImGui::Button("Add bounce")) generateCubemaps(true);
}
}
@ -1962,12 +2005,13 @@ struct EnvironmentProbePlugin final : public PropertyGrid::IPlugin
Array<u8> m_data;
bool m_in_progress = false;
EntityPtr m_reload_probe = INVALID_ENTITY;
bool m_reload_probes = false;
int m_irradiance_size;
int m_radiance_size;
int m_reflection_size;
bool m_save_reflection;
u64 m_probe_guid;
Array<EntityRef> m_probes;
JobSystem::SignalHandle m_signal = JobSystem::INVALID_HANDLE;

View file

@ -229,7 +229,7 @@ void SceneView::renderSelection()
item.mesh = mesh.render_data;
item.shader = mesh.material->getShader()->m_render_data;
item.mtx = universe.getRelativeMatrix(e, m_editor->getViewport().pos);
item.material_render_states = mesh.material->getRenderStates();
item.material = mesh.material->getRenderData();
}
}
}
@ -241,15 +241,16 @@ void SceneView::renderSelection()
for (const Item& item : m_items) {
const Mesh::RenderData* rd = item.mesh;
const ffr::ProgramHandle prog = Shader::getProgram(item.shader, rd->vertex_decl, m_define_mask);
const ffr::ProgramHandle prog = Shader::getProgram(item.shader, rd->vertex_decl, m_define_mask | item.material->define_mask);
if (!prog.isValid()) continue;
ffr::update(drawcall_ub, &item.mtx.m11, sizeof(item.mtx));
ffr::bindTextures(item.material->textures, 0, item.material->textures_count);
ffr::useProgram(prog);
ffr::bindVertexBuffer(0, rd->vertex_buffer_handle, 0, rd->vb_stride);
ffr::bindIndexBuffer(rd->index_buffer_handle);
ffr::setState(item.material_render_states);
ffr::setState(item.material->render_states);
ffr::drawTriangles(rd->indices_count, rd->index_type);
}
}
@ -257,7 +258,7 @@ void SceneView::renderSelection()
struct Item {
ShaderRenderData* shader;
Mesh::RenderData* mesh;
u64 material_render_states;
Material::RenderData* material;
Matrix mtx;
};

View file

@ -524,9 +524,7 @@ struct PipelineImpl final : Pipeline
if (m_scene) callInitScene();
}
void clearBuffers()
{
void clearBuffers() {
PROFILE_FUNCTION();
for (Renderbuffer& rb : m_renderbuffers) {
++rb.frame_counter;
@ -540,6 +538,13 @@ struct PipelineImpl final : Pipeline
}
}
void define(const char* define, bool enable) override {
LuaWrapper::DebugGuard guard(m_lua_state);
lua_rawgeti(m_lua_state, LUA_REGISTRYINDEX, m_lua_env);
LuaWrapper::setField(m_lua_state, -1, define, enable);
lua_pop(m_lua_state, 1);
}
ffr::BufferHandle getDrawcallUniformBuffer() override { return m_drawcall_ub; }
void setViewport(const Viewport& viewport) override

View file

@ -73,6 +73,7 @@ public:
virtual void callLuaFunction(const char* func) = 0;
virtual void setViewport(const Viewport& viewport) = 0;
virtual ffr::BufferHandle getDrawcallUniformBuffer() = 0;
virtual void define(const char* define, bool enable) = 0;
virtual Draw2D& getDraw2D() = 0;
virtual void clearDraw2D() = 0;

View file

@ -2872,29 +2872,6 @@ public:
return m_active_global_light_entity;
}
void reloadEnvironmentProbe(EntityRef entity) override
{
auto& probe = m_environment_probes[entity];
ResourceManagerHub& rm = m_engine.getResourceManager();
if (probe.texture) probe.texture->getResourceManager().unload(*probe.texture);
probe.texture = nullptr;
StaticString<MAX_PATH_LENGTH> path;
if (probe.flags.isSet(EnvironmentProbe::REFLECTION)) {
path << "universes/" << m_universe.getName() << "/probes/" << probe.guid << ".dds";
probe.texture = rm.load<Texture>(Path(path));
probe.texture->setFlag(Texture::Flags::SRGB, true);
}
path = "universes/";
path << m_universe.getName() << "/probes/" << probe.guid << "_irradiance.dds";
if(probe.irradiance) probe.irradiance->getResourceManager().unload(*probe.irradiance);
probe.irradiance = rm.load<Texture>(Path(path));
path = "universes/";
path << m_universe.getName() << "/probes/" << probe.guid << "_radiance.dds";
if (probe.radiance) probe.irradiance->getResourceManager().unload(*probe.radiance);
probe.radiance = rm.load<Texture>(Path(path));
}
void getEnvironmentProbes(Array<EnvProbeInfo>& probes) override
{
@ -2914,6 +2891,9 @@ public:
}
}
Span<EntityRef> getAllEnvironmentProbes() override {
return m_environment_probes.keys();
}
EnvironmentProbe& getEnvironmentProbe(EntityRef entity) override
{
@ -3262,12 +3242,27 @@ public:
{
EnvironmentProbe& probe = m_environment_probes.insert(entity);
ResourceManagerHub& rm = m_engine.getResourceManager();
probe.texture = rm.load<Texture>(Path("textures/common/default_probe.dds"));
probe.texture->setFlag(Texture::Flags::SRGB, true);
probe.irradiance = rm.load<Texture>(Path("textures/common/default_probe.dds"));
StaticString<MAX_PATH_LENGTH> path;
if (probe.flags.isSet(EnvironmentProbe::REFLECTION)) {
path << "universes/" << m_universe.getName() << "/probes/" << probe.guid << ".dds";
probe.texture = rm.load<Texture>(Path(path));
probe.texture->setFlag(Texture::Flags::SRGB, true);
}
else {
probe.texture = nullptr;
}
path = "universes/";
path << m_universe.getName() << "/probes/" << probe.guid << "_irradiance.dds";
probe.irradiance = rm.load<Texture>(Path(path));
probe.irradiance->setFlag(Texture::Flags::SRGB, true);
probe.radiance = rm.load<Texture>(Path("textures/common/default_probe.dds"));
path = "universes/";
path << m_universe.getName() << "/probes/" << probe.guid << "_radiance.dds";
probe.radiance = rm.load<Texture>(Path(path));
probe.radiance->setFlag(Texture::Flags::SRGB, true);
probe.radius = 1;
probe.flags.set(EnvironmentProbe::ENABLED);
probe.guid = randGUID();

View file

@ -324,6 +324,7 @@ public:
virtual float getLightRange(EntityRef entity) = 0;
virtual void setLightRange(EntityRef entity, float value) = 0;
virtual Span<EntityRef> getAllEnvironmentProbes() = 0;
virtual EnvironmentProbe& getEnvironmentProbe(EntityRef entity) = 0;
virtual void enableEnvironmentProbe(EntityRef entity, bool enable) = 0;
virtual bool isEnvironmentProbeEnabled(EntityRef entity) = 0;
@ -337,7 +338,6 @@ public:
virtual Texture* getEnvironmentProbeTexture(EntityRef entity) const = 0;
virtual Texture* getEnvironmentProbeIrradiance(EntityRef entity) const = 0;
virtual Texture* getEnvironmentProbeRadiance(EntityRef entity) const = 0;
virtual void reloadEnvironmentProbe(EntityRef entity) = 0;
virtual u64 getEnvironmentProbeGUID(EntityRef entity) const = 0;
virtual float getEnvironmentProbeRadius(EntityRef entity) = 0;
virtual void setEnvironmentProbeRadius(EntityRef entity, float radius) = 0;