diff --git a/src/dlangui/core/math3d.d b/src/dlangui/core/math3d.d index 027fbb4f..767983e2 100644 --- a/src/dlangui/core/math3d.d +++ b/src/dlangui/core/math3d.d @@ -1512,9 +1512,94 @@ struct mat4 { return res; } + /** + * Decomposes the scale, rotation and translation components of this matrix. + * + * @param scale The scale. + * @param rotation The rotation. + * @param translation The translation. + */ + bool decompose(vec3 * scale, vec4 * rotation, vec3 * translation) const { + if (translation) + { + // Extract the translation. + translation.x = m[12]; + translation.y = m[13]; + translation.z = m[14]; + } + // Nothing left to do. + if (!scale && !rotation) + return true; + + // Extract the scale. + // This is simply the length of each axis (row/column) in the matrix. + vec3 xaxis = vec3(m[0], m[1], m[2]); + float scaleX = xaxis.length(); + + vec3 yaxis = vec3(m[4], m[5], m[6]); + float scaleY = yaxis.length(); + + vec3 zaxis = vec3(m[8], m[9], m[10]); + float scaleZ = zaxis.length(); + + // Determine if we have a negative scale (true if determinant is less than zero). + // In this case, we simply negate a single axis of the scale. + float det = determinant(); + if (det < 0) + scaleZ = -scaleZ; + + if (scale) + { + scale.x = scaleX; + scale.y = scaleY; + scale.z = scaleZ; + } + + // Nothing left to do. + if (!rotation) + return true; + + //// Scale too close to zero, can't decompose rotation. + //if (scaleX < MATH_TOLERANCE || scaleY < MATH_TOLERANCE || fabs(scaleZ) < MATH_TOLERANCE) + // return false; + // TODO: support rotation + return false; + } + + /** + * Gets the translational component of this matrix in the specified vector. + * + * @param translation A vector to receive the translation. + */ + void getTranslation(ref vec3 translation) const + { + decompose(null, null, &translation); + } + + @property float determinant() const + { + float a0 = m[0] * m[5] - m[1] * m[4]; + float a1 = m[0] * m[6] - m[2] * m[4]; + float a2 = m[0] * m[7] - m[3] * m[4]; + float a3 = m[1] * m[6] - m[2] * m[5]; + float a4 = m[1] * m[7] - m[3] * m[5]; + float a5 = m[2] * m[7] - m[3] * m[6]; + float b0 = m[8] * m[13] - m[9] * m[12]; + float b1 = m[8] * m[14] - m[10] * m[12]; + float b2 = m[8] * m[15] - m[11] * m[12]; + float b3 = m[9] * m[14] - m[10] * m[13]; + float b4 = m[9] * m[15] - m[11] * m[13]; + float b5 = m[10] * m[15] - m[11] * m[14]; + // Calculate the determinant. + return (a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0); + } + + static __gshared const mat4 IDENTITY; } + + unittest { vec3 a, b, c; a.clear(5); diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index 19c84e16..f807d076 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -351,6 +351,15 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect { checkgl!glUniformMatrix4fv(getUniformLocation(id), 1, false, matrix.m.ptr); } + /// returns true if effect has uniform + override bool hasUniform(DefaultUniform id) { + return getUniformLocation(id) >= 0; + } + + /// returns true if effect has uniform + override bool hasUniform(string uniformName) { + return getUniformLocation(uniformName) >= 0; + } /// draw mesh using this program (program should be bound by this time and all uniforms should be set) override void draw(Mesh mesh) { diff --git a/src/dlangui/graphics/scene/camera.d b/src/dlangui/graphics/scene/camera.d index ecf5d485..cbf595bc 100644 --- a/src/dlangui/graphics/scene/camera.d +++ b/src/dlangui/graphics/scene/camera.d @@ -53,7 +53,7 @@ class Camera : Node3d { _dirtyView = true; } - @property ref const(mat4) viewMatrix() { + override @property ref const(mat4) viewMatrix() { if (_dirtyView) { _viewMatrix = matrix.invert(); _dirtyView = false; @@ -62,7 +62,7 @@ class Camera : Node3d { } /// get projection*view matrix - @property ref const(mat4) projectionViewMatrix() { + override @property ref const(mat4) projectionViewMatrix() { if (_dirtyTransform || _dirtyViewProjection) { _viewProjectionMatrix = _projectionMatrix * viewMatrix; _dirtyViewProjection = false; diff --git a/src/dlangui/graphics/scene/material.d b/src/dlangui/graphics/scene/material.d index 85ffe249..fa6c046f 100644 --- a/src/dlangui/graphics/scene/material.d +++ b/src/dlangui/graphics/scene/material.d @@ -75,7 +75,12 @@ class Material : RefCountedObject { texture.texture.setSamplerParams(true); } // TODO: more uniforms - _effect.setUniform(DefaultUniform.u_worldViewProjectionMatrix, node.projectionViewModelMatrix); + if (_effect.hasUniform(DefaultUniform.u_worldViewProjectionMatrix)) + _effect.setUniform(DefaultUniform.u_worldViewProjectionMatrix, node.projectionViewModelMatrix); + if (_effect.hasUniform(DefaultUniform.u_cameraPosition)) + _effect.setUniform(DefaultUniform.u_cameraPosition, node.cameraPosition); + if (_effect.hasUniform(DefaultUniform.u_worldViewMatrix)) + _effect.setUniform(DefaultUniform.u_worldViewMatrix, node.worldViewMatrix); } void drawMesh(Mesh mesh) { diff --git a/src/dlangui/graphics/scene/mesh.d b/src/dlangui/graphics/scene/mesh.d index 120223d3..54cecb71 100644 --- a/src/dlangui/graphics/scene/mesh.d +++ b/src/dlangui/graphics/scene/mesh.d @@ -29,6 +29,12 @@ abstract class GraphicsEffect : RefCountedObject { void setUniform(DefaultUniform id, vec4 vec); + /// returns true if effect has uniform + bool hasUniform(DefaultUniform id); + + /// returns true if effect has uniform + bool hasUniform(string uniformName); + void draw(Mesh mesh); } @@ -51,9 +57,9 @@ enum DefaultUniform : int { u_modulateAlpha, //uniform float u_modulateAlpha; u_worldViewProjectionMatrix, //uniform mat4 u_worldViewProjectionMatrix; - u_matrixPalette, //uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3]; 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_clipPlane, //uniform vec4 u_clipPlane; diff --git a/src/dlangui/graphics/scene/node.d b/src/dlangui/graphics/scene/node.d index ce0f72f2..440145cd 100644 --- a/src/dlangui/graphics/scene/node.d +++ b/src/dlangui/graphics/scene/node.d @@ -7,6 +7,7 @@ import dlangui.core.collections; import dlangui.graphics.scene.scene3d; import dlangui.graphics.scene.drawableobject; import dlangui.graphics.scene.light; +import dlangui.graphics.scene.camera; /// 3D scene node class Node3d : Transform { @@ -97,10 +98,68 @@ class Node3d : Transform { return this; } + /// active camera or null of no camera + @property Camera activeCamera() { + if (!scene) + return null; + return scene.activeCamera; + } + + @property vec3 cameraPosition() { + auto cam = activeCamera; + if (cam) + return cam.translationWorld; + return vec3(0, 0, 0); + } + + /// get view matrix based on active camera + @property ref const(mat4) viewMatrix() { + auto cam = activeCamera; + if (cam) + return cam.viewMatrix; + return mat4.IDENTITY; + } + + /// get projection*view matrix based on active camera + @property ref const(mat4) projectionViewMatrix() { + auto cam = activeCamera; + if (cam) + return cam.projectionViewMatrix; + return mat4.IDENTITY; + } + protected mat4 _projectionViewModelMatrix; + /// returns projectionMatrix * viewMatrix * modelMatrix @property ref const(mat4) projectionViewModelMatrix() { + // TODO: optimize _projectionViewModelMatrix = _scene.projectionViewMatrix * matrix; return _projectionViewModelMatrix; } + + /// returns world matrix + @property ref const(mat4) worldMatrix() { + if (!parent) + return matrix; + _worldMatrix = parent.worldMatrix * matrix; + return _worldMatrix; + } + + /** + * Gets the world view matrix corresponding to this node. + * + * @return The world view matrix of this node. + */ + @property ref const(mat4) worldViewMatrix() { + static mat4 worldView; + worldView = viewMatrix * worldMatrix; + return worldView; + } + + /// returns translation vector (position) of this node in world space + @property vec3 translationWorld() { + vec3 translation; + worldMatrix.getTranslation(translation); + return translation; + } } diff --git a/src/dlangui/graphics/scene/scene3d.d b/src/dlangui/graphics/scene/scene3d.d index 1a0a57c5..6eccef98 100644 --- a/src/dlangui/graphics/scene/scene3d.d +++ b/src/dlangui/graphics/scene/scene3d.d @@ -22,7 +22,7 @@ class Scene3d : Node3d { /// active camera - @property Camera activeCamera() { + override @property Camera activeCamera() { if (_activeCamera) return _activeCamera; // TODO: find camera in child nodes @@ -44,14 +44,6 @@ class Scene3d : Node3d { //ignore } - /// get projection*view matrix - @property ref const(mat4) projectionViewMatrix() { - if (_activeCamera) - return _activeCamera.projectionViewMatrix; - static mat4 dummyIdentityMatrix; - return dummyIdentityMatrix; - } - protected bool _wireframe; void drawScene(bool wireframe) { _wireframe = wireframe;