Jump to content
Unity Insider Forum

Zer0Cool

Members
  • Gesamte Inhalte

    2.040
  • Benutzer seit

  • Letzter Besuch

  • Tagessiege

    145

Beiträge erstellt von Zer0Cool

  1. Mal ein Videowunsch von mir.

    Könntest du mal ein Video machen (oder mehrere) für einen totalen Blender-Änfänger mit folgendem Inhalt:
    - Erklärung der verschiedenen Version
    - Installation
    - UI-Basics, also Menüpunkte oder Tastenkürzel die man immer wieder braucht (Einstellung aller UI-Fenster)
    - Erklärung wichtiger Operationen
    - Erstellung einiger simpler Geometrie: Treppen, Wände, kleines Haus, Fässer, Felsen (einfache Geometrie die man in einem Spiel so braucht, muss ja nicht gleich ein ganzes Schloss sein)
    - Texturing, UV-Mapping einzelner einfacher Objekte
    - Erstellung eines Texturatlas für X-Objekte

  2. Falls es jemand gebrauchen kann, hier eine kleine Klasse die den Spieler mehrere zuvor zugewiesene Ziele betrachten lässt. Der Spieler dreht dabei seinen Körper und seinen Kopf in Richtung des Ziels welches am besten mit seiner Sichtlinie übereinstimmt. Die Distanz des Ziels wird dabei ebenfalls mit betrachtet, allerdings nur sehr rudimentär.

    Ich habe noch zusätzlich eingebaut, dass der Spieler seinen rechten Arm in Richtung des aktuellen Ziels bewegt (lässt sich deaktivieren über eine Property).


    o8q2RWT.png

    kgmf0MM.png

    using UnityEngine;
    using System;
    using System.Collections;
    
    [RequireComponent(typeof(Animator))]
    public class IKControl : MonoBehaviour
    {
        public Transform[] lookObj = null;
        public float weightDamping = 1.5f;
        public float maxDistance = 10f;
        public bool RightHandToTarget = true;
        
        private Animator animator;
        private Transform lastPrimaryTarget;
        private Quaternion savedRotation;
        private float lerpEndDistance = 0.1f;
        private float finalLookWeight = 0;
        private bool transitionToNextTarget = false;
    
        void Start()
        {
            animator = GetComponent<Animator>();
        }
        
        // Callback for calculating IK
        void OnAnimatorIK()
        {
            if (lookObj != null)
            {
                Transform primaryTarget = null;
                float closestLookWeight = 0;
    
                // Here we find the target which is closest (by angle) to the players view line
                foreach (Transform target in lookObj)
                {
                    Vector3 lookAt = target.position - transform.position;
                    lookAt.y = 0f;
    
                    // Filter out all objects that are too far away
                    if (lookAt.magnitude > maxDistance) continue;
              
                    // Find best matching object to the players view line
                    float dotProduct = Vector3.Dot(new Vector3(transform.forward.x, 0f, transform.forward.z).normalized, lookAt.normalized);
                    float lookWeight = Mathf.Clamp(dotProduct, 0f, 1f);
                    if (lookWeight > closestLookWeight)
                    {
                        closestLookWeight = lookWeight;
                        primaryTarget = target;
                    }
                }
    
                if (primaryTarget != null)
                {
                    if ((lastPrimaryTarget != null) && (lastPrimaryTarget != primaryTarget) && (finalLookWeight > 0f))
                    {
                        // Here we start a new transition because the player looks already to a target but
                        // we have found another target the player should look at
                        transitionToNextTarget = true;
                    }
                }
    
                // The player is in a neutral look position but has found a new target
                if ((primaryTarget != null) && !transitionToNextTarget)
                {
                    lastPrimaryTarget = primaryTarget;
                    finalLookWeight = Mathf.Lerp(finalLookWeight, closestLookWeight, Time.deltaTime * weightDamping);
                    float bodyWeight = finalLookWeight * .75f;
                    animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
                    animator.SetLookAtPosition(primaryTarget.position);
    
                    if (RightHandToTarget)
                    {
                        Vector3 relativePos = primaryTarget.position - transform.position;
                        Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
                        animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
                        animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
                        animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight* 0.5f * closestLookWeight);
                        animator.SetIKPosition(AvatarIKGoal.RightHand, primaryTarget.position);
                    }
                }
    
                // Let the player smoothly look away from the last target to the neutral look position
                if ((primaryTarget == null && lastPrimaryTarget != null) || transitionToNextTarget)
                {
                    finalLookWeight = Mathf.Lerp(finalLookWeight, 0f, Time.deltaTime * weightDamping);
                    float bodyWeight = finalLookWeight * .75f;
                    animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
                    animator.SetLookAtPosition(lastPrimaryTarget.position);
    
                    if (RightHandToTarget)
                    {
                        Vector3 relativePos = lastPrimaryTarget.position - transform.position;
                        Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
                        animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
                        animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
                        animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight*0.5f * closestLookWeight);
                        animator.SetIKPosition(AvatarIKGoal.RightHand, lastPrimaryTarget.position);
                    }
    
                    if (finalLookWeight < lerpEndDistance)
                    {
                        transitionToNextTarget = false;
                        finalLookWeight = 0f;
                        lastPrimaryTarget = null;
                    }
                }
    
            }
        }
    }

     

  3. Am 1.8.2020 um 04:54 schrieb donny:

    Ist es möglich, dass jemand diese Zeile erklärt?

    
    Ability _ability = UnityEngine.Object.Instantiate((Ability)Resources.Load(_abilityName, typeof(Ability))) as Ability;

    Finde es schade, dass man auf alles genau eingeht und dann so eine Monsterzeile einfach unkommentiert lässt.

    Hab mir nicht alles im Detail angeschaut, aber was er hier macht ist, er erzeugt eine Instanz aus dem Ability-Asset (ScriptableObject) mit dem Namen "_abilityName" und läd das Asset dabei über Resources.Load. Danach packt er diese Ability zu den verfügbaren Abilities des Spielers.

    • Like 1
  4. Noch eine kleine Ergänzung. Game Design (in Richtung Level Design) hat für mich auch sehr viel mit Architektur im Allgemeinen zu tun, in gewissem Sinne vermischen sich dabei Skills wie künstlerisches Empfinden die eher in Richtung Art-Design gehen (wie Techniken aus der Malerei, Kunstgeschichte, Farblehre und ähnliches) oder aber auch technische Expertise die eher in Richtung Architektur geht (Techniken der historischen und modernen Architektur). Beides hat damit erst einmal nichts mit Programmieren oder 3D-Design (verwendete Tool oder Expertise mit diesen Tools) zu tun.
    Versteht man unter den Aufgaben des Game-Designers dann ebenfalls Aufgaben wie Story-Design, Charakter-Design, Game-Logiken und ähnliche Dinge dann kann man den Begriff des Game-Designers um diese Aufgabenbereiche erweitern, was dann ggf. weitere Skills des Game-Designers in diesen Themenbereichen erfordern kann. Gleiches gilt dann eben auch für einen Game-Designer der ebenfalls 3D-Art produzieren kann, was den Vorteil hat, das diese Assets sich dann perfekt in die geplante Game-Architektur (Level-Design) einbinden lassen, da sie diesem Konzept bereits entsprechen.

  5. Ich beziehe mich mal nicht direkt auf URP aber auf deine Frage und gehe davon aus, das sie eigentlich nicht URP-spezifisch ist.
    Also die Checkbox in den Unity Lightning-Settings für Ambient Occlusion ist für den Lightmapper und hat daher nur einen Effekt wenn du eine Lightmap für die Scene erstellst. Im Postprocessing (auch URP) gibt es einen eigenen Ambient Occlusion-Effekt der aber nichts mit dem Haken in den Unity Lightnings-Settings zu tun hat. Hierbei wird das Kamerabild der Scene nachträglich über diesen Effekt modifiziert. Du kannst also sowohl die AO in deiner erstellten Lightmap aktivieren und extra über einen Kamera-Postprocessing-Effekt abermals AO hinzufügen.

    Deine letzte Frage mit dem "klares Licht" habe ich nicht verstanden.

     

  6. Funktionieren die Lampen auch ohne Post-Processing-Effekte (vor allem Bloom?) und HDR oder anderes formuliert funktionieren sie auch im Gamma Color Space ohne HDR (Hintergrund der Frage ist, dass man dann so Sachen in die Assets einfügt wie Point Lights, Spot Lights und Area Lights in verschiedenen Varianten dann auch für den Linear Color Space da man hier dann ja quasi 2 Lichtquellen haben kann mit Emissive Materials).
    Wenn sie es nicht schon haben, ist es immer gut, wenn jede Lampe ein kleines Script besitzt mit dessen Hilfe man die Eigenschaften der Lampe verstellen kann, wie Farbe, Leuchtkraft usw.

    Ansonsten schöne Arbeit :)

  7. Versuch mal den "Library"-Folder des Projektes zu löschen (vorher Unity beenden) und dann das Projekt neu in Unity zu öffnen (vorher aber am besten ein Backup machen wie immer). Wenn das alles nicht geholfen hat, dann könnte man auch die Projektsettings komplett zurücksetzen (d.h. das Verzeichnis "ProjectSettings" ebenfalls löschen), aber das würde ich erstmal nicht machen (weil hier kann man auch "Projektdaten" verlieren wie gesetzte Tags / Layers usw.).

  8. Macht schon wesentlich mehr her, nun sieht man auch das der Charakter sich ansonsten "frei" bewegen kann :) 

    Ich denke man könnte noch viel an der Kamera basteln, aktuell sieht die Verfolgung des Charakters sehr "steif" aus (vielleicht auch nur ein Smooth-Follow-Setting an deiner aktuellen Kamera) und dadurch sieht es so aus als ob die Geometrie sich unter dem Charakter dreht. Ansonsten muss man sich halt überlegen wie man dem Zuschauer über die Kamera das Bewegen des Charakters über die Oberflächen noch besser vermittelt.

  9. Schaut nice aus, aber nun musst du auch springen, sonst gibt es ja keinen Gravitationseffekt ;) 

    Zudem kannst du ja mal den Unity Character aus den alten Unity-Standard-Assets nehmen, damit du auch eine Laufanimation hast, den Rest kann man ja einfach über Board werfen. Übrigens die alten Unity Standard-Assets kann man sich noch über die Downloadseite holen (oder im Store aber die Version schien mir älter):
    https://unity3d.com/de/get-unity/download/archive

    Dann auf Unity 2018 und ganz nach unten zur Version "Unity 2018.1.9" (hab ich heute auch mal gemacht)

  10. Bin jetzt nicht so der Blender-Import-Profi, aber wenn 2 Meshes unter dem Gameobject in Unity existieren  (nachdem man das Asset in die Szene gezogen hat) dann vemute ich das Unity hier ein Mesh mit einem Submesh erzeugt. Es wäre besser diese beiden Meshes jeweils nur einem Gameobjekt zuzuordnen, ich denke das geht auch noch nachdem man das FBX aus Blender in ein Unity-Asset importiert hat.
    Wenn du die beiden Meshes jeweils einem Gameobject zugeordnet hast kannst du diese dann wieder ganz normal über Code ansprechen oder über eine Unity-Animation animieren. Eventuell kannst du aus dem Originalasset auch gleich 2 Assets in Unity erzeugen, wobei dann jedes Asset dann nur 1 Mesh enthält. Notfalls kann man auch aus einem Gameobjekt in der Szene wieder ein Asset erzeugen (sollte man die Meshes des Assets in der Assetview nicht aufteilen können)

    Wegen der Materialien, beim Import kannst du unter "Material Creation Mode" "none" angeben, dann importiert Unity keine Materialien aus dem FBX (und erzeugt wohl ein einfaches Diffuse-Material). 

  11. Hat jemand schon Erfahrungen mit der Unity Culling Api gesammelt? Speziell interessiert mich hier die Performance. Zum Anderen ist es korrekt, daß man nur Spheres definieren kann und keine Boxes? Wie sieht die Performance aus, sagen wir mal bei ca. 10k Spheres, wie bei 100k? Ich werde zwar demnächst selber ein paar Tests machen, aber wäre schon einmal interessant, welche Erfahrungen ihr so gemacht habt. Ich hoffe das die Performance sehr gut ist und diese API die Spheren sehr performant verarbeiten kann... (wenn es schon nur mit Spheren funktioniert).

  12. Es gibt eine Klasse die nur diese Striche macht, die ist aber nicht von mir:

    Beispielanwendung:

    public class Example : MonoBehaviour
    {
       [HorizontalLine]
       ...
       ...
    }


    HorizontalLineAttribute.cs

    using UnityEngine;
    
    [System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true, Inherited = true)]
    public class HorizontalLineAttribute : PropertyAttribute
    {
    }


    HorizontalLineDrawer.cs

    using UnityEngine;
    using UnityEditor;
    
    [CustomPropertyDrawer(typeof(HorizontalLineAttribute))]
    public class HorizontalLineDrawer : DecoratorDrawer
    {
        public override float GetHeight()
        {
            return 11;
        }
    
        public override void OnGUI(Rect position)
        {
            GUI.Box(new Rect(position.x, position.y + 4, position.width, 3), GUIContent.none);
        }
    }

    Leider vertragen sich beide Drawer nicht, daher habe ich meine obere Klasse noch einmal erweitert, sie oben.

  13. da ich eigene Inspektoren für jedes Skript nicht mag, habe ich einmal einen Dekorator erstellt, den man in jedes Skript sehr leicht einbauen kann.
    Die Klassen sind bewusst einfach gehalten und enthalten nur das absolut notwendigste.

    Beispielanwendung:

    public class Example : MonoBehaviour
    {
       [Logo(64, 16, "Assets/Textures/myLogo.png", true)]
       ...
       ...
    }

    Der 1. Parameter definiert die Höhe der Textur, der 2. das Spacing über und unter der Texture (16 / 2) und der 3. Parameter den Pfad zum Texturlogo.
    Der 4. Parameter bestimmt, ob das Logo noch einmal in einen Rahmen verpackt wird.

    Ergebnis:

    LELGi8b.png


    Hier die Klassen:

    LogoAttribute.cs (kann beliebig im Projektfolder platziert werden)

    using UnityEngine;
    using UnityEditor;
    
    /// <summary>
    /// This class defines the LogoAttribute, so that it can be used in your regular MonoBehaviour scripts.
    /// <para>
    /// (c) by Zer0Cool for the Unity Insider Forum (forum.unity-community.de)
    /// Skype: zer0f0rce
    /// Discord: zer0f0rce #8769
    /// </para>
    /// 
    /// Usage:
    /// [LogoAttribute(64, 16, "Assets/Textures/mylogo.png", false)]
    /// 
    /// Hint:
    /// This class is used together with <see cref="LogoDrawer"/>.   
    /// </summary>
    public class LogoAttribute : PropertyAttribute
    {
        public Texture2D texture;
        public string assetLogoPath;
        public int height;
        public int padding;
        public bool border;
    
        public LogoAttribute(int height, int padding, string assetLogoPath, bool border)
        {
            this.assetLogoPath = assetLogoPath;
            this.height = height;
            this.padding = padding;
            this.border = border;
            this.texture = (Texture2D)AssetDatabase.LoadAssetAtPath(assetLogoPath, typeof(Texture));
        }
    }


    LogoDrawer.cs (muss innerhalb des Projektfolders in einem Editorverzeichnis platziert werden)
     

    using UnityEngine;
    using UnityEditor;
    
    /// <summary>
    /// This class decorates a MonoBehaviour script with a logo.
    /// <para>
    /// Defines how the <see cref="LogoAttribute"/> should be drawn in the inspector, when inspecting a GameObject with a MonoBehaviour which uses it.
    /// </para>
    /// <para>
    /// (c) by Zer0Cool for the Unity Insider Forum (forum.unity-community.de)
    /// Skype: zer0f0rce
    /// Discord: zer0f0rce #8769
    /// </para>
    /// 
    /// Usage:
    /// [LogoAttribute(64, 16, "Assets/Textures/mylogo.png", false)]
    /// 
    /// Hint:
    /// This class is used together with <see cref="LogoAttribute"/> and has to be placed inside an editor folder.   
    /// </summary>
    [CustomPropertyDrawer(typeof(LogoAttribute))]
    public class LogoDrawer : DecoratorDrawer
    {
    
        private static GUIStyle s_TempStyle = new GUIStyle();
    
        LogoAttribute logoAttribute
        {
            get { return ((LogoAttribute)attribute); }
        }
    
        public override float GetHeight()
        {
            float _height;
            if (logoAttribute.border) _height = logoAttribute.height + logoAttribute.padding * 2 + logoAttribute.padding / 2;
            else _height = logoAttribute.height + logoAttribute.padding * 2;
    
            return _height;
        }
    
        public override void OnGUI(Rect position)
        {
            // if this is not a repain or the property is null exit now
            if (Event.current.type != EventType.Repaint || logoAttribute.texture == null)
                return;
    
            //create object field for the sprite
            Rect spriteRect;
            spriteRect = new Rect(position.x, position.y, position.width, logoAttribute.height);
            spriteRect.width = position.width - EditorGUIUtility.singleLineHeight / 2;
            spriteRect.y += logoAttribute.padding;
    
            s_TempStyle.normal.background = logoAttribute.texture;
            if (logoAttribute.border) GUI.Box(new Rect(position.x, position.y + logoAttribute.padding / 3, position.width, 3), GUIContent.none);
            s_TempStyle.Draw(spriteRect, GUIContent.none, false, false, false, false);
            if (logoAttribute.border) GUI.Box(new Rect(position.x, position.y + GetHeight() - logoAttribute.padding, position.width, 3), GUIContent.none);
        }
    }

     

    • Like 1
  14. Ich habe die Klasse noch einmal erweitert. Sie kann nun auch den "Farbmix" über mehrere Texturen des Terrains liefern. Siehe Methode "ReadMixedTerrainColor".
    Die Methode "ReadDominantTerrainColor" liefert die Farbe der dominanten (größter Anteil) Textur des Terrains. Diese Methode liefert schneller einen Wert zurück, da sie nur eine Textur auslesen muss.

  15. Heute mal wieder eine kleine Helferklasse, die die Farbe des aktuellen Terrains an einem bestimmten Punkt auslesen kann. Ich verwende diese Klassen aktuell für einen Gras-Shader, aber ich denke auch andere Einsatzmöglichkeiten sind denkbar. Der Gras-Shader verwendet die ermittelte Farbe für eine Überblendung der Grasfarbe vom Boden. Da das Auslesen der Terrainfarbe an einem bestimmten Punkt mit einigen Hindernissen verbunden war,  dachte ich mir, ich stelle diese Hilfsklasse der Community zur Verfügung.

    Die Klasse bestimmt entweder die Farbe der dominanten Terraintextur (schneller) oder ermittelt den Texturmix über alle Texturen (langsamer) an Punkt XY. Die Klasse ist beim Zugriff auf die Texturen optimiert und verbraucht daher Speicher in Größenordnung der "gefundenen" Terraintexturen. Zudem wurde durchgehend Color32 verwendet.

    Beispielverwendung der Klasse:
    1) Klasse in die Szene ziehen
    2) Mit der Maus auf den Terrainboden clicken
    3) Die ermittelte Farbe wird im Inspektor des Skriptes im Feld "currentDominantColor" oder ""currentMixedColor"" angezeigt.

    Sollte noch jemand einen Fehler finden, bitte melden. Ein Test der Klasse gestaltet sich schwierig ;)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //
    // Klasse zum Auslesen der dominanten Texturfarbe eines Terrains.
    // (c) by Zer0Cool for the Unity Insider Forum (forum.unity-community.de)
    // Skype: zer0f0rce
    // Discord: zer0f0rce #8769
    //
    // Eckdaten:
    // Die Terraintexturen müssen nicht Read/Write enabled sein und wiederholte Zugriffe auf die Texturen werden gecached.
    //
    // Hintergrund:
    // Diese Klasse kann beispielsweise dafür verwendet werden, um kleineren Objekten auf dem Terrain (über einen Shader) 
    // eine Farbüberblendung vom Terrainboden zu ermöglichen.
    //
    
    public class ProbeTerrainTexture : MonoBehaviour {
    
        public Color32 currentDominantColor;
        public Color32 currentMixedColor;
    
        private Terrain terrain;
        private TerrainData terrainData;
        private Vector3 terrainPos;
    
        struct TextureData
        {
            public Color32[] pixels;
            public int width;
            public int height;
        }
    
        private Dictionary<string, TextureData> textureCache;
    
        public void SetTerrain(Terrain terrain)
        {
            this.terrain = terrain;
            terrainData = terrain.terrainData;
            terrainPos = terrain.transform.position;
            textureCache = new Dictionary<string, TextureData>();
        }
    
        void Start()
        {
            SetTerrain(Terrain.activeTerrain);
        }
    
        void Update()
        {
            if (!Input.GetMouseButtonDown(0))
                return;
    
            RaycastHit hit;
            if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit))
                return;
    
            currentDominantColor = ReadDominantTerrainColor(hit);
            currentMixedColor = ReadMixedTerrainColor(hit);
        }
    
        public Color32 ReadMixedTerrainColor(RaycastHit hit)
        {
            float[] allTextures = GetAllTextures(hit.point);
    
            Color32 mixedDiffuse = new Color32(0, 0, 0, 0);
            // Loop all alphamaps
            for (int i=0; i < terrainData.alphamapLayers; i++)
            {
                Color32 col = ReadTerrainColor(i, hit.textureCoord);
                float weight = allTextures[i];
                mixedDiffuse.r = (byte)(mixedDiffuse.r + (byte)((float)(col.r) * weight));
                mixedDiffuse.g = (byte)(mixedDiffuse.g + (byte)((float)(col.g) * weight));
                mixedDiffuse.b = (byte)(mixedDiffuse.b + (byte)((float)(col.b) * weight));
                mixedDiffuse.a = (byte)(mixedDiffuse.a + (byte)((float)(col.a) * weight));
            }
    
            return mixedDiffuse;
        }
    
        public Color32 ReadDominantTerrainColor(RaycastHit hit)
        {
            int dominantTexture = GetMainTexture(hit.point);
            return ReadTerrainColor(dominantTexture, hit.textureCoord);
        }
    
        public Color32 ReadTerrainColor(int splatPrototypeIndex, Vector2 uv)
        {
            SplatPrototype splatPrototype = terrainData.splatPrototypes[splatPrototypeIndex];
            Texture2D tex = splatPrototype.texture;
    
            Vector2 terrainUV = uv;
            Vector2 tileSize = splatPrototype.tileSize;
            Vector2 uvTiling = new Vector2(terrainData.size.x / tileSize.x, terrainData.size.z / tileSize.y); // 100 / 15 = 6.666
    
            Vector2 realUV = new Vector2((terrainUV.x * uvTiling.x) % 1, (terrainUV.y * uvTiling.y) % 1);
    
            realUV.x *= tex.width;
            realUV.y *= tex.height;
    
            return ReadTexturePixel(tex, (int)realUV.x, (int)realUV.y);
        }
    
        private Color32 ReadTexturePixel(Texture2D source, int x, int y)
        {
            TextureData data = new TextureData();
            if (!textureCache.ContainsKey(source.name))
            {
                source.filterMode = FilterMode.Point;
                RenderTexture rt = RenderTexture.GetTemporary(source.width, source.height);
                rt.filterMode = FilterMode.Point;
                RenderTexture.active = rt;
                Graphics.Blit(source, rt);
    
                Texture2D nTex = new Texture2D(source.width, source.height);
                nTex.ReadPixels(new Rect(0, 0, source.width, source.height), 0, 0);
                nTex.Apply();
                Color32[] pixels = nTex.GetPixels32(0);
                data.pixels = pixels;
                data.width = source.width;
                data.height = source.height;
                textureCache.Add(source.name, data);
                RenderTexture.active = null;
                RenderTexture.ReleaseTemporary(rt);
            }
    
            data = textureCache[source.name];
            Color32 pix = data.pixels[(data.width * y) + x];
            return pix;
        }
    
        private float[] GetTextureMix(Vector3 WorldPos)
        {
            // returns an array containing the relative mix of textures
            // on the main terrain at this world position.
    
            // The number of values in the array will equal the number
            // of textures added to the terrain.
    
            // calculate which splat map cell the worldPos falls within (ignoring y)
            int mapX = (int)(((WorldPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth);
            int mapZ = (int)(((WorldPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight);
    
            // get the splat data for this cell as a 1x1xN 3d array (where N = number of textures)
            float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 1, 1);
    
            // extract the 3D array data to a 1D array:
            float[] cellMix = new float[splatmapData.GetUpperBound(2) + 1];
    
            for (int n = 0; n < cellMix.Length; n++)
            {
                cellMix[n] = splatmapData[0, 0, n];
            }
            return cellMix;
        }
    
        private int GetMainTexture(Vector3 WorldPos)
        {
            // returns the zero-based index of the most dominant texture
            // on the main terrain at this world position.
            float[] mix = GetTextureMix(WorldPos);
    
            float maxMix = 0;
            int maxIndex = 0;
    
            // loop through each mix value and find the maximum
            for (int n = 0; n < mix.Length; n++)
            {
                if (mix[n] > maxMix)
                {
                    maxIndex = n;
                    maxMix = mix[n];
                }
            }
            return maxIndex;
        }
    
        private float[] GetAllTextures(Vector3 WorldPos)
        {
            // returns all splatmap textures at world position.
            return GetTextureMix(WorldPos); 
        }
    
    }

     

    • Like 1
  16. Ist der ideale Anwendungsfall für einen Kameraeffekt-Shader. Dieser Effektshader verarbeitet dabei aber den gesamten Blickbereich (Frustum) der Kamera. 
    Nun muss man aber diverse Dinge beachten / bedenken:
    - bewegt sich deine Kamera, also folgt sie dem Spieler, d.h. verschiebt sich das Kamera-Frustum?
    - soll auch der Hintergrund durch den Effektshader beeinflusst werden?

    Sollte sich die Kamera mit dem Spieler mitbewegen, wird es komplexer, da sich hier der Bildschirmausschnitt mit verschiebt und dadurch der Ausschnitt der Shadowmap mit verschoben werden muss. Soll der Effektshader nur bestimmte Gegenstände beeinflussen, dann müssen diese Gegenstände in einen eigenen Layer und die "Effektkamera" darf dann nur diese Objekte rendern. Das "Weichzeichnen" nennt sich Antialiasing. Es gibt Effektshader die einen Antialiasing Effekt erzeugen können, indem Fall müsste man so einen umschreiben, daß er nur die Shadowmap weichzeichnet und nicht die Maintextur ... Die Farbwerte (Helligkeit) der Shadowmap würden dann im letzten Schritt mit den Farbwerten der Maintextur vermischt werden (die Maintextur ist bei einem Effektshader immer der Bildschirminhalt der Kamera)

    • Thanks 1
×
×
  • Neu erstellen...