diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d index 222b4ec5..7e088ecf 100644 --- a/examples/d3d/src/d3d.d +++ b/examples/d3d/src/d3d.d @@ -65,19 +65,19 @@ class UiWidget : VerticalLayout, CellVisitor { ScrollBar { id: sbTranslationX; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 200; alpha: 0.6 } TextWidget { text: "Rotation X" } TextWidget { id: lblRotationX; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF } - ScrollBar { id: sbRotationX; orientation: horizontal; minValue: -100; maxValue: 100; position: 10; minWidth: 200; alpha: 0.6 } + ScrollBar { id: sbRotationX; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 200; alpha: 0.6 } TextWidget { text: "Translation Y" } TextWidget { id: lblTranslationY; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF } - ScrollBar { id: sbTranslationY; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 200; alpha: 0.6 } + ScrollBar { id: sbTranslationY; orientation: horizontal; minValue: -100; maxValue: 100; position: 15; minWidth: 200; alpha: 0.6 } TextWidget { text: "Rotation Y" } TextWidget { id: lblRotationY; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF } - ScrollBar { id: sbRotationY; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 150; alpha: 0.6 } + ScrollBar { id: sbRotationY; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 150; alpha: 0.6 } TextWidget { text: "Translation Z" } TextWidget { id: lblTranslationZ; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF } - ScrollBar { id: sbTranslationZ; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 150; alpha: 0.6 } + ScrollBar { id: sbTranslationZ; orientation: horizontal; minValue: -100; maxValue: 100; position: 45; minWidth: 150; alpha: 0.6 } TextWidget { text: "Rotation Z" } TextWidget { id: lblRotationZ; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF } - ScrollBar { id: sbRotationZ; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 150; alpha: 0.6 } + ScrollBar { id: sbRotationZ; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 150; alpha: 0.6 } TextWidget { text: "Near" } TextWidget { id: lblNear; text: "0.1"; minWidth: 80; backgroundColor: 0x80FFFFFF } ScrollBar { id: sbNear; orientation: horizontal; minValue: 1; maxValue: 100; position: 1; minWidth: 150; alpha: 0.6 } @@ -102,15 +102,6 @@ class UiWidget : VerticalLayout, CellVisitor { controlsToVars(); assignHandlers(); - mat4 m; - m.translate(1, 2, -1); - Log.d("M*v=", m * vec3(0, 0, 0)); - Log.d("M*v=", m * vec3(10, 10, 10)); - m.translate(0, 0, -2); - Log.d("M*v=", m * vec3(0, 0, 0)); - Log.d("M*v=", m * vec3(10, 10, 10)); - - _scene = new Scene3d(); _cam = new Camera(); @@ -190,9 +181,9 @@ class UiWidget : VerticalLayout, CellVisitor { translationX = childById!ScrollBar("sbTranslationX").position / 10.0f; translationY = childById!ScrollBar("sbTranslationY").position / 10.0f; translationZ = childById!ScrollBar("sbTranslationZ").position / 10.0f; - rotationX = childById!ScrollBar("sbRotationX").position * 2.5f; - rotationY = childById!ScrollBar("sbRotationY").position * 2.5f; - rotationZ = childById!ScrollBar("sbRotationZ").position * 2.5f; + rotationX = childById!ScrollBar("sbRotationX").position; + rotationY = childById!ScrollBar("sbRotationY").position; + rotationZ = childById!ScrollBar("sbRotationZ").position; childById("lblNear").text = to!dstring(near); childById("lblFar").text = to!dstring(far); childById("lblTranslationX").text = to!dstring(translationX); @@ -270,9 +261,8 @@ class UiWidget : VerticalLayout, CellVisitor { //_cam.translate(vec3(0, 0, -1.1)); // - angle/1000 //_cam.translate(vec3(0, 3, - angle/1000)); // //_cam.rotateZ(30.0f + angle * 0.3456778); - mat4 projectionViewMatrix = _cam.projectionViewMatrix; - Log.d("projectionViewMatrix: ", projectionViewMatrix); + mat4 projectionViewMatrix = _cam.projectionViewMatrix; // ======== Model Matrix ================== mat4 modelMatrix; @@ -284,6 +274,46 @@ class UiWidget : VerticalLayout, CellVisitor { //modelMatrix.rotatex(angle * 1.98765f); mat4 projectionViewModelMatrix = projectionViewMatrix * modelMatrix; + //Log.d("projectionViewModelMatrix: ", projectionViewModelMatrix.dump); + + //{ + // mat4 projection; + // projection.setPerspective(45.0f, cast(float)rc.width / rc.height, near, far); + // mat4 view; + // view.translate(translationX, translationY, translationZ); + // Log.d(" .viewMatrix.trans ", view.dump); + // view.rotateX(rotationX); + // Log.d(" .viewMatrix.rx ", view.dump); + // view.rotateY(rotationY); + // Log.d(" .viewMatrix.ry ", view.dump); + // view.rotateZ(rotationZ); + // Log.d(" .viewMatrix.rz ", view.dump); + // mat4 projectionView = projection * view; + // Log.d(" .projectionMatrix: ", projection.dump); + // Log.d(" .viewMatrix: ", view.dump); + // Log.d(" .projectionViewMatrix: ", projectionView.dump); + // Log.d(" .projectionViewMMatrix: ", (projectionView * modelMatrix).dump); + //} + + //{ + // import gl3n.linalg; + // static string dump(mat4 m) { + // m.transpose; + // return to!string(m[0]) ~ to!string(m[1]) ~ to!string(m[2]) ~ to!string(m[3]); + // } + // static float toRad(float angle) { return angle * 2 * PI / 360; } + // mat4 projection = mat4.perspective(rc.width, rc.height, 45.0f, near, far); + // mat4 view = mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)).rotatey(toRad(rotationY)).rotatez(toRad(rotationZ)); + // Log.d("gl3n.viewMatrix: tr ", dump(mat4.identity.translate(translationX, translationY, translationZ))); + // Log.d("gl3n.viewMatrix: rx ", dump(mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)))); + // Log.d("gl3n.viewMatrix: ry ", dump(mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)).rotatey(toRad(rotationY)))); + // Log.d("gl3n.viewMatrix: rz ", dump(mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)).rotatey(toRad(rotationY)).rotatez(toRad(rotationZ)))); + // mat4 projectionView = projection * view; + // Log.d("gl3n.projectionMatrix: ", dump(projection)); + // Log.d("gl3n.viewMatrix: ", dump(view)); + // Log.d("gl3n.projectionViewMatrix: ", dump(projectionView)); + // Log.d("gl3n.projectionViewMMatrix: ", dump(projectionView * mat4.identity)); + //} //projectionViewModelMatrix.setIdentity(); //Log.d("matrix uniform: ", projectionViewModelMatrix.m); diff --git a/src/dlangui/core/math3d.d b/src/dlangui/core/math3d.d index 66143e4a..1af3cc16 100644 --- a/src/dlangui/core/math3d.d +++ b/src/dlangui/core/math3d.d @@ -876,6 +876,11 @@ bool fuzzyNull(float v) { struct mat4 { float[16] m = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + @property string dump() const { + import std.conv : to; + return to!string(m[0..4]) ~ to!string(m[4..8]) ~ to!string(m[8..12]) ~ to!string(m[12..16]); + } + //alias m this; this(float v) { @@ -883,22 +888,22 @@ struct mat4 { } this(const ref mat4 v) { - m[0..15] = v.m[0..15]; + m[0..16] = v.m[0..16]; } this(const float[16] v) { - m[0..15] = v[0..15]; + m[0..16] = v[0..16]; } ref mat4 opAssign(const ref mat4 v) { - m[0..15] = v.m[0..15]; + m[0..16] = v.m[0..16]; return this; } ref mat4 opAssign(const mat4 v) { - m[0..15] = v.m[0..15]; + m[0..16] = v.m[0..16]; return this; } ref mat4 opAssign(const float[16] v) { - m[0..15] = v[0..15]; + m[0..16] = v[0..16]; return this; } @@ -961,37 +966,6 @@ struct mat4 { m[3*4 + 3] = 0.0f; } - void setPerspective2(float angle, float aspect, float nearPlane, float farPlane) - { - // Bail out if the projection volume is zero-sized. - if (nearPlane == farPlane || aspect == 0.0f) - return; - - // Construct the projection. - float radians = (angle / 2.0f) * PI / 180.0f; - float sine = sin(radians); - if (sine == 0.0f) - return; - float cotan = cos(radians) / sine; - float clip = farPlane - nearPlane; - m[0*4 + 0] = cotan / aspect; - m[1*4 + 0] = 0.0f; - m[2*4 + 0] = 0.0f; - m[3*4 + 0] = 0.0f; - m[0*4 + 1] = 0.0f; - m[1*4 + 1] = cotan; - m[2*4 + 1] = 0.0f; - m[3*4 + 1] = 0.0f; - m[0*4 + 2] = 0.0f; - m[1*4 + 2] = 0.0f; - m[2*4 + 2] = -(nearPlane + farPlane) / clip; - m[3*4 + 2] = -(2.0f * nearPlane * farPlane) / clip; - m[0*4 + 3] = 0.0f; - m[1*4 + 3] = 0.0f; - m[2*4 + 3] = -1.0f; - m[3*4 + 3] = 0.0f; - } - ref mat4 lookAt(const vec3 eye, const vec3 center, const vec3 up) { vec3 forward = (center - eye).normalized(); vec3 side = vec3.crossProduct(forward, up).normalized(); @@ -1021,6 +995,56 @@ struct mat4 { return this; } + mat4 invert() 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. + float det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; + + mat4 inverse; + + // Close to zero, can't invert. + if (fabs(det) <= 0.00000001f) + return inverse; + + // Support the case where m == dst. + inverse.m[0] = m[5] * b5 - m[6] * b4 + m[7] * b3; + inverse.m[1] = -m[1] * b5 + m[2] * b4 - m[3] * b3; + inverse.m[2] = m[13] * a5 - m[14] * a4 + m[15] * a3; + inverse.m[3] = -m[9] * a5 + m[10] * a4 - m[11] * a3; + + inverse.m[4] = -m[4] * b5 + m[6] * b2 - m[7] * b1; + inverse.m[5] = m[0] * b5 - m[2] * b2 + m[3] * b1; + inverse.m[6] = -m[12] * a5 + m[14] * a2 - m[15] * a1; + inverse.m[7] = m[8] * a5 - m[10] * a2 + m[11] * a1; + + inverse.m[8] = m[4] * b4 - m[5] * b2 + m[7] * b0; + inverse.m[9] = -m[0] * b4 + m[1] * b2 - m[3] * b0; + inverse.m[10] = m[12] * a4 - m[13] * a2 + m[15] * a0; + inverse.m[11] = -m[8] * a4 + m[9] * a2 - m[11] * a0; + + inverse.m[12] = -m[4] * b3 + m[5] * b1 - m[6] * b0; + inverse.m[13] = m[0] * b3 - m[1] * b1 + m[2] * b0; + inverse.m[14] = -m[12] * a3 + m[13] * a1 - m[14] * a0; + inverse.m[15] = m[8] * a3 - m[9] * a1 + m[10] * a0; + + float mul = 1.0f / det; + inverse *= mul; + return inverse; + } + ref mat4 setLookAt(const vec3 eye, const vec3 center, const vec3 up) { setIdentity(); lookAt(eye, center, up); @@ -1073,9 +1097,8 @@ struct mat4 { } /// multiply this matrix by another matrix - mat4 opOpAssign(string op : "*")(const ref mat4 m2) { + void opOpAssign(string op : "*")(const ref mat4 m2) { this = mul(this, m2); - return this; } /// multiply two matrices @@ -1274,28 +1297,24 @@ struct mat4 { /// add value to all components of matrix - ref mat4 opOpAssign(string op : "+")(float v) { + void opOpAssign(string op : "+")(float v) { foreach(ref item; m) item += v; - return this; } /// multiply all components of matrix by value - ref mat4 opOpAssign(string op : "*")(float v) { + void opOpAssign(string op : "*")(float v) { foreach(ref item; m) item *= v; - return this; } /// subtract value from all components of matrix - ref mat4 opOpAssign(string op : "-")(float v) { + void opOpAssign(string op : "-")(float v) { foreach(ref item; m) item -= v; - return this; } /// divide all components of vector by matrix - ref mat4 opOpAssign(string op : "/")(float v) { + void opOpAssign(string op : "/")(float v) { foreach(ref item; m) item /= v; - return this; } /// inplace rotate around Z axis diff --git a/src/dlangui/graphics/scene/camera.d b/src/dlangui/graphics/scene/camera.d index 289876cd..5b5a10ca 100644 --- a/src/dlangui/graphics/scene/camera.d +++ b/src/dlangui/graphics/scene/camera.d @@ -8,8 +8,10 @@ import dlangui.core.math3d; class Camera : Node3d { protected mat4 _projectionMatrix; + protected mat4 _viewMatrix; protected mat4 _viewProjectionMatrix; - protected bool _dirtyViewProjection; + protected bool _dirtyViewProjection = true; + protected bool _dirtyView = true; protected bool _enabled; @@ -39,10 +41,24 @@ class Camera : Node3d { _dirtyViewProjection = true; } + override protected void invalidateTransform() { + _dirtyTransform = true; + _dirtyViewProjection = true; + _dirtyView = true; + } + + @property ref const(mat4) viewMatrix() { + if (_dirtyView) { + _viewMatrix = matrix.invert(); + _dirtyView = false; + } + return _viewMatrix; + } + /// get projection*view matrix @property ref const(mat4) projectionViewMatrix() { if (_dirtyTransform || _dirtyViewProjection) { - _viewProjectionMatrix = _projectionMatrix * matrix; + _viewProjectionMatrix = _projectionMatrix * viewMatrix; _dirtyViewProjection = false; } return _viewProjectionMatrix; diff --git a/src/dlangui/graphics/scene/transform.d b/src/dlangui/graphics/scene/transform.d index 8e37269a..16a02178 100644 --- a/src/dlangui/graphics/scene/transform.d +++ b/src/dlangui/graphics/scene/transform.d @@ -20,6 +20,10 @@ class Transform { setIdentity(); } + protected void invalidateTransform() { + _dirtyTransform = true; + } + /// get scale vector public @property ref const(vec3) scaling() const { return _scale; } /// get scale X @@ -30,15 +34,15 @@ class Transform { public @property float scalingZ() const { return _scale.z; } /// set scale vector - public @property void scaling(const ref vec3 value) { _scale = value; _hasScale = true; _dirtyTransform = true; } + public @property void scaling(const ref vec3 value) { _scale = value; _hasScale = true; invalidateTransform(); } /// set scale vector x, y, z to the same value - public @property void scaling(float value) { _scale.x = _scale.y = _scale.z = value; _hasScale = true; _dirtyTransform = true; } + public @property void scaling(float value) { _scale.x = _scale.y = _scale.z = value; _hasScale = true; invalidateTransform(); } /// set scale X - public @property void scalingX(float value) { _scale.x = value; _hasScale = true; _dirtyTransform = true; } + public @property void scalingX(float value) { _scale.x = value; _hasScale = true; invalidateTransform(); } /// set scale Y - public @property void scalingY(float value) { _scale.y = value; _hasScale = true; _dirtyTransform = true; } + public @property void scalingY(float value) { _scale.y = value; _hasScale = true; invalidateTransform(); } /// set scale Z - public @property void scalingZ(float value) { _scale.z = value; _hasScale = true; _dirtyTransform = true; } + public @property void scalingZ(float value) { _scale.z = value; _hasScale = true; invalidateTransform(); } /// get translation vector public @property ref const(vec3) translation() const { return _translation; } @@ -50,44 +54,44 @@ class Transform { public @property float translationZ() const { return _translation.z; } /// set translation vector - public @property void translation(inout vec3 value) { _translation = value; _hasTranslation = true; _dirtyTransform = true; } + public @property void translation(inout vec3 value) { _translation = value; _hasTranslation = true; invalidateTransform(); } /// set translation vector x, y, z to the same value - public @property void translation(float value) { _translation.x = _translation.y = _translation.z = value; _hasTranslation = true; _dirtyTransform = true; } + public @property void translation(float value) { _translation.x = _translation.y = _translation.z = value; _hasTranslation = true; invalidateTransform(); } /// set translation x - public @property void translationX(float value) { _translation.x = value; _hasTranslation = true; _dirtyTransform = true; } + public @property void translationX(float value) { _translation.x = value; _hasTranslation = true; invalidateTransform(); } /// set translation y - public @property void translationY(float value) { _translation.y = value; _hasTranslation = true; _dirtyTransform = true; } + public @property void translationY(float value) { _translation.y = value; _hasTranslation = true; invalidateTransform(); } /// set translation z - public @property void translationZ(float value) { _translation.z = value; _hasTranslation = true; _dirtyTransform = true; } + public @property void translationZ(float value) { _translation.z = value; _hasTranslation = true; invalidateTransform(); } /// translate by vector - public void translate(vec3 value) { _translation += value; _hasTranslation = true; _dirtyTransform = true; } + public void translate(vec3 value) { _translation += value; _hasTranslation = true; invalidateTransform(); } /// translate X - public void translateX(float value) { _translation.x += value; _hasTranslation = true; _dirtyTransform = true; } + public void translateX(float value) { _translation.x += value; _hasTranslation = true; invalidateTransform(); } /// translate Y - public void translateY(float value) { _translation.y += value; _hasTranslation = true; _dirtyTransform = true; } + public void translateY(float value) { _translation.y += value; _hasTranslation = true; invalidateTransform(); } /// translate Z - public void translateZ(float value) { _translation.z += value; _hasTranslation = true; _dirtyTransform = true; } + public void translateZ(float value) { _translation.z += value; _hasTranslation = true; invalidateTransform(); } /// scale by vector - public void scale(vec3 value) { _scale.x *= value.x; _scale.y *= value.y; _scale.z *= value.z; _hasScale = true; _dirtyTransform = true; } + public void scale(vec3 value) { _scale.x *= value.x; _scale.y *= value.y; _scale.z *= value.z; _hasScale = true; invalidateTransform(); } /// scale all axis by the same values - public void scale(float value) { _scale *= value; _hasScale = true; _dirtyTransform = true; } + public void scale(float value) { _scale *= value; _hasScale = true; invalidateTransform(); } /// scale X - public void scaleX(float value) { _scale.x *= value; _hasScale = true; _dirtyTransform = true; } + public void scaleX(float value) { _scale.x *= value; _hasScale = true; invalidateTransform(); } /// scale Y - public void scaleY(float value) { _scale.y *= value; _hasScale = true; _dirtyTransform = true; } + public void scaleY(float value) { _scale.y *= value; _hasScale = true; invalidateTransform(); } /// scale Z - public void scaleZ(float value) { _scale.z *= value; _hasScale = true; _dirtyTransform = true; } + public void scaleZ(float value) { _scale.z *= value; _hasScale = true; invalidateTransform(); } /// rotate around X axis - public void rotateX(float angle) { _rotation.rotateX(angle); _hasRotation = true; _dirtyTransform = true; } + public void rotateX(float angle) { _rotation.rotateX(angle); _hasRotation = true; invalidateTransform(); } /// rotate around Y axis - public void rotateY(float angle) { _rotation.rotateY(angle); _hasRotation = true; _dirtyTransform = true; } + public void rotateY(float angle) { _rotation.rotateY(angle); _hasRotation = true; invalidateTransform(); } /// rotate around Z axis - public void rotateZ(float angle) { _rotation.rotateZ(angle); _hasRotation = true; _dirtyTransform = true; } + public void rotateZ(float angle) { _rotation.rotateZ(angle); _hasRotation = true; invalidateTransform(); } /// rotate around custom axis - public void rotate(float angle, const ref vec3 axis) { _rotation.rotate(angle, axis); _hasRotation = true; _dirtyTransform = true; } + public void rotate(float angle, const ref vec3 axis) { _rotation.rotate(angle, axis); _hasRotation = true; invalidateTransform(); } /// set transform to identity transform public void setIdentity() {