3

我正在开发一个 2d 自上而下的游戏。我有一个在单个大纹理上移动并在其上投射阴影的对象(只是一个模糊的深色精灵)。然而我发现,由于我的纹理有凹凸、岩石、折痕等,看起来影子精灵只是在地面上方盘旋。所以我想我可以使用我的纹理作为置换贴图来根据纹理的表面扭曲阴影精灵。我正在尝试在 Shader Graph 中实现它,但我无法获得底层纹理的正确位置和比例来投射阴影。
我试图实现一个简化版本的着色器,它精确地再现了Ground Texture它悬停在上面的部分。

在此处输入图像描述

在这种情况下,缩放似乎关闭了,生成的纹理比原始纹理小很多。我不确定这个位置,但它似乎也关闭了。我错过了什么吗?还是有更简单的方法来实现这一点?

提前致谢。

4

1 回答 1

2

我不确定这是否是最优雅的解决方案,但我找到了一个。

我应该使用Tiling and Offset节点来缩放和移动地面纹理的 UV。这是着色器图:

在此处输入图像描述

现在,此着色器使对象将其放置在其上的地面纹理部分投影到自身上。它似乎与纹理完美对齐。

地面位置在代码中计算:

[RequireComponent(typeof(SpriteRenderer))]
public class displaced_shadow : MonoBehaviour
{
    SpriteRenderer sr;
    Rect rect;
    MaterialPropertyBlock material_properties;
    float pixels_per_unit;

    public Vector2 Size //get size of the texture in Unity units
    {
        get { return new Vector2(rect.width * transform.localScale.x/ pixels_per_unit, rect.height * transform.localScale.y/ pixels_per_unit); } 
    }

    private void Awake()
    {
        sr = GetComponent<SpriteRenderer>();
        rect = sr.sprite.rect;
        pixels_per_unit = sr.sprite.pixelsPerUnit;
        material_properties = new MaterialPropertyBlock();
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 relative_position = CalculateRelativePostion();
        FeedMaterial(relative_position);
    }

    private Vector2 CalculateRelativePostion() //calculate the position relative to the background in [0,1] range
    {
        if (background_floor.This == null) return Vector3.zero;

        Vector2 bg_position = background_floor.This.Position; //get the size and position of the background texture
        Vector2 bg_size = background_floor.This.Size;

        float origin_x1 = transform.position.x - Size.x/2f; //calculate the top left corner positions in case textures have their origins in the center
        float origin_y1 = transform.position.y - Size.y / 2f;
        float origin_x2 = bg_position.x - bg_size.x / 2f;
        float origin_y2 = bg_position.y - bg_size.y / 2f;

        float x = (origin_x1 - origin_x2) / bg_size.x; //get the [0,1] position of the object relative to the ground texture
        float y = (origin_y1 - origin_y2) / bg_size.y;

        return new Vector2(x, y);
    }

    private void FeedMaterial(Vector2 relative_position)
    {
        sr.GetPropertyBlock(material_properties);
        material_properties.SetVector("_GroundPosition", relative_position);
        sr.SetPropertyBlock(material_properties);
    }
}
于 2020-06-30T13:06:35.510 回答