haha, that was on purpose!
Three positive feedback! Waitin for more.
haha, that was on purpose!
Three positive feedback! Waitin for more.
Hello again!
This time there seems to be a problem with scaling. I created a 3D cube and when the model matrix is scaled, it shrinks and grows back to its original dimensions! Here's how the model matrix is calculated:
[code=delphi]
if UpdateNeeded then
begin
CachedMatrix := Mat4Scale(Mat4Translate(Mat4CreateRotationEuler(FR otation),
Vec3Negate(FPosition)), FScale);
UpdateNeeded := False;
end;
Result := CachedMatrix;
[/code]
I suppose the scaling should be placed somewhere else, but where?
Oh, and here's Mat4Scale's code:
[code=delphi]
function Mat4Scale(const M: TBrainMatrix; const V: TBrainVector): TBrainMatrix; inline;
begin
Result := M;
Result.M[0, 0] := Result.M[0, 0] + V.X;
Result.M[1, 1] := Result.M[1, 1] + V.Y;
Result.M[2, 2] := Result.M[2, 2] + V.Z;
end;
[/code]
Any ideas, guys?
If you scale matrix by constant it goes like:
[pascal]procedure Scale(var M: TMatrix; const s: Single);
var i: Integer;
begin
for i:=0 to 2 do begin
M[i, 0]:=M[i, 0] * s;
M[i, 1]:=M[i, 1] * s;
M[i, 2]:=M[i, 2] * s;
end;
end;[/pascal]
Extending that function to work with vector might be something like: (i'm just guessing here...)
[pascal]procedure Scale(var M: TMatrix; const v: TVector);
var i: Integer;
begin
for i:=0 to 2 do begin
M[i, 0]:=M[i, 0] * v.x;
M[i, 1]:=M[i, 1] * v.y;
M[i, 2]:=M[i, 2] * v.z;
end;
end;[/pascal]
I tried it, but if the scale vector is (1,1,1), multiplication won't change the matrix.
Exactly! Because the vector contains scaling "factors", a factor of one means "keep this the same" (a * 1 = a).
Because the scaling vector contains factors, your code will not work:
[pascal]
function Mat4Scale(const M: TBrainMatrix; const V: TBrainVector): TBrainMatrix; inline;
begin
Result := M;
Result.M[0, 0] := Result.M[0, 0] + V.X;
Result.M[1, 1] := Result.M[1, 1] + V.Y;
Result.M[2, 2] := Result.M[2, 2] + V.Z;
end;
[/pascal]
Let's say you have an identity matrix:
And you want to make it twice as big (factor 2). Acoording to your code, this would result in:1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
0, 0, 0, 1
The numbers in the diagonal part of the matrix are also used as scaling factors. As you see, it will result in 3x scaling instead of 2x.3, 0, 0, 0
0, 3, 0, 0
0, 0, 3, 0
0, 0, 0, 1
So, first of all, treat the numbers as factors!
Secondly, concatenating two transforms is ALWAYS done by matrix multiplication. In this case we would have a scaling matrix, constructed by vector V. It would look like this:
Secondly, we have our original matrix M.V.x, 0, 0, 0
0, V.y, 0, 0
0, 0, V.z, 0
0, 0, 0, 1
We need to multiply these to get the matrix M with the scaling applied on it.
This brings me to a more difficult issue:
Matrix multiplication is not commutative, which means that A x B will not yield the same result as B x A. We should be aware of the order in which we multiply matrices.
I still haven't figured this part out, so I better don't give any advice, other than that you have to be carefull.
This is what I'd do:
[pascal]
function Mat4Scale(const M: TBrainMatrix; const V: TBrainVector): TBrainMatrix; inline;
begin
Result := MatIdentity();
Result.M[0, 0] := V.X; //The identity matrix has only 1's diagonally, so multiplying
Result.M[1, 1] := V.Y; //V with 1 makes no sense.. we can assign it directly
Result.M[2, 2] := V.Z;
//multiply with M here, this could be
Result = MatMultiply( Result, M)
// OR !!
Result = MatMultiply( M, Result )
end;
[/pascal]
Also, I suggest you study a few examples of matrices and see how they affect geometry:
http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx
(I know it's direct3D, but you can still use this knowledge).
Also, take a very close look at existing matrix code, instead of writing your own (I use math code written by others. )
Hope this helps
Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.
Thanks for this, chronozphere, but I've already tried this approach and it didn't work either.
Maybe I should scale the vertices when creating an object, let's say a triangle?
[code=delphi]
// No scaling
Vertices.Add(Vec3(0.0, 1.0, 0.0));
Vertices.Add(Vec3(-1.0, -1.0, 0.0));
Vertices.Add(Vec3(1.0, -1.0, 0.0));
// Scaling on
Vertices.Add(Vec3(0.0 * FScale.X, 1.0 * FScale.Y, 0.0 * FScale.Z));
Vertices.Add(Vec3(-1.0 * FScale.X, -1.0 * FScale.Y, 0.0 * FScale.Z));
Vertices.Add(Vec3(1.0 * FScale.X, -1.0 * FScale.Y, 0.0 * FScale.Z));
[/code]
But then everytime I change scaling, I'd have to re-build the object's VAO and VBOs... That is certainly not what I want.
It does work for me. (Oh, note that if your matrix has translation included in it, it will be used in scaling aswell. You need to multiply rotation matrix in different function without translation part)
[pascal]procedure Scale(var M: TMatrix; const v: TVector); overload;
var M2: TMatrix;
begin
M2:=NewMatrix;
M2[0,0]:=v.x; M2[1,1]:=v.y; M2[2,2]:=v.z;
M:=Multiply(M,M2);
end;
// call it like this to triple size in Y direction:
Scale(m2,vector(1,3,1));
// if you use this kind of vector nothing will happen as intended
Scale(m2,vector(1,1,1));[/pascal]
yeah.. That's why matrices are THE way to do transformations.But then everytime I change scaling, I'd have to re-build the object's VAO and VBOs... That is certainly not what I want.
Can you tell me what doesn't work?
Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.
I tried these both (not at the same time, of course):
[code=delphi]
FScale := Vec3(2.0, 2.0, 2.0);
// #1
CachedMatrix := Mat4Multiply(Mat4Multiply(Mat4CreateRotationEuler( FRotation),
Mat4CreateTranslation(Vec3Negate(FPosition))), Mat4CreateScale(FScale));
// #2
CachedMatrix := Mat4Multiply(Mat4Multiply(Mat4CreateRotationEuler( FRotation),
Mat4CreateScale(FScale)), Mat4CreateTranslation(Vec3Negate(FPosition)));
[/code]
EDIT
I got it working. It's still in tests, though. Here's the code anyway:
[code=delphi]
CachedMatrix := Mat4Translate(Mat4Multiply(Mat4CreateRotationEuler (FRotation),
Mat4CreateScale(FScale)), Vec3Negate(FPosition));
[/code]
It's me again.
The problem with scalling has been solved once and for all. Everything works like a charm.
Now, I want to expand the possibilities of my camera class by adding a third-person mode. The idea to create the camera matrix is simple:
[code=delphi]
CachedMatrix := LookAt(Position, Target.Position, Vec3(0.0, 1.0, 0.0));
[/code]
This works great, but now, how do I implement moving and strafing? In a first-person mode, I used these:
[code=delphi]
procedure TBrainCamera.Move(const AFactor: Single);
begin
if (AFactor <> 0.0) then
begin
FDirection := Mat4GetDirectionVector(Mat4CreateRotationEuler(Rot ation));
case FCamType of
ctFree:
Position := Vec3(Position.X + (FDirection.X * -AFactor),
Position.Y + (FDirection.Y * -AFactor),
Position.Z + (FDirection.Z * -AFactor));
ctFirstPerson:
Position := Vec3(Position.X + (FDirection.X * -AFactor),
Position.Y, Position.Z + (FDirection.Z * -AFactor));
end;
UpdateNeeded := True;
UpdateInvNeeded := True;
end;
end;
procedure TBrainCamera.Strafe(const AFactor: Single);
begin
if (AFactor <> 0.0) then
begin
FDirection := Mat4GetDirectionVector(Mat4CreateRotationEuler(Rot ation));
Position := Vec3(Position.X + (FDirection.Z * -AFactor),
Position.Y, Position.Z + (-FDirection.X * -AFactor));
UpdateNeeded := True;
UpdateInvNeeded := True;
end;
end;
[/code]
My first idea was to translate the target object and change the camera position accordingly to a new target's position. So the code for a third-person camera would be here:
[code=delphi]
procedure TBrainCamera.Move(const AFactor: Single);
begin
{...}
ctThirdPerson:
begin
Target.Move(AFactor);
Position := Vec3Subtract(Target.Position, Position);
end;
[/code]
But this approach doesn't seem to work.
EDIT
I followed the instructions given here, but it didn't help either.
From all I know, the best thing would be to base the camera on quaternions, but that would mean re-inventing the whole design from the ground up. I don't want them and I believe it can be done on Euler angles.
Do you have any suggestions?
Bookmarks