Jump to content
Unity Insider Forum
  • Announcements

    • Lars

      Allgemeine Forenregeln   03/13/2017

      Forenregeln Nimm dir bitte einen Moment um die nachfolgenden Regeln durchzulesen. Wenn du diese Regeln akzeptierst und die Registration fortsetzen willst, klick einfach auf den "Mit der Registrierung fortfahren"-Button. Um diese Registration abzubrechen, klick bitte einfach auf den "Zurück" Button deines Browsers. Wir garantieren nicht für die Richtigkeit, Vollständigkeit und Brauchbarkeit der Nachrichten und sind auch nicht dafür verantwortlich. Die Beiträge drücken die Meinung des Autors des Beitrags aus, nicht zwangsläufig das, wofür die Forensoftware steht. Jeder Nutzer, der denkt, dass ein veröffentlichter Beitrag unzulässig bzw. störend ist, ist aufgefordert uns unverzüglich per E-Mail zu kontaktieren. Wir haben das Recht störende Beiträge zu löschen und bemühen uns, das in einem realistischem Zeitraum zu erledigen (sofern wir beschlossen haben, dass die Löschung notwendig ist). Du akzeptierst, durchgehend während der Nutzung dieses Services, dass du dieses Forum nicht dazu missbrauchen wirst, Inhalte zu veröffentlichen, welche bewusst falsch und/oder verleumderisch, ungenau, beleidigend, vulgär, hasserfüllt, belästigend, obszön, sexuell belästigend, bedrohlich, die Privatsphäre einer Person verletzend oder in irgend einer Art und Weise das Gesetz verletzen. Des Weiteren akzeptierst du, dass du keine urheberrechtlich geschützte Inhalte ohne Erlaubnis des Besitzers in diesem Forum veröffentlichst. Mit dem Klick auf den "Mit der Registrierung fortfahren"-Button, akzeptierst du zudem unsere Datenschutzerklärung und stimmst der Speicherung deiner IP-Adresse und personenbezogenen Daten zu, die dafür benötigt werden, um dich im Falle einer rechtswidrigen Tat zurückverfolgen zu können bzw. permanent oder temporär aus dem Forum ausschließen zu können. Es besteht keine Pflicht zur Abgabe der Einwilligung, dies erfolgt alles auf freiwilliger Basis.   Zusatzinformationen Der Forenbetreiber hat das Recht, Nutzer ohne Angabe von Gründen permanent aus dem Forum auszuschließen. Des Weiteren hat er das Recht, Beiträge, Dateianhänge, Umfrage, Blogeinträge, Galleriebilder oder Signaturen ohne Angabe von Gründen zu entfernen. Mit der Registrierung verzichtest du auf alle Rechte an den von dir erstellten Inhalten, bzw. treten diese an das Unity-Insider.de und Unity-Community.de ab. Dies bedeutet im Klartext, dass das Unity-Insider.de und Unity-Community.de frei über deine Texte verfügen kann, sofern diese nicht wiederum die Rechte anderer verletzen. Es besteht weiterhin kein Anspruch von registrierten Nutzern bzw. ehemaligen registrierten Nutzern darauf, dass erstellte Inhalte und/oder die Mitgliedschaft (User) wieder gelöscht werden (Erhaltung der Konsistenz dieses Forums).   Einwilligungserklärung Wenn du mit der Speicherung deiner personenbezogenen Daten sowie den vorstehenden Regeln und Bestimmungen einverstanden bist, kannst du mit einem Klick auf den Mit der Registrierung fortfahren-Button unten fortfahren. Ansonsten drücke bitte Zurück. Stand: 07.03.2011

Zer0Cool

Members
  • Content count

    1,844
  • Joined

  • Last visited

  • Days Won

    130

Zer0Cool last won the day on March 30

Zer0Cool had the most liked content!

Community Reputation

387 Excellent

7 Followers

About Zer0Cool

  • Rank
    Advanced Member
  • Birthday 01/04/1974

Contact Methods

  • Website URL
    http://https://www.facebook.com/huginmuninstudios
  • Skype
    zer0f0rce

Profile Information

  • Gender
    Male
  • Location
    Germany

Recent Profile Visitors

4,098 profile views
  1. Mass Place Trees/Grass/Rocks etc.

    Hab am Shader nur die Schwingfrequenz geändert, verzerren tut sich da eigentlich nix, daß muss dann ein anderes Problem sein, hast du den Mesh geändert? Hier der Shader ohne die Schwingfrequenzänderung, aber ich vermute das dies nicht das Problem war, Vielleicht hattest du auch an den Variablen des Shaders gedreht und diese haben sich nun durch das erneute Einspielen des Shader zurückgesetzt ? Shader "Custom/Grass/GrassBending" { Properties{ _Color("Main Color", Color) = (1,1,1,1) //_MainTex("Base (RGB) Trans (A)", 2D) = "white" {} _MyArr("Tex", 2DArray) = "" {} _Cutoff("Alpha cutoff", Range(0,1)) = 0.5 _ShakeDisplacement("Displacement", Range(0, 1.0)) = 1.0 _ShakeTime("Shake Time", Range(0, 1.0)) = 1.0 _ShakeWindspeed("Shake Windspeed", Range(0, 1.0)) = 1.0 _ShakeBending("Shake Bending", Range(0, 1.0)) = 1.0 } SubShader{ Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" } LOD 200 Cull Off CGPROGRAM // to use texture arrays we need to target DX10/OpenGLES3 which // is shader model 3.5 minimum #pragma target 3.5 #pragma surface surf Lambert alphatest:_Cutoff vertex:vert addshadow UNITY_DECLARE_TEX2DARRAY(_MyArr); // sampler2D _MainTex; // fixed4 _Color; float _ShakeDisplacement; float _ShakeTime; float _ShakeWindspeed; float _ShakeBending; float dist; float _GrassAlpha; struct Input { //float2 uv_MainTex; float2 uv_MyArr; float3 worldPos; }; void FastSinCos(float4 val, out float4 s, out float4 c) { val = val * 6.408849 - 3.1415927; float4 r5 = val * val; float4 r6 = r5 * r5; float4 r7 = r6 * r5; float4 r8 = r6 * r5; float4 r1 = r5 * val; float4 r2 = r1 * r5; float4 r3 = r2 * r5; float4 sin7 = { 1, -0.16161616, 0.0083333, -0.00019841 }; float4 cos8 = { -0.5, 0.041666666, -0.0013888889, 0.000024801587 }; s = val + r1 * sin7.y + r2 * sin7.z + r3 * sin7.w; c = 1 + r5 * cos8.x + r6 * cos8.y + r7 * cos8.z + r8 * cos8.w; } // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_CBUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) UNITY_DEFINE_INSTANCED_PROP(float, _TextureIndex) // put more per-instance properties here UNITY_INSTANCING_CBUFFER_END void vert(inout appdata_full v) { float factor = (1 - _ShakeDisplacement - v.color.r) * 0.5; const float _WindSpeed = (_ShakeWindspeed + v.color.g); const float _WaveScale = _ShakeDisplacement; const float4 _waveXSize = float4(0.048, 0.06, 0.24, 0.096); const float4 _waveZSize = float4 (0.024, .08, 0.08, 0.2); const float4 waveSpeed = float4 (1.2, 2, 1.6, 4.8); float4 _waveXmove = float4(0.024, 0.04, -0.12, 0.096); float4 _waveZmove = float4 (0.006, .02, -0.02, 0.1); float4 waves; waves = v.vertex.x * _waveXSize; waves += v.vertex.z * _waveZSize; waves += _Time.x * (1 - _ShakeTime * 2 - v.color.b) * waveSpeed *_WindSpeed; float4 s, c; waves = frac(waves); FastSinCos(waves, s,c); float waveAmount = v.texcoord.y * (v.color.a + _ShakeBending); s *= waveAmount; s *= normalize(waveSpeed); s = s * s; float fade = dot(s, 1.3); s = s * s; float3 waveMove = float3 (0,0,0); waveMove.x = dot(s, _waveXmove); waveMove.z = dot(s, _waveZmove); v.vertex.xz -= mul((float3x3)unity_WorldToObject, waveMove).xz; } void surf(Input IN, inout SurfaceOutput o) { //fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(_Color); fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_MyArr, float3(IN.uv_MyArr, UNITY_ACCESS_INSTANCED_PROP(_TextureIndex))) * UNITY_ACCESS_INSTANCED_PROP(_Color); o.Albedo = c.rgb; float dist = distance(_WorldSpaceCameraPos, IN.worldPos); dist = clamp(dist / 300, 0.4, 1.0); o.Alpha = c.a - dist - _GrassAlpha; } ENDCG } Fallback "Transparent/Cutout/VertexLit" } Die Textur kannst du hier ändern, 256x1 gibt es nicht, aber du kannst 256x256 einstellen: / See Texture2DArray in unity scripting API. Texture2DArray textureArray = new Texture2DArray(256, 256, slices, TextureFormat.RGBA32, false);
  2. Mass Place Trees/Grass/Rocks etc.

    Ich habe oben das Skript noch einmal verändert, da das Übergeben der Properties im Falle "ohne GOs" noch falsch war. Du kannst das Ganze anwenden wie du lustig bist. Das Problem im Falle ohne GOs ist (also die nicht interaktiven Grasinstanzen), hier sind die Instanzen auf 1023 limitiert und daher müsstest du das obige Beispielskript erweitern, so das es die Gras-Details in Chunks von 1023 gerendert werden. Das bedeutet 1 DC für 1023 Instanzen. "Graphics.DrawMeshInstanced" kann leider nur 1023 Instanzen auf einmal rendern. "Normale Grasmengen" bewegen sich so um die 100000 Instanzen..., d.h. du würdest letztendlich 100 DCs für das Gras benötigen... Das interaktive Gras würdest du dann mit GOs erzeugen. Hier würde ich einem quadratischen Bereich um den Spieler definierten. Also Zusammenfassung: - du berechnest Positionen für alle Grasinstanzen, diese können auch über ein Tool erzeugt werden - diese Positionen werden entweder mit GO oder ohne GO gerendert (siehe Skript oben) - die GOs keinesfalls jedes Frame neu erzeugen, sondern nur die Positionen umsetzen - die Spielerposition definiert die Anzahl und Positionen der interaktiven Instanzen je Frame! - interaktive Instanzen mit GOs werden um den Spieler herum gerendert (beispielsweise 5x5 Meter) - alle anderen nicht interaktiven Grasinstanzen werden ohne GOs in Chunks von 1023 gerendert - die interaktiven Grasinstanzen werden jedes Frame von nicht interaktiven Instanzen abgezogen Besser wäre es evtl. zu tricksen, du kannst auch alle Grasinstanzen einfach ohne GOs rendern! und die interaktiven Grasinstanzen als leere GOs in die Scene packen. Damit musst du das Array für die nicht interaktiven Instanzen nicht jedes Frame ändern und das spart viel FPS! Sobald der Spieler beispielsweise Grasdetails entfernt hat (modifiziert) hat, werden diese aus dem Array für die nicht interaktiven Grasdetails entfernt. Das Ganze ist leider nicht optimal, da eine Änderung am Array immer eine CPU Belastung auslöst, es wäre also günstig, die Änderung des Arrays für die Grasinstanzen nicht jedes Frame zu ändern. Ein anderes Problem ist noch die pure Menge an Grasdetails. Bei "Graphics.DrawMeshInstanced" werden immer alle Grasinstanzen übergeben, die gerendert werden sollen. Diese werden nicht über Distanz oder der Kamera gecullt. Dafür muss man selbst sorgen. Eine Mögliche Lösung ohne Computeshader wäre sein Terrain in Chunks aufzuteilen und Chunks zu rendern die in Spielernähe sind. Jedes Chunk würde dabei seine Grasdetails kennen und diese Rendern. Entfernt sich ein Spieler zu weit vom Chunk wird dieser deaktiviert. Aber wie du siehst, ist das Ganze dennoch recht komplex (auch wenn ich den Weg dargestellt habe), weshalb ich auch mein eigenes Gras-Shader-System gestartet. Zumal man das Ganze mit Computeshadern kombinieren kann und eben auch Instancing Indirekt verwenden kann.
  3. Mass Place Trees/Grass/Rocks etc.

    Du wolltest doch einen Shader der mehrere Texturen verwenden kann?
  4. Mass Place Trees/Grass/Rocks etc.

    So, hier der Shader. Ich habe ihn noch etwas verbessert, daß alle Instanzen nicht gleich schwingen. Der Shader verwendet eigentlich Vertexfarben für die Instanzen, aber scheinbar wurde er umgeschrieben, so daß er auch ohne Vertexfarben funktioniert. Shader "Custom/Grass/GrassBending" { Properties{ _Color("Main Color", Color) = (1,1,1,1) //_MainTex("Base (RGB) Trans (A)", 2D) = "white" {} _MyArr("Tex", 2DArray) = "" {} _Cutoff("Alpha cutoff", Range(0,1)) = 0.5 _ShakeDisplacement("Displacement", Range(0, 1.0)) = 1.0 _ShakeTime("Shake Time", Range(0, 1.0)) = 1.0 _ShakeWindspeed("Shake Windspeed", Range(0, 1.0)) = 1.0 _ShakeBending("Shake Bending", Range(0, 1.0)) = 1.0 } SubShader{ Tags{ "Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout" } LOD 200 Cull Off CGPROGRAM // to use texture arrays we need to target DX10/OpenGLES3 which // is shader model 3.5 minimum #pragma target 3.5 #pragma surface surf Lambert alphatest:_Cutoff vertex:vert addshadow UNITY_DECLARE_TEX2DARRAY(_MyArr); // sampler2D _MainTex; // fixed4 _Color; float _ShakeDisplacement; float _ShakeTime; float _ShakeWindspeed; float _ShakeBending; float dist; float _GrassAlpha; struct Input { //float2 uv_MainTex; float2 uv_MyArr; float3 worldPos; }; void FastSinCos(float4 val, out float4 s, out float4 c) { val = val * 6.408849 - 3.1415927; float4 r5 = val * val; float4 r6 = r5 * r5; float4 r7 = r6 * r5; float4 r8 = r6 * r5; float4 r1 = r5 * val; float4 r2 = r1 * r5; float4 r3 = r2 * r5; float4 sin7 = { 1, -0.16161616, 0.0083333, -0.00019841 }; float4 cos8 = { -0.5, 0.041666666, -0.0013888889, 0.000024801587 }; s = val + r1 * sin7.y + r2 * sin7.z + r3 * sin7.w; c = 1 + r5 * cos8.x + r6 * cos8.y + r7 * cos8.z + r8 * cos8.w; } // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_CBUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) UNITY_DEFINE_INSTANCED_PROP(float, _TextureIndex) // put more per-instance properties here UNITY_INSTANCING_CBUFFER_END void vert(inout appdata_full v) { float factor = (1 - _ShakeDisplacement - v.color.r) * 0.5; const float _WindSpeed = (_ShakeWindspeed + v.color.g); const float _WaveScale = _ShakeDisplacement; const float4 _waveXSize = float4(0.048, 0.06, 0.24, 0.096); const float4 _waveZSize = float4 (0.024, .08, 0.08, 0.2); const float4 waveSpeed = float4 (1.2, 2, 1.6, 4.8); float4 _waveXmove = float4(0.024, 0.04, -0.12, 0.096); float4 _waveZmove = float4 (0.006, .02, -0.02, 0.1); float4 waves; waves = v.vertex.x * _waveXSize; waves += v.vertex.z * _waveZSize; // Worldkoordinaten berechen, um eine Zufallsfrequenz zu erzeugen float4 worldPos = mul(unity_ObjectToWorld, v.vertex); waves += (_Time.x + worldPos.x + worldPos.y + worldPos.z) * (1 - _ShakeTime * 2 - v.color.b) * waveSpeed *_WindSpeed; float4 s, c; waves = frac(waves); FastSinCos(waves, s,c); float waveAmount = v.texcoord.y * (v.color.a + _ShakeBending); s *= waveAmount; s *= normalize(waveSpeed); s = s * s; float fade = dot(s, 1.3); s = s * s; float3 waveMove = float3 (0,0,0); waveMove.x = dot(s, _waveXmove); waveMove.z = dot(s, _waveZmove); v.vertex.xz -= mul((float3x3)unity_WorldToObject, waveMove).xz; } void surf(Input IN, inout SurfaceOutput o) { //fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(_Color); fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_MyArr, float3(IN.uv_MyArr, UNITY_ACCESS_INSTANCED_PROP(_TextureIndex))) * UNITY_ACCESS_INSTANCED_PROP(_Color); o.Albedo = c.rgb; float dist = distance(_WorldSpaceCameraPos, IN.worldPos); dist = clamp(dist / 300, 0.4, 1.0); o.Alpha = c.a - dist - _GrassAlpha; } ENDCG } Fallback "Transparent/Cutout/VertexLit" } Dieser Shader wird nun auf einem Material angewendet mit einem Textur-Array-Asset. Das TexturArray-Asset kannst du überfolgende Klasse erzeugen. Wichtig: - die Arraygröße ist im Code auf 1024 festgelegt, d.h. alle Texturen brauchen eine Größe von 1024x1024 - die Anzahl der Texturen habe ich aktuell auf 2 festgelegt - alle Texturen müssen Read-Write-Enabled werden! using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; public class CreateTexture2DArray : EditorWindow{ [MenuItem("GameObject/Create Texture Array")] static void Create() { string filename; // CHANGEME: Number of textures you want to add in the array int slices = 2; // See Texture2DArray in unity scripting API. Texture2DArray textureArray = new Texture2DArray(1024, 1024, slices, TextureFormat.RGBA32, false); for (int i = 0; i < slices; i++) { filename = EditorUtility.OpenFilePanel("Select Texture for Array", Application.dataPath, "png"); filename = filename.Replace(Application.dataPath, "Assets"); if (filename.Length != 0) { Texture2D tex = (Texture2D)AssetDatabase.LoadAssetAtPath(filename, typeof(Texture2D)); Debug.Log("Loading " + filename); Debug.Log(tex.width); Debug.Log(tex.height); textureArray.SetPixels(tex.GetPixels(0), i, 0); } } textureArray.Apply(); filename = EditorUtility.SaveFilePanel("Select name for texture array asset", Application.dataPath, "TextureArray", "asset"); filename = filename.Replace(Application.dataPath, "Assets"); if (filename.Length != 0) { AssetDatabase.CreateAsset(textureArray, filename); Debug.Log("Saved asset to " + filename); } } } Und zu guter Letzt noch ein Stück Code, wo du sehen kannst, wie man den Shader sowohl für Instancing mit GOs und ohne GOs ansteuert: using System.Collections.Generic; using UnityEngine; public class InstancingTester : MonoBehaviour { #region Public properties public bool withGOs = false; public bool debug = false; public GameObject prefab; public int instanceCount = 10000; // grass detail number public int seed; public Vector2 size; public float startHeight = 1000; public float grassOffset = 0.0f; #endregion #region Private properties private Mesh instanceMesh; private Material instanceMaterial; private bool updatePositions = false; private List<Matrix4x4> matrices; private MaterialPropertyBlock properties; private Vector4[] colors; private float[] textures; #endregion void Start() { instanceMesh = prefab.GetComponent<MeshFilter>().sharedMesh; instanceMaterial = prefab.GetComponent<Renderer>().sharedMaterial; if (withGOs) DrawMeshesWithGO(); } void Update() { if (!withGOs) { // Update starting position buffer if (!updatePositions) UpdateBuffersDrawMeshInstanced(); Graphics.DrawMeshInstanced(instanceMesh, 0, instanceMaterial, matrices, properties); } } void UpdateBuffersDrawMeshInstanced() { Random.InitState(seed); properties = new MaterialPropertyBlock(); matrices = new List<Matrix4x4>(instanceCount); colors = new Vector4[instanceCount]; textures = new float[instanceCount]; for (int i = 0; i < instanceCount; i++) { Vector3 origin = transform.position; origin.y = startHeight; origin.x += size.x * Random.Range(-0.5f, 0.5f); origin.z += size.y * Random.Range(-0.5f, 0.5f); Ray ray = new Ray(origin, Vector3.down); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { origin = hit.point; origin.y += grassOffset; matrices.Add(Matrix4x4.TRS(origin, Quaternion.identity, Vector3.one)); // Setze Random Farbe colors[i] = new Color(Random.value, Random.value, Random.value); // Setze Random Texturindex textures[i] = (float)Random.Range(0, 2); } } properties.SetVectorArray("_Color", colors); properties.SetFloatArray("_TextureIndex", textures); updatePositions = true; } void DrawMeshesWithGO() { properties = new MaterialPropertyBlock(); for (int i = 0; i < instanceCount; i++) { Vector3 origin = transform.position; origin.y = startHeight; origin.x += size.x * Random.Range(-0.5f, 0.5f); origin.z += size.y * Random.Range(-0.5f, 0.5f); Ray ray = new Ray(origin, Vector3.down); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { origin = hit.point; origin.y += grassOffset; GameObject t = Instantiate(prefab); t.transform.localPosition = origin; t.transform.SetParent(transform); // Setze Random Farbe properties.SetColor("_Color", new Color(Random.value, Random.value, Random.value)); // Setze Random Texturindex properties.SetFloat("_TextureIndex", (float)Random.Range(0,2)); t.GetComponent<MeshRenderer>().SetPropertyBlock(properties); } } } } Der Testcode braucht einen Collider unter dem GameObjekt in der Szene. Dies kann ein Terrain oder ein Mesh sein. Die Instanzen werden per Zufall gesetzt und bekommen eine Zufallsfarbe und eine Zufallstextur. Der Vector size definiert die Größe der Fläche beispielsweise 10x10.
  5. Mass Place Trees/Grass/Rocks etc.

    Wird doch etwas kniffelig, da Texturen nur als Texture-Array übergeben werden können und nun muss ich erst einmal ein Texture-Array erzeugen, damit ich dann den Shader testen kann... aber das hat schon einmal geklappt
  6. Mass Place Trees/Grass/Rocks etc.

    Ok ich versuche mal den Shader für Color und Textur umzuschreiben.
  7. Mass Place Trees/Grass/Rocks etc.

    Die Farbe wird an das Material so übergeben. "fixed4" steht für einen Vector mit 4 Floats was gleichbedeutend mit einer Color in Unity ist. MaterialPropertyBlock props = new MaterialPropertyBlock(); MeshRenderer renderer; foreach (GameObject obj in objects) { float r = Random.Range(0.0f, 1.0f); float g = Random.Range(0.0f, 1.0f); float b = Random.Range(0.0f, 1.0f); props.SetColor("_Color", new Color(r, g, b)); renderer = obj.GetComponent<MeshRenderer>(); renderer.SetPropertyBlock(props); } Ich kann dir gerne einmal ein kleines Demoprojekt erstellen, wenn dir das alles zu verwirrend ist, damit du einen Startpunkt hast.
  8. Mass Place Trees/Grass/Rocks etc.

    Leider ist mein Grasshader noch nicht fertig (es fehlt noch ein Tool zum Platzieren von Gras und ich wollte auch noch Occlusion Culling einbauen), sonst könnte ich dir hier leicht sowas einbauen. Wenn du noch etwas warten kannst, ich denke mein Grassshader ist in 1-2 Monaten soweit. Ansonsten würde ich hier einen kleinen Trick anwenden und erst einmal "leichtere Variante" also Instanzing Direct verwenden (die Performance ist dann vielleicht nicht optimal aber annehmbar). Ich würde das Gras welches nicht in der Nähe des Spielers ist per Instancing ohne Gameobjekte darstellen und die Positionen per Code an Graphics.DrawMeshInstanced übergeben. Du kannst allerdings hier immer nur 1023 Graspositionen auf einmal übergeben! Das Gras in der Nähe des Spielers würde ich dabei aussparen und dieses Gras dann als GameObjekte darstellen, aber auch mit Instancing. Damit kannst du dann alles mögliche mit diesem Gras in der Nähes des Spieler anstellen wie Collider verpassen, Skripte verpassen oder sonstiges. Hier ein Beispielcode für das nicht interaktive Gras mit Rendering über Instanzing Direct: List<Matrix4x4> transformList = new List<Matrix4x4>(); Mesh cubeMesh; Material cubeMaterial; //These for loops create offsets from the position at which you want to draw your cube built from cubes. for(int x = -1; x < 1; x++) { for(int y = -1; y < 1; y++) { for(int z = -1; x < 1; z++) { //We will assume you want to create your cube of cubes at 0,0,0 Vector3 position = new Vector3(0, 0, 0); //Take the origin position, and apply the offsets position.x += x; position.y += y; position.z += z; //Create a matrix for the position created from this iteration of the loop Matrix4x4 matrix = new Matrix4x4(); //Set the position/rotation/scale for this matrix matrix.SetTRS(position, Quaternion.Euler(Vector3.zero), Vector3.one); //Add the matrix to the list, which will be used when we use DrawMeshInstanced. transformList.Add(matrix); } } } //After the for loops are finished, and transformList has several matrices in it, simply pass DrawMeshInstanced the mesh, a material, and the list of matrices containing all positional info. Graphics.DrawMeshInstanced(cubeMesh, 0, cubeMaterial, transformList); Nun musst du nur noch entscheiden, welche Eigenschaften des Grases zusätzlich variieren sollen. Die Postion des Grases wird dabei über die GameObjekte in der Szene bestimmt (Nahgras) oder per Code (siehe oben) für Ferngras. Normalerweise variiert man die Farbe oder eben auch die Texturen per Grassinstanz. Ich kann dir gerne einen Shader erstellen (aus obigem Code), mit welchen du diese beiden Properties variieren kannst.
  9. Mass Place Trees/Grass/Rocks etc.

    Dieser Shader unterstützt kein Instancing, auch kein Instancing indirekt. Die Performance verändert sich vermutlich aufgrund eines veränderten Renderings. Wenn du beispielsweise vorher einen Transparent-Shader mit Blending verwendet hast verbraucht dieser mehr Performance, der obige Shader macht einen "Cutout" und dieser ist wesentlich schneller. Einen Shader der "normales" Instancing (oder auch direktes Instancing) unterstützt erkennst du so im Shadercode: UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) // <= Diese Zeile definiert eine Property die instanziiert wird! In diesem Fall die Farbe. UNITY_INSTANCING_BUFFER_END(Props) Einen Shader der mit Instancing indirect arbeitet erkennst an diesem Codeschnipsel: void setup() { #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED ... // An dieser Stelle übergibt der Shader entweder Matrizdaten oder er berechnet diese Matrizen aus Position / Scale und Rotation // Der Shader benötigt an dieser Stelle die Daten der Matrizen für jede einzelne Instanz. // Die benötigten Matrizen je Instanz sind unity_WorldToObject und unity_ObjectToWorld ... #endif } Was sind die Unterschiede zwischen Instancing (direct) und Instancing indirect? Ich habe mal eine kleine Liste erstellt nach meinem Kenntnisstand (eine 100%tige Trennung ist schwierig, da sie beide Methoden teilweise überschneiden): Performance Instancing indirect ist schneller, da keine Gameobjekte in der Szene verwendet werden und daher der GameObjekt-Overhead entfällt Instancing direct ist einfacher anzuwenden, da dem Shader keine Matrizen übergeben werden müssen die Objekte sind in der Unityszene vorhanden und werden über Unity gebatched und an den Instancing Shader als Batch übergeben (man sieht den Performancevorteil an den sinkenden DCs im Debugfenster) Instancing direct arbeitet mit vorhandenen GameObjekten innerhalb der Unityszene oder mit Graphics.DrawMeshInstanced Die Instanzdaten kommen also entweder aus den GameObjekten innerhalb der Szene oder werden über Graphics.DrawMeshInstanced übergeben Instancing indirect arbeitet ohne GameObjekte in der Unityszene Die Instanzdaten müssen per Skript erzeugt werden und werden über Graphics.DrawMeshInstancedIndirect gerendert Beim Instancing direct ist die Anzahl der Instanzen pro DC auf 1023 Instanzen beschränkt (siehe Graphics.DrawMeshInstanced) Beispiel Instancing direct: https://docs.unity3d.com/Manual/GPUInstancing.html Beispiel Instancing indirect: https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html Anmerkung: Sobald man ohne GameObjekte innerhalb der Szene arbeitet entfallen Frustum Culling (Kamera Culling) und Occlusion Culling. Der Grund ist einfach, beide Features benötigen GameObjekte und sobald diese nicht mehr verwendet werden, muss man sich selbst um das Culling kümmern (dieses macht dann richtig Arbeit bei einer eigenen Grasshaderlösung) Wenn du unbedingt (wovon ich allerdings abraten würde) jedem Grashalm ein Skript zuweisen musst wäre die beste Methode Instancing direkt mit GameObjekten in der Szene. Warum möchtest du jeder Grasinstanz ein Skript zuweisen?
  10. Bei in Unity erstellten Animationen ist es ein wenig anders (.anim-Files) als bei FBX Files. Hier kann man sich entscheiden, ob Root-Motion-Data erzeugt werden soll oder nicht. Dein Problem könnte wie gesagt schon damit zusammenhängen, zudem du dir scheinbar nicht im Klaren darüber bist, ob deine Animation Root-Motion verwendet oder nicht: https://unity3d.com/de/learn/tutorials/topics/animation/authoring-root-motion Das kein Button fürs Erzeugen von Root-Motion da ist könnte daran liegen, daß du nur Childs deines Animationsobjektes animierst. Aber laut deines Gifs von oben hat deine Jump Up-Animation auch keine Bewegung des deines Sprites nach oben, nur die Jump Down schiebt das Sprite nach unten. Sieht also nach "einem Fehler" in der Jump-Up-Animation aus. Für mich sind aber beiden Animationen seltsam. Entweder man steuert die Y-Position des Sprites per Skript oder eben nicht und dann sollten die Animationen des Sprites entweder NICHT nach oben und unten bewegen oder eben in einer konstanten Art und Weise nach oben und unten, so daß das Sprite wieder an seiner Ausgangsposition landet. Beides vermischt (wie in deinem Fall) macht keinen Sinn.
  11. Mass Place Trees/Grass/Rocks etc.

    Der Haken bedeutet erst einmal nur, daß Unity den Shader für Instancing ansteuert. Der Shader selbst muss aber zudem für Instancing ausgelegt sein. Der Shader muss dabei einzelne Attribute (instanziierte Attribute) wie Position, Farbe speziell verarbeiten, leider kann man dies nicht erkennen ohne in den Shadercode zu schauen. Der Standardshader unterstützt beispielsweise von Haus aus keinerlei Attribute, hierfür muss man dann einen Surface-Shader vom Standardshader ableiten und die Merkmale im Shadercode ausprogrammieren. Als 2. Voraussetzung, damit das Instancing funktioniert, muss man nun zusätzlich die instanziierten Attribute (des Shaders) per Skriptcode mit Daten befüllen (siehe MaterialPropertyBlock). Damit ist "adding per instance data" gemeint. Und ja, man kann auch Texturen als instanziiertes Attribut verwenden und damit einem Objekt mit einem Material 5 verschiedene Texturen verpassen (was wieder DCs einspart). Damit hättest du nicht mehr 5 Materialien, sondern 1 Material mit einem Shader der Instancing unterstützt. Voraussetzung ist natürlich immer, daß sich die Objekte den gleichen Mesh teilen... Ergänzend sei noch gesagt, daß das oben beschriebene "einfache" Instancing immer noch langsamer ist als "Instancing Indirekt", aber das führe ich jetzt nicht weiter aus, daß würde hier den Rahmen sprengen. Dies ist die Technik die ich für meine Grasshaderlösung verwende. Es gibt aber bereits einige Assets im Store die den gleichen Weg gegangen sind.
  12. Ich denke mal du störst dich an der fehlenden Root-Motion. Diese kannst du hier einstellen und zwar unter "Root Transform Position (Y)" / "Bake Into Pose". Für eine Bewegung des NPCs nach oben über die Animation sollte da kein Haken gesetzt sein: https://docs.unity3d.com/Manual/RootMotion.html Zudem muss im Animator "Apply Root Motion" aktiviert sein:
  13. Mass Place Trees/Grass/Rocks etc.

    Ja, das Tool ist recht umfangreich, bietet dafür aber auch (wenn ich mich recht erinnere) eine Funktion zum Kombinieren der Objektdetails. Das kann man zwar auch per Hand machen, aber so ist es doch bequemer. Gras solltest du keinesfalls als einzelne GameObjekts platzieren (es sein denn es sind man 10 Grasbüschel und und 10 Grasbüschel da), auch mit LODs nicht, jedes einzelne GameObjekt "konsumiert" (laut meinen Messungen) einiges an CPU-Zeit, ich habe ab 100 Objekten (+ mittelgroßer Meshdaten) erhebliche Einbrüche in der Performance erlebt. Man kann das Problem zwar deutlich Abschwächen, indem man die Objekte in einem Mesh kombiniert, aber wie gesagt, ich hatte damit selbst bei nur "50 - 100" kombinierten Meshes bereits deutliche FPS-Einbrüche. Die "Gras-Meshdaten" die das Unityterrain intern erzeugt waren im Gegensatz dazu deutlich performanter, da hier wohl nicht der Umweg über ein Gameobjekt gegangen werden muss. Ich hatte allerdings bei meinem Messungen damals nicht bedacht, daß die Unity "Gras-Meshes" keine Schatten werfen und daher die Performance meiner kombinierten Grasmeshes um 2/3 schlechter war, daher kann es sein, daß kombinierte Meshdaten noch im Rahmen bleiben. Ansonsten war laut meinen Messungen die schnellste Methode ein Instanced Indirect Shader, der die Grasmeshes direkt auf der CPU instanziert. Dieser benötigt quasi 1 DC (je LOD und Material) und erzeugt dann innerhalb der GPU sämtliche Meshinstanzen.
  14. Mass Place Trees/Grass/Rocks etc.

    Dieses Tool machte für mich einen gute Eindruck, habe aber noch nicht damit gearbeitet: https://assetstore.unity.com/packages/tools/painting/meshbrush-14453 Ansonsten, wenn es um (das Generieren von) größere Flächen geht und nicht um den "Feinschliff" kann ich nur Gaia empfehlen. Größere Grassflächen würde ich aber nicht über solch ein Tool platzieren, das zerstört die Performance, daher bin ich ja auch dabei hierfür eine eigene Lösung zu entwickeln (es gibt aber auch schon einige neue Assets im Store die den gleichen Weg gegangen sind). Insofern Bäume gute LODs haben kann man diese damit platzieren, aber auch hier sollte man bei größeren Mengen an Bäumen aufpassen. Unity verbrennt einfach zur viel Performance für ein einzelnes GameObject, hier sollte man dann über die GPU instanziieren.
  15. Sehe ich auch so wie @Silveryard Sollte es wirklich an den Referenzen in der Szene liegen (alles sieht danach aus), dann würde ich eine leere Szene als "Willkommensbildschirm" erstellen (ggf. mit Lade-UI) und dann die Startszene über LoadSceneAsync im Hintergrund laden und Anzeigen, wenn die Szene fertig geladen ist. Man kann mittlerweile eine Szene im Hintergrund laden und sie sogar "suspenden", d.h. man kann selbst festladen, ob sie nach dem asynchronen Ladevorgang angezeigt werden soll oder nicht. Ob ich nun AssetBundles oder komplette Szenen im Hintergrund lade bleibt dabei Geschmackssache, ich würde AssetBundles aber eher für App-Erweiterungen (erweiterter Content) verwenden und nicht für die Kernanwendung.
×