Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • 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
2
Question by jamesflowerdew · Apr 09, 2014 at 10:16 AM · meshframeratecombine

is there a more optimal way of drawing multiple meshes?

Hi there,

I've been working on ways to "grass and tree" non terrain meshes for months now, and so far the winner is using DrawMesh(), but this has problems. The most noticeable being that one drawcall is needed for every mesh that's rendered (I'm talking around 300 minimum here), and these could theoretically be all done with one drawcall. Is there a way to "batch" these meshes and positions at runtime (they change as you move around the lanscape, so it has to be fast). Here's my function that renders the meshes.

 void UpdateMultiMesh(){
     Vector3 vFront=pPos+gCam.forward;
     
     //moo
     pBigMesh=null;
     Vector3 vGrass;
     Camera vCam=gCam.camera;
     MaterialPropertyBlock vBlock=new MaterialPropertyBlock();
     float vSqrMaxDist=pMaxDist*pMaxDist;
     if(pGLength>0){
         for (int vGrassNum=0 ;vGrassNum<pGLength;vGrassNum++){
             vGrass=pGrasses[vGrassNum];
             Vector3 vDelta =vGrass-vFront;
             if (vDelta.sqrMagnitude<vSqrMaxDist){
                 Graphics.DrawMesh(pMeshes[vGrassNum % pMeshCount],vGrass,pIdentity,pMats[pMatIDs[vGrassNum]],5,vCam,0,vBlock,false,true);
             }
         }
     }
 }

I also tried building more complex single meshes by hand by adding vertices normals etc, but the speed was certainly no better. Again the code is below.

     void UpdateBigMesh(){
         if(pBigMesh==null){
             BuildBigMesh();
         }
         if(pGLength>0){
             GetBillboardVerts();    
             int vVert=0;
             int vVertRatio=4;
             if(pTris){
                 vVertRatio=3;
             }
             Vector3[] vVerts=new Vector3[pGrasses.Length*vVertRatio];
             Vector3[] vNors=new Vector3[pGrasses.Length*vVertRatio];
             if(vVerts.Length>65000){
                 Debug.Log("Too big! unity doesn't allow this :(");
                 return;
             }
             for (int vGrassNum=0 ;vGrassNum<pGLength;vGrassNum++){
                 pTempMesh=pMeshes[vGrassNum % pMeshCount];
                 Vector3 vGrass=pGrasses[vGrassNum];
                 vVert=vGrassNum*vVertRatio;
                 pTempMesh.vertices.CopyTo(vVerts,vVert);
                 pNormals.CopyTo(vNors,vVert);
                 for(int vNum=0;vNum<vVertRatio;vNum++){
                     vVerts[vVert+vNum]+=vGrass;
                 }
             }
             pBigMesh.normals=vNors;
             pBigMesh.vertices=vVerts;
             int vMat=0;
             if(pMatID<pMats.Length){
                 vMat=pMatID;
             }
             Graphics.DrawMesh(pBigMesh,Vector3.zero,pIdentity, pMats[vMat], 0);
         }
     }

Any pointers as to how to speed this up would be great, but the obvious thing seems be a queueing of all multi-meshes for just one draw call.

[Update: just figured out a combine meshes equivalent of the big mesh builder, but it's actually slower than building by hand as above]

sharing :

     void UpdateOtherBigMesh(){
         //if(pBigMesh==null){
             List<CombineInstance> combine = new List<CombineInstance>();
             CombineInstance vCombo=new CombineInstance();
            Matrix4x4 vTrans=transform.localToWorldMatrix;
             
             int vVerts=0;
             Vector3 vPos;
             for (int vGrassNum=0 ;vGrassNum<pGLength;vGrassNum++){
                 pTempMesh=pMeshes[vGrassNum % pMeshCount];
                 vVerts+=pTempMesh.vertices.Length;
                 if(vVerts<65000){
                     vCombo.mesh = pTempMesh;
                     vPos=pPosterGrasses[vGrassNum].pos;
                     vTrans[0,3]=vPos.x;
                     vTrans[1,3]=vPos.y;
                     vTrans[2,3]=vPos.z;
                     vCombo.transform =vTrans;
                        combine.Add(vCombo);
                 }
             }
             CombineInstance [] vRealCombo=combine.ToArray();
             pBigMesh = new Mesh();
             pBigMesh.CombineMeshes(vRealCombo);
         //}
         int vMat=0;
         if(pMatID<pMats.Length){
             vMat=pMatID;
         }
         Graphics.DrawMesh(pBigMesh,Vector3.zero,pIdentity, pMats[vMat], 0);
     }

Comment
Add comment · Show 5
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
avatar image jamesflowerdew · Jul 22, 2014 at 09:55 AM 0
Share

Is there an answer to this?

a method of grouping these drawcalls would revolutionise what I'm doing here :(

polygon cout seems to be of little impact until I go stupid with a really complex model, so evidently it is quite literally the multitudes of seperate draw calls that has the frame rate punch.

avatar image robertbu · Jul 22, 2014 at 02:01 PM 1
Share

I ran some experiments a year and a half ago, and found the same thing. Drawcalls would batch when I used game objects, but when I used Draw$$anonymous$$esh() drawcalls would not batch. Note that objects will not batch if you have over 900 vertex attributes. Consider combining your meshes.

avatar image jamesflowerdew · Jul 25, 2014 at 02:12 PM 0
Share

hi robertbu , thanks, I'm at that point but can't combine the sheer magnitude of things that I need here easily.

Williamleu that sounds like a brilliant idea re vertex or geometry shaders, do you have any pointers on that?

Can a vertex shader grab one vertex and bang out 4 verts with the approprate data to render a plane at the given point?

Can a surface shader be mucked about with like a vertex/fragment shader? I built this rather dodgy shader based on http://en.wikibooks.org/wiki/Cg_Program$$anonymous$$g/Unity/Billboards

 Shader "Cg  shader for billboards" {
    Properties {
       _$$anonymous$$ainTex ("Texture Image", 2D) = "white" {}
    }
    SubShader {
       Tags{"Queue"="Transparent"}
        Cull Off
     ZWrite Off
        Alphatest Greater[_CutOff]
     Blend SrcAlpha One$$anonymous$$inusSrcAlpha
       Pass {  
       
          CGPROGRA$$anonymous$$
  
          #pragma  vertex vert  
          #pragma fragment frag 
          uniform half4 _LightColor0;
          // User-specified uniforms            
          uniform sampler2D _$$anonymous$$ainTex; 
          struct vertexInput {
             float4 vertex : POSITION;
             float4 tex : TEXCOORD0;
          };
          struct vertexOutput {
             float4 pos : SV_POSITION;
             float4 tex : TEXCOORD0;
             
          };
          vertexOutput vert(vertexInput input)  {
              vertexOutput output;
              output.pos = mul(UNITY_$$anonymous$$ATRIX_P,mul(UNITY_$$anonymous$$ATRIX_$$anonymous$$V, float4(0.0, 0.0, 0.0, 1.0))+float4(input.vertex.x, input.vertex.y, -input.vertex.z, 0.0));
             output.tex =input.tex;
                return output;
          }
  
          float4 frag(vertexOutput input) : COLOR {
          //float4 c=
              return tex2D(_$$anonymous$$ainTex, float2(input.tex.xy)) *float4(_LightColor0.r,_LightColor0.g,_LightColor0.b,1);// * ( atten * 2);;   
          }
  
          ENDCG
       }
    }
 }

Then changed the frag for a surf, and added my own lighting model, no cigar. From what I can tell, surf uses "vertex" in place of "pos", but they seem to use different world/camera space coordinates as the results are wong.

$$anonymous$$y limited knowledge tells me that geometry shaders is that they can and more but are dx11 only, and the only samples I've found online don't work here so I'm nervous.

I'm sorry if my questions are stupid. The doccumentation that I've found online for shader development hasn't really helped me "get" shaders particularly, even if it has helped me build some quite nice ones.

avatar image WilliamLeu · Jul 25, 2014 at 02:45 PM 0
Share

Geometry shaders can create new things, vertex shaders can only transform existing vertices. There may be some sufficient web examples that you can port.

avatar image jamesflowerdew · Jul 25, 2014 at 04:47 PM 0
Share

hmmm :( already tried google, I'm sure that perfect search term is out there, but I haven't found it. also... animating is cool, but peripheral (I can do that). I'm at the "grass - fast" stage not the "wave" one. thanks anyway

1 Reply

· Add your reply
  • Sort: 
avatar image
2

Answer by WilliamLeu · Jul 23, 2014 at 02:43 AM

Depending on what you're doing for grass and foliage, you might want to consider going down the vertex or geometry shader route. Maybe assign UV2 to something that can be used to procedurally animate the verts in shader.

Comment
Add comment · Show 2 · 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
avatar image jamesflowerdew · Aug 22, 2014 at 10:31 AM 0
Share

hi WilliamLeu,

If "vertex shader" means vertex/fragment shader I'm already going down this route:

     Properties{
         _Color ("$$anonymous$$ain Color", Color) = (1,1,1,1)
         _$$anonymous$$ainTex ("Base (RGBA) ", 2D) = "white" {}
         _CutOff ("Cut Off", Range (0,1)) = 0.7
         _Speed ("Speed",Float) = .5
         _Power ("Power",Float) = .1
         _Translucency("Translucency",Range(0,1)) = .5
     }
     SubShader{
         Cull Off
         
         Tags { "RenderType"="Transparent" }
         AlphaTest Greater [_CutOff]
         LOD 200
         CGPROGRA$$anonymous$$
         #pragma surface surf Wrap$$anonymous$$oo vertex:vert alphatest:_CutOff addshadow halfasview
         float4 _Color;
         sampler2D _$$anonymous$$ainTex;
         float _Speed,_Power;
         half _Translucency;
         struct Input {
             float4 light;
             float2 uv_$$anonymous$$ainTex:TEXCOORD0;
             float alpha;
         };
 
 
         void vert(inout appdata_full v, out Input o) {
             UNITY_INITIALIZE_OUTPUT(Input,o);
             float vPos= v.vertex.x+v.vertex.y/100;
             float fsin,fcos;
             float vOffset=vPos+(_Time.z*_Speed);
             fsin=sin(vOffset);
             fcos=cos(vOffset);
             v.vertex.z+=fcos*_Power*v.vertex.y;
             v.vertex.x+=fsin*_Power*v.vertex.y;
         
         }
         void surf (Input IN, inout SurfaceOutput o) {
             fixed4 vAlb = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex);
             o.Albedo = vAlb.rgb*_Color;
             o.Alpha = vAlb.a;
         }
         
         half4 LightingWrap$$anonymous$$oo (SurfaceOutput s, half3 dir, half atten) {
               half4 c = _LightColor0 * ( atten * 2)+UNITY_LIGHT$$anonymous$$O$$anonymous$$_A$$anonymous$$BIENT;
               half NorLight = dot (s.Normal, dir);
               c = lerp(c*NorLight,c,_Translucency);
             c.rgb *= s.Albedo;
             c.a = s.Alpha;
             return c;
         }
         
         
 
         ENDCG
     }
 }

I include this rather over complex shader just to reiterate that this really isn't about waving, waving is cool.

If you mean fixed function shaders, maybe you can help me.

Ths far I haven't found a fixed function shader that can read lighting without reading the normals of it's mesh, and thus lighting stupidly as the camera pans arund it and it's angle to the light source changes.

Geometry shaders are dx11 to my knowledge (is this right?), and whilst my pc handles dx11 with love, it doesn't in unity or the webplayer without serious fiddling, and I'm not keen to encourage our web audience to go into their nVidia settings to configure internet explorer at this point.

$$anonymous$$aybe you mean something else? Conceptually I don't struggle with the idea of using something more akin to a mesh-based particle rendering system for grass, which may indeed be something that is done in the shader, as opposed to with meshes, but thus far, attempts of this sort in unity have not been very successful here.

avatar image jamesflowerdew · Aug 22, 2014 at 10:34 AM 0
Share

where I'm at: (appologies to future readers, these links will be temporary)

grass_test2

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.

Follow this Question

Answers Answers and Comments

22 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How/Where to learn about mesh operations? (help) 1 Answer

Combine meshes, Weld planes together 0 Answers

What's the Script for Combining Prefabs 2 Answers

Combine Objects/Meshes to reduce drawCalls 2 Answers

CombineChildren not working under ExecuteInEditMode() 1 Answer


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