您当前的位置: 首页 >  Jave.Lin ar

Unity Shader - Ray Marching - T1 - SimpleSphere

Jave.Lin 发布时间:2020-04-24 16:37:17 ,浏览量:4

文章目录
  • CSharp
  • Shader
  • 运行效果
  • 总结
  • Project

自学Raymarching汇总:Unity Shader - Ray Marching Study Summary - 学习汇总

今天开始Raymarching第一任务:简单的球体

CSharp
using System.Collections;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
// jave.lin 2020.04.24 - 球体挂载器
public class SphereHolder : MonoBehaviour
{
    [Range(0.0f, 10.0f)]
    public float radius = 1;
    public Vector4 spInfo
    {
        get
        {
            Vector4 result = transform.position;
            result.w = radius;
            return result;
        }
    }
#if UNITY_EDITOR
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.cyan;
        Gizmos.DrawWireSphere(transform.position, radius);
    }
#endif
}

using UnityEngine;
// jave.lin 2020.04.24 - 球体
public class T1_SimpleSphere : MonoBehaviour
{
    private int _Ray_hash = Shader.PropertyToID("_Ray"); 
    private int _Sphere_hash = Shader.PropertyToID("_Sphere"); 

    public bool raymarching = true; 
    public Camera cam;
    public Material mat;

    public SphereHolder sh;
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        var aspect = cam.aspect;                // 宽高比
        var near = cam.nearClipPlane;           // 近截面距离长度
        var rightDir = transform.right;         // 相机的右边方向(单位向量)
        var upDir = transform.up;               // 相机的顶部方向(单位向量)
        var forwardDir = transform.forward;     // 相机的正前方(单位向量)
        // fov = field of view,就是相机的顶面与底面的连接相机作为点的夹角,
        // 我们取一半就好,与相机正前方方向的线段 * far就是到达远截面的位置(这条边当做下面的tan公式的邻边使用)
        // tan(a) = 对 比 邻 = 对/邻
        // 邻边的长度是知道的,就是far值,加上fov * 0.5的角度,就可以求出高度(对边)
        // tan(a)=对/邻
        // 对=tan(a)*邻
        var halfOfHeight = Mathf.Tan(cam.fieldOfView * 0.5f * Mathf.Deg2Rad) * near;
        // 剩下要求宽度
        // aspect = 宽高比 = 宽/高
        // 宽 = aspect * 高
        var halfOfWidth = aspect * halfOfHeight;
        // 前,上,右的角落偏移向量
        var forwardVec = forwardDir * near;
        var upVec = upDir * halfOfHeight;
        var rightVec = rightDir * halfOfWidth;
        // 左下角 bottom left
        var bl = forwardVec - upVec - rightVec;
        // 左上角 top left
        var tl = forwardVec + upVec - rightVec;
        // 右上角 top right
        var tr = forwardVec + upVec + rightVec;
        // 右下角 bottom right
        var br = forwardVec - upVec + rightVec;

        // 视锥体近截面角落点的射线
        var frustumFarCornersRay = Matrix4x4.identity;
        // 经shader中顶点颜色赋值后出入到屏幕,可以确定,第0是:左下角,1:左上角,2:右上角,3:右下角
        frustumFarCornersRay.SetRow(0, bl);
        frustumFarCornersRay.SetRow(1, tl);
        frustumFarCornersRay.SetRow(2, tr);
        frustumFarCornersRay.SetRow(3, br);
        mat.SetMatrix(_Ray_hash, frustumFarCornersRay);
        // sphere informations
        mat.SetVector(_Sphere_hash, sh.spInfo);
        // blit
        if (raymarching) Graphics.Blit(source, destination, mat);
        else Graphics.Blit(source, destination);
    }
}

Shader
/* T2_SimpleSphere.cginc
  jave.lin 2020.04.24
 */

#include "UnityCG.cginc"
#include "../SDFs.cginc"
struct appdata {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    uint vid : SV_VertexID;
};
struct v2f {
    float4 vertex : SV_POSITION;
    float2 uv : TEXCOORD0;
    float3 ray : TEXCOORD1;
};

sampler2D _MainTex;
float4x4 _Ray;                  // 视锥体角落射线
float4 _Sphere;                 // 球体信息:.xyz = pos, .w = radius

#define EPSILON 0.01            // 最小接触距离
#define MAX_STEP_TIMES 100      // 最大步进次数

float sceneDF(float3 pos) {  	// 获取场景中所有几何体当中最近距离的
    // 使用自己的 DIY 版
    // sphere d
    // float sphereDist = length(pos - _Sphere.xyz) - _Sphere.w;

    // 使用 IQ 大神SDFs版
    float sphereDist = sdSphere(pos - _Sphere.xyz, _Sphere.w);
    return sphereDist;
}

fixed4 getColor(v2f i) {
    float3 ori = i.ray;                 // 射线起点
    float3 dir = normalize(i.ray);      // 射线方向
    float3 pos;                         // 当前步进到的位置
    float dist;                         // 当前步进到的最近距离
    float d;                            // 当前最近距离
    float far = _ProjectionParams.z;    // far

    ori += _WorldSpaceCameraPos.xyz;    // 偏移,加上相机位置
    pos = ori;                          // 从起点出发
    UNITY_LOOP
    for (int it = 0; it             
关注
打赏
1688896170
查看更多评论
0.0519s