用代码来画画 —— Ray-Marching(光线步进)【Unity Shader】
来源:互联网 发布:百度大数据交响乐 编辑:程序博客网 时间:2024/05/01 12:20
参考自:
http://blog.csdn.net/baidu_26153715/article/details/46510703
http://imgtec.eetrend.com/blog/8845
http://ogldev.atspace.co.uk/www/tutorial13/tutorial13.html
效果如图:
完整代码及详细注释如下【修正了源代码的一些错误】:
Shader "Custom/RayMarching"{Properties{//_MainTex ("Texture", 2D) = "white" {}//_Cube("cubemap", cube) = ""{}}// 代码参考自 http://blog.csdn.net/baidu_26153715/article/details/46510703SubShader{// No culling or depthCull Off ZWrite Off ZTest AlwaysPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"// 球体 [Signed Distance Function]float sdfSphere(float3 p, float s){return length(p) - s;}// 立方体float sdfBox(float3 p, float3 b){return length(max(abs(p) - b, 0.));}// p 从相机空间换算到世界坐标系(即世界坐标系下光线步进的方向)float3 CameraSpace2WorldSpace(in float3 camPos, in float3 p){float3 target = float3(0, 0, 0);float3 AxisY = float3(0, 1, 0);float3 z = normalize(target - camPos); // lookfloat3 x = normalize(cross(z, AxisY)); // rightfloat3 y = normalize(cross(z, x)); // up // 注意:(right, up, look) * world = camera,Cg 矩阵是按行存储float3 theWorldSpaceP = float3(// dot(p, x), dot(p, y), dot(p, z)//p.x*x + p.y*y + p.z*z//mul(float3x3(x, y, z), p)mul(p, float3x3(x, y, z)) // 交换相乘位置相当于转置);return theWorldSpaceP;}// 步进的光线终点和球体表面的距离float map(in float3 pos){//float d = sdfSphere(pos, 1);float d = sdfBox(pos, float3(.5, .5, .5));return d;}float3 normal(in float3 pos){float2 offset = float2(.01, 0);float3 nDir = normalize(float3(// 通过计算 xyz 三个方向的差值(梯度),归一化后得到法线方向map(pos + offset.xyy) - map(pos - offset.xyy),map(pos + offset.yxy) - map(pos - offset.yxy),map(pos + offset.yyx) - map(pos - offset.yyx)));return nDir;}float marching(in float3 origin, in float3 dir){float t = 1;// 步进的光线总长度int i;for (i = 0; i<64; ++i){// 随着光线的步进,检查是否到达球体的表面float3 graphic = origin + t*dir;float d = map(graphic);// 当距离小于一个最小阈值,或者长度超过一个最大阈值,则中断循环if (d < .02 || t>20)break;// 步进t += d;}return t;}float3 render(in float3 pos, in float3 p){// 距离辅助的 ray-marchingfloat d = marching(pos, p);// 计算法线方向(世界坐标系)float3 nDir = normal(pos + p*d);float3 c = 0;if (d<30){// 光源方向(世界坐标系)float3 lDir = normalize(half3(0, 1, 0));// diffusefloat diff = max(0, dot(lDir, nDir));// 将法线方向作为颜色返回c = nDir;}return c;}struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};v2f vert (appdata v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.uv = v.uv;return o;}//sampler2D _MainTex;fixed4 frag (v2f i) : SV_Target{float time = _Time.y;float2 uv = i.uv * 2 - 1; // 相机坐标系float3 p = normalize(float3(uv, 2));// 相机的世界坐标(随时间变化)float3 camPos = float3(3 + sin(time), 3, 3 + cos(time));// 将 p 点换从相机坐标系换算到世界坐标系float3 theNewP = CameraSpace2WorldSpace(camPos, p);// 渲染模型的法线fixed3 col = render(camPos, theNewP);return fixed4(col, 1);}ENDCG}}FallBack "Diffuse"}
加上光照计算的效果:
取 并集(Union) 的效果:
实际应用:用 SDF 和 Raymarch 让代码 “画画”
1 0
- 用代码来画画 —— Ray-Marching(光线步进)【Unity Shader】
- 用代码来画画 —— Ray-Marching(光线步进) 多个立体图形的绘制【GLSL】
- Unity CG 写一个超酷的 ray-marching(shader纯代码写3D)
- ray marching shader
- ray marching shader 2:viewspace 转换 worldspace
- 0.0 用代码画画——作者简介
- Unity3d Ray Marching
- 用代码画画
- 【Ray Trace from Groud Up】光线追踪代码实现解析
- Unity Shader-遮挡处理(X-Ray,遮挡描边,遮挡半透,遮挡溶解)
- Unity Shader-遮挡处理(X-Ray,遮挡描边,遮挡半透,遮挡溶解)
- 【Unity-Shader】Unity60个内置Shader代码浅析(一)
- Unity Shader——移动端Shader的优化(Optimize Shader)
- Real-Time Rendering (8) - 光线求交(Ray intersection)
- Unity Shader学习6 —— Unity创建一个Shader
- 【Unity Shader入门精要】— Unity Shader基础
- 【Unity Shader入门精要】— 开始Unity Shader之旅
- 0.2 用代码画画——目标读者、教材特色、内容大纲
- 一个可能的C++primer Plus第164页第6题的答案
- Apache/Tomcat/JBOSS/Neginx/lighttpd/Jetty
- Linux VI编辑&退出
- JavaScript学习(2)--Array数组
- 1019. 数字黑洞 (20)
- 用代码来画画 —— Ray-Marching(光线步进)【Unity Shader】
- git忽略某文件夹,但保留文件夹内的其它文件夹
- Git 常用技巧
- 《转》android利用socket与java后台交互的设计与实现
- Canvas画图设置渐变色
- Git操作指南
- JQuery -- this 和 $(this) 的区别
- Action 中获取表单数据的三种方式
- 中山大学转专业过程及心得