I am trying to get the world position of a pixel inside a fragmented shader.
Let me explain. I have followed this tutorial
for a fragmented shader that let’s me paint on 3D objects. Right now it works through texture coordinates but I want it to work through pixel’s world position. So when I click on a 3D model to be able to compare the Vector3 position (where the click happended) to the pixel Vector3 position and if the distance is small enough to lerp the color.
This is the setup I have. I created a new 3D project just for making the shader with the intent to export it later into my main project. In the scene I have the default main camera, directional light, a object with a script that shows me the fps and a default 3D cube with a mesh collider. I created a new material and a new Standard Surface Shader and added it to the cube. After that I assigned the next C# script to the cube with the shader and a camera reference.
If you want you can download the sample project https://www.dropbox.com/s/sof3w6aeqtrckuw/Shader Painting.rar?dl=0
As for what I have tried to solve the problem is this. I searched on google about the problem this thread is about and tried to implement it in my project. I have also found some projects that have the feature I need like this one Mesh Texture painting in Unity Using Shaders | by Shahriar Shahrabi | Medium. This one works exactly how I need it, but it doesn’t work on iOS. The 3D object is turns to black. You can check out a previous post I made ( Custom shaders not working in editor and build when switching the platform to mobile ) to solve the problem and also talked with the creator on twitter but he can’t help me. Also I have tried Paint in 3D | Painting | Unity Asset Store that works ok but in my main project runs with very little fps, it’s hard for me to customize it for my needs and it doesn’t paint on the edges of my 3D model.
I also tried some debuging, for example return fixed4(i.worldPos, 1) which showed me a fade between red,green and yellow. And return (float4)_Coordinate; which made the object change colors depending on where I click, I think that means the the mouse position is working alright.
Most attempts I had to solve this problem ended up breaking the painting and the object just turning black. Someone on a forum said that for world-space coordinates, the distances change - a value of 1 represents 1 meter, which might be larger or smaller than I am accounting for. Mabye that means that I need to some more math with the i.worldPos to make it match with the click position.
This is the code I am using.
Draw.shader
Shader "Unlit/Draw"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Coordinate("Coordinate",Vector)=(0,0,0,0)
_Color("Paint Color",Color)=(1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Coordinate,_Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
float draw =pow(saturate(1-distance(i.uv,_Coordinate.xy)),100);
fixed4 drawcol = _Color * (draw * 1);
return saturate(col + drawcol);
}
ENDCG
}
}
}
Draw.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Draw : MonoBehaviour
{
public Camera cam;
public Shader paintShader;
RenderTexture splatMap;
Material snowMaterial,drawMaterial;
RaycastHit hit;
private void Awake()
{
Application.targetFrameRate = 200;
}
void Start()
{
drawMaterial = new Material(paintShader);
drawMaterial.SetVector("_Color", Color.red);
snowMaterial = GetComponent<MeshRenderer>().material;
splatMap = new RenderTexture(1024, 1024, 0, RenderTextureFormat.ARGBFloat);
snowMaterial.mainTexture = splatMap;
}
void Update()
{
if (Input.GetMouseButton(0))
{
if(Physics.Raycast(cam.ScreenPointToRay(Input.mousePosition),out hit))
{
drawMaterial.SetVector("_Coordinate", new Vector4(hit.textureCoord.x, hit.textureCoord.y, 0, 0));
RenderTexture temp = RenderTexture.GetTemporary(splatMap.width, splatMap.height, 0, RenderTextureFormat.ARGBFloat);
Graphics.Blit(splatMap, temp);
Graphics.Blit(temp, splatMap, drawMaterial);
RenderTexture.ReleaseTemporary(temp);
}
}
}
}
Thank you!
Btw. Does anyone know how to insert links with a name name on this forum? It is a bit messy to just post the entire link between the texts.