/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common/arguments.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "generated/resources/resources.h" using namespace filament; using namespace filament::math; using Backend = Engine::Backend; struct GroundPlane { VertexBuffer* vb; IndexBuffer* ib; Material* mat; utils::Entity renderable; }; struct App { Skybox* skybox; utils::Entity light; std::map materials; MeshAssimp* meshes; mat4f transform; GroundPlane plane; }; static const char* MODEL_FILE = "assets/models/monkey/monkey.obj"; static const char* IBL_FOLDER = "assets/ibl/lightroom_14b"; static constexpr bool ENABLE_SHADOWS = true; static GroundPlane createGroundPlane(Engine* engine); static const Config config { .title = "shadowtest", .iblDirectory = FilamentApp::getRootAssetsPath() + IBL_FOLDER, .scale = 1, .splitView = false }; int main(int argc, char** argv) { App app; config.backend = samples::parseArgumentsForBackend(argc, argv); auto setup = [&app](Engine* engine, View* view, Scene* scene) { auto& tcm = engine->getTransformManager(); auto& rcm = engine->getRenderableManager(); auto& em = utils::EntityManager::get(); // Add geometry into the scene. app.meshes = new MeshAssimp(*engine); app.meshes->addFromFile(FilamentApp::getRootAssetsPath() + MODEL_FILE, app.materials); auto ti = tcm.getInstance(app.meshes->getRenderables()[0]); app.transform = mat4f{ mat3f(1), float3(0, 0, -4) } * tcm.getWorldTransform(ti); for (auto renderable : app.meshes->getRenderables()) { auto instance = rcm.getInstance(renderable); if (rcm.hasComponent(renderable)) { rcm.setCastShadows(instance, ENABLE_SHADOWS); rcm.setReceiveShadows(instance, false); scene->addEntity(renderable); } } // Add light sources into the scene. app.light = em.create(); LightManager::Builder(LightManager::Type::SUN) .color(Color::toLinear(sRGBColor(0.98f, 0.92f, 0.89f))) .intensity(110000) .direction({ 0.7, -1, -0.8 }) .sunAngularRadius(1.9f) .castShadows(ENABLE_SHADOWS) .build(*engine, app.light); scene->addEntity(app.light); // Hide skybox and add ground plane. app.skybox = Skybox::Builder().color({0.5f,0.75f,1.0f,1.0f}).build(*engine); scene->setSkybox(app.skybox); app.plane = createGroundPlane(engine); scene->addEntity(app.plane.renderable); }; auto cleanup = [&app](Engine* engine, View*, Scene*) { engine->destroy(app.plane.renderable); engine->destroy(app.plane.mat); engine->destroy(app.plane.vb); engine->destroy(app.plane.ib); engine->destroy(app.light); engine->destroy(app.skybox); for (auto& item : app.materials) { engine->destroy(item.second); } delete app.meshes; }; FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { auto& tcm = engine->getTransformManager(); auto ti = tcm.getInstance(app.meshes->getRenderables()[0]); tcm.setTransform(ti, app.transform * mat4f::rotation(now, float3{ 0, 1, 0 })); }); FilamentApp::get().run(config, setup, cleanup); return 0; } static GroundPlane createGroundPlane(Engine* engine) { Material* shadowMaterial = Material::Builder() .package(RESOURCES_GROUNDSHADOW_DATA, RESOURCES_GROUNDSHADOW_SIZE) .build(*engine); shadowMaterial->setDefaultParameter("strength", 0.7f); const static uint32_t indices[] { 0, 1, 2, 2, 3, 0 }; const static float3 vertices[] { { -10, 0, -10 }, { -10, 0, 10 }, { 10, 0, 10 }, { 10, 0, -10 }, }; short4 tbn = packSnorm16(normalize(positive(mat3f{ float3{1.0f, 0.0f, 0.0f}, float3{0.0f, 0.0f, 1.0f}, float3{0.0f, 1.0f, 0.0f} }.toQuaternion())).xyzw); const static short4 normals[] { tbn, tbn, tbn, tbn }; VertexBuffer* vertexBuffer = VertexBuffer::Builder() .vertexCount(4) .bufferCount(2) .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3) .attribute(VertexAttribute::TANGENTS, 1, VertexBuffer::AttributeType::SHORT4) .normalized(VertexAttribute::TANGENTS) .build(*engine); vertexBuffer->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor( vertices, vertexBuffer->getVertexCount() * sizeof(vertices[0]))); vertexBuffer->setBufferAt(*engine, 1, VertexBuffer::BufferDescriptor( normals, vertexBuffer->getVertexCount() * sizeof(normals[0]))); IndexBuffer* indexBuffer = IndexBuffer::Builder().indexCount(6).build(*engine); indexBuffer->setBuffer(*engine, IndexBuffer::BufferDescriptor( indices, indexBuffer->getIndexCount() * sizeof(uint32_t))); auto& em = utils::EntityManager::get(); utils::Entity renderable = em.create(); RenderableManager::Builder(1) .boundingBox({{ 0, 0, 0 }, { 10, 1e-4f, 10 }}) .material(0, shadowMaterial->getDefaultInstance()) .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vertexBuffer, indexBuffer, 0, 6) .culling(false) .receiveShadows(ENABLE_SHADOWS) .castShadows(false) .build(*engine, renderable); auto& tcm = engine->getTransformManager(); tcm.setTransform(tcm.getInstance(renderable), mat4f::translation(float3{ 0, -1, -4 })); return { .vb = vertexBuffer, .ib = indexBuffer, .mat = shadowMaterial, .renderable = renderable, }; }