Light entry step --RayMarching

About ray stepper
RayMarching is a fast real-time rendering of a scene, I understand that the position of analog video camera, depending on the angle of expansion of the vertebral body according to the position of the camera as an origin, the progress of formula emitting radiation, radiation when an object collides Thereafter, it returns to its depth information, if not before returning to the maximum distance depends on the vertebral body, it can be judged that the pixel is not in this respect to the object, the final calculation of the light based on the information returned.
As can be seen, RayMarching there is an error, if improve accuracy, reduce the step size, and too many cycles, resulting in low efficiency.
Feeling RayMarching currently used to render clouds, fog these similar volume rendering more.

Getting achieve

First with RayMarching depicts a sphere, and finally performing lighting calculations
Reference: https: //www.shadertoy.com/view/llt3R4

Analog cameras ray
float3 rayDirection (filedOfView a float, float2 size, float2 fragCoord) {
float2 = fragCoord-size XY / 2;
a float Z = size.y / Tan (radians (filedOfView) /2.0);
return the normalize (float3 (XY, - z));
}
. 1
2
. 3
. 4
. 5
first, the center of the screen coordinate origin is set to (0.0,0.0), radiation z values are fixed, which can be regarded as the angle of view filedOfView two edges of the vertebral body, returns normalized ray vector.

对射线进行碰撞检测
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 is
13 is
14
15
to eye coordinate as a starting point, the collision direction simulated ray testing, return to the depth of the point of impact, if the maximum depth is still no collision, the maximum depth

The depth of color Returns
a float shortestDistanceToSurface dist = (Eye, the dir, minDist, maxDist);
IF (dist> = maxDist-Epsilon) {
return float4 (0.0,0.0,0.0,0.0);
}
a 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
problem
collision detection sphere is relatively easy, if we want to put a cube to "scene" in , how do?

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

What kind of feeling is not particularly easy to control drawing objects, we need to use some mathematical means, what those RayMarching painting with my brother really admire.

Normal direction
Now, we know that the vertex coordinates xyz three directions by calculating the difference (gradient), obtained after normalization, an approximate normal direction

float3 normalCalculate (float3 P) {
return the normalize (float3 (
sphereSDF (float3 (PX + Epsilon, Py, PZ)) - sphereSDF (float3 (PX - Epsilon, Py, PZ)),
sphereSDF (float3 (PX, Py + Epsilon, PZ)) - sphereSDF (float3 (PX, Py - Epsilon, PZ)),
sphereSDF (float3 (PX, Py, PZ + Epsilon)) - sphereSDF (float3 (PX, Py, PZ - Epsilon))
));
}
. 1
2
. 3
. 4
. 5
. 6
. 7
can be tested using the matlab draw a curved surface, which surface normal is calculated


Clear;
[the XY] = meshgrid now (-0.5: 0.05: 0.5, -0.5: 0.05: 0.5);
.. = 0.25 the Z-X-2-the Y ^ 2 ^;
. vecx = sqrt (((X-from 0.0001 +) ^ 2 the Z ^ 2 + Y. +)) - sqrt (((X--from 0.0001) ^ 2 + 2 ^ + the Z Y.));.
vecy = sqrt ((X. ^ 2 + (the Y from 0.0001 +) ^ 2+. . the Z)) - sqrt ((X. ^ 2 + (the Y-from 0.0001) the Z + ^ 2));
% Mesh (X-, the Y, the Z);
Quiver (X-, the Y, vecx, vecy);
. 1
2
. 3
. 4
. 5
. 6
. 7
is calculated in accordance with the normal direction of the light
setting position information of a light source, ambient light, diffuse color, specular color, high coefficient of light, the light can be calculated

代码部分
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
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

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

Guess you like

Origin www.cnblogs.com/ly570/p/10989731.html