光线步进——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使用者,因为我本身自己 ... 
随机推荐
- Burpsuite实验一
			一.实验准备 win7系统 burpsuite 二.实验目的 进行重放攻击,观察结果 三.实验内容 本次实验并没有采取在虚拟机下进行,而是直接在win7系统中进行.首先配置一下环境,选择你常用的浏览器 ... 
- 「网络流24题」「LuoguP4016」 负载平衡问题
			Description GGG 公司有 nnn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 nnn 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. ... 
- 读取每行的数据,加入到list中
			有txt文件中,每行都有一个字符串或者数据,将每行的数据转换到一个list中 例如: 1 2 3 6 实现: f = open("test1.txt",'r') list1 = [ ... 
- 笔记本创建wifi热点
			如何在Win8系统上建立WIFI热点 | 浏览: 2511 | 更新: 2013-04-10 01:55 | 标签: win8 59 28 全文阅读分步阅读 步骤 1 2 3 4 5 6 7 8 ... 
- 把文件类型转化为byte[]
			转自:https://blog.csdn.net/xinxiqi/article/details/78899159 package com.sanqing.util; import java.io.B ... 
- 通过链接将JSP页面中一变量传到另一JSP界面中
			A.jsp 发送 <a herf="B.jsp?name=<%=name%>">传递到B页面</a> B.jsp 接收 <%String ... 
- iView 实战系列教程(21课时)_1.iView 实战教程之配置篇
			1.iView 实战教程之配置篇 点击添加插件,. 选中后安装 全部导入还是按需导入. 2.是否需要自定义主题变量 3.多语言的设置. 这里我们全部选择为默认 然后点击继续. 启动项目 入口文件导入了 ... 
- ORACLE知识点整理之一
			1. 安装客户端 去官方网站下载 此处略 2. 客户端登陆身份 Oracle有三种身份登录方式:Normal.sysdba.sysoper. normal身份:普通用户身份,默认选项(默认可以不写), ... 
- hdoj1160【DP】
			现在还很弱,贴一个我bin的结题报告日后写到一定会了加油 说说感觉,读题不读好,然后读完想不出,知道是dp不好好想,先排序一列,再求另一列,dp[ i ]代表长度,那么需要输出整个序列需要路径和一个标 ... 
- 简述网站、B/S架构与C/S架构
			一.什么是网站? 定义:网站是指在因特网上根据一定的规则,使用HTML等工具制作的用于展示特定内容相关网页的集合. 简单地说,网站是一种沟通工具(或者说是一种软件——建设网站也是软件开发的一种),我们 ... 
