333 lines
10 KiB
C#
333 lines
10 KiB
C#
//-----------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------
|
|
// file="Camera"
|
|
// Project: StgSharp
|
|
// AuthorGroup: Nitload
|
|
// Copyright (c) Nitload. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
// copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
// -----------------------------------------------------------------------
|
|
// -----------------------------------------------------------------------
|
|
using StgSharp.Graphics.OpenGL;
|
|
using StgSharp.Graphics.ShaderEdit;
|
|
|
|
using System;
|
|
|
|
namespace StgSharp.Mathematics.Graphics
|
|
{
|
|
public sealed class Camera : IglConvertable
|
|
{
|
|
|
|
private bool _isLookAtAvailable;
|
|
internal Matrix44 _lookAt;
|
|
internal Matrix44 _projection;
|
|
internal Matrix44 cameraAtt;
|
|
internal Matrix44 rotation;
|
|
internal Matrix44 rotationAtt;
|
|
internal Radius _pitch;
|
|
internal Radius _row;
|
|
internal Radius _yaw;
|
|
internal Uniform<Matrix44> convertedUniform;
|
|
internal Vec3 _target, up;
|
|
|
|
public Camera()
|
|
{
|
|
cameraAtt = Matrix44.Unit;
|
|
_target = Vec3.Zero;
|
|
up = Vec3.Zero;
|
|
_isLookAtAvailable = false;
|
|
_lookAt = Matrix44.Unit;
|
|
rotationAtt = Matrix44.Unit;
|
|
_projection = new Matrix44();
|
|
}
|
|
|
|
public Camera(
|
|
Vec3 position,
|
|
Vec3 target,
|
|
Vec3 up
|
|
)
|
|
: this()
|
|
{
|
|
rotationAtt = Matrix44.Unit;
|
|
cameraAtt = new Matrix44();
|
|
SetViewDirection(position, target, up);
|
|
_pitch = Radius.Zero;
|
|
_row = Radius.Zero;
|
|
_yaw = Radius.Zero;
|
|
}
|
|
|
|
public Matrix44 Projection => _projection;
|
|
|
|
public Matrix44 View
|
|
{
|
|
get
|
|
{
|
|
if (_isLookAtAvailable) {
|
|
return _lookAt;
|
|
}
|
|
Matrix44 move = Matrix44.Unit;
|
|
move.column[3].vec -= cameraAtt.column[3].vec;
|
|
_lookAt = rotationAtt.Transpose * move;
|
|
_isLookAtAvailable = true;
|
|
return _lookAt;
|
|
}
|
|
}
|
|
|
|
public Matrix44 CameraMatrix()
|
|
{
|
|
return Projection * View;
|
|
}
|
|
|
|
public void DisplayGLtypeDefinition()
|
|
{
|
|
Console.WriteLine("uniform matrix4x4 cameraName;");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get all uniform related to this <see cref="Camera" />.
|
|
/// </summary>
|
|
/// <param _label="source">
|
|
/// Shader program requires this camera.
|
|
/// </param>
|
|
/// <param _label="uniformName">
|
|
/// ContextName of all related uniforms. If you fallow form from <see ///
|
|
/// cref="IglConvertable.DisplayGLtypeDefinition" />
|
|
/// </param>
|
|
/// <exception cref="ArgumentException">
|
|
///
|
|
/// </exception>
|
|
public unsafe void GainAllUniforms(
|
|
ShaderProgram source,
|
|
params string[] uniformName
|
|
)
|
|
{
|
|
if (uniformName is null || uniformName.Length != 1) {
|
|
throw new ArgumentException(
|
|
"Camera needs exactly one uniform.", nameof(uniformName));
|
|
}
|
|
convertedUniform = source.GetUniform<Matrix44>(uniformName[0]);
|
|
}
|
|
|
|
public void MoveNear(
|
|
float distance
|
|
)
|
|
{
|
|
cameraAtt.column[3].Z -= distance;
|
|
_isLookAtAvailable = false;
|
|
}
|
|
|
|
public void MoveRight(
|
|
float distance
|
|
)
|
|
{
|
|
cameraAtt.column[3].X -= distance;
|
|
_isLookAtAvailable = false;
|
|
}
|
|
|
|
public void MoveUp(
|
|
float distance
|
|
)
|
|
{
|
|
cameraAtt.column[3].Y -= distance;
|
|
_isLookAtAvailable = false;
|
|
}
|
|
|
|
public unsafe void SetAllUniforms()
|
|
{
|
|
// Console.WriteLine(Projection * ViewBase);
|
|
OpenGLFunction.CurrentGL.SetUniformValue(convertedUniform, Projection * View);
|
|
}
|
|
|
|
public void SetViewDirection(
|
|
Vec3 position,
|
|
Vec3 target,
|
|
Vec3 up
|
|
)
|
|
{
|
|
Vec3 direction = position - target;
|
|
if ((position.reg == cameraAtt.column[3].reg) &&
|
|
(this.up == up) &&
|
|
(cameraAtt.column[3].reg == direction.reg)) {
|
|
return;
|
|
}
|
|
if (direction.GetLength() == 0)
|
|
{
|
|
// deadlock
|
|
throw new ArgumentException("Direction bust is not zero.");
|
|
}
|
|
if (Vec3.IsParallel(direction, up)) {
|
|
throw new ArgumentException("Direction and UP is on on same way");
|
|
}
|
|
_target = direction;
|
|
this.up = up;
|
|
|
|
_isLookAtAvailable = false;
|
|
|
|
direction.Orthogonalize(ref up);
|
|
|
|
Vec3 right = Linear.Orthogonalize(Linear.Cross(up, direction));
|
|
|
|
cameraAtt.column[0].reg = right.reg;
|
|
cameraAtt.column[1].reg = up.reg;
|
|
cameraAtt.column[2].reg = direction.reg;
|
|
cameraAtt.column[3].reg = position.reg;
|
|
|
|
InternalPitch();
|
|
InternalRow();
|
|
InternalYaw();
|
|
}
|
|
|
|
public void SetViewRange(
|
|
Radius fovRadius,
|
|
Vec2 size,
|
|
Vec2 offset,
|
|
(float front, float back) depthRange
|
|
)
|
|
{
|
|
float
|
|
distance = _target.GetLength(),
|
|
near = distance - depthRange.front,
|
|
far = distance + depthRange.back,
|
|
offsetX = offset.X,
|
|
offsetY = offset.Y,
|
|
width = MathF.Abs(GeometryScaler.Tan(fovRadius / 2) * near * 2),
|
|
height = width * size.Y / size.X;
|
|
|
|
_projection.column[0].X = 2 * near / width;
|
|
_projection.column[1].Y = 2 * near / height;
|
|
_projection.column[2].X = 2 * offsetX / width;
|
|
_projection.column[2].Y = 2 * offsetY / height;
|
|
_projection.column[2].Z = (far + near) / (near - far);
|
|
_projection.column[2].W = -1;
|
|
_projection.column[3].Z = 2 * near * far / (near - far);
|
|
}
|
|
|
|
public void Test(
|
|
params Vec4[] vec
|
|
)
|
|
{
|
|
Console.WriteLine(View);
|
|
Console.WriteLine(Projection);
|
|
Console.WriteLine(Projection * View);
|
|
Console.WriteLine(View);
|
|
foreach (Vec4 item in vec) {
|
|
Console.Write($"{Projection * View * item};");
|
|
}
|
|
}
|
|
|
|
ShaderStruct IglConvertable.GetConvertedGLtype()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
~Camera() { }
|
|
|
|
#region rotation
|
|
|
|
public void Yaw(
|
|
Radius r
|
|
)
|
|
{
|
|
_yaw -= r;
|
|
|
|
// Console.WriteLine(_yaw._radius);
|
|
// Console.WriteLine(rotationAtt);
|
|
InternalYaw();
|
|
}
|
|
|
|
public void Pitch(
|
|
Radius r
|
|
)
|
|
{
|
|
_pitch -= r;
|
|
|
|
// Console.WriteLine(_pitch._radius);
|
|
// Console.WriteLine(rotationAtt);
|
|
InternalPitch();
|
|
}
|
|
|
|
public void Row(
|
|
Radius r
|
|
)
|
|
{
|
|
_row -= r;
|
|
|
|
// Console.WriteLine(_row._radius);
|
|
// Console.WriteLine(rotationAtt);
|
|
InternalRow();
|
|
}
|
|
|
|
internal void InternalPitch()
|
|
{
|
|
/*
|
|
_isLookAtAvailable = false;
|
|
|
|
Matrix32 partialCoord = new Matrix32(cameraAtt.colum1.vec, cameraAtt.colum2.vec);
|
|
float angle = _pitch._radius;
|
|
|
|
Matrix22 rotation = new Matrix22(
|
|
Scaler.Cos(angle), -Scaler.Sin(angle), Scaler.Sin(angle), Scaler.Cos(angle));
|
|
|
|
partialCoord *= rotation;
|
|
rotationAtt.colum1.reg = partialCoord.colum0.reg;
|
|
rotationAtt.colum2.reg = partialCoord.colum1.reg;
|
|
rotationAtt.isTransposed = false;
|
|
/**/
|
|
}
|
|
|
|
internal void InternalRow()
|
|
{
|
|
/*
|
|
_isLookAtAvailable = false;
|
|
|
|
Matrix32 partialCoord = new Matrix32(cameraAtt.colum0.vec, cameraAtt.colum1.vec);
|
|
float angle = _row._radius;
|
|
|
|
Matrix22 rotation = new Matrix22(
|
|
Scaler.Cos(angle), -Scaler.Sin(angle), Scaler.Sin(angle), Scaler.Cos(angle));
|
|
|
|
partialCoord *= rotation;
|
|
rotationAtt.colum0.reg = partialCoord.colum0.reg;
|
|
rotationAtt.colum1.reg = partialCoord.colum1.reg;
|
|
rotationAtt.isTransposed = false;
|
|
*/
|
|
}
|
|
|
|
internal void InternalYaw()
|
|
{
|
|
/*
|
|
_isLookAtAvailable = false;
|
|
|
|
Matrix32 partialCoord = new Matrix32(cameraAtt.colum0.vec, cameraAtt.colum2.vec);
|
|
float angle = _yaw._radius;
|
|
Matrix22 rotation = new Matrix22(
|
|
Scaler.Cos(angle), -Scaler.Sin(angle), Scaler.Sin(angle), Scaler.Cos(angle));
|
|
|
|
partialCoord *= rotation;
|
|
rotationAtt.colum0.reg = partialCoord.colum0.reg;
|
|
rotationAtt.colum2.reg = partialCoord.colum1.reg;
|
|
rotationAtt.isTransposed = false;
|
|
*/
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|