• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Tyrathect · May 09, 2013 at 03:06 AM · shadergraphicssurface shadervertex shader

Can I unpack normal / tangent / uv information in the vertex function in a surface shader?

In the following code, I try to use indexes passed in as uv.x and uv.y to look up the tangent, normal, and actual uv for the vertex. I set up a mesh with a appropriate data (a cube) but the result is that the cube is always drawn black (the worldNormal always ends up as zero).

I've tried sending in a mesh with no normals, and no tangents, and I've also tried sending in a mesh with dummy normals and tangents. Neither seems to work.

Is there some way to make this sort of thing work? Is there some general way to pass in custom data, and use it to generate the actual vertex data?

I've included the shader and C# script code I use to build the mesh.

Here's the shader. Take a look at the vertex_unpacker function.

 Shader "Custom/CubeShader" {
     Properties {
         _MainTex ("Base (RGB)", 2D) = "white" {}
     }
     SubShader {
         Tags { "RenderType"="Opaque" }
         
         CGPROGRAM
         // Upgrade NOTE: excluded shader from DX11, Xbox360, OpenGL ES 2.0 because it uses unsized arrays
         #pragma exclude_renderers gles flash
         //d3d11 xbox360 
         #pragma surface surf Lambert vertex:vertex_unpacker
 
         sampler2D _MainTex;
         float3 _normals[6] = 
         {
             float3(1,0,0),
             float3(-1,0,0),
             float3(0,0,1),
             float3(0,0,-1),
             float3(0,1,0),
             float3(0,-1,0)
         };
         
         float4 _tangents[6] = 
         {
             float4(0,0,1,1),
             float4(0,0,-1,1),
             float4(-1,0,0,1),
             float4(1,0,0,1),
             float4(0,0,1,1),
             float4(0,0,-1,1)
         };
 
         float4 _uvs[4] =
         {
             float4(0,0,0,0),
             float4(1,0,0,0),
             float4(0,1,0,0),
             float4(1,1,0,0)
         };
     
 
         struct Input {
             float3 worldNormal;
         };
         
         void vertex_unpacker(inout appdata_full i) {
             int face = i.texcoord.x;
             int vx  = i.texcoord.y;
             i.normal = _normals[face];
             i.tangent = _tangents[face];
             i.texcoord = _uvs[vx];
         }
 
         void surf (Input IN, inout SurfaceOutput o) {
             o.Albedo = IN.worldNormal.xyz;
             o.Alpha = 1;
         }
         ENDCG
     } 
     FallBack "Diffuse"
 }

And here's the script that builds the cube:

 using UnityEngine;
 using System.Collections;
 
 public class CubeBuilder : MonoBehaviour {
 
     // Use this for initialization
     
     enum Faces
     {
         POSX,
         NEGX,
         POSZ,
         NEGZ,
         POSY,
         NEGY
     };
     
     enum C
     {
         RUF,
         RUB,
         LUF,
         LUB,
         
         RLF,
         RLB,
         LLF,
         LLB,
         
     };
     
     void Start () 
     {
         MeshFilter filter = GetComponent<MeshFilter>();
         if (filter != null)
         {
             Mesh mesh = new Mesh();
             filter.sharedMesh = mesh;
             Vector3[] cubeCorners = new Vector3[8];
             Vector3 v3 = Vector3.zero;
             for (int i = 0; i < 8; i++)
             {
                 v3.x = (i & 2) == 0 ? 1 : -1;
                 v3.y = (i & 4) == 0 ? 1 : -1;
                 v3.z = (i & 1) == 0 ? 1 : -1;
                 cubeCorners[i] = v3;
             }
             
            
             Vector3[] faceVertexes = new Vector3[24]
             {
                 cubeCorners[(int)C.RUB],
                 cubeCorners[(int)C.RUF],
                 cubeCorners[(int)C.RLB],
                 cubeCorners[(int)C.RLF],
                 
                 cubeCorners[(int)C.LUF],
                 cubeCorners[(int)C.LUB],
                 cubeCorners[(int)C.LLF],
                 cubeCorners[(int)C.LLB],
                 
                 cubeCorners[(int)C.RUF],
                 cubeCorners[(int)C.LUF],
                 cubeCorners[(int)C.RLF],
                 cubeCorners[(int)C.LLF],
                 
                 cubeCorners[(int)C.LUB],
                 cubeCorners[(int)C.RUB],
                 cubeCorners[(int)C.LLB],
                 cubeCorners[(int)C.RLB],
                 
                 cubeCorners[(int)C.LUF],
                 cubeCorners[(int)C.RUF],
                 cubeCorners[(int)C.LUB],
                 cubeCorners[(int)C.RUB],
                 
                 cubeCorners[(int)C.RLF],
                 cubeCorners[(int)C.LLF],
                 cubeCorners[(int)C.RLB],
                 cubeCorners[(int)C.LLB],
             };
             
             Vector2[] faceUVs = new Vector2[24];
             for(int face = 0; face < 6; face++)
                 for(int i = 0; i < 4; i++)
                 {
                     faceUVs[face*4+i] = new Vector2(face,i);
                 }
             
             
             int[] indexes = new int[36];
             
             for (int i = 0; i < 6; i++)
             {
                 int j = i*6;
                 int vxcount = i*4;
                 indexes[j++] = vxcount;
                 indexes[j++] = vxcount+1;
                 indexes[j++] = vxcount+2;
                 indexes[j++] = vxcount+2;
                 indexes[j++] = vxcount+1;
                 indexes[j++] = vxcount+3;
             }
             
             mesh.vertices = faceVertexes;
             mesh.uv = faceUVs;
             mesh.triangles = indexes;
         }
     }
     
     // Update is called once per frame
     void Update () {
     
     }
 }
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Tyrathect · May 09, 2013 at 03:15 PM

Thanks for looking at this.

worldNormal gets filled in automatically. If you replace line 51 of the shader with i.normal = float3(1,0,0), you get appropriate output. It has to work this way because some of the data you get in the fragment shader relies on the tangent space calculation which you can't set explicitly. Some things have to be set automatically.

I've verified that the indexes are passed in correctly by outputting them directly as color, so the only thing left is that the tables aren't getting filled in. There must be another way to declare this type of constant data.


UPDATE:

I think this boils down to not being able to set the data in the _normals/_tangents/_uvs arrays.

The data doesn't appear to be available when the program is run, and as far as I can tell there's no way to set an array from a script.

This seems like a serious oversight. I'll see if I can find some more information.


UPDATE 2

Using the workaround posted here I got it to work, but I'm guessing that I'm doing an extra API call for each member of the array now, which is sad.

It sure would be easier to have a real array type, but everything else worked just fine (and I didn't need to use dummy normals or tangents).

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

13 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Vertex-fragment shader pass not working in WebGL build. 0 Answers

How to get pure black shadow on gradient shader 0 Answers

How do I modify this shader to receive shadows ??? 0 Answers

Shadow artifacts on vertex animation shader 1 Answer

'vert': output parameter 'o' not completely initialized 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges