#183 light bindings

This commit is contained in:
Vadim Lopatin 2016-04-04 14:56:58 +03:00
parent 5f0356b3d9
commit 846c25c652
10 changed files with 369 additions and 10 deletions

View File

@ -1595,6 +1595,17 @@ struct mat4 {
return (a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0);
}
@property vec3 forwardVector() const
{
return vec3(-m[8], -m[9], -m[10]);
}
@property vec3 backVector() const
{
return vec3(m[8], m[9], m[10]);
}
static __gshared const mat4 IDENTITY;
}

View File

@ -319,6 +319,14 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect {
return res;
}
override void setUniform(string uniformName, const vec2[] vec) {
checkgl!glUniform2fv(getUniformLocation(uniformName), cast(int)vec.length, vec[0].vec.ptr);
}
override void setUniform(DefaultUniform id, const vec2[] vec) {
checkgl!glUniform2fv(getUniformLocation(id), cast(int)vec.length, vec[0].vec.ptr);
}
override void setUniform(string uniformName, vec2 vec) {
checkgl!glUniform2fv(getUniformLocation(uniformName), 1, vec.vec.ptr);
}
@ -335,6 +343,14 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect {
checkgl!glUniform3fv(getUniformLocation(id), 1, vec.vec.ptr);
}
override void setUniform(string uniformName, const vec3[] vec) {
checkgl!glUniform3fv(getUniformLocation(uniformName), cast(int)vec.length, vec[0].vec.ptr);
}
override void setUniform(DefaultUniform id, const vec3[] vec) {
checkgl!glUniform3fv(getUniformLocation(id), cast(int)vec.length, vec[0].vec.ptr);
}
override void setUniform(string uniformName, vec4 vec) {
checkgl!glUniform4fv(getUniformLocation(uniformName), 1, vec.vec.ptr);
}
@ -343,6 +359,14 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect {
checkgl!glUniform4fv(getUniformLocation(id), 1, vec.vec.ptr);
}
override void setUniform(string uniformName, const vec4[] vec) {
checkgl!glUniform4fv(getUniformLocation(uniformName), cast(int)vec.length, vec[0].vec.ptr);
}
override void setUniform(DefaultUniform id, const vec4[] vec) {
checkgl!glUniform4fv(getUniformLocation(id), cast(int)vec.length, vec[0].vec.ptr);
}
override void setUniform(string uniformName, ref const(mat4) matrix) {
checkgl!glUniformMatrix4fv(getUniformLocation(uniformName), 1, false, matrix.m.ptr);
}
@ -351,6 +375,30 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect {
checkgl!glUniformMatrix4fv(getUniformLocation(id), 1, false, matrix.m.ptr);
}
override void setUniform(string uniformName, const(mat4)[] matrix) {
checkgl!glUniformMatrix4fv(getUniformLocation(uniformName), cast(int)matrix.length, false, matrix[0].m.ptr);
}
override void setUniform(DefaultUniform id, const(mat4)[] matrix) {
checkgl!glUniformMatrix4fv(getUniformLocation(id), cast(int)matrix.length, false, matrix[0].m.ptr);
}
override void setUniform(string uniformName, float v) {
checkgl!glUniform1f(getUniformLocation(uniformName), v);
}
override void setUniform(DefaultUniform id, float v) {
checkgl!glUniform1f(getUniformLocation(id), v);
}
override void setUniform(string uniformName, const float[] v) {
checkgl!glUniform1fv(getUniformLocation(uniformName), cast(int)v.length, v.ptr);
}
override void setUniform(DefaultUniform id, const float[] v) {
checkgl!glUniform1fv(getUniformLocation(id), cast(int)v.length, v.ptr);
}
/// returns true if effect has uniform
override bool hasUniform(DefaultUniform id) {
return getUniformLocation(id) >= 0;

View File

@ -137,6 +137,8 @@ class Effect : GLProgram {
return getAttribLocation(DefaultAttribute.a_color);
case TEXCOORD0:
return getAttribLocation(DefaultAttribute.a_texCoord);
case NORMAL:
return getAttribLocation(DefaultAttribute.a_normal);
default:
return super.getVertexElementLocation(type);
}

View File

@ -2,6 +2,9 @@ module dlangui.graphics.scene.light;
import dlangui.core.math3d;
import dlangui.core.types;
import dlangui.graphics.scene.node;
import std.conv : to;
enum LightType : ubyte {
directional,
@ -12,12 +15,39 @@ enum LightType : ubyte {
/// Reference counted Light object
alias LightRef = Ref!Light;
class Light : RefCountedObject {
class Light : RefCountedObject {
protected Node3d _node;
protected vec3 _color;
protected this(vec3 color) {}
@property vec3 color() { return _color; }
protected bool _autobind = true;
protected bool _enabled = true;
protected this(vec3 color) { _color = color; }
@property vec3 color() const { return _color; }
@property Light color(vec3 c) { _color = c; return this; }
@property LightType type() { return LightType.directional; }
@property LightType type() const { return LightType.directional; }
@property bool autobind() const { return _autobind; }
@property Light autobind(bool flg) { _autobind = flg; return this; }
@property bool enabled() const { return _enabled; }
@property Light enabled(bool flg) { _enabled = flg; return this; }
@property Node3d node() { return _node; }
@property Light node(Node3d n) { _node = n; return this; }
/// direction in world coordinates
@property vec3 direction() { return _node ? _node.forwardVectorWorld : vec3(0, 0, 1); }
/// position in world coordinates
@property vec3 position() { return _node ? _node.translationWorld : vec3(0, 0, 0); }
@property float range() const { return 1.0; }
@property void range(float v) { assert(false); }
@property float rangeInverse() const { return 1.0; }
/// create new directional light
static Light createDirectional(vec3 color) {
return new DirectionalLight(color);
@ -29,3 +59,171 @@ protected class DirectionalLight : Light {
super(color);
}
}
protected class PointLight : Light {
protected float _range = 1;
protected float _rangeInverse = 1;
protected this(vec3 color, float range = 1) {
super(color);
_range = range;
_rangeInverse = 1 / range;
}
override @property LightType type() const { return LightType.point; }
override @property float range() const { return _range; }
override @property void range(float v) {
_range = v;
_rangeInverse = 1 / v;
}
override @property float rangeInverse() const { return _rangeInverse; }
}
alias LightCounts = int[3];
/// light collection
struct Lights {
Light[] directional;
Light[] point;
Light[] spot;
void reset() {
directional = null;
point = null;
spot = null;
}
@property bool empty() { 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; }
@property int pointCount() const { return cast(int)point.length; }
@property int spotCount() const { return cast(int)spot.length; }
/// return light count definition for shaders, e.g. "DIRECTIONAL_LIGHT_COUNT 2;POINT_LIGHT_COUNT 1"
@property string defs() const {
if (!directional.length && !point.length && !spot.length)
return null;
char[] buf;
if (directional.length) {
buf ~= "DIRECTIONAL_LIGHT_COUNT ";
buf ~= directional.length.to!string;
}
if (point.length) {
if (buf)
buf ~= ";";
buf ~= "POINT_LIGHT_COUNT ";
buf ~= point.length.to!string;
}
if (spot.length) {
if (buf)
buf ~= ";";
buf ~= "SPOT_LIGHT_COUNT ";
buf ~= spot.length.to!string;
}
return cast(string)buf;
}
void remove(Light light) {
import std.algorithm : remove;
switch(light.type) {
case LightType.directional:
foreach(index, v; directional)
if (v is light) {
directional = directional.remove(index);
return;
}
directional ~= light;
break;
case LightType.point:
foreach(index, v; point)
if (v is light) {
point = point.remove(index);
return;
}
point ~= light;
break;
case LightType.spot:
foreach(index, v; spot)
if (v is light) {
spot = spot.remove(index);
return;
}
spot ~= light;
break;
default:
break;
}
}
/// returns true if light is added (not a duplicate, and enabled)
bool add(Light light) {
switch(light.type) {
case LightType.directional:
foreach(v; directional)
if (v is light)
return false;
directional ~= light;
return true;
case LightType.point:
foreach(v; point)
if (v is light)
return false;
point ~= light;
return true;
case LightType.spot:
foreach(v; spot)
if (v is light)
return false;
spot ~= light;
return true;
default:
return false;
}
}
Lights clone() {
Lights res;
if (directional.length)
res.directional ~= directional;
if (point.length)
res.point ~= point;
if (spot.length)
res.spot ~= spot;
return res;
}
}
struct LightParams {
Lights _lights;
/// returns true if light is added (not a duplicate, and enabled)
bool add(Light light) {
if (!light.node || !light.enabled || !_lights.add(light))
return false;
switch(light.type) {
case LightType.directional:
u_directionalLightDirection ~= light.direction;
u_directionalLightColor ~= light.color;
return true;
case LightType.point:
u_pointLightPosition ~= light.position;
u_pointLightColor ~= light.color;
u_pointLightRangeInverse ~= light.rangeInverse;
return true;
case LightType.spot:
// TODO
return true;
default:
return false;
}
}
vec3[] u_directionalLightDirection;
vec3[] u_directionalLightColor;
vec3[] u_pointLightPosition;
vec3[] u_pointLightColor;
float[] u_pointLightRangeInverse;
vec3[] u_spotLightPosition;
vec3[] u_spotLightDirection;
vec3[] u_spotLightColor;
float[] u_spotLightRangeInverse;
float[] u_spotLightInnerAngleCos;
float[] u_spotLightOuterAngleCos;
}

View File

@ -9,6 +9,7 @@ import dlangui.graphics.gldrawbuf;
import dlangui.graphics.scene.effect;
import dlangui.graphics.scene.node;
import dlangui.graphics.scene.mesh;
import dlangui.graphics.scene.light;
/// Reference counted Material object
alias MaterialRef = Ref!Material;
@ -25,6 +26,8 @@ class Material : RefCountedObject {
// colors
protected vec4 _diffuseColor = vec4(1, 1, 1, 1);
protected vec3 _ambientColor = vec3(1, 1, 1);
protected vec4 _modulateColor = vec4(1, 1, 1, 1);
protected float _modulateAlpha = 1;
// TODO: more material properties
@ -40,6 +43,10 @@ class Material : RefCountedObject {
@property Material diffuseColor(vec4 color) { _diffuseColor = color; return this; }
@property vec3 ambientColor() { return _ambientColor; }
@property Material ambientColor(vec3 color) { _ambientColor = color; return this; }
@property vec4 modulateColor() { return _modulateColor; }
@property Material modulateColor(vec4 color) { _modulateColor = color; return this; }
@property float modulateAlpha() { return _modulateAlpha; }
@property Material modulateColor(float a) { _modulateAlpha = a; return this; }
@property EffectRef effect() {
if (_effect.isNull && !_effectId.empty)
@ -98,6 +105,10 @@ class Material : RefCountedObject {
_effect.setUniform(DefaultUniform.u_ambientColor, _ambientColor);
if (_effect.hasUniform(DefaultUniform.u_diffuseColor))
_effect.setUniform(DefaultUniform.u_diffuseColor, _diffuseColor);
if (_effect.hasUniform(DefaultUniform.u_modulateColor))
_effect.setUniform(DefaultUniform.u_modulateColor, _modulateColor);
if (_effect.hasUniform(DefaultUniform.u_modulateAlpha))
_effect.setUniform(DefaultUniform.u_modulateAlpha, _modulateAlpha);
}
void drawMesh(Mesh mesh) {

View File

@ -15,20 +15,44 @@ abstract class GraphicsEffect : RefCountedObject {
void setUniform(string uniformName, ref const(mat4) matrix);
void setUniform(string uniformName, const(mat4)[] matrix);
void setUniform(string uniformName, float v);
void setUniform(string uniformName, const float v[]);
void setUniform(string uniformName, vec2 vec);
void setUniform(string uniformName, const vec2[] vec);
void setUniform(string uniformName, vec3 vec);
void setUniform(string uniformName, const vec3[] vec);
void setUniform(string uniformName, vec4 vec);
void setUniform(string uniformName, const vec4[] vec);
void setUniform(DefaultUniform id, ref const(mat4) matrix);
void setUniform(DefaultUniform id, const(mat4)[] matrix);
void setUniform(DefaultUniform id, float v);
void setUniform(DefaultUniform id, const float[] v);
void setUniform(DefaultUniform id, vec2 vec);
void setUniform(DefaultUniform id, const vec2[] vec);
void setUniform(DefaultUniform id, vec3 vec);
void setUniform(DefaultUniform id, const vec3[] vec);
void setUniform(DefaultUniform id, vec4 vec);
void setUniform(DefaultUniform id, const vec4[] vec);
/// returns true if effect has uniform
bool hasUniform(DefaultUniform id);
@ -42,7 +66,13 @@ enum DefaultUniform : int {
// colors
u_ambientColor, // vec3
u_diffuseColor, // vec4
u_lightmapTexture, // sampler2D
// textures
u_diffuseTexture, //uniform sampler2D u_diffuseTexture;
u_lightmapTexture, //uniform sampler2D u_lightmapTexture;
u_normalmapTexture, //uniform sampler2D u_normalmapTexture;
// lights
u_directionalLightColor, //uniform vec3 u_directionalLightColor[DIRECTIONAL_LIGHT_COUNT];
u_directionalLightDirection, //uniform vec3 u_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];
u_pointLightColor, //uniform vec3 u_pointLightColor[POINT_LIGHT_COUNT];
@ -52,7 +82,9 @@ enum DefaultUniform : int {
u_spotLightRangeInverse, //uniform float u_spotLightRangeInverse[SPOT_LIGHT_COUNT];
u_spotLightInnerAngleCos, //uniform float u_spotLightInnerAngleCos[SPOT_LIGHT_COUNT];
u_spotLightOuterAngleCos, //uniform float u_spotLightOuterAngleCos[SPOT_LIGHT_COUNT];
u_spotLightPosition, //uniform vec3 u_spotLightPosition[SPOT_LIGHT_COUNT];
u_spotLightDirection, //uniform vec3 u_spotLightDirection[SPOT_LIGHT_COUNT];
u_specularExponent, //uniform float u_specularExponent;
u_modulateColor, //uniform vec4 u_modulateColor;
u_modulateAlpha, //uniform float u_modulateAlpha;
@ -60,10 +92,11 @@ enum DefaultUniform : int {
// matrix
u_worldViewProjectionMatrix, //uniform mat4 u_worldViewProjectionMatrix;
u_inverseTransposeWorldViewMatrix, //uniform mat4 u_inverseTransposeWorldViewMatrix;
u_worldViewMatrix, //uniform mat4 u_worldViewMatrix;
u_matrixPalette, //uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
u_cameraPosition, //uniform vec3 u_cameraPosition;
u_worldMatrix, //uniform mat4 u_worldMatrix;
u_worldViewMatrix, //uniform mat4 u_worldViewMatrix;
u_cameraPosition, //uniform vec3 u_cameraPosition;
u_matrixPalette, //uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
u_clipPlane, //uniform vec4 u_clipPlane;
}

View File

@ -3,10 +3,13 @@ module dlangui.graphics.scene.model;
import dlangui.graphics.scene.drawableobject;
import dlangui.graphics.scene.mesh;
import dlangui.graphics.scene.material;
import dlangui.graphics.scene.light;
class Model : DrawableObject {
protected MaterialRef _material;
protected MeshRef _mesh;
protected bool _autobindLights = true;
protected Lights _lights;
this() {
}
@ -19,6 +22,19 @@ class Model : DrawableObject {
@property ref MaterialRef material() { return _material; }
@property ref MeshRef mesh() { return _mesh; }
@property bool autobindLights() { return _autobindLights; }
@property Model autobindLights(bool flg) { _autobindLights = flg; return this; }
Model bindLight(Light light) {
_lights.add(light);
return this;
}
Model unbindLight(Light light) {
_lights.remove(light);
return this;
}
override void draw(Node3d node, bool wireframe) {
/// override it
_material.bind(node);

View File

@ -42,6 +42,18 @@ class Node3d : Transform {
/// light attached to node
@property ref LightRef light() { return _light; }
/// attach light to node
@property Node3d light(Light v) {
if (_light.get is v)
return this;
Node3d oldNode = v.node;
v.node = this;
_light = v;
if (oldNode)
oldNode._light = null;
return this;
}
/// returns scene for node
@property Scene3d scene() {
if (_scene)
@ -162,4 +174,13 @@ class Node3d : Transform {
worldMatrix.getTranslation(translation);
return translation;
}
/**
* Returns the forward vector of the Node in world space.
*
* @return The forward vector in world space.
*/
@property vec3 forwardVectorWorld() {
return worldMatrix.forwardVector;
}
}

View File

@ -166,10 +166,10 @@ struct ObjModelImport {
if (!mesh.isNull)
return;
if (_txCount) {
mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0));
mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, /*VertexElementType.COLOR, */ VertexElementType.TEXCOORD0));
_meshHasTexture = true;
} else {
mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR));
mesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL /*, VertexElementType.COLOR*/));
_meshHasTexture = false;
}
}

View File

@ -3,6 +3,7 @@ module dlangui.graphics.scene.scene3d;
import dlangui.core.types;
import dlangui.graphics.scene.node;
import dlangui.graphics.scene.camera;
import dlangui.graphics.scene.light;
public import dlangui.core.math3d;
@ -47,6 +48,7 @@ class Scene3d : Node3d {
protected bool _wireframe;
void drawScene(bool wireframe) {
_wireframe = wireframe;
updateAutoboundLights();
visit(this, &sceneDrawVisitor);
}
@ -55,6 +57,23 @@ class Scene3d : Node3d {
node.drawable.draw(node, _wireframe);
return false;
}
void updateAutoboundLights() {
_lights.reset();
visit(this, &lightBindingVisitor);
}
protected bool lightBindingVisitor(Node3d node) {
if (!node.light.isNull && node.light.enabled && node.light.autobind)
_lights.add(node.light);
return false;
}
protected Lights _lights;
@property ref const(Lights) boundLights() {
return _lights;
}
}
/// depth-first recursive node traversion, stops if visitor returns true