-
-
Save Jellonator/0686c6e74d06745957de5a96fa00ec6c to your computer and use it in GitHub Desktop.
shader_type canvas_item; | |
uniform mat4 TRANSFORM; | |
uniform vec2 DEPTH; | |
uniform bool REPEAT_X; | |
uniform bool REPEAT_Y; | |
uniform bool FLIP; | |
void fragment() { | |
// Create the matrix. A workaround is used to modify the matrix's W column | |
// because Godot's transforms are 3x4, not 4x4. | |
mat4 mat = mat4(1.0); | |
mat[0].w = DEPTH.x; | |
mat[1].w = DEPTH.y; | |
// Transform UV into [-1, 1] range | |
vec2 uv = UV * 2.0 - vec2(1, 1); | |
// Turn position into 4d vector | |
vec4 pos = vec4(uv, 1.0, 1.0); | |
pos = mat * pos; | |
pos.xy = pos.xy / pos.w; | |
// Apply transformation to position | |
float w = pos.w; | |
pos.z = 0.0; | |
pos.w = 1.0; | |
// Apply depth to position | |
pos = TRANSFORM * pos; | |
// divide position by w coordinate; this applies perspective | |
// Set UV to position; transform its range to [0, 1] | |
uv = (pos.xy + vec2(1, 1)) * 0.5; | |
// Determine if uv is in range or repeating pattern | |
if (((uv.x > 0.0 && uv.x < 1.0) || REPEAT_X) && ((uv.y > 0.0 && uv.y < 1.0) || REPEAT_Y) && (w > 0.0 || FLIP)) { | |
// Apply texture | |
uv = mod(uv, 1.0); | |
COLOR = texture(TEXTURE, uv); | |
} else { | |
COLOR = vec4(0, 0, 0, 0); | |
} | |
} |
Disclaimer: I have not tested the above code yet. I'll test this once I get home, and I'll post any revisions.
I'm close to getting this to work, I think? I'm translating it over to C# though and might have fumbled a few things and I'm also doing some questionable things with Viewports where I create a copy of the objects I want to display with the mode 7 and leave the originals to keep game logic completely 2D. I'll put the project link below if you wanted to look, otherwise I'll report back as I attempt to figure out what I messed up.
Sharing here before I forgot. I was just able to get the above code to work in C# with some slight changes. Working on some other touches now but the only way I was able to wrap my head around the entire thing and understand it properly was to use the Systems.Numerics and convert it all to a Matrix4x4.
// good luck with the below
using Godot;
using System;
using System.Numerics;
public class object_test : Node2D
{
Godot.ShaderMaterial mode7;
Godot.Node2D parent;
Godot.Sprite spriteToMove;
private Matrix4x4 perspectiveMatrix = new Matrix4x4();
private Matrix4x4 viewMatrix = new Matrix4x4();
private Godot.Vector2 screenSize = new Godot.Vector2(1024,1024);
private float halfHeight = 512;
public override void _Ready()
{
parent = GetParent() as Node2D;
mode7 = parent.Material as ShaderMaterial;
spriteToMove = GetNode<Sprite>("Sprite");
Godot.Vector2 temp = new Godot.Vector2(0, 20);
Create2DPerspectiveMatrix(temp);
}
private void Create2DPerspectiveMatrix(Godot.Vector2 depth)
{
Vector4 _line1 = new Vector4(1f, 0f, 0f, depth.x);
Vector4 _line2 = new Vector4(0f, 1f, 0f, depth.y);
Vector4 _line3 = new Vector4(0f, 0f, 1f, 0f);
Vector4 _line4 = new Vector4(0f, 0f, 0f, 1f);
perspectiveMatrix.M11 = _line1.X;
perspectiveMatrix.M12 = _line1.Y;
perspectiveMatrix.M13 = _line1.Z;
perspectiveMatrix.M14 = _line1.W;
perspectiveMatrix.M21 = _line2.X;
perspectiveMatrix.M22 = _line2.Y;
perspectiveMatrix.M23 = _line2.Z;
perspectiveMatrix.M24 = _line2.W;
perspectiveMatrix.M31 = _line3.X;
perspectiveMatrix.M32 = _line3.Y;
perspectiveMatrix.M33 = _line3.Z;
perspectiveMatrix.M34 = _line3.W;
perspectiveMatrix.M41 = _line4.X;
perspectiveMatrix.M42 = _line4.Y;
perspectiveMatrix.M43 = _line4.Z;
perspectiveMatrix.M44 = _line4.W;
}
private void CreateViewMatrix(Godot.Transform _transform, Godot.Vector2 _depth)
{
Vector4 _line1 = new Vector4(_transform.basis.x.x, _transform.basis.x.y, _transform.basis.x.z, 0f);
Vector4 _line2 = new Vector4(_transform.basis.y.x, _transform.basis.y.y, _transform.basis.y.z, 0f);
Vector4 _line3 = new Vector4(_transform.basis.z.x, _transform.basis.z.y, _transform.basis.z.z, 0f);
Vector4 _line4 = new Vector4(_transform.origin.x, _transform.origin.y, 0f, 1f);
viewMatrix.M11 = _line1.X;
viewMatrix.M12 = _line1.Y;
viewMatrix.M13 = _line1.Z;
viewMatrix.M14 = _line1.W;
viewMatrix.M21 = _line2.X;
viewMatrix.M22 = _line2.Y;
viewMatrix.M23 = _line2.Z;
viewMatrix.M24 = _line2.W;
viewMatrix.M31 = _line3.X;
viewMatrix.M32 = _line3.Y;
viewMatrix.M33 = _line3.Z;
viewMatrix.M34 = _line3.W;
viewMatrix.M41 = _line4.X;
viewMatrix.M42 = _line4.Y;
viewMatrix.M43 = _line4.Z;
viewMatrix.M44 = _line4.W;
}
public Godot.Vector3 MultPositionByVect4(Godot.Vector2 worldPos, Matrix4x4 mat)
{
Vector4 temp = new Vector4(worldPos.x, worldPos.y, 0f, 1f);
Vector4 _transformed = Vector4.Transform(temp, mat);
Godot.Vector3 _newReturn = new Godot.Vector3(_transformed.X / _transformed.W, _transformed.Y / _transformed.W, _transformed.W);
return _newReturn;
}
public override void _Process(float delta)
{
Godot.Transform _transform = (Godot.Transform)mode7.GetShaderParam("TRANSFORM");
GD.Print(_transform);
Godot.Vector2 _depth = (Godot.Vector2)mode7.GetShaderParam("DEPTH");
Create2DPerspectiveMatrix(_depth);
CreateViewMatrix(_transform, _depth);
Matrix4x4 _mat = perspectiveMatrix * viewMatrix;
//Matrix4x4 _mat = viewMatrix * perspectiveMatrix;
Matrix4x4 _inverted = new Matrix4x4();
Matrix4x4.Invert(_mat, out _inverted);
//Matrix4x4 _mat = viewMatrix * perspectiveMatrix;
//Godot.Vector2 worldPos = (this.GlobalPosition / (screenSize / 2)) - Godot.Vector2.One;
float wX = this.GlobalPosition.x;
float xY = this.GlobalPosition.y;
Godot.Vector2 worldpos = (this.GlobalPosition / (screenSize / 2)) - Godot.Vector2.One;
Godot.Vector3 newPos = MultPositionByVect4(worldpos, _inverted);
Godot.Vector2 final = new Godot.Vector2(newPos.x, newPos.y);
//Godot.Vector2 finalPos = new Godot.Vector2(newPos.x, newPos.y);
//Godot.Vector2 finalPos1 = new Godot.Vector2(finalPos + Godot.Vector2.One) * (screenSize / 2);
spriteToMove.GlobalPosition = (final + Godot.Vector2.One) * (screenSize / 2);
}
}
Yeah I wrote this a while ago, and this gist definitely needs a bit of cleaning up. That being said, I'll try my best and come up with something.
One way I like to look at this is:
DEPTH
is used to generate a projection matrixTRANSFORM
is a view matrixIn the original shader, I use the W component of vec4 as the weight. However, we will instead need to use the Z component of a vec3 as a weight instead, as Godot has no Vector4 (although you could implement something like this yourself). This is fine, because you only need three components and a 3x3 matrix type for 2d transforms. I will also be hi-jacking the
Basis
type for the 3x3 matrix.Disclaimer: I have not tested the above code yet. I'll test this once I get home, and I'll post any revisions.