1
\$\begingroup\$

I mocked up a shader how I wanted it with the node editor in Blender. Now I'm trying to write it in HLSL. In Blender there is a node group called "Texture Coordinate". If I use the "uv" node from the group it behaves like a normal unlit frag shader but if I use the "object" node to give coordinates to the texture, it ignores the uv data and just maps the texture like an image overlayed onto the object.

This is actually the effect I want. However, I can't find a way to replicate this in HLSL. As far as I can see I can use TEXCOORD0 and POSITION as texture coordinates to produce uv mapping and world mapping respectively for a texture onto an object. Maybe what I want is object mapping?

And if it matters I'm using a generated texture

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

The Texture Coordinate node is commonly used for the coordinates of textures, typically used as inputs for the Vector input for texture nodes.

Object Node

enter image description here

enter image description here

Shader "Blender/ObjectNode"
{
    SubShader
    {

        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;
                float4 worldPos : TEXCOORD2;
            };

            float4 _Pos;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                return i.worldPos;
            }
            ENDCG
        }
    }
}

Generated Node

you can achive generated node by Remapping world position from [-1,1] to [1,0]

enter image description here

enter image description here

 Shader "Blender/GeneratedNode"
{
    SubShader
    {

        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;
                float4 worldPos : TEXCOORD2;
            };

            float4 _Pos;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                return i.worldPos*0.5+0.5;
            }
            ENDCG
        }
    }
}

Remapping is a way to extending coordinates: enter image description here

Resetting Position

as you now when we move object in blender we have this result:

enter image description here

but in unity we haven't same result:

enter image description here

we should reset position to fixing this problem:

enter image description here

Shader "Blender/ObjectNode"
{
    Properties
    {
        _Pos("Pos",Vector) = (0,0,0,0)
    }
    SubShader
    {

        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;
                float4 worldPos : TEXCOORD2;
            };

            float4 _Pos;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex-_Pos);
                o.uv = v.uv;
                return o;
            }
            
            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                return i.worldPos;
            }
            ENDCG
        }
    }
}

then attach this script to your object to updating position:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class ResetPos : MonoBehaviour {
    void Update () {
        GetComponent<MeshRenderer>().material.SetVector("_Pos",transform.position);     
    }
}

Update

ObjectNode

Shader "ObjectNode" {
    Properties {
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
 
        CGPROGRAM
        #pragma surface surf Lambert vertex:vert
 
        struct Input {
            float3 objPos;
        };
 
        void vert (inout appdata_full v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input,o);
            o.objPos = v.vertex;
        }
 
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = IN.objPos;
            o.Alpha = 1;
        }
        ENDCG
    }
}

GeneratedNode

Shader "GeneratedNode" {
    Properties {
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
 
        CGPROGRAM
        #pragma surface surf Lambert vertex:vert
 
        struct Input {
            float3 objPos;
        };
 
        void vert (inout appdata_full v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input,o);
            o.objPos = v.vertex;
        }
 
        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = IN.objPos*0.5+0.5;
            o.Alpha = 1;
        }
        ENDCG
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Wow this is such a good answer! I'm glad to to know how to achieve "generated" but the one I actually specified was the "object" node like you have in your blender screencap. The remapping secret to that? Thanks! Also how did you find this out? I couldn't find any resources about object texture coordinates in written shaders online or even a list of a types of texture coordinates. \$\endgroup\$
    – Willem
    Commented Feb 13, 2019 at 22:03
  • \$\begingroup\$ @Willem can you tell me what is missing in my answer? I explained "object" node? what is problem? because if my answer was correct you should accepted it.do you need more detailed answer? anyway I will updated my answer \$\endgroup\$ Commented Feb 14, 2019 at 5:04
  • \$\begingroup\$ useful link: github.com/UnityCommunity/UnityLibrary/wiki/… and halisavakis.com/shader-bits-world-and-screen-space-position \$\endgroup\$ Commented Feb 14, 2019 at 5:05
  • \$\begingroup\$ Ok this all seems good except I'm now struggling to account for rotation of the object. How to make sure the generated texture follows the objects rotation? Thanks \$\endgroup\$
    – Willem
    Commented Mar 1, 2019 at 15:10
  • \$\begingroup\$ @Willem I edit my question.by using object position everything is done! sorry I shouldn't use world position. \$\endgroup\$ Commented Mar 2, 2019 at 4:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .