UnityComputeShader Challenge2
大部分内容与Challenge1中的一致,重复的地方不做说明
using UnityEngine;
using System.Collections;
public class Challenge2 : MonoBehaviour
{
public ComputeShader shader;
//纹理的分辨率,正方形
public int texResolution = 1024;
Renderer rend;
RenderTexture outputTexture;
int kernelHandle;
//多边形的边数
public int sides = 3;
public Color fillColor = new Color(1.0f, 1.0f, 0.0f, 1.0f);
public Color clearColor = new Color( 0, 0, 0.3f, 1.0f );
// Use this for initialization
void Start()
{
outputTexture = new RenderTexture(texResolution, texResolution, 0);
outputTexture.enableRandomWrite = true;
outputTexture.Create();
rend = GetComponent<Renderer>();
rend.enabled = true;
InitShader();
}
private void InitShader()
{
kernelHandle = shader.FindKernel("CSMain");
shader.SetVector("fillColor", fillColor);
shader.SetVector("clearColor", clearColor);
shader.SetInt("sides", sides);
shader.SetInt("texResolution", texResolution);
shader.SetTexture(kernelHandle, "Result", outputTexture);
rend.material.SetTexture("_MainTex", outputTexture);
}
private void DispatchShader(int x, int y)
{
shader.Dispatch(kernelHandle, x, y, 1);
}
void Update(){
//该数值可以影响shader内的rotate
shader.SetFloat( "time", Time.time );
DispatchShader(texResolution / 8, texResolution / 8);
}
}
#pragma kernel CSMain
//定义2Π常量
#define PI2 6.28318530718
RWTexture2D<float4> Result;
int texResolution;
float4 fillColor;
float4 clearColor;
int sides;
float time;
//引入噪点发生器
#include "noiseSimplex.cginc"
float polygon(float2 pt, float2 center, float radius, int sides, float rotate, float edge_thickness){
pt -= center;//这一步将原点归0,原本得原点位置是0.5,0.5 归零之后翻遍直角坐标系中,理解并计算三角函数
//Angle and radius from the current pixel /
//theta 返回得是弧度值即kΠ,rotate为流逝得时间,浮点数
float theta = atan2(pt.y, pt.x) + rotate;
//计算多边形 一瓣所占据得弧度值
float rad = PI2/float(sides);
// Shaping function that modulate the distance /
// 这里得目的是计算当前像素,余弦映射到最近的顶点与原点线段上的长度,不画图很容易思考,设想三角形有三个此时原点在O(0,0),a,b,c 三个点与原点会形成三个向量o->a,o->b,o->c,分别为oa,ob,oc。如何确定一个点是否在该三角形内呢?假定p点是目标点,形成的向量为op,首先找到距离这个最近的即oa,ob,oc中哪个与op夹角最小。假定现在 ∠oa,op最小,theta就是这个∠的弧度值,然后计算op在oa上的映射长度,方式是计算op在oa的反余弦,oa的长度实际上就是指定的半径radius超过的部分自然判定为不在多边形内部
float d = cos(floor(0.5 + theta/rad)*rad-theta)*length(pt);
//渐变过渡,类似于羽化能力,edge_thickness就是控制羽化边缘范围
return 1.0 - smoothstep(radius, radius + edge_thickness, d);
}
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{ //归一之后将屏幕的中点从0.5,0.5 挪动到0,0
float2 pos = float2( (((float2)id.xy)/(float)texResolution)-0.5 );
float2 center = 0;
float radius = 0.15;
float inPolygon = polygon( pos, center, radius, sides, time, 0.001 );
//snoise 生成噪点
float noise = snoise(pos * 100);
//线性插值,确定该像素颜色
float4 color = lerp(clearColor, fillColor * noise, inPolygon);
Result[id.xy] = color;
}
运行之后的效果如下