如何在 Unity 着色器中为 VR 获取正确的屏幕坐标?
How to get correct screen coordinates for VR in Unity Shaders?
我无法获得正确的屏幕坐标,因此我制作了这个小型 MWE 来复制我在主项目中看到的那种行为。我在 Unity 3D 中使用单通道渲染和 Windows 混合现实耳机。我有一个着色器,它被设置为一个新的 material "ppMaterial",它又被用于
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination, ppMaterial);
}
在这个 MWE 中,着色器只是应该在屏幕边缘绘制圆圈,所以我制作了这个简单的着色器:
Shader "Custom/ScreenShader" {
Properties {
}
SubShader {
Pass {
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
half4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
float getDist(float2 isIn, float2 pos2){
return sqrt((isIn.x - pos2.x)*(isIn.x - pos2.x) + (isIn.y - pos2.y)*(isIn.y - pos2.y));
}
float4 NearBoundary(float2 isIn, v2f i)
{
float2 pos2 = float2(0.5,0.5);
float2 pos3 = float2(0,0.5);
float2 pos4 = float2(0.5,0.0);
float dist2 = getDist(isIn, pos2);
float dist3 = getDist(isIn, pos3);
float dist4 = getDist(isIn, pos4);
if(dist2<0.1){
return float4(0,0.5,0.5,1);
}
if(dist3.x<0.3){
return float4(0.5,0,0.5,1);
}
if(dist4.x<0.3){
return float4(0.5,0,0.5,1);
}
return tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv, _MainTex_ST));
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.uv = v.uv;
return o;
}
half4 frag(v2f i) : SV_Target {
float2 screenPos = i.screenPos;
return NearBoundary(screenPos, i);
}
ENDCG
}
}
}
但这不起作用,点没有分别绘制在中心和边界,它们应该在的位置。如何为每只眼睛获取 (0,1) 范围内的正确屏幕坐标?
原来问题是提供坐标的相机设置了目标纹理,这似乎弄乱了坐标。然后,screenPos 必须设置
screenPos.x -= unity_StereoEyeIndex * 0.5;
screenPos.x *= 2;
另外,插入
RenderTextureDescriptor d = XRSettings.eyeTextureDesc;
d.width = d.width / 2; // THIS DOES NOT MAKE SENSE
RenderTexture t = new RenderTexture(d);
在 C# 代码中以及设置
uv.y = 1-uv.y
在着色器中终于解决了所有问题。
为遇到这些超级奇怪问题的其他人发布此信息...
我无法获得正确的屏幕坐标,因此我制作了这个小型 MWE 来复制我在主项目中看到的那种行为。我在 Unity 3D 中使用单通道渲染和 Windows 混合现实耳机。我有一个着色器,它被设置为一个新的 material "ppMaterial",它又被用于
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination, ppMaterial);
}
在这个 MWE 中,着色器只是应该在屏幕边缘绘制圆圈,所以我制作了这个简单的着色器:
Shader "Custom/ScreenShader" {
Properties {
}
SubShader {
Pass {
CGPROGRAM
#pragma fragment frag
#pragma vertex vert
#include "UnityCG.cginc"
uniform sampler2D _MainTex;
half4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
float getDist(float2 isIn, float2 pos2){
return sqrt((isIn.x - pos2.x)*(isIn.x - pos2.x) + (isIn.y - pos2.y)*(isIn.y - pos2.y));
}
float4 NearBoundary(float2 isIn, v2f i)
{
float2 pos2 = float2(0.5,0.5);
float2 pos3 = float2(0,0.5);
float2 pos4 = float2(0.5,0.0);
float dist2 = getDist(isIn, pos2);
float dist3 = getDist(isIn, pos3);
float dist4 = getDist(isIn, pos4);
if(dist2<0.1){
return float4(0,0.5,0.5,1);
}
if(dist3.x<0.3){
return float4(0.5,0,0.5,1);
}
if(dist4.x<0.3){
return float4(0.5,0,0.5,1);
}
return tex2D(_MainTex, UnityStereoScreenSpaceUVAdjust(i.uv, _MainTex_ST));
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.screenPos = ComputeScreenPos(o.vertex);
o.uv = v.uv;
return o;
}
half4 frag(v2f i) : SV_Target {
float2 screenPos = i.screenPos;
return NearBoundary(screenPos, i);
}
ENDCG
}
}
}
但这不起作用,点没有分别绘制在中心和边界,它们应该在的位置。如何为每只眼睛获取 (0,1) 范围内的正确屏幕坐标?
原来问题是提供坐标的相机设置了目标纹理,这似乎弄乱了坐标。然后,screenPos 必须设置
screenPos.x -= unity_StereoEyeIndex * 0.5;
screenPos.x *= 2;
另外,插入
RenderTextureDescriptor d = XRSettings.eyeTextureDesc;
d.width = d.width / 2; // THIS DOES NOT MAKE SENSE
RenderTexture t = new RenderTexture(d);
在 C# 代码中以及设置
uv.y = 1-uv.y
在着色器中终于解决了所有问题。
为遇到这些超级奇怪问题的其他人发布此信息...