当前位置: 首页 > ops >正文

Unity Shader unity文档学习笔记(十九):粘土效果,任意网格转化成一个球(顶点动画,曲面着色器)

任意网格转换球原理:
由某一点向网格的所有顶点发射一条射线,到圆上,最终就会形成一个圆
在这里插入图片描述
在这里插入图片描述
关键的代码

                float4 worldPos =  mul(unity_ObjectToWorld, v.vertex);// 计算原始顶点到圆心的向量float3 toCenter = worldPos - _WorldSourcePos;float3 dirObj = normalize(toCenter); // 世界空间方向(圆心→顶点的单位向量)// 计算世界空间目标位置(圆周上的点)float3 targetWorldPos = _WorldTargetPos + dirObj * _Radius; // 世界空间目标位置// 将目标位置转换回模型空间(用于顶点混合)float3 targetModelPos = mul(unity_WorldToObject, float4(targetWorldPos, 1)).xyz;float3 baseLocalPos = lerp(v.vertex, targetModelPos, _Transition);o.vertex = UnityObjectToClipPos(baseLocalPos);

整个shader

Shader "Custom/WorldCenterCircleShader"
{Properties{_MainTex("MainTex",2D) ="white"{}_Radius ("目标圆半径", Float) = 1.0       // 最终圆的半径(世界空间)_WorldSourcePos ("原世界坐标", Vector) = (0,0,0) // 原世界坐标_WorldTargetPos ("目标世界坐标", Vector) = (0,0,0) // 目标世界坐标_Color ("基础颜色", Color) = (1,0,0,1)   // 圆的颜色_Transition ("过渡系数", Range(0,1)) = 0 // 0=原模型,1=完整圆(世界空间变形)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;  // 模型空间顶点位置float3 normal : NORMAL;    // 模型空间原始法线float2 uv:TEXCOORD0;//纹理};struct v2f{float4 vertex : SV_POSITION; // 裁剪空间位置float3 worldPos : TEXCOORD0; // 世界空间位置(用于光照)float3 normal : NORMAL;      // 过渡后的法线(模型空间,用于光照)float2 uv:TEXCOORD1; };sampler2D _MainTex;float _Radius;float3 _WorldSourcePos;float3 _WorldTargetPos;fixed4 _Color;float _Transition;float _MinX;float _MaxX;v2f vert (appdata v){v2f o;float4 worldPos =  mul(unity_ObjectToWorld, v.vertex);// 计算原始顶点到圆心的向量float3 toCenter = worldPos - _WorldSourcePos;float3 dirObj = normalize(toCenter); // 世界空间方向(圆心→顶点的单位向量)// 计算世界空间目标位置(圆周上的点)float3 targetWorldPos = _WorldTargetPos + dirObj * _Radius; // 世界空间目标位置// 将目标位置转换回模型空间(用于顶点混合)float3 targetModelPos = mul(unity_WorldToObject, float4(targetWorldPos, 1)).xyz;float3 baseLocalPos = lerp(v.vertex, targetModelPos, _Transition);// 转换为裁剪空间o.vertex = UnityObjectToClipPos(baseLocalPos);float3 originalNormal = normalize(UnityObjectToWorldNormal(v.normal));float3 circleNormal = normalize(toCenter); // 圆周法线(指向外侧)float3 normal = lerp(originalNormal, circleNormal, _Transition); o.normal = mul(normal, (float3x3)unity_WorldToObject);o.uv = v.uv;return o;}fixed4 frag (v2f i) : SV_Target{//float4 texColor = tex2D(_MainTex, i.uv); //tex2D(smapler, x) 二维纹理查找// 简单漫反射光照(使用过渡后的模型空间法线)float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);// 法线从模型空间转换到世界空间(光照计算需要世界空间法线)float3 normalDir = normalize(i.normal);float diff = saturate(dot(lightDir, normalDir));//fixed4 col = texColor + _Color * (diff * 0.5 + 0.5); // 环境光+漫反射fixed4 col = _Color * diff; // 环境光+漫反射return col;}ENDCG}}FallBack "Diffuse"
}

效果请添加图片描述
但是这种方式对网格顶点是有要求的,如果顶点不够多就会这样
在这里插入图片描述

在这里插入图片描述

这样
在这里插入图片描述
在这里插入图片描述
项目的网格不可能每个顶点都这么多,有没有办法给网格新增一些顶点,当然是有:曲面着色器:
unity的正方体
在这里插入图片描述
参数调到5
在这里插入图片描述
调到10

在这里插入图片描述
转换后:
在这里插入图片描述
曲面细分shader:

Shader "Unlit/TessShader"
{Properties{_TessellationUniform("TessellationUniform",Range(1,64)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM//定义2个函数 hull domain#pragma hull hullProgram#pragma domain ds#pragma vertex tessvert#pragma fragment frag#include "UnityCG.cginc"//引入曲面细分的头文件#include "Tessellation.cginc" #pragma target 5.0struct VertexInput{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;float4 tangent : TANGENT;};struct VertexOutput{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;};VertexOutput vert (VertexInput v)//这个函数应用在domain函数中,用来空间转换的函数{VertexOutput o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;o.tangent = v.tangent;o.normal = v.normal;return o;}//有些硬件不支持曲面细分着色器,定义了该宏就能够在不支持的硬件上不会变粉,也不会报错#ifdef UNITY_CAN_COMPILE_TESSELLATION//顶点着色器结构的定义struct TessVertex{float4 vertex : INTERNALTESSPOS;float3 normal : NORMAL;float4 tangent : TANGENT;float2 uv : TEXCOORD0;};struct OutputPatchConstant { //不同的图元,该结构会有所不同//该部分用于Hull Shader里面//定义了patch的属性//Tessellation Factor和Inner Tessellation Factorfloat edge[3] : SV_TESSFACTOR;float inside  : SV_INSIDETESSFACTOR;};TessVertex tessvert (VertexInput v){//顶点着色器函数TessVertex o;o.vertex  = v.vertex;o.normal  = v.normal;o.tangent = v.tangent;o.uv      = v.uv;return o;}float _TessellationUniform;OutputPatchConstant hsconst (InputPatch<TessVertex,3> patch){//定义曲面细分的参数OutputPatchConstant o;o.edge[0] = _TessellationUniform;o.edge[1] = _TessellationUniform;o.edge[2] = _TessellationUniform;o.inside  = _TessellationUniform;return o;}[UNITY_domain("tri")]//确定图元,quad,triangle等[UNITY_partitioning("fractional_odd")]//拆分edge的规则,equal_spacing,fractional_odd,fractional_even[UNITY_outputtopology("triangle_cw")][UNITY_patchconstantfunc("hsconst")]//一个patch一共有三个点,但是这三个点都共用这个函数[UNITY_outputcontrolpoints(3)]      //不同的图元会对应不同的控制点TessVertex hullProgram (InputPatch<TessVertex,3> patch,uint id : SV_OutputControlPointID){//定义hullshaderV函数return patch[id];}[UNITY_domain("tri")]//同样需要定义图元VertexOutput ds (OutputPatchConstant tessFactors, const OutputPatch<TessVertex,3>patch,float3 bary :SV_DOMAINLOCATION)//bary:重心坐标{VertexInput v;v.vertex = patch[0].vertex*bary.x + patch[1].vertex*bary.y + patch[2].vertex*bary.z;v.tangent = patch[0].tangent*bary.x + patch[1].tangent*bary.y + patch[2].tangent*bary.z;v.normal = patch[0].normal*bary.x + patch[1].normal*bary.y + patch[2].normal*bary.z;v.uv = patch[0].uv*bary.x + patch[1].uv*bary.y + patch[2].uv*bary.z;VertexOutput o = vert (v);return o;}#endiffloat4 frag (VertexOutput i) : SV_Target{return float4(1.0,1.0,1.0,1.0);}ENDCG}}Fallback "Diffuse"
}

加上顶点动画后的shader
主要改动
在这里插入图片描述

Shader "Unlit/TessShader"
{Properties{_TessellationUniform("TessellationUniform",Range(1,64)) = 1_Radius ("目标圆半径", Float) = 1.0       // 最终圆的半径(世界空间)_WorldSourcePos ("原世界坐标", Vector) = (0,0,0) // 原世界坐标_WorldTargetPos ("目标世界坐标", Vector) = (0,0,0) // 目标世界坐标_Transition ("过渡系数", Range(0,1)) = 0 // 0=原模型,1=完整圆(世界空间变形)}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM//定义2个函数 hull domain#pragma hull hullProgram#pragma domain ds#pragma vertex tessvert#pragma fragment frag#include "UnityCG.cginc"//引入曲面细分的头文件#include "Tessellation.cginc" #pragma target 5.0float _Radius;float3 _WorldSourcePos;float3 _WorldTargetPos;fixed4 _Color;float _Transition;float _TessellationUniform;struct VertexInput{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;float4 tangent : TANGENT;};struct VertexOutput{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;};VertexOutput vert (VertexInput v)//这个函数应用在domain函数中,用来空间转换的函数{VertexOutput o;float4 worldPos =  mul(unity_ObjectToWorld, v.vertex);// 计算原始顶点到圆心的向量float3 toCenter = worldPos - _WorldSourcePos;float3 dirObj = normalize(toCenter); // 世界空间方向(圆心→顶点的单位向量)// 计算世界空间目标位置(圆周上的点)float3 targetWorldPos = _WorldTargetPos + dirObj * _Radius; // 世界空间目标位置// 将目标位置转换回模型空间(用于顶点混合)float3 targetModelPos = mul(unity_WorldToObject, float4(targetWorldPos, 1)).xyz;float3 baseLocalPos = lerp(v.vertex, targetModelPos, _Transition);o.vertex = UnityObjectToClipPos(baseLocalPos);o.uv = v.uv;o.tangent = v.tangent;float3 originalNormal = normalize(UnityObjectToWorldNormal(v.normal));float3 circleNormal = normalize(toCenter); // 圆周法线(指向外侧)float3 normal = lerp(originalNormal, circleNormal, _Transition); //o.normal = normal;o.normal = mul(normal, (float3x3)unity_WorldToObject);return o;}//有些硬件不支持曲面细分着色器,定义了该宏就能够在不支持的硬件上不会变粉,也不会报错#ifdef UNITY_CAN_COMPILE_TESSELLATION//顶点着色器结构的定义struct TessVertex{float4 vertex : INTERNALTESSPOS;float3 normal : NORMAL;float4 tangent : TANGENT;float2 uv : TEXCOORD0;};struct OutputPatchConstant { //不同的图元,该结构会有所不同//该部分用于Hull Shader里面//定义了patch的属性//Tessellation Factor和Inner Tessellation Factorfloat edge[3] : SV_TESSFACTOR;float inside  : SV_INSIDETESSFACTOR;};TessVertex tessvert (VertexInput v){//顶点着色器函数TessVertex o;o.vertex  = v.vertex;o.normal  = v.normal;o.tangent = v.tangent;o.uv      = v.uv;return o;}OutputPatchConstant hsconst (InputPatch<TessVertex,3> patch){//定义曲面细分的参数OutputPatchConstant o;o.edge[0] = _TessellationUniform;o.edge[1] = _TessellationUniform;o.edge[2] = _TessellationUniform;o.inside  = _TessellationUniform;return o;}[UNITY_domain("tri")]//确定图元,quad,triangle等[UNITY_partitioning("fractional_odd")]//拆分edge的规则,equal_spacing,fractional_odd,fractional_even[UNITY_outputtopology("triangle_cw")][UNITY_patchconstantfunc("hsconst")]//一个patch一共有三个点,但是这三个点都共用这个函数[UNITY_outputcontrolpoints(3)]      //不同的图元会对应不同的控制点TessVertex hullProgram (InputPatch<TessVertex,3> patch,uint id : SV_OutputControlPointID){//定义hullshaderV函数return patch[id];}[UNITY_domain("tri")]//同样需要定义图元VertexOutput ds (OutputPatchConstant tessFactors, const OutputPatch<TessVertex,3>patch,float3 bary :SV_DOMAINLOCATION)//bary:重心坐标{VertexInput v;v.vertex = patch[0].vertex*bary.x + patch[1].vertex*bary.y + patch[2].vertex*bary.z;v.tangent = patch[0].tangent*bary.x + patch[1].tangent*bary.y + patch[2].tangent*bary.z;v.normal = patch[0].normal*bary.x + patch[1].normal*bary.y + patch[2].normal*bary.z;v.uv = patch[0].uv*bary.x + patch[1].uv*bary.y + patch[2].uv*bary.z;VertexOutput o = vert (v);return o;}#endiffloat4 frag (VertexOutput i) : SV_Target{return float4(1.0,1.0,1.0,1.0);}ENDCG}}Fallback "Diffuse"
}
http://www.xdnf.cn/news/17730.html

相关文章:

  • 【代码随想录day 20】 力扣 669. 修剪二叉搜索树
  • 【CLR via C#(第3版)阅读笔记】类型基础
  • PostgreSQL——视图
  • 嵌入式C/C++面试大全
  • Gradle(四)Maven 项目迁移 Gradle 项目实践
  • spring mvc HttpMessageConverter 消息转换器
  • 【KALI】第一篇 安装Kali Linux虚拟机之详细操作步骤讲解
  • CNN - 卷积层
  • 利用 Java 爬虫按图搜索 1688 商品(拍立淘)实战指南
  • 高效TypeScript开发:VSCode终极配置指南
  • Varjo XR虚拟现实军用车辆驾驶与操作培训
  • 【MATLAB代码】滑动窗口均值滤波、中值滤波、最小值/最大值滤波对比。订阅专栏后可查看完整代码
  • OpenCV中对图像进行平滑处理的4种方式
  • 《多级缓存架构设计与实现全解析》
  • 【跨越 6G 安全、防御与智能协作:从APT检测到多模态通信再到AI代理语言革命】
  • 机器视觉的磁芯定位贴合应用
  • GraphRAG查询(Query)流程实现原理分析
  • Java+Vue构建的MES信息管理系统,含完整源码,功能涵盖生产跟踪、质量管控等,助力企业实现精细化、智能化生产管理
  • 【16-softmax回归】
  • AI 赋能的软件工程全生命周期应用
  • springboot+vue实现通过poi完成excel
  • Postman 平替 技术解析:架构优势与实战指南
  • 观察者模式(C++)
  • 【Leetcode hot 100】76.最小覆盖字串
  • 【HarmonyOS】Window11家庭中文版开启鸿蒙模拟器失败提示未开启Hyoer-V
  • SwiftUI 页面弹窗操作
  • 用飞算JavaAI一键生成电商平台项目:从需求到落地的高效实践
  • 使用免费API开发口播数字人
  • [机器学习]07-基于多层感知机的鸢尾花数据集分类
  • c++中的Lambda表达式详解