首页 > 其他分享 >模拟spotlight

模拟spotlight

时间:2022-09-21 19:44:33浏览次数:90  
标签:List vertex spotLight spotLightCount v2f float4 spotlight 模拟

 

实现方式:将聚光灯颜色按与光源的距离叠加到光照模型上,阴影用shadowmap:在光源处放一个相机,生成一张深度图和转换矩阵,再用主相机渲染出的片元的深度余存储的深度相比,小于的是阴影。

贴图数组:(18条消息) Texture2DArray 功能测试_上午八点的博客-CSDN博客_texture2darray

///shader
///功能: 描边
Shader "Custom/DailyGameHex"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_OutlineCol("OutlineCol", Color) = (1,0,0,1)
_OutlineFactor("OutlineFactor", Range(0,1)) = 0.1
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD 100
//描边
Pass
{
//剔除正面,只渲染背面,对于大多数模型适用,不过如果需要背面的,就有问题了
Cull Front
CGPROGRAM

//使用vert函数和frag函数
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _OutlineCol;
float _OutlineFactor;
struct v2f
{
float4 pos : SV_POSITION;
};

v2f vert(appdata_full v)
{
v2f o;
//在vertex阶段,每个顶点按照法线的方向偏移一部分,不过这种会造成近大远小的透视问题
//v.vertex.xyz += v.normal * _OutlineFactor;
o.pos = UnityObjectToClipPos(v.vertex);
//将法线方向转换到视空间
float3 vnormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
//将视空间法线xy坐标转化到投影空间,只有xy需要,z深度不需要了
float2 offset = TransformViewToProjection(vnormal.xy);
//在最终投影阶段输出进行偏移操作
o.pos.xy += offset * _OutlineFactor;
return o;
}

fixed4 frag(v2f i) : SV_Target
{
//这个Pass直接输出描边颜色
return _OutlineCol;
}

ENDCG

}
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma fragmentoption ARB_precision_hint_fastest
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fwdbase

#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : POSITION;
float3 normal : NORMAL;
float4 worldPos : TEXCOORD2;
SHADOW_COORDS(3)
};

sampler2D _MainTex;
float4 _MainTex_ST;

float4 SpotLightColor[5];//聚光灯颜色
float4 SpotLightPos[5];//聚光灯位置
float4 SpotLightDir[5];//聚光灯照射方向
float SpotLightAngle[5];//聚光灯角度
float SpotLightBrightness[5];//聚光灯亮度

float4x4 SHADOW_MAP_VP[5];//相机变换矩阵
//sampler2D ShadowMapTexture[5];//聚光灯阴影深度图
UNITY_DECLARE_TEX2DARRAY(ShadowMapTexture);//聚光灯阴影深度图
//聚光灯数量
int spotLightCount;

v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
TRANSFER_SHADOW(o);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
// 平行光
fixed4 col = tex2D(_MainTex, i.uv);
float4 lightColor = _LightColor0;
float3 lightDir = WorldSpaceLightDir(i.worldPos);
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos.xyz);
fixed4 finalCol = col * lightColor * saturate(dot(lightDir, i.normal)) * atten;

for(int index=0;index<spotLightCount;index++)
{
//聚光灯方向
float4 worldDir = SpotLightPos[index] - i.worldPos;
float3 spotLightDir = mul(unity_WorldToObject, worldDir).xyz;
spotLightDir = normalize(spotLightDir);
float3 downdir = normalize(mul(unity_WorldToObject,SpotLightDir[index].xyz));
float spotLight = max(SpotLightAngle[index] - abs(degrees(acos(dot(downdir, spotLightDir)))),0);
fixed4 secondCol = (col * 0.5 + SpotLightBrightness[index]) * (col * SpotLightColor[index] * spotLight * 0.01);

if(spotLight != 0)
{
//计算NDC坐标
fixed4 ndcpos = mul(SHADOW_MAP_VP[index] , i.worldPos);
ndcpos.xyz = ndcpos.xyz / ndcpos.w;
//从[-1,1]转换到[0,1]
float3 uvpos = ndcpos * 0.5 + 0.5;

//float depth = DecodeFloatRGBA(tex2D(ShadowMapTexture[i], uvpos.xy));
float depth = DecodeFloatRGBA(UNITY_SAMPLE_TEX2DARRAY(ShadowMapTexture, float3(uvpos.xy, index)));
secondCol = secondCol * step(depth, ndcpos.z + 0.00005);
}

finalCol = finalCol + secondCol;
}

return finalCol;
}

ENDCG
}

}
Fallback "Mobile/Diffuse"
}

///光源相机的shader,拿深度图

Shader "Hidden/ShadowMap" {
Properties {
}

SubShader {
Tags { "RenderType"="Opaque" }

/**/
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct v2f {
float4 vertex : POSITION;
float2 depth: TEXCOORD1;
};

float3 worldLightVector;

v2f vert(appdata_base v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.depth = o.vertex.zw;
return o;
}

fixed4 frag(v2f i) : SV_Target{
//discard;
float depth = i.depth.x / i.depth.y;
return EncodeFloatRGBA(depth);
}
ENDCG
}
}
}

 

c#

/// <summary>
/// 初始化建筑shader参数
/// </summary>
public IEnumerator DalayInitLightShaderSetting()
{
OpenOrCloseBakeCamera(true);
yield return new WaitForSeconds(0.5f);
int spotLightCount = listSpotLight.FindAll(sp => sp.gameObject.activeInHierarchy).Count;
renderMat.SetInt("spotLightCount", spotLightCount);
List<Matrix4x4> matrixList = new List<Matrix4x4>(spotLightCount);
List<RenderTexture> texList = new List<RenderTexture>(spotLightCount);
List<Vector4> dirList = new List<Vector4>(spotLightCount);
List<Vector4> posList = new List<Vector4>(spotLightCount);
List<float> angleList = new List<float>(spotLightCount);
List<Color> colorList = new List<Color>(spotLightCount);
List<float> brightnessList = new List<float>(spotLightCount);

for (int i=0;i< listSpotLight.Count; i++)
{
ShadowMapCamera spotLight = listSpotLight[i];
if (!spotLight.gameObject.activeInHierarchy)
continue;
//spotLight.Bake(true);
matrixList.Add(spotLight.GetShadowMapMatrix());
dirList.Add(spotLight.lightDir);
texList.Add(spotLight.GetDepathRenderTexture());
posList.Add(spotLight.transform.position);
angleList.Add(spotLight.lightAngle);
colorList.Add(spotLight.spotLightColor);
brightnessList.Add(spotLight.spotLightBrightness);
//spotLight.Bake(false);
}
//没有聚光灯不作处理
if(spotLightCount > 0)
{
//深度贴图和相机变换矩阵
if (texList.Count > 0)
{
Texture2DArray texArr = new Texture2DArray(depthRTSize, depthRTSize, texList.Count, TextureFormat.RGBA32, false, false);
for (int i = 0; i < texList.Count; i++)
{
Graphics.CopyTexture(texList[i], 0, 0, texArr, i, 0);
}
renderMat.SetTexture("ShadowMapTexture", texArr);
renderMat.SetMatrixArray("SHADOW_MAP_VP", matrixList);
}

renderMat.SetVectorArray("SpotLightDir", dirList);
renderMat.SetVectorArray("SpotLightPos", posList);
renderMat.SetFloatArray("SpotLightAngle", angleList);
renderMat.SetColorArray("SpotLightColor", colorList);
renderMat.SetFloatArray("SpotLightBrightness", brightnessList);
}


OpenOrCloseBakeCamera(false);
}

标签:List,vertex,spotLight,spotLightCount,v2f,float4,spotlight,模拟
From: https://www.cnblogs.com/mcyushao/p/16716921.html

相关文章

  • 31. [实例]Cookie模拟登录
    1.前言在使用爬虫采集数据的规程中,我们会遇到许多不同类型的网站,比如一些网站需要用户登录后才允许查看相关内容,如果遇到这种类型的网站,又应该如何编写爬虫程序呢?Cookie......
  • 9.20 模拟赛总结
    又挂分,乐。作业多,少写几句。T1基础dp,T2tarjan板子,T3大模拟。T1写完过不去样例,调了半小时,一共没几行的代码写出了不下五处错,谔谔。T2写完(看上去)没有什么锅。T3......
  • CSP-S模拟6 题解
    开个坑,今后我要写题解了!A.玩水挺有趣的一道题,我们首先从\(2\)条路径的情况考虑符合答案的路径一定满足这种格式:两条路径先重合,再分开,最后再重合观察一下,注意到第一......
  • CSP-S模拟6
    A.玩水一直以为这是\(dp\),但是只是一个性质/结论code#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;typedefunsignedlonglongull;i......
  • 题目:模拟网站的登录,客户端录入账号密码,然后服务器端进行验证(TCP)
    题目:模拟网站的登录,客户端录入账号密码,然后服务器端进行验证(TCP)封装的类packagecom.gao.Project.Pro4;importjava.io.Serializable;publicclassUserimplements......
  • 题目:模拟网站的登录,客户端录入账号密码,然后服务器端进行验证(TCP)(完善)
    完善(加入完整的处理异常的方式、多线程接收用户请求)(TCP)封装的类packagecom.gao.Project.Pro5;importjava.io.Serializable;publicclassUserimplementsSerial......
  • CSP-S模拟7 序列问题 钱仓 自然数 环路
    T1:线性DP,求最长不下降子序列优化(cdp,树状数组)T2:断环为链,结论T3:序列上区间统计答案,线段树维护T4:咕了,矩阵乘法+分治优化,我就打个暴力T1:给你一个长度n的序列A(n<=5e5,ai<=......
  • 【Coel.学习笔记】随机化算法:模拟退火与爬山法
    简介模拟退火(\(\text{SimulateAnneal}\))和爬山法是随机化算法,二者的原理都在于通过随机生成答案并检查,把答案逐步缩小在一个可行的区间,尽可能地靠近正确答案。在考场......
  • CSP-S模拟7
    学校体检:内科:问,你是神经病吗;答,不是。下一个。外科:问,你做过手术吗;答,没有。下一个。基础检查:问,你身高体重是多少;答,……。下一个。此处应有乌鸦飞过*** A.序列问题我......
  • 模拟springboot自动转配原理
    packagecom.tlj.app;importorg.springframework.beans.factory.annotation.Configurable;importorg.springframework.context.annotation.Bean;importorg.springf......