From: György Straub Date: Wed, 15 Jan 2020 16:34:23 +0000 (+0000) Subject: Added Deferred Shading example. X-Git-Tag: dali_1.9.2~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-demo.git;a=commitdiff_plain;h=b15bfd014dc5256883442603549fdc10b5002a8f Added Deferred Shading example. Change-Id: I4a74037a3587d466a913e0a90e0e9a45a62424a0 Signed-off-by: György Straub --- diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index 5751ee1..4bdee68 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -70,6 +70,9 @@ + + + diff --git a/examples-reel/dali-examples-reel.cpp b/examples-reel/dali-examples-reel.cpp index f525f07..cc9872c 100644 --- a/examples-reel/dali-examples-reel.cpp +++ b/examples-reel/dali-examples-reel.cpp @@ -47,6 +47,7 @@ int DALI_EXPORT_API main(int argc, char **argv) demo.AddExample(Example("buttons.example", DALI_DEMO_STR_TITLE_BUTTONS)); demo.AddExample(Example("clipping.example", DALI_DEMO_STR_TITLE_CLIPPING)); demo.AddExample(Example("clipping-draw-order.example", DALI_DEMO_STR_TITLE_CLIPPING_DRAW_ORDER)); + demo.AddExample(Example("deferred-shading.example", DALI_DEMO_STR_TITLE_DEFERRED_SHADING)); demo.AddExample(Example("dissolve-effect.example", DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION)); demo.AddExample(Example("drag-and-drop.example", DALI_DEMO_STR_TITLE_DRAG_AND_DROP)); demo.AddExample(Example("effects-view.example", DALI_DEMO_STR_TITLE_EFFECTS_VIEW)); @@ -74,6 +75,7 @@ int DALI_EXPORT_API main(int argc, char **argv) demo.AddExample(Example("pivot.example", DALI_DEMO_STR_TITLE_PIVOT)); demo.AddExample(Example("primitive-shapes.example", DALI_DEMO_STR_TITLE_PRIMITIVE_SHAPES)); demo.AddExample(Example("progress-bar.example", DALI_DEMO_STR_TITLE_PROGRESS_BAR)); + demo.AddExample(Example("remote-image-loading.example", DALI_DEMO_STR_TITLE_REMOTE_IMAGE)); demo.AddExample(Example("rendering-basic-light.example", DALI_DEMO_STR_TITLE_BASIC_LIGHT)); demo.AddExample(Example("rendering-line.example", DALI_DEMO_STR_TITLE_RENDERING_DRAW_LINE)); demo.AddExample(Example("rendering-triangle.example", DALI_DEMO_STR_TITLE_RENDERING_DRAW_TRIANGLE)); @@ -91,7 +93,6 @@ int DALI_EXPORT_API main(int argc, char **argv) demo.AddExample(Example("text-label-multi-language.example", DALI_DEMO_STR_TITLE_TEXT_LABEL_MULTI_LANGUAGE)); demo.AddExample(Example("text-label-emojis.example", DALI_DEMO_STR_TITLE_EMOJI_TEXT)); demo.AddExample(Example("text-scrolling.example", DALI_DEMO_STR_TITLE_TEXT_SCROLLING)); - demo.AddExample(Example("remote-image-loading.example", DALI_DEMO_STR_TITLE_REMOTE_IMAGE)); demo.AddExample(Example("textured-mesh.example", DALI_DEMO_STR_TITLE_TEXTURED_MESH)); demo.AddExample(Example("tilt.example", DALI_DEMO_STR_TITLE_TILT_SENSOR)); demo.AddExample(Example("tooltip.example", DALI_DEMO_STR_TITLE_TOOLTIP)); diff --git a/examples/deferred-shading/deferred-shading.cpp b/examples/deferred-shading/deferred-shading.cpp new file mode 100644 index 0000000..425e533 --- /dev/null +++ b/examples/deferred-shading/deferred-shading.cpp @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * 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 "dali/dali.h" +#include "dali/public-api/actors/actor.h" +#include "dali/public-api/rendering/renderer.h" +#include +#include +#include + +using namespace Dali; + +namespace +{ +//============================================================================= +// Demonstrates deferred shading with multiple render targets (for color, +// position, and normal), a Phong lighting model and 32 point lights. +// +// Invoked with the --show-lights it will render a mesh at each light position. +//============================================================================= + +#define QUOTE(x) DALI_COMPOSE_SHADER(x) + +#define MAX_LIGHTS 32 + +#define DEFINE_MAX_LIGHTS "const int kMaxLights = " QUOTE(MAX_LIGHTS) ";" + +#define DEFINE(x) "#define " DALI_COMPOSE_SHADER(x) DALI_COMPOSE_SHADER(\n) + +//============================================================================= +// PRE-PASS +//============================================================================= +const char* const PREPASS_VSH = DALI_COMPOSE_SHADER(#version 300 es\n +precision mediump float;) + DALI_COMPOSE_SHADER( + +// DALI uniforms +uniform mat4 uMvpMatrix; +uniform mat3 uNormalMatrix; +uniform vec3 uSize; + +uniform vec3 uDepth_InvDepth_Near;\n) + DEFINE(DEPTH uDepth_InvDepth_Near.x) + DEFINE(INV_DEPTH uDepth_InvDepth_Near.y) + DEFINE(NEAR uDepth_InvDepth_Near.z) + DALI_COMPOSE_SHADER( + +in vec3 aPosition; +in vec3 aNormal; + +out vec4 vPosition; +out vec3 vNormal; + +vec4 Map(vec4 v) // projection space -> texture +{ + return vec4(v.xyz / (2.f * v.w) + vec3(.5f), (v.w - NEAR) * INV_DEPTH); +} + +void main() +{ + vec4 position = uMvpMatrix * vec4(aPosition * uSize, 1.f); + vPosition = Map(position); + gl_Position = position; + + vNormal = normalize(uNormalMatrix * aNormal); +}); + +//============================================================================= +const char* const PREPASS_FSH = DALI_COMPOSE_SHADER(#version 300 es\n +precision mediump float; + +// DALI uniform +uniform vec4 uColor; + +in vec4 vPosition; +in vec3 vNormal; + +// These are our outputs. +layout(location = 0) out vec3 oNormal; +layout(location = 1) out vec4 oPosition; +layout(location = 2) out vec3 oColor; + +void main() +{ + oColor = uColor.rgb; + oPosition = vPosition; + oNormal = normalize(vNormal) * .5f + .5f; +}); + +//============================================================================= +// MAIN (LIGHTING) PASS +//============================================================================= +const char* const MAINPASS_VSH = DALI_COMPOSE_SHADER(#version 300 es\n +precision mediump float; + +// DALI uniforms +uniform mat4 uMvpMatrix; +uniform vec3 uSize; + +in vec3 aPosition; +in vec2 aTexCoord; + +out vec2 vUv; + +void main() +{ + vec4 position = uMvpMatrix * vec4(aPosition * uSize, 1.f); + vUv = aTexCoord; + + gl_Position = position; +}); + +//============================================================================= +const char* const MAINPASS_FSH = DALI_COMPOSE_SHADER(#version 300 es\n +precision mediump float;\n) + DEFINE_MAX_LIGHTS + DALI_COMPOSE_SHADER( + +const float kAttenuationConst = .05f; +const float kAttenuationLinear = .1f; +const float kAttenuationQuadratic = .15f; + +// G-buffer +uniform sampler2D uTextureNormal; +uniform sampler2D uTexturePosition; +uniform sampler2D uTextureColor; + +uniform mat4 uInvProjection; + +uniform vec3 uDepth_InvDepth_Near;\n) + DEFINE(DEPTH uDepth_InvDepth_Near.x) + DEFINE(INV_DEPTH uDepth_InvDepth_Near.y) + DEFINE(NEAR uDepth_InvDepth_Near.z) + DALI_COMPOSE_SHADER( + +// Light source uniforms +struct Light +{ + vec3 position; // view space + float radius; + vec3 color; +}; + +uniform Light uLights[kMaxLights]; + +in vec2 vUv; + +out vec4 oColor; + +vec4 Unmap(vec4 m) // texture -> projection +{ + m.w = m.w * DEPTH + NEAR; + m.xyz = (m.xyz - vec3(.5)) * (2.f * m.w); + return m; +} + +vec3 CalculateLighting(vec3 pos, vec3 normal) +{ + vec3 viewDir = normalize(pos); + vec3 viewDirRefl = -reflect(viewDir, normal); + + vec3 light = vec3(0.04f); // fake ambient term + for (int i = 0; i < kMaxLights; ++i) + { + vec3 rel = pos - uLights[i].position; + float distance = length(rel); + rel /= distance; + + float a = uLights[i].radius / (kAttenuationConst + kAttenuationLinear * distance + + kAttenuationQuadratic * distance * distance); // attenuation + + float l = max(0.f, dot(normal, rel)); // lambertian + float s = pow(max(0.f, dot(viewDirRefl, rel)), 256.f); // specular + + light += (uLights[i].color * (l + s)) * a; + } + + return light; +} + +void main() +{ + vec3 normSample = texture(uTextureNormal, vUv).xyz; + if (dot(normSample, normSample) == 0.f) + { + discard; // if we didn't write this texel, don't bother lighting it. + } + + vec3 normal = normalize(normSample - .5f); + + vec4 posSample = texture(uTexturePosition, vUv); + vec3 pos = (uInvProjection * Unmap(posSample)).xyz; + + vec3 color = texture(uTextureColor, vUv).rgb; + vec3 finalColor = color * CalculateLighting(pos, normal); + + oColor = vec4(finalColor, 1.f); +}); + +//============================================================================= +// PRNG for floats. +struct FloatRand +{ + std::random_device mDevice; + std::mt19937 mMersenneTwister; + std::uniform_real_distribution mDistribution; + + FloatRand() + : mMersenneTwister(mDevice()), + mDistribution(0., 1.) + {} + + float operator()() + { + return mDistribution(mMersenneTwister); + } +}; + +//============================================================================= +float FastFloor(float x) +{ + return static_cast(x) - static_cast(x < 0); +} + +//============================================================================= +Vector3 FromHueSaturationLightness(Vector3 hsl) +{ + Vector3 rgb; + if (hsl.y * hsl.y > 0.f) + { + if(hsl.x >= 360.f) + { + hsl.x -= 360.f; + } + hsl.x /= 60.f; + + int i = FastFloor(hsl.x); + float ff = hsl.x - i; + float p = hsl.z * (1.0 - hsl.y); + float q = hsl.z * (1.0 - (hsl.y * ff)); + float t = hsl.z * (1.0 - (hsl.y * (1.f - ff))); + + switch (i) + { + case 0: + rgb.r = hsl.z; + rgb.g = t; + rgb.b = p; + break; + + case 1: + rgb.r = q; + rgb.g = hsl.z; + rgb.b = p; + break; + + case 2: + rgb.r = p; + rgb.g = hsl.z; + rgb.b = t; + break; + + case 3: + rgb.r = p; + rgb.g = q; + rgb.b = hsl.z; + break; + + case 4: + rgb.r = t; + rgb.g = p; + rgb.b = hsl.z; + break; + + case 5: + default: + rgb.r = hsl.z; + rgb.g = p; + rgb.b = q; + break; + } + } + else + { + rgb = Vector3::ONE * hsl.z; + } + + return rgb; +} + +//============================================================================= +Geometry CreateTexturedQuadGeometry(bool flipV) +{ + // Create geometry -- unit square with whole of the texture mapped to it. + struct Vertex + { + Vector3 aPosition; + Vector2 aTexCoord; + }; + + Vertex vertexData[] = { + { Vector3(-.5f, .5f, .0f), Vector2(.0f, 1.0f) }, + { Vector3(.5f, .5f, .0f), Vector2(1.0f, 1.0f) }, + { Vector3(-.5f, -.5f, .0f), Vector2(.0f, .0f) }, + { Vector3(.5f, -.5f, .0f), Vector2(1.0f, .0f) }, + }; + + if (flipV) + { + std::swap(vertexData[0].aTexCoord, vertexData[2].aTexCoord); + std::swap(vertexData[1].aTexCoord, vertexData[3].aTexCoord); + } + + PropertyBuffer vertexBuffer = PropertyBuffer::New( Property::Map() + .Add( "aPosition", Property::VECTOR3 ) + .Add( "aTexCoord", Property::VECTOR2 ) ); + vertexBuffer.SetData( vertexData, std::extent::value ); + + Geometry geometry = Geometry::New(); + geometry.AddVertexBuffer( vertexBuffer ); + geometry.SetType( Geometry::TRIANGLE_STRIP ); + return geometry; +} + +//============================================================================= +Geometry CreateOctahedron(bool invertNormals) +{ + Vector3 positions[] = { + Vector3{ -1.f, 0.f, 0.f }, + Vector3{ 1.f, 0.f, 0.f }, + Vector3{ 0.f, -1.f, 0.f }, + Vector3{ 0.f, 1.f, 0.f }, + Vector3{ 0.f, 0.f, -1.f }, + Vector3{ 0.f, 0.f, 1.f }, + }; + + struct Vertex + { + Vector3 position; + Vector3 normal; + }; + Vertex vertexData[] = { + { positions[0] }, + { positions[3] }, + { positions[5] }, + + { positions[5] }, + { positions[3] }, + { positions[1] }, + + { positions[1] }, + { positions[3] }, + { positions[4] }, + + { positions[4] }, + { positions[3] }, + { positions[0] }, + + { positions[0] }, + { positions[5] }, + { positions[2] }, + + { positions[5] }, + { positions[1] }, + { positions[2] }, + + { positions[1] }, + { positions[4] }, + { positions[2] }, + + { positions[4] }, + { positions[0] }, + { positions[2] }, + }; + + // Calculate normals + for (uint32_t i = 0; i < std::extent::value / 3; ++i) + { + uint32_t idx = i * 3; + + Vector3 normal = (vertexData[idx + 2].position - vertexData[idx].position). + Cross(vertexData[idx + 1].position - vertexData[idx].position); + normal.Normalize(); + normal *= invertNormals * 2.f - 1.f; + + vertexData[idx++].normal = normal; + vertexData[idx++].normal = normal; + vertexData[idx].normal = normal; + } + + // Configure property buffers and create geometry. + PropertyBuffer vertexBuffer = PropertyBuffer::New(Property::Map() + .Add("aPosition", Property::VECTOR3) + .Add("aNormal", Property::VECTOR3)); + vertexBuffer.SetData(vertexData, std::extent::value); + + Geometry geometry = Geometry::New(); + geometry.AddVertexBuffer( vertexBuffer ); + geometry.SetType( Geometry::TRIANGLES ); + return geometry; +} + +//============================================================================= +enum RendererOptions +{ + OPTION_NONE = 0x0, + OPTION_BLEND = 0x01, + OPTION_DEPTH_TEST = 0x02, + OPTION_DEPTH_WRITE = 0x04 +}; + +Renderer CreateRenderer(TextureSet textures, Geometry geometry, Shader shader, uint32_t options = OPTION_NONE) +{ + Renderer renderer = Renderer::New(geometry, shader); + renderer.SetProperty(Renderer::Property::BLEND_MODE, + (options & OPTION_BLEND) ? BlendMode::ON : BlendMode::OFF); + renderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, + (options & OPTION_DEPTH_TEST) ? DepthTestMode::ON : DepthTestMode::OFF); + renderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, + (options & OPTION_DEPTH_WRITE) ? DepthWriteMode::ON : DepthWriteMode::OFF); + renderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK); + + if (!textures) + { + textures = TextureSet::New(); + } + + renderer.SetTextures(textures); + return renderer; +} + +//============================================================================= +void CenterActor(Actor actor) +{ + actor.SetAnchorPoint( AnchorPoint::CENTER ); + actor.SetParentOrigin( ParentOrigin::CENTER ); +} + +//============================================================================= +void RegisterDepthProperties(float depth, float near, Handle& h) +{ + h.RegisterProperty("uDepth_InvDepth_Near", Vector3(depth, 1.f / depth, near)); +} + +} + +//============================================================================= +class DeferredShadingExample : public ConnectionTracker +{ +public: + struct Options + { + enum + { + NONE = 0x0, + SHOW_LIGHTS = 0x1, + }; + }; + + DeferredShadingExample(Application& app, uint32_t options = Options::NONE) + : mApp(app), + mOptions(options) + { + app.InitSignal().Connect( this, &DeferredShadingExample::Create ); + app.TerminateSignal().Connect( this, &DeferredShadingExample::Destroy ); + } + +private: + void Create(Application& app) + { + // Grab stage, configure layer + Stage stage = Stage::GetCurrent(); + auto rootLayer = stage.GetRootLayer(); + rootLayer.SetBehavior(Layer::LAYER_3D); + + auto stageSize = stage.GetSize(); + auto stageHalfSize = stageSize * .5f; + auto invStageHalfSize = Vector2::ONE / stageHalfSize; + + float unit = stageSize.y / 24.f; + + // Get camera - we'll be re-using the same old camera in the two passes. + RenderTaskList tasks = stage.GetRenderTaskList(); + CameraActor camera = tasks.GetTask(0).GetCameraActor(); + + auto zCameraPos = camera.GetProperty(Actor::Property::POSITION_Z).Get(); + camera.SetFarClippingPlane(zCameraPos + stageSize.y * .5f); + camera.SetNearClippingPlane(zCameraPos - stageSize.y * .5f); + + const float zNear = camera.GetNearClippingPlane(); + const float zFar = camera.GetFarClippingPlane(); + const float depth = zFar - zNear; + + // Create root of scene that shall be rendered off-screen. + auto sceneRoot = Actor::New(); + CenterActor(sceneRoot); + + mSceneRoot = sceneRoot; + stage.Add(sceneRoot); + + // Create an axis to spin our actors around. + auto axis = Actor::New(); + CenterActor(axis); + sceneRoot.Add(axis); + mAxis = axis; + + // Create an octahedral mesh for our main actors and to visualise the light sources. + Geometry mesh = CreateOctahedron(false); + + // Create main actors + Shader preShader = Shader::New(PREPASS_VSH, PREPASS_FSH); + TextureSet noTexturesThanks = TextureSet::New(); + Renderer meshRenderer = CreateRenderer(noTexturesThanks, mesh, preShader, + OPTION_DEPTH_TEST | OPTION_DEPTH_WRITE); + meshRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK); + meshRenderer.RegisterProperty("uInvStageHalfSize", invStageHalfSize); + RegisterDepthProperties(depth, zNear, meshRenderer); + float c = 1.f; + for (auto v: { + Vector3{ -c, -c, -c }, + Vector3{ c, -c, -c }, + Vector3{ -c, c, -c }, + Vector3{ c, c, -c }, + Vector3{ -c, -c, c }, + Vector3{ c, -c, c }, + Vector3{ -c, c, c }, + Vector3{ c, c, c }, + + Vector3{ 0.f, -c, -c }, + Vector3{ 0.f, c, -c }, + Vector3{ 0.f, -c, c }, + Vector3{ 0.f, c, c }, + + Vector3{ -c, 0.f, -c }, + Vector3{ c, 0.f, -c }, + Vector3{ -c, 0.f, c }, + Vector3{ c, 0.f, c }, + + Vector3{ -c, -c, 0.f }, + Vector3{ c, -c, 0.f }, + Vector3{ -c, c, 0.f }, + Vector3{ c, c, 0.f }, + }) + { + Actor a = Actor::New(); + CenterActor(a); + + Vector3 position{ v * unit * 5.f }; + a.SetPosition(position); + + float scale = (c + ((v.x + v.y + v.z) + c * 3.f) * .5f) / (c * 4.f); + Vector3 size{ Vector3::ONE * scale * unit * 2.f }; + a.SetSize(size); + + a.SetColor(Color::WHITE * .25f + + (Color::RED * (v.x + c) / (c * 2.f) + + Color::GREEN * (v.y + c) / (c * 2.f) + + Color::BLUE * (v.z + c) / (c * 2.f)) * .015625f); + a.AddRenderer(meshRenderer); + + axis.Add(a); + } + + // Create off-screen textures, fbo and render task. + uint32_t width = static_cast(stageSize.x); + uint32_t height = static_cast(stageSize.y); + + Texture rttNormal = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGB888, + width, height); + Texture rttPosition = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, + width, height); + Texture rttColor = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGB888, + width, height); + FrameBuffer fbo = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH); + fbo.AttachColorTexture(rttNormal); + fbo.AttachColorTexture(rttPosition); + fbo.AttachColorTexture(rttColor); + + RenderTask sceneRender = tasks.CreateTask(); + sceneRender.SetViewportSize(stageSize); + sceneRender.SetFrameBuffer(fbo); + sceneRender.SetCameraActor(camera); + sceneRender.SetSourceActor(sceneRoot); + sceneRender.SetInputEnabled(false); + sceneRender.SetCullMode(false); + sceneRender.SetClearEnabled(true); + sceneRender.SetClearColor(Color::BLACK); + sceneRender.SetExclusive(true); + + mSceneRender = sceneRender; + + // Create final image for deferred shading + auto finalImage = Actor::New(); + CenterActor(finalImage); + finalImage.SetSize(stageSize); + + TextureSet finalImageTextures = TextureSet::New(); + finalImageTextures.SetTexture(0, rttNormal); + finalImageTextures.SetTexture(1, rttPosition); + finalImageTextures.SetTexture(2, rttColor); + + Sampler sampler = Sampler::New(); + sampler.SetFilterMode(FilterMode::NEAREST, FilterMode::NEAREST); + finalImageTextures.SetSampler(0, sampler); + finalImageTextures.SetSampler(1, sampler); + finalImageTextures.SetSampler(2, sampler); + + Shader shdMain = Shader::New(MAINPASS_VSH, MAINPASS_FSH); + Geometry finalImageGeom = CreateTexturedQuadGeometry(true); + Renderer finalImageRenderer = CreateRenderer(finalImageTextures, finalImageGeom, shdMain); + finalImageRenderer.RegisterProperty("uStageHalfSize", stageHalfSize); + RegisterDepthProperties(depth, zNear, finalImageRenderer); + + auto propInvProjection = finalImageRenderer.RegisterProperty("uInvProjection", Matrix::IDENTITY); + Constraint cnstrInvProjection = Constraint::New(finalImageRenderer, propInvProjection, + [zCameraPos, zNear, depth](Matrix& output, const PropertyInputContainer& input) { + output = input[0]->GetMatrix(); + DALI_ASSERT_ALWAYS(output.Invert() && "Failed to invert projection matrix."); + }); + cnstrInvProjection.AddSource(Source(camera, CameraActor::Property::PROJECTION_MATRIX)); + cnstrInvProjection.AddSource(Source(camera, CameraActor::Property::VIEW_MATRIX)); + cnstrInvProjection.Apply(); + + finalImage.AddRenderer(finalImageRenderer); + + mFinalImage = finalImage; + stage.Add(finalImage); + + // Create a node for our lights + auto lights = Actor::New(); + CenterActor(lights); + sceneRoot.Add(lights); + + // Create Lights + const bool showLights = mOptions & Options::SHOW_LIGHTS; + Renderer lightRenderer; + if (showLights) + { + Geometry lightMesh = CreateOctahedron(true); + lightRenderer = CreateRenderer(noTexturesThanks, lightMesh, preShader, + OPTION_DEPTH_TEST | OPTION_DEPTH_WRITE); + lightRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::FRONT); + } + + Vector3 lightPos{ unit * 12.f, 0.f, 0.f }; + float theta = M_PI * 2.f / MAX_LIGHTS; + float cosTheta = std::cos(theta); + float sinTheta = std::sin(theta); + for (int i = 0; i < MAX_LIGHTS; ++i) + { + Vector3 color = FromHueSaturationLightness(Vector3((360.f * i) / MAX_LIGHTS, .5f, 1.f)); + + Actor light = CreateLight(lightPos * (1 + (i % 8)) / 8.f, unit * 16.f, color, camera, finalImageRenderer); + + float z = (((i & 1) << 1) - 1) * unit * 8.f; + lightPos = Vector3(cosTheta * lightPos.x - sinTheta * lightPos.y, sinTheta * lightPos.x + cosTheta * lightPos.y, z); + + if (showLights) + { + light.SetProperty(Actor::Property::SIZE, Vector3::ONE * unit / 8.f); + light.AddRenderer(lightRenderer); + } + + lights.Add(light); + } + + // Take them for a spin. + Animation animLights = Animation::New(40.f); + animLights.SetLooping(true); + animLights.AnimateBy(Property(lights, Actor::Property::ORIENTATION), Quaternion(Radian(M_PI * 2.f), Vector3::YAXIS)); + animLights.Play(); + + // Event handling + stage.KeyEventSignal().Connect(this, &DeferredShadingExample::OnKeyEvent); + + mPanDetector = PanGestureDetector::New(); + mPanDetector.DetectedSignal().Connect(this, &DeferredShadingExample::OnPan); + mPanDetector.Attach(stage.GetRootLayer()); + } + + void Destroy(Application& app) + { + Stage::GetCurrent().GetRenderTaskList().RemoveTask(mSceneRender); + mSceneRender.Reset(); + + UnparentAndReset(mSceneRoot); + UnparentAndReset(mFinalImage); + } + + Actor CreateLight(Vector3 position, float radius, Vector3 color, CameraActor camera, Renderer renderer) + { + Actor light = Actor::New(); + CenterActor(light); + light.SetProperty(Actor::Property::COLOR, Color::WHITE); + light.SetProperty(Actor::Property::POSITION, position); + + auto iPropRadius = light.RegisterProperty("radius", radius); + auto iPropLightColor = light.RegisterProperty("lightcolor", color); + + // Create light source uniforms on lighting shader. + char buffer[128]; + char* writep = buffer + sprintf(buffer, "uLights[%d].", mNumLights); + ++mNumLights; + + strcpy(writep, "position"); + auto oPropLightPos = renderer.RegisterProperty(buffer, position); + + strcpy(writep, "radius"); + auto oPropLightRadius = renderer.RegisterProperty(buffer, radius); + + strcpy(writep, "color"); + auto oPropLightColor = renderer.RegisterProperty(buffer, color); + + // Constrain the light position, radius and color to lighting shader uniforms. + // Convert light position to view space; + Constraint cLightPos = Constraint::New(renderer, oPropLightPos, [](Vector3& output, const PropertyInputContainer& input) + { + Vector4 worldPos(input[0]->GetVector3()); + worldPos.w = 1.f; + + worldPos = input[1]->GetMatrix() * worldPos; + output = Vector3(worldPos); + }); + cLightPos.AddSource(Source(light, Actor::Property::WORLD_POSITION)); + cLightPos.AddSource(Source(camera, CameraActor::Property::VIEW_MATRIX)); + cLightPos.Apply(); + + Constraint cLightRadius = Constraint::New(renderer, oPropLightRadius, + EqualToConstraint()); + cLightRadius.AddSource(Source(light, iPropRadius)); + cLightRadius.Apply(); + + Constraint cLightColor = Constraint::New(renderer, oPropLightColor, + EqualToConstraint()); + cLightColor.AddSource(Source(light, iPropLightColor)); + cLightColor.Apply(); + + return light; + } + + void OnPan(Actor, PanGesture const& gesture) + { + Quaternion q = mAxis.GetProperty(Actor::Property::ORIENTATION).Get(); + Quaternion qx(Radian(Degree(gesture.screenDisplacement.y) * -.5f), Vector3::XAXIS); + Quaternion qy(Radian(Degree(gesture.screenDisplacement.x) * .5f), Vector3::YAXIS); + mAxis.SetProperty(Actor::Property::ORIENTATION, qy * qx * q); + } + + void OnKeyEvent(const KeyEvent& event) + { + if(event.state == KeyEvent::Down) + { + if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) ) + { + mApp.Quit(); + } + } + } + + Application& mApp; + uint32_t mOptions; + + Actor mSceneRoot; + Actor mAxis; + + RenderTask mSceneRender; + Actor mFinalImage; + + int mNumLights = 0; + + PanGestureDetector mPanDetector; +}; + + +int main(int argc, char** argv) +{ + const bool showLights = [](int argc, char** argv) + { + auto endArgs = argv + argc; + return std::find_if(argv, endArgs, [](const char* arg) + { + return strcmp(arg, "--show-lights") == 0; + }) != endArgs; + }(argc, argv); + + Application app = Application::New(&argc, &argv); + DeferredShadingExample example(app, (showLights ? DeferredShadingExample::Options::SHOW_LIGHTS : 0)); + app.MainLoop(); + return 0; +} diff --git a/resources/po/en_GB.po b/resources/po/en_GB.po index b520b9d..d5c26e5 100755 --- a/resources/po/en_GB.po +++ b/resources/po/en_GB.po @@ -58,6 +58,9 @@ msgstr "Contact Cards" msgid "DALI_DEMO_STR_TITLE_CUBE_TRANSITION" msgstr "Cube Effect" +msgid "DALI_DEMO_STR_TITLE_DEFERRED_SHADING" +msgstr "Deferred Shading" + msgid "DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION" msgstr "Dissolve Effect" diff --git a/resources/po/en_US.po b/resources/po/en_US.po index 9647ce0..c8f0c68 100755 --- a/resources/po/en_US.po +++ b/resources/po/en_US.po @@ -43,6 +43,9 @@ msgstr "Clipping" msgid "DALI_DEMO_STR_TITLE_CLIPPING_DRAW_ORDER" msgstr "Clipping Draw Order" +msgid "DALI_DEMO_STR_TITLE_DEFERRED_SHADING" +msgstr "Deferred Shading" + msgid "DALI_DEMO_STR_TITLE_GAUSSIAN_BLUR_VIEW" msgstr "Gaussian Blur" diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index 2969f79..fbb8155 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -49,6 +49,7 @@ extern "C" #define DALI_DEMO_STR_TITLE_CARD_ACTIVE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CARD_ACTIVE") #define DALI_DEMO_STR_TITLE_CLIPPING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CLIPPING") #define DALI_DEMO_STR_TITLE_CLIPPING_DRAW_ORDER dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CLIPPING_DRAW_ORDER") +#define DALI_DEMO_STR_TITLE_DEFERRED_SHADING dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_DEFERRED_SHADING") #define DALI_DEMO_STR_TITLE_GAUSSIAN_BLUR_VIEW dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_GAUSSIAN_BLUR_VIEW") #define DALI_DEMO_STR_TITLE_GESTURES dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_GESTURES") #define DALI_DEMO_STR_TITLE_COLOR_GRADIENT dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_COLOR_GRADIENT") @@ -153,6 +154,7 @@ extern "C" #define DALI_DEMO_STR_TITLE_COMPRESSED_TEXTURE_FORMATS "Compressed Texture Formats" #define DALI_DEMO_STR_TITLE_CONTACT_CARDS "Contact Cards" #define DALI_DEMO_STR_TITLE_CUBE_TRANSITION "Cube Effect" +#define DALI_DEMO_STR_TITLE_DEFERRED_SHADING "Deferred Shading" #define DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION "Dissolve Effect" #define DALI_DEMO_STR_TITLE_DRAG_AND_DROP "Drag and Drop" #define DALI_DEMO_STR_TITLE_EFFECTS_VIEW "Effects View"