Hi, I’m writing a shader that assigns to the pixels color the corresponding world position.
Shader
Shader "Custom/Uvs_to_WorldPositions"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Unlit
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
float3 worldPos;
};
half4 LightingUnlit(SurfaceOutput s, half3 lightDir, half atten)
{
return half4(s.Albedo, s.Alpha);
}
void surf(Input IN, inout SurfaceOutput o)
{
float3 col = IN.worldPos;
o.Albedo = col.rgb;
}
ENDCG
}
Fallback "Diffuse"
}
My objective is to write a texture in which each pixel represents a uv coordinate and the pixel’s color represents the world position.
For example, pixel (x,y) represents the uv coordinates (xxx,yyy).
So, I basically need to write a texture with this shader output.
I know how to use the Blit() function, but it won’t help here because of the world positions (and obviously, Blit() can’t handle them).
How can I do?
Thanks,
Francesco
bgolus
March 6, 2017, 11:01pm
2
You need a shader that outputs the clip position as the UVs.
o.pos = float4(v.uv * 2.0 - 1.0, 0.0, 1.0);
1 Like
Hi @bgolus , thanks for the answer… it led me to the solution!
The right idea was:
“Flatten” the vertices basing on their uv coordinates by modifying the o.pos property
Set output color basing on the original vertex position
Render the resulting screen space square and save the texture
This is the vertex/fragment shader which outputs the world position of the uv:
Shader
Shader "Custom/UVs_to_WorldPositions" {
SubShader{
Pass{
Lighting Off
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
// vertex input: position, UV
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v){
v2f o;
float4 p = v.vertex;
float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
o.pos = float4(v.uv.x * 2.0 - 1.0, v.uv.y * 2.0 - 1.0, 1.0, 1.0);
o.color.xyz = worldPos;
o.color.w = 1.0;
return o;
}
fixed4 frag(v2f i) : SV_Target{
return i.color;
}
ENDCG
}
}
}
And here’s its output on a render texture (the mesh is a primitive sphere):
“Houston, we have a problem…” @bgolus
I summarize what I’m doing:
Given a 3D model, I create 2 textures (uncompressed, read/write enabled, point filtering).
To create them I use two shaders and then a ReadPixles():
Shader for World Positions
Shader "Custom/UV_to_WorldPos" {
SubShader{
Pass{
Lighting Off
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
float4 color : COLOR;
float4 worldSpacePosition : TEXCOORD0;
};
// vertex input: position, UV
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v){
v2f o;
float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
o.worldSpacePosition = mul(unity_ObjectToWorld, v.vertex);
o.pos = float4(v.uv.x * 2.0 - 1.0, v.uv.y * 2.0 - 1.0, 1.0, 1.0);
return o;
}
float4 frag(v2f i) : SV_Target{
return i.worldSpacePosition;
}
ENDCG
}
}
}
Shader for Normals
Shader "Custom/UV_to_Normal" {
SubShader{
Pass{
Lighting Off
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
// vertex input: normal, UV
struct appdata {
float4 normal : NORMAL;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v) {
v2f o;
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.pos = float4(v.uv.x * 2.0 - 1.0, v.uv.y * 2.0 - 1.0, 1.0, 1.0);
o.color.xyz = (worldNormal*0.5)+0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag(v2f i) : SV_Target{
return i.color;
}
ENDCG
}
}
}
Texture A, which in each pixel stores the world position of a point of the model. (I assume that the model points have (x,y,z) in the range (0,1).
Texture B, which in each pixel stores the normal of a point of the model, normalized to (0,1).
A script reads one by one the pixels of both texture A and texture B (respectively: Pa and Pb), and it creates a ray.
The ray’s origin is a Vector3 in which the (x,y,z) values are Pa’s (r,g,b) values.
The ray’s direction is a Vector3 in which the (x,y,z) values are Pb’s (r,g,b) values.
The problem is that some of the rays don’t start in the right position. I really don’t know why…
I think there may be 2 reasons:
The texture A contains some wrong values (due to float precision?)
When reading the textures, the GetPixel() function doesn’t return the right, precise color.
I don’t know if I was clear explaining this issue!! Do you have some idea of what’s going on?
1 Like
bgolus
March 9, 2017, 6:44pm
5
fra3point:
The texture A contains some wrong values (due to float precision?)
Are the textures you’re creating using RGBAFloat?
1 Like
No, they were ARGB32 (8bit per channel), so the precision was too low. Changing to RGBAFloat did the trick!
Thanks a lot, @bgolus !
P.S. Sorry for abusing your help so often, I am very grateful to you!
1 Like