UnityComputeShader Challenge1

UnityComputeShader Challenge1

using UnityEngine;
using System.Collections;

public class Challenge1 : MonoBehaviour
{
	//editor拖拽对应的 compute文件
    public ComputeShader shader;
    //纹理的大小
    public int texResolution = 1024;
	//着色器
    Renderer rend;
    //用于存储计算输出
    RenderTexture outputTexture;

    int kernelHandle;

    // Use this for initialization
    void Start()
    {
        //创建纹理,width,height,depth
        outputTexture = new RenderTexture(texResolution, texResolution, 0);
        //是否允许随机读写
        outputTexture.enableRandomWrite = true;
        outputTexture.Create();

        rend = GetComponent<Renderer>();
        rend.enabled = true;

        InitShader();
    }

    private void InitShader()
    {	//获得compute 中的kernel 函数
        kernelHandle = shader.FindKernel("Square");

        int halfRes = texResolution >> 1;
        int quarterRes = texResolution >> 2;
		//矩形盒的两个点
        Vector4 rect = new Vector4( quarterRes, quarterRes, halfRes, halfRes );
		//设置参数
        shader.SetVector( "rect", rect );
        shader.SetTexture(kernelHandle, "Result", outputTexture);
       	//将输出的材质应用到当前组件上,editor中设置对应mesh
        rend.material.SetTexture("_MainTex", outputTexture);
		//分发任务,启动对象的线程组数量,这里为什么是8 在compute文件中通过[numthreads(8, 8, 1)]  设置了一组线程组的大小,8 8 1分别表示x方向上8个线程,y方向上8个z方向上1,总计64个线程。因为对应的texture x,y,z 分别是 1024,1024,1 为了覆盖所有的像素,就需要 1024/64=8,这就是为什么这里是8的原因
        DispatchShader(texResolution / 8, texResolution / 8);
    }

    private void DispatchShader(int x, int y)
    {
        shader.Dispatch(kernelHandle, x, y, 1);
    }

    void Update()
    {	//这里没看懂干嘛的
        if (Input.GetKeyUp(KeyCode.U))
        {
            DispatchShader(texResolution / 8, texResolution / 8);
        }
    }
}


// Each #kernel tells which function to compile; you can have many kernels
// 告诉编译器,那些函数是内核函数
#pragma kernel Square

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
// 声明可读可写的属性,
RWTexture2D<float4> Result;
//float4 32bit*4 我的理解方式是float 四元组
float4 rect;
//判定是否在矩形内,这里判定还是蛮有意思的,可以使用非if else的形式确定,点是否在矩形内,由于线程组内使用的程序计数器是统一的,所以if else会导致,不符合的线程等待符合的线程,从而大幅降低线程性能,而这种方式可以确保所有线程并行效率,比如点a,点b a属于矩形内,b不属于矩形内。当进行判定的时候如果使用if else,则线程组内需要执行两次调度,但是下面的方式可以并行执行,只需要一次
float inSquare( float2 pt, float4 rect ){
    //补充说明step函数,很好理解,第一个参数是一个阶梯,第二个参数如果在阶梯的上面则返回1,否则返回0。上面的意思是数值更大,通常用于去除if else 
    float horz = step( rect.x, pt.x ) - step( rect.x + rect.z, pt.x );//一个点是否在一个线段上(a,b),先判断x是否大于a,再排除掉x>b的情况
    float vert = step( rect.y, pt.y ) - step( rect.y + rect.w, pt.y );
    return horz * vert;//仅当x轴和y轴满足条件 即 1*1=1 || -1*-1 才会返回 1,其余条件都是0
}
//生命线程组大小, id 为 unit3元组,分辨表示,当前线程的位置,一个不恰当的理解方式就是该像素,处于纹理的坐标假设像素是一个个的小颗粒,小颗粒的长宽高分别都是1
[numthreads(8,8,1)]
void Square (uint3 id : SV_DispatchThreadID)
{
	//这里参数是否意味着,inSquare内上下文是拿不到 rect的
    //验证后发现 及时不传递rect,还是可以有正确的表现
    float res = inSquare( (float2)id.xy, rect );

    Result[id.xy] = float4(0.0, 0.0, res, 1.0);
}

运行效果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值