Skip to content

Instantly share code, notes, and snippets.

@Jellonator
Created January 2, 2020 22:42
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Jellonator/0686c6e74d06745957de5a96fa00ec6c to your computer and use it in GitHub Desktop.
Save Jellonator/0686c6e74d06745957de5a96fa00ec6c to your computer and use it in GitHub Desktop.
Mode 7 shader for Godot
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);
}
}
@BThacker
Copy link

BThacker commented Jan 23, 2022

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);
    }    
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment