From 97cf1943198d50e2cf3b1323a6c1ea79940d51ce Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 4 Apr 2016 15:36:16 +0300 Subject: [PATCH] #183 light bindings --- src/dlangui/graphics/scene/light.d | 104 ++++++++++++++++++++++++-- src/dlangui/graphics/scene/material.d | 32 +++++++- src/dlangui/graphics/scene/model.d | 21 +++++- src/dlangui/graphics/scene/scene3d.d | 8 +- 4 files changed, 155 insertions(+), 10 deletions(-) diff --git a/src/dlangui/graphics/scene/light.d b/src/dlangui/graphics/scene/light.d index ad960030..47f2a2f0 100644 --- a/src/dlangui/graphics/scene/light.d +++ b/src/dlangui/graphics/scene/light.d @@ -48,10 +48,23 @@ class Light : RefCountedObject { @property void range(float v) { assert(false); } @property float rangeInverse() const { return 1.0; } + @property float innerAngle() const { assert(false); } + @property float innerAngleCos() const { assert(false); } + @property float outerAngle() const { assert(false); } + @property float outerAngleCos() const { assert(false); } + /// create new directional light static Light createDirectional(vec3 color) { return new DirectionalLight(color); } + /// create new point light + static Light createPoint(vec3 color, float range) { + return new PointLight(color, range); + } + /// create new point light + static Light createSpot(vec3 color, float range, float innerAngle, float outerAngle) { + return new SpotLight(color, range, innerAngle, outerAngle); + } } protected class DirectionalLight : Light { @@ -63,7 +76,7 @@ protected class DirectionalLight : Light { protected class PointLight : Light { protected float _range = 1; protected float _rangeInverse = 1; - protected this(vec3 color, float range = 1) { + protected this(vec3 color, float range) { super(color); _range = range; _rangeInverse = 1 / range; @@ -79,6 +92,28 @@ protected class PointLight : Light { override @property float rangeInverse() const { return _rangeInverse; } } +protected class SpotLight : PointLight { + protected float _innerAngle; + protected float _innerAngleCos; + protected float _outerAngle; + protected float _outerAngleCos; + protected this(vec3 color, float range, float innerAngle, float outerAngle) { + import std.math; + super(color, range); + _innerAngle = innerAngle; + _outerAngle = outerAngle; + _innerAngleCos = cos(innerAngle); + _outerAngleCos = cos(outerAngle); + } + + override @property LightType type() const { return LightType.spot; } + + override @property float innerAngle() const { return _innerAngle; } + override @property float innerAngleCos() const { return _innerAngleCos; } + override @property float outerAngle() const { return _outerAngle; } + override @property float outerAngleCos() const { return _outerAngleCos; } +} + alias LightCounts = int[3]; /// light collection @@ -87,11 +122,11 @@ struct Lights { Light[] point; Light[] spot; void reset() { - directional = null; - point = null; - spot = null; + directional.length = 0; + point.length = 0; + spot.length = 0; } - @property bool empty() { return directional.length + point.length + spot.length > 0; } + @property bool empty() const { return directional.length + point.length + spot.length > 0; } /// returns point types by type @property LightCounts counts() const { return [cast(int)directional.length, cast(int)point.length, cast(int)spot.length]; } @property int directionalCount() const { return cast(int)directional.length; } @@ -191,6 +226,58 @@ struct Lights { struct LightParams { Lights _lights; + @property bool empty() const { return _lights.empty; } + + void reset() { + _lights.reset(); + u_directionalLightDirection.length = 0; + u_directionalLightColor.length = 0; + + u_pointLightPosition.length = 0; + u_pointLightColor.length = 0; + u_pointLightRangeInverse.length = 0; + + u_spotLightPosition.length = 0; + u_spotLightDirection.length = 0; + u_spotLightColor.length = 0; + u_spotLightRangeInverse.length = 0; + u_spotLightInnerAngleCos.length = 0; + u_spotLightOuterAngleCos.length = 0; + } + + void reset(ref LightParams params) { + reset(); + if (params._lights.directional.length) + _lights.directional ~= params._lights.directional; + if (params._lights.point.length) + _lights.point ~= params._lights.point; + if (params._lights.spot.length) + _lights.spot ~= params._lights.spot; + + u_directionalLightDirection ~= params.u_directionalLightDirection; + u_directionalLightColor ~= params.u_directionalLightColor; + + u_pointLightPosition ~= params.u_pointLightPosition; + u_pointLightColor ~= params.u_pointLightColor; + u_pointLightRangeInverse ~= params.u_pointLightRangeInverse; + + u_spotLightPosition ~= params.u_spotLightPosition; + u_spotLightDirection ~= params.u_spotLightDirection; + u_spotLightColor ~= params.u_spotLightColor; + u_spotLightRangeInverse ~= params.u_spotLightRangeInverse; + u_spotLightInnerAngleCos ~= params.u_spotLightInnerAngleCos; + u_spotLightOuterAngleCos ~= params.u_spotLightOuterAngleCos; + } + + void add(ref Lights lights) { + foreach(light; lights.directional) + add(light); + foreach(light; lights.point) + add(light); + foreach(light; lights.spot) + add(light); + } + /// returns true if light is added (not a duplicate, and enabled) bool add(Light light) { if (!light.node || !light.enabled || !_lights.add(light)) @@ -206,7 +293,12 @@ struct LightParams { u_pointLightRangeInverse ~= light.rangeInverse; return true; case LightType.spot: - // TODO + u_spotLightPosition ~= light.position; + u_spotLightDirection ~= light.direction; + u_spotLightColor ~= light.color; + u_spotLightRangeInverse ~= light.rangeInverse; + u_spotLightInnerAngleCos ~= light.innerAngleCos; + u_spotLightOuterAngleCos ~= light.outerAngleCos; return true; default: return false; diff --git a/src/dlangui/graphics/scene/material.d b/src/dlangui/graphics/scene/material.d index c4bcd91b..9940617e 100644 --- a/src/dlangui/graphics/scene/material.d +++ b/src/dlangui/graphics/scene/material.d @@ -87,7 +87,7 @@ class Material : RefCountedObject { return this; } - void bind(Node3d node) { + void bind(Node3d node, LightParams * lights = null) { assert(!effect.isNull); effect.bind(); if (!texture.isNull) { @@ -109,6 +109,36 @@ class Material : RefCountedObject { _effect.setUniform(DefaultUniform.u_modulateColor, _modulateColor); if (_effect.hasUniform(DefaultUniform.u_modulateAlpha)) _effect.setUniform(DefaultUniform.u_modulateAlpha, _modulateAlpha); + if (lights && !lights.empty) { + if (lights.u_directionalLightDirection.length) { + if (_effect.hasUniform(DefaultUniform.u_directionalLightDirection)) + _effect.setUniform(DefaultUniform.u_directionalLightDirection, lights.u_directionalLightDirection); + if (_effect.hasUniform(DefaultUniform.u_directionalLightColor)) + _effect.setUniform(DefaultUniform.u_directionalLightColor, lights.u_directionalLightColor); + } + if (lights.u_pointLightPosition.length) { + if (_effect.hasUniform(DefaultUniform.u_pointLightPosition)) + _effect.setUniform(DefaultUniform.u_pointLightPosition, lights.u_pointLightPosition); + if (_effect.hasUniform(DefaultUniform.u_pointLightColor)) + _effect.setUniform(DefaultUniform.u_pointLightColor, lights.u_pointLightColor); + if (_effect.hasUniform(DefaultUniform.u_pointLightRangeInverse)) + _effect.setUniform(DefaultUniform.u_pointLightRangeInverse, lights.u_pointLightRangeInverse); + } + if (lights.u_spotLightPosition.length) { + if (_effect.hasUniform(DefaultUniform.u_spotLightPosition)) + _effect.setUniform(DefaultUniform.u_spotLightPosition, lights.u_spotLightPosition); + if (_effect.hasUniform(DefaultUniform.u_spotLightDirection)) + _effect.setUniform(DefaultUniform.u_spotLightDirection, lights.u_spotLightDirection); + if (_effect.hasUniform(DefaultUniform.u_spotLightColor)) + _effect.setUniform(DefaultUniform.u_spotLightColor, lights.u_spotLightColor); + if (_effect.hasUniform(DefaultUniform.u_spotLightRangeInverse)) + _effect.setUniform(DefaultUniform.u_spotLightRangeInverse, lights.u_spotLightRangeInverse); + if (_effect.hasUniform(DefaultUniform.u_spotLightInnerAngleCos)) + _effect.setUniform(DefaultUniform.u_spotLightInnerAngleCos, lights.u_spotLightInnerAngleCos); + if (_effect.hasUniform(DefaultUniform.u_spotLightOuterAngleCos)) + _effect.setUniform(DefaultUniform.u_spotLightOuterAngleCos, lights.u_spotLightOuterAngleCos); + } + } } void drawMesh(Mesh mesh) { diff --git a/src/dlangui/graphics/scene/model.d b/src/dlangui/graphics/scene/model.d index f825afd6..c3d472c8 100644 --- a/src/dlangui/graphics/scene/model.d +++ b/src/dlangui/graphics/scene/model.d @@ -35,9 +35,28 @@ class Model : DrawableObject { return this; } + protected static __gshared LightParams _lightParamsBuffer; + @property protected LightParams * lights(Node3d node) { + if (!node.scene) + return null; + if (_lights.empty) { + if (node.scene.boundLights.empty) + return null; + return node.scene.boundLightsPtr; + } + if (node.scene.boundLights.empty) { + _lightParamsBuffer.reset(); + _lightParamsBuffer.add(_lights); + } else { + _lightParamsBuffer.reset(node.scene.boundLights); + _lightParamsBuffer.add(_lights); + } + return &_lightParamsBuffer; + } + override void draw(Node3d node, bool wireframe) { /// override it - _material.bind(node); + _material.bind(node, lights(node)); _material.drawMesh(_mesh); _material.unbind(); } diff --git a/src/dlangui/graphics/scene/scene3d.d b/src/dlangui/graphics/scene/scene3d.d index c59f46ff..6a0d0407 100644 --- a/src/dlangui/graphics/scene/scene3d.d +++ b/src/dlangui/graphics/scene/scene3d.d @@ -69,11 +69,15 @@ class Scene3d : Node3d { return false; } - protected Lights _lights; + protected LightParams _lights; - @property ref const(Lights) boundLights() { + @property ref LightParams boundLights() { return _lights; } + + @property LightParams * boundLightsPtr() { + return _lights.empty ? null : &_lights; + } } /// depth-first recursive node traversion, stops if visitor returns true