zoukankan      html  css  js  c++  java
  • 光线步进——RayMarching入门

    入门实现

    先用RayMarching描绘一个球体,最后在进行光照计算
    参考:https://www.shadertoy.com/view/llt3R4

    模拟摄像机射线
    float3 rayDirection(float filedOfView, float2 size, float2 fragCoord){
    float2 xy=fragCoord-size/2;
    float z=size.y/tan(radians(filedOfView)/2.0);
    return normalize(float3(xy,-z));
    }
    1
    2
    3
    4
    5
    首先,把屏幕中心设置为坐标原点(0.0,0.0),射线的z值都是固定的,其中filedOfView可以看成视椎体两条棱的夹角,返回归一化的射线向量。

    对射线进行碰撞检测
    float sphereSDF(float3 samplePoint){
    return length(samplePoint) - 1.0;
    }
    1
    2
    3
    float shortestDistanceToSurface(float3 eye,float3 marchingDirection,float start,float end){
    float depth = start;
    for(int i=0;i<maxMarchingSteps;i++){
    float dist=sphereSDF(eye+depth*marchingDirection);
    if(dist < epsilon){
    return depth;
    }

    depth+=dist;
    if(depth>=end){
    return end;
    }
    }
    return end;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    以eye坐标为起点,沿着模拟射线的方向进行碰撞检测,返回碰撞点的深度,如果到最大深度仍然没有碰撞,则发挥最大深度

    根据深度返回颜色
    float dist=shortestDistanceToSurface(eye,dir,minDist,maxDist);
    if(dist>=maxDist-epsilon){
    return float4(0.0,0.0,0.0,0.0);
    }
    float value=floor(dist*10.0)*_StepValue;
    return float4(1-value,sin(value*10.0),0.0,1.0);
    1
    2
    3
    4
    5
    6
    存在问题
    球体的碰撞检测是比较容易的,如果我们想放一个立方体到“场景”里,怎么搞?

    float cubeSDF(float3 samplePoint){
    float3 d=abs(samplePoint)-float3(0.5,0.5,0.5);
    return length(max(d,0.0));
    }
    1
    2
    3
    4

    感觉绘制什么样的物体并不是特别容易控制,需要使用一些数学手段,真佩服哪些用RayMarching画画的那些老哥。

    计算法线方向
    现在,我们知道顶点坐标,通过计算 xyz 三个方向的差值(梯度),归一化后得到一个近似的法线方向

    float3 normalCalculate(float3 p){
    return normalize(float3(
    sphereSDF(float3(p.x + epsilon, p.y, p.z)) - sphereSDF(float3(p.x - epsilon, p.y, p.z)),
    sphereSDF(float3(p.x, p.y + epsilon, p.z)) - sphereSDF(float3(p.x, p.y - epsilon, p.z)),
    sphereSDF(float3(p.x, p.y, p.z + epsilon)) - sphereSDF(float3(p.x, p.y, p.z - epsilon))
    ));
    }
    1
    2
    3
    4
    5
    6
    7
    可以利用matlab进行检验,绘制一个曲面,计算它的表面法线


    clear;
    [X Y]=meshgrid(-0.5:0.05:0.5, -0.5:0.05:0.5);
    Z=0.25-X.^2-Y.^2;
    vecX=sqrt(((X+0.0001).^2+Y.^2+Z))-sqrt(((X-0.0001).^2+Y.^2+Z));
    vecY=sqrt((X.^2+(Y+0.0001).^2+Z))-sqrt((X.^2+(Y-0.0001).^2+Z));
    %mesh(X,Y,Z);
    quiver(X,Y,vecX,vecY);
    1
    2
    3
    4
    5
    6
    7
    根据法线方向计算光照
    设定光源位置,环境光,漫反射颜色,高光颜色,高光系数等信息,计算光照即可

    代码部分
    Shader "Unlit/RayMarching_1"
    {
    Properties
    {
    _MainTex ("Texture", 2D) = "white" {}
    _StepValue("StepValue",Range(0.001,0.025))=0.001
    _LightPos("LightPos",vector)=(0,0,0,0)
    _AmbientCol("AmbientCol",Color)=(1,1,1,1)
    _DiffuseCol("DiffuseCol",Color)=(1,1,1,1)
    _SpecularCol("SpecularCol",Color)=(1,1,1,1)
    _Gloss("Gloss",Range(0.1,255))=10
    }
    SubShader
    {
    Pass
    {
    ZTest Always Cull Off ZWrite Off
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #include "UnityCG.cginc"

    #define maxMarchingSteps 255
    #define minDist 0.0
    #define maxDist 1000.0
    #define epsilon 0.00001
    #define sizeX (_ScreenParams.x/_ScreenParams.y)

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _StepValue;
    float4 _LightPos;
    float4 _AmbientCol;
    float4 _DiffuseCol;
    float4 _SpecularCol;
    float _Gloss;

    float cubeSDF(float3 samplePoint){
    float3 d=abs(samplePoint)-float3(0.5,0.5,0.5);
    return length(max(d,0.0));
    }

    float sphereSDF(float3 samplePoint){
    return length(samplePoint) - 0.7;
    }

    float sceneSDF(float3 samplePoint){
    return sphereSDF(samplePoint);
    }

    float3 rayDirection(float filedOfView, float2 size, float2 fragCoord){
    float2 xy=fragCoord-size/2;
    float z=size.y/tan(radians(filedOfView)/2.0);
    return normalize(float3(xy,-z));
    }

    float shortestDistanceToSurface(float3 eye,float3 marchingDirection,float start,float end){
    float depth = start;
    for(int i=0;i<maxMarchingSteps;i++){
    float dist=sceneSDF(eye+depth*marchingDirection);
    if(dist < epsilon){
    return depth;
    }

    depth+=dist;
    if(depth>=end){
    return end;
    }
    }
    return end;
    }

    float3 normalCalculate(float3 p){
    return normalize(float3(
    sceneSDF(float3(p.x + epsilon, p.y, p.z)) - sceneSDF(float3(p.x - epsilon, p.y, p.z)),
    sceneSDF(float3(p.x, p.y + epsilon, p.z)) - sceneSDF(float3(p.x, p.y - epsilon, p.z)),
    sceneSDF(float3(p.x, p.y, p.z + epsilon)) - sceneSDF(float3(p.x, p.y, p.z - epsilon))
    ));
    }

    float3 LightCalculate(float3 eyePos,float3 pos,float3 lightPos,float3 ambientCol,float3 diffuseColor){
    float3 normal = normalCalculate(pos);
    float3 col=diffuseColor*max(dot(normal,normalize(lightPos-pos)),0);
    col+=ambientCol;
    float3 halfDir = normalize(lightPos-pos + eyePos-pos);
    float3 specular = _SpecularCol.rgb * pow(max(0, dot(normal, halfDir)), _Gloss);
    col+=specular;
    return col;
    }

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    return o;
    }

    float4 frag (v2f i) : SV_Target
    {
    i.uv.x*=_ScreenParams.x/_ScreenParams.y;
    float3 dir=rayDirection(45.0,float2(sizeX,1.0),i.uv);
    float3 eye= float3(0.0,0.0,5.0);
    float dist=shortestDistanceToSurface(eye,dir,minDist,maxDist);
    if(dist>=maxDist-epsilon){
    return float4(0.0,0.0,0.0,1.0);
    }
    float3 pos=eye+dist*dir;

    float3 col=LightCalculate(eye,pos,_LightPos.xyz,_AmbientCol.xyz,_DiffuseCol.xyz);
    return float4(col,1);
    //return float4(0.5,0.5,0.5,1);
    //float value=floor(dist*10.0)*_StepValue;
    //return float4(sin(value*1000),1-value,0.0,1.0);
    }

    ENDCG
    }
    }
    }

    --------------------- 

  • 相关阅读:
    为图片指定区域添加链接
    数值取值范围问题
    【leetcode】柱状图中最大的矩形(第二遍)
    【leetcode 33】搜索旋转排序数组(第二遍)
    【Educational Codeforces Round 81 (Rated for Div. 2) C】Obtain The String
    【Educational Codeforces Round 81 (Rated for Div. 2) B】Infinite Prefixes
    【Educational Codeforces Round 81 (Rated for Div. 2) A】Display The Number
    【Codeforces 716B】Complete the Word
    一个简陋的留言板
    HTML,CSS,JavaScript,AJAX,JSP,Servlet,JDBC,Structs,Spring,Hibernate,Xml等概念
  • 原文地址:https://www.cnblogs.com/hyhy904/p/11026664.html
Copyright © 2011-2022 走看看