光线步进——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
}
}
}
---------------------
光线步进——RayMarching入门的更多相关文章
- 在Unity中实现屏幕空间反射Screen Space Reflection(4)
第四部分讲一下如何在2D屏幕空间步进光线. http://casual-effects.blogspot.com/2014/08/screen-space-ray-tracing.html 中的代码感 ...
- 在Unity中实现屏幕空间反射Screen Space Reflection(1)
本篇文章我会介绍一下我自己在Unity中实现的SSR效果 出发点是理解SSR效果的原理,因此最终效果不是非常完美的(代码都是够用就行),但是从学习的角度来说足以学习到SSR中的核心算法. 如果对核心算 ...
- 深入Guerrilla Games解密次世代开山大作《杀戮地带暗影坠落》(The technology of Killzone Shadow Fall)
文章摘要:这几天终于有时间,把全文翻译完了,自己感觉不是太满意,不过大家能看懂就好,就当一个学习的机会.整篇文章通过SONY第一方游戏工作室Guerrilla Games主创的语录,为我们展现了次世代 ...
- 在Unity中渲染一个黑洞
在Unity中渲染一个黑洞 前言 N年前观看<星际穿越>时,被其中的"卡冈图雅"黑洞所震撼.制作团队表示这是一个最贴近实际的黑洞效果,因为它是通过各种科学理论实现的.当 ...
- Shadertoy 教程 Part 1 - 介绍
Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...
- 从零3D基础入门XNA 4.0(2)——模型和BasicEffect
[题外话] 上一篇文章介绍了3D开发基础与XNA开发程序的整体结构,以及使用Model类的Draw方法将模型绘制到屏幕上.本文接着上一篇文章继续,介绍XNA中模型的结构.BasicEffect的使用以 ...
- opengl入门学习
OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...
- Lua简易入门教程
环境:lua for windows (lfW)主页:http://luaforwindows.luaforge.net/https://code.google.com/p/luaforwindows ...
- 转 猫都能学会的Unity3D Shader入门指南(二)
猫都能学会的Unity3D Shader入门指南(二) 关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己 ...
随机推荐
- http基础知识摘录
HTTP是一个基于请求/响应模式的,无状态的协议 (只有客户端发送请求服务器才会响应,否则服务器不会主动发送信息的,无状态指客户端发过来一个请求服务端给你发回一个响应,接着你再去发送一个请求,服务器根 ...
- vue项目中的路径别名
每次写引入组件的路径,如果路径嵌套比较深,那么会比较麻烦,我们可以在webpack.base.conf.js,中设置路径的别名,默认webpack设置src的别名为@ 建议配置src下一级目录的别名, ...
- 011--python基础知识
一.python类型 编译型和解释型 编译型: 优点:编译器一般会有预编译的过程对代码进行优化.因为编译只做一次,运行时不需要编译,所以编译型语言的程序执行效率高.可以脱离语言环境独立运行. 缺点:编 ...
- js实现属性只读
第一种 Object.defineProperty 这种是在vue源码中看见的 let obj = { $data: {} }; Object.defineProperty(obj, '$data', ...
- bzoj 3230: 相似子串【SA+st表+二分】
总是犯低级错误,st表都能写错-- 正反分别做一遍SA,预处理st表方便查询lcp,然后处理a[i]表示前i个后缀一共有多少个本质不同的子串,这里的子串是按字典序的,所以询问的时候直接在a上二分排名就 ...
- Luogu2261[CQOI2007]余数求和 【数论】By cellur925
题目传送门 省选题竟然送了这么多分,60分直接暴力算就行.(算了,07年的省选) 数学题嘛,通常我们需要把式子展开,然后寻找一些性质化简=w=. 展开式以及寻找规律的过程lyd老师讲的很清楚T_T,放 ...
- 第二类Stirling数初探 By cellur925
上午noi.ac崩崩崩了,栽在组合数学上,虽说最后在辰哥&Chemist的指导下A掉了此题,也发现自己组合数学太弱了qwq. 在luogu上找题,结果找到了一个第二类斯特林数的题(还是双倍经验 ...
- Comet OJ - Contest #4--前缀和
原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...
- 洛谷 P1339 [USACO09OCT]热浪Heat Wave
题目链接:https://www.luogu.org/problemnew/show/P1339 解题思路: 一道简单的最短路水题,dijkstra解法模板思路:https://www.cnblogs ...
- UltraEdit - 怎么显示文件标签栏和侧边栏
显示文件标签栏 view -> views/lists -> open Files Tabs 显示侧边栏 view -> views/lists -> File Tree Vi ...