Jump to content
Unity Insider Forum

minuschki

Members
  • Posts

    86
  • Joined

  • Last visited

  • Days Won

    2

Everything posted by minuschki

  1. Hallo chrische5 Das ist das Resultat, welches der derzeitige Shader produziert. Sascha hat das aber wieder einmal völlig einleuchtend erklärt, dass der Shader die Steigung der Flächen berücksichtigt. Somit ist das für mich auch ok. Schön wäre aber für mich eine Lösung, welche alle Objekte in der Welt in eine Winterlandschaft umwandelt, also so quasi ein globaler Shader ohne dass man bei jedem einzelnen Objekt das Material ändern muss! Ist das machbar?
  2. Hallo zusammen Ich habe einen Schnee-Shader gefunden, der auf meine Mesh-Berge Schnee legt. Man kann in einem Regler auch die Höhe des Schnees einstellen, allerdings beginnt der Schnee in den tieferen Flächen und steigt dann je nach eingestelltem Level in die Höhe. Ich fände es aber logischer, wenn der Shader zuerst die Gipfel mit Schnee bedeckt und je nach Level dann die tieferen Flächen berücksichtigt. Was muss man am Shader ändern, damit er die Schneefallgrenze von oben nach unten anwendet? Shader "Custom/SnowShader" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 _MainNormal ("MainNormal", 2D) = "bump" {} [Header(Snow info)] _SnowTexture("Snow texture", 2D) = "white" {} _SnowNormal("Snow normal", 2D) = "bump" {} _SnowColor("Snow color", color) = (1,1,1,1) _SnowDirection ("Snow direction", Vector) = (0, 1, 0) _SnowLevel ("Snow level", Range(-1, 1)) = 0 _SnowGlossiness("Snow glossiness", Range(0, 1)) = 0.5 _SnowMetallic ("Snow Metallic", Range(0,1)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; float2 uv_MainNormal; float2 uv_SnowNormal; float2 uv_SnowTexture; float3 worldNormal; INTERNAL_DATA }; half _Glossiness; half _Metallic; fixed4 _Color; sampler2D _MainNormal; sampler2D _SnowTexture; sampler2D _SnowNormal; fixed4 _SnowColor; float4 _SnowDirection; float _SnowLevel; float _SnowGlossiness; float _SnowMetallic; // 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_BUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_BUFFER_END(Props) void surf (Input IN, inout SurfaceOutputStandard o) { //Color and normals of the main textures fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; float3 normals = UnpackNormal (tex2D(_MainNormal, IN.uv_MainNormal)); //Color and normals of the snow textures fixed4 snowColor = tex2D(_SnowTexture, IN.uv_SnowTexture) * _SnowColor; float3 snowNormals = UnpackNormal(tex2D(_SnowNormal, IN.uv_SnowNormal)); //Snow direction calculation half snowDot = step(_SnowLevel, dot(WorldNormalVector(IN, normals), normalize(_SnowDirection))); o.Normal = lerp(normals, snowNormals, snowDot); o.Albedo = lerp(c.rgb, snowColor.rgb, snowDot); o.Metallic = lerp(_Metallic, _SnowMetallic, snowDot); o.Smoothness = lerp(_Glossiness, _SnowGlossiness, snowDot); o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
  3. Hallo Sascha Danke für deine Erklärung! Wenn ich deinen Input richtig interpretiere, sollten also: mesh.RecalculateNormals (); mesh.RecalculateBounds(); ausreichen.
  4. Hallo zusammen Ich habe eine Frage zu "mesh.Recalculate". Sollte man, nachdem ich ein Mesh per Skript von Grund auf kreiert habe oder bei einem bestehenden Mesh die Vertices in der y-Achse verschoben habe, ein "mesh.Recalculate" durchführen? Wenn ja: mesh.RecalculateNormals(); oder mesh.RecalculateTangents(); oder mesh.RecalculateBounds(); oder alle drei? ps. Dem Mesh wurde auch ein MeshCollider hinzugefügt, der nach der Manipulation geupdatet werden soll. Zudem hat das verwendete Material neben dem Albedo auch eine Normal Map. Ich erwähne das nur, falls das einen Einfluss auf die Verwendung der "mesh.Recalculate"-Varianten haben könnte. Eigentlich sind mir die Funktionen der einzelnen Varianten nicht ganz klar und die Erklärungen der Unity-Hilfe sind auch eher dürftig. Danke für eure belehrenden Inputs!
  5. Und schon wieder ein Volltreffer! Danke, dein Tipp ist ist bereits umgesetzt und funktioniert perfekt!
  6. Ich hätte da noch ein kleines Problem! Das erstellte Mesh hat den Pivot-Punkt bei der Ecke links unten, was wiederum zu Folge hat, dass sich das Objekt bei einer Rotation um die Y-Achse um diese Ecke dreht. Es sollte sich aber um das Zentrum drehen. Ich habe mir vorgestellt, man könne den Pivot per Skript ins Zentrum setzen, was aber offenbar nicht möglich ist. Bei meiner Suche nach einer Lösung des Problems, finde ich nur so Basteleien mit Parent-Gameobject, offset und so weiter, was ich aber sehr umständlich finde. Mir schwebt eigentlich eine Lösung vor, die folgendermassen aussieht: Man erstellt in der Hierarchie ein Empty GameObject (Drehpunkt ist bereits im Zentrum) und fügt ihm die Komponenten <Transform> und <Meshfilter> hinzu. Danach möchte ich das mittels Script ertellte Mesh dem Empty GameObject übergeben, aber so, dass der Drehpunkt im Zentrum verbleibt! Ist das möglich? Mein Versuch ist insofern fehlgeschlagen, dass ich zwar das Mesh auf das Empty GameObject übertragen konnte, aber der Pivot dummerweise wiederum in die untere linke Ecke verschoben wird.
  7. Danke für deine Erklärung! Ich habe deinen Rat befolgt und siehe da, es klappt wie gewünscht. Wieder was dazugelernt! Besten Dank und noch einen schönen Tag! uvs[i] = new Vector2(verts[i].x / 250, verts[i].z / 250);
  8. Hallo zusammen Ich erstelle mit dem angehängten Script ein Mesh, welches eine Graustufenbild als hightmap benutzt. Das funktioniert tadellos. Das Problem ist aber beim Hinzufügen eines Bildes als Textur. In der letzten Zeile füge ich ein Material hinzu. Die Textur soll aber nicht gekachelt, sondern als ganzes Bild über dem gesamten Mesh angezeigt werden (siehe Bild 2). Wie kann ich das hinkriegen? Besten Dank im Voraus! using System.Collections; using System.Collections.Generic; using UnityEngine; public class BergMaker : MonoBehaviour { public Material myMaterial; public void BergGenerieren() { Texture2D hMap = Resources.Load("Berg1") as Texture2D; List<Vector3> verts = new List<Vector3>(); List<int> tris = new List<int>(); //Bottom left section of the map, other sections are similar for(int i = 0; i < 250; i++) { for(int j = 0; j < 250; j++) { //Add each new vertex in the plane verts.Add(new Vector3(i, hMap.GetPixel(i,j).grayscale * 50, j)); //Skip if a new square on the plane hasn't been formed if (i == 0 || j == 0) continue; //Adds the index of the three vertices in order to make up each of the two tris tris.Add(250 * i + j); //Top right tris.Add(250 * i + j - 1); //Bottom right tris.Add(250 * (i - 1) + j - 1); //Bottom left - First triangle tris.Add(250 * (i - 1) + j - 1); //Bottom left tris.Add(250 * (i - 1) + j); //Top left tris.Add(250 * i + j); //Top right - Second triangle } } Vector2[] uvs = new Vector2[verts.Count]; for (var i = 0; i < uvs.Length; i++) //Give UV coords X,Z world coords uvs[i] = new Vector2(verts[i].x, verts[i].z); GameObject plane = new GameObject("ProcPlane"); //Create GO and add necessary components plane.transform.position = new Vector3(-125, -20, 50); plane.AddComponent<MeshFilter>(); plane.AddComponent<MeshRenderer>(); Mesh procMesh = new Mesh(); procMesh.vertices = verts.ToArray(); //Assign verts, uvs, and tris to the mesh procMesh.uv = uvs; procMesh.triangles = tris.ToArray(); procMesh.RecalculateNormals(); //Determines which way the triangles are facing plane.GetComponent<MeshFilter>().mesh = procMesh; //Assign Mesh object to MeshFilter plane.GetComponent<MeshRenderer>().material = myMaterial; } }
  9. Hallo Sascha Ich frage mich, ob man die unten gezeigte for-Schleife nicht erheblich optimieren könnte. Immerhin werden da jedesmal alle 40401 Meshpunkte kontrolliert, obwohl schlussendlich nur etwa 300 innerhalb des Radius liegen und manipuliert werden müssen. Im Moment ruckelt es recht stark. Ich denke aber, die Berechnung könnte doch viel flüssiger ablaufen, wenn man nur das quadratische Feld der möglichen Kandidaten (localHitPoint +- Radius in x und z Richtung) kontrollieren würde. Stehe ich da völlig im Schilf oder gäbe es diese Möglichkeit? Eventuell mit einer Doppelschleife, die weiss nicht wie aussehen würde? for (int v = 0; v < modVerts.Length; v++) { Vector3 distance = modVerts [v] - localHitPoint; float force = deformPower / (1f + localHitPoint.sqrMagnitude); if (distance.sqrMagnitude < radius * radius) { modVerts [v] = modVerts [v] + (Vector3.up * force) / smoothingFactor; } }
  10. Hallo Sascha Hans Rosenthal würde sagen: "Das war Spitze!" Ich habe deine beiden Korrekturen übernommen und siehe da, es funktioniert tadellos. Besten Dank für die rasche und wie immer kompetente Hilfe!
  11. Hallo zusammen Zur Situation: Ich habe einen Berg als Mesh in die Szene importiert, dessen Form ich durch gezielte Mausklicks verändern möchte. Der Berg besitzt einen MeshCollider, so dass ein hit.point beim Anklicken des Objekts ausgelesen werden kann. Mit Debug.DrawLine habe ich das kontrolliert und die Linie endet genau am gewünschten Punkt. Nun sollte bei allen Meshpunkten, die sich innerhalb eines definierten Radius befinden, der Wert der Höhe leicht angehoben werden. Das Problem: Offenbar passen die Koordinaten der Meshpunkte und des hit.point nicht zueinander! Das Array "verticies" hat eine Länge von 40401. Da der Berg quadratisch ist, ergibt das eine Seitenlänge von 201 x 201 Meshpunkten. Damit er gross genug in der Szene erscheint, steht im Inspektor bei Scale: x: 100, y: 100, z:100 und seine Position ist etwas seitlich verschoben und zurückgesetzt: x: 60, y: 0, z : 680. Wenn ich auf den Berg klicke erhalte ich für den hit.point beispielweise x-Werte zwischen -350 und +350, je nachdem, ob man ganz link bzw. ganz recht auf den Berg klickt. Die Höhenverschiebung funktioniert aber gar nicht oder höchsten an einer falschen Stelle. Wenn ich die Bedingung "if (distance.sqrMagnitude < radius)" durch "if (Random.Range(0, 2) == 1)" ersetze, erscheint der ganze Berg sehr zackig, was immerhin bedeutet, dass die Meshpunkte manipuliert werden können. Was muss man im Script ändern, damit die Werte des hit.point und die Meshpunkte mit einander korrekt korrelieren? Besten Dank für eure Hilfe! using System.Collections; using System.Collections.Generic; using UnityEngine; public class MeshModeler : MonoBehaviour { [Range(1.5f, 2f)] public float radius = 2f; [Range(0.5f, 5f)] public float deformPower = 2f; Mesh mesh; Vector3[] verticies; Vector3[] modifiedVerts; void Start () { mesh = GetComponent<MeshFilter>().mesh; verticies = mesh.vertices; modifiedVerts = mesh.vertices; } void Update () { if (Input.GetMouseButton (0)) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition); if (Physics.Raycast (ray, out hit, 3000)) { for(int v = 0; v < modifiedVerts.Length; v++) { Vector3 distance = modifiedVerts [v] - hit.point; float smoothingFactor = 20f; float force = deformPower / (1f + hit.point.sqrMagnitude); if (distance.sqrMagnitude < radius) { modifiedVerts [v] = modifiedVerts [v] + (Vector3.up * force) / smoothingFactor; } } RecalculateMesh (); } } } void RecalculateMesh() { mesh.vertices = modifiedVerts; GetComponent<MeshCollider> ().sharedMesh = mesh; mesh.RecalculateNormals (); } }
  12. Danke malzbie für deine Antwort Ich habe deinen Tipp ausprobiert, aber es hat nicht geholfen. Ich muss dazu auch sagen, dass meine Unityversion 2017.4 ist und es deswegen nicht funktioniert.
  13. Hallo zusammen Ich habe ein recht aktuelles Skript gefunden, das es erlauben soll, ein Terrain in Runtime manuell zu verändern. Anscheinend kann man mit einem selbsterstellten Pinsel das Gelände stellenweise erhöhen, absenken, smoothen oder abflachen. Zudem soll es möglich sein, auf das Terrain direkt mit dem Pinsel eine Textur zu malen. Eigentlich genau das, wonach ich suche. Das Skript ist zu finden unter: https://answers.unity.com/questions/1743422/paint-terrain-texture-on-runtime.html Leider funktioniert das Skript aber nicht wie gewünscht und verweigert seinen Dienst. So erhalte ich ein paar Fehlermeldungen: Zeile 36: public TerrainLayer[] paints; // a list containing all of the paints Zeile 59: wird das int terX bemängelt Zeile 99: t.terrainLayers = paints; // wird rot markiert Zeile 122: RMC.SetIndicators(); // wird rot markiert Ein Kommentarschreiber (Siendel) schlägt ein anderes Script für die paint-Funktion vor, damit diese fehlerfrei läuft. Ein anderer Kommentarschreiber (dayn9) schreibt: In GenerateBrush the Color.greyscale property should already be between 0 and 1. Könnte bitte mal jemand den angehängten Code testen, ob ihr es zum Laufen bringt! Es wäre eine Supersache, wenn das funtionieren würde! Danke für eure Hilfe using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; public class TerrainEditor : MonoBehaviour { //place these where you would normally declare variables public Terrain targetTerrain; //The terrain obj you want to edit float[,] terrainHeightMap; //a 2d array of floats to store int terrainHeightMapWidth; //Used to calculate click position int terrainHeightMapHeight; float[,] heights; //a variable to store the new heights TerrainData targetTerrainData; // stores the terrains terrain data public enum EffectType { raise, lower, flatten, smooth, paint, }; public Texture2D[] brushIMG; // This will allow you to switch brushes float[,] brush; // this stores the brush.png pixel data public int brushSelection; // current selected brush public int areaOfEffectSize = 100; // size of the brush [Range(0.01f,1f)] // you can remove this if you want public float strength; // brush strength public float flattenHeight = 0; // the height to which the flatten mode will go public EffectType effectType; public TerrainLayer[] paints;// a list containing all of the paints public int paint; // variable to select paint float[,,] splat; // A splat map is what unity uses to overlay all of your paints on to the terrain void Awake() { brush = GenerateBrush(brushIMG[brushSelection], areaOfEffectSize); // This will take the brush image from our array and will resize it to the area of effect targetTerrain = FindObjectOfType<Terrain>(); // this will find terrain in your scene, alternatively, if you know you will only have one terrain, you can make it a public variable and assign it that way } void Update() { if (input.GetMouseButtonDown(0)) { Transform cam = Camera.main.transform; Ray ray = new Ray(cam.position, cam.forward); RaycastHit hit; if(Physics.Raycast (ray, hit, 500)) { targetTerrain = GetTerrainAtObject(hit.transform.gameObject); SetEditValues(targetTerrain); GetTerrainCoordinates(hit, out int terX, out int terZ); ModifyTerrain(terX, terZ); // Vorschlag von Kommentarschreiber Siedel: // Vector3 newCor = ConvertWordCor2TerrCor(hit.point); // ModifyTerrain((int)newCor.x, (int)newCor.z); } } } private void GetTerrainCoordinates(RaycastHit hit, out int x,out int z) { int offset = areaOfEffectSize / 2; //This offsets the hit position to account for the size of the brush which gets drawn from the corner out //World Position Offset Coords, these can differ from the terrain coords if the terrain object is not at (0,0,0) Vector3 tempTerrainCoodinates = hit.point - hit.transform.position; //This takes the world coords and makes them relative to the terrain Vector3 terrainCoordinates = new Vector3( tempTerrainCoodinates.x / GetTerrainSize().x, tempTerrainCoodinates.y / GetTerrainSize().y, tempTerrainCoodinates.z / GetTerrainSize().z); // This will take the coords relative to the terrain and make them relative to the height map(which often has different dimensions) Vector3 locationInTerrain = new Vector3 ( terrainCoordinates.x * terrainHeightMapWidth, 0, terrainCoordinates.z * terrainHeightMapHeight ); //Finally, this will spit out the X Y values for use in other parts of the code x = (int)locationInTerrain.x - offset; z = (int)locationInTerrain.z - offset; } public void SetPaint(int num) { paint = num; } public void SetLayers(TerrainData t) { t.terrainLayers = paints; } public void SetBrushSize(int value)//adds int value to brush size(make negative to shrink) { areaOfEffectSize += value; if (areaOfEffectSize > 50) { areaOfEffectSize = 50; } else if(areaOfEffectSize < 1) { areaOfEffectSize = 1; } brush = GenerateBrush(brushIMG[brushSelection], areaOfEffectSize); // regenerates the brush with new size } public void SetBrushStrength(float value)//same idea as SetBrushSize() { strength += value; if (strength > 1) { strength = 1; } else if (strength < 0.01f) { strength = 0.01f; } } public void SetBrush(int num) { brushSelection = num; brush = GenerateBrush(brushIMG[brushSelection], areaOfEffectSize); RMC.SetIndicators(); } void ModifyTerrain(int x, int z) { //These AreaOfEffectModifier variables below will help us if we are modifying terrain that goes over the edge, you will see in a bit that I use Xmod for the the z(or Y) values, which was because I did not realize at first that the terrain X and world X is not the same so I had to flip them around and was too lazy to correct the names, so don't get thrown off by that. int AOExMod = 0; int AOEzMod = 0; int AOExMod1 = 0; int AOEzMod1 = 0; if (x < 0) // if the brush goes off the negative end of the x axis we set the mod == to it to offset the edited area { AOExMod = x; } else if (x + areaOfEffectSize > terrainHeightMapWidth)// if the brush goes off the posative end of the x axis we set the mod == to this { AOExMod1 = x + areaOfEffectSize - terrainHeightMapWidth; } if (z < 0)//same as with x { AOEzMod = z; } else if (z + areaOfEffectSize > terrainHeightMapHeight) { AOEzMod1 = z + areaOfEffectSize - terrainHeightMapHeight; } if (effectType != EffectType.paint) // the following code will apply the terrain height modifications { heights = targetTerrainData.GetHeights(x - AOExMod, z - AOEzMod, areaOfEffectSize + AOExMod - AOExMod1, areaOfEffectSize + AOEzMod - AOEzMod1); // this grabs the heightmap values within the brushes area of effect } ///Raise Terrain if (effectType == EffectType.raise) { for (int xx = 0; xx < areaOfEffectSize + AOEzMod - AOEzMod1; xx++) { for (int yy = 0; yy < areaOfEffectSize + AOExMod - AOExMod1; yy++) { heights[xx, yy] += brush[xx-AOEzMod, yy-AOExMod] * strength; //for each point we raise the value by the value of brush at the coords * the strength modifier } } targetTerrainData.SetHeights(x - AOExMod, z - AOEzMod, heights); // This bit of code will save the change to the Terrain data file, this means that the changes will persist out of play mode into the edit mode } ///Lower Terrain, just the reverse of raise terrain else if (effectType == EffectType.lower) { for (int xx = 0; xx < areaOfEffectSize + AOEzMod; xx++) { for (int yy = 0; yy < areaOfEffectSize + AOExMod; yy++) { heights[xx, yy] -= brush[xx - AOEzMod, yy - AOExMod] * strength; } } targetTerrainData.SetHeights(x - AOExMod, z - AOEzMod, heights); } //this moves the current value towards our target value to flatten terrain else if (effectType == EffectType.flatten) { for (int xx = 0; xx < areaOfEffectSize + AOEzMod; xx++) { for (int yy = 0; yy < areaOfEffectSize + AOExMod; yy++) { heights[xx, yy] = Mathf.MoveTowards(heights[xx, yy], flattenHeight/600, brush[xx - AOEzMod, yy - AOExMod] * strength); } } targetTerrainData.SetHeights(x - AOExMod, z - AOEzMod, heights); } //Takes the average of surrounding points and moves the point towards that height else if (effectType == EffectType.smooth) { float[,] heightAvg = new float[heights.GetLength(0), heights.GetLength(1)]; for (int xx = 0; xx < areaOfEffectSize + AOEzMod; xx++) { for (int yy = 0; yy < areaOfEffectSize + AOExMod; yy++) { heightAvg[xx, yy] = GetSurroundingHeights(heights, xx, yy); // calculates the value we want each point to move towards } } for (int xx1 = 0; xx1 < areaOfEffectSize + AOEzMod; xx1++) { for (int yy1 = 0; yy1 < areaOfEffectSize + AOExMod; yy1++) { heights[xx1, yy1] = Mathf.MoveTowards(heights[xx1, yy1], heightAvg[xx1, yy1], brush[xx1 - AOEzMod, yy1 - AOExMod] * strength); // moves the points towards their targets } } targetTerrainData.SetHeights(x - AOExMod, z - AOEzMod, heights); } //This is where we do the painting, sorry its buried so far in here else if (effectType == EffectType.paint) { splat = targetTerrain.terrainData.GetAlphamaps(x - AOExMod, z - AOEzMod, areaOfEffectSize + AOExMod, areaOfEffectSize + AOEzMod); //grabs the splat map data for our brush area for (int xx = 0; xx < areaOfEffectSize + AOEzMod; xx++) { for (int yy = 0; yy < areaOfEffectSize + AOExMod; yy++) { float[] weights = new float[targetTerrain.terrainData.alphamapLayers]; //creates a float array and sets the size to be the number of paints your terrain has for (int zz = 0; zz < splat.GetLength(2); zz++) { weights[zz] = splat[xx, yy, zz];//grabs the weights from the terrains splat map } weights[paint] += brush[xx - AOEzMod, yy - AOExMod] * strength*2000; // adds weight to the paint currently selected with the int paint variable //this next bit normalizes all the weights so that they will add up to 1 float sum = weights.Sum(); for (int ww = 0; ww < weights.Length; ww++) { weights[ww] /= sum; splat[xx, yy, ww] = weights[ww]; } } } //applies the changes to the terrain, they will also persist targetTerrain.terrainData.SetAlphamaps(x - AOExMod, z - AOEzMod, splat); targetTerrain.Flush(); } } public Terrain GetTerrainAtObject(GameObject gameObject) { if (gameObject.GetComponent<Terrain>()) { //This will return the Terrain component of an object (if present) return gameObject.GetComponent<Terrain>(); } return default(Terrain); } public TerrainData GetCurrentTerrainData() { if (targetTerrain) { return targetTerrain.terrainData; } return default(TerrainData); } public Terrain GetCurrentTerrain() { if (targetTerrain) { return targetTerrain; } return default(Terrain); } public void SetEditValues(Terrain terrain) { targetTerrainData = GetCurrentTerrainData(); terrainHeightMap = GetCurrentTerrainHeightMap(); terrainHeightMapWidth = GetCurrentTerrainWidth(); terrainHeightMapHeight = GetCurrentTerrainHeight(); } private float GetSurroundingHeights(float[,] height,int x, int z) { float value; // this will temporarily hold the value at each point float avg = height[x, z]; // we will add all the heights to this and divide by int num bellow to get the average height int num = 1; for (int i = 0; i < 4; i++) //this will loop us through the possible surrounding spots { try // This will try to run the code bellow, and if one of the coords is not on the terrain(ie we are at an edge) it will pass the exception to the Catch{} below { // These give us the values surrounding the point if (i == 0) {value = height[x + 1, z];} else if (i == 1) {value = height[x - 1, z];} else if (i == 2) {value = height[x, z + 1];} else {value = height[x, z - 1];} num++; // keeps track of how many iterations were successful avg += value; } catch (System.Exception) { } } avg = avg / num; return avg; } public Vector3 GetTerrainSize() { if (targetTerrain) { return targetTerrain.terrainData.size; } return Vector3.zero; } public float[,] GetCurrentTerrainHeightMap() { if (targetTerrain) { // the first 2 0's indicate the coords where we start, the next values indicate how far we extend the area, so what we are saying here is I want the heights starting at the Origin and extending the entire width and height of the terrain return targetTerrain.terrainData.GetHeights(0, 0, targetTerrain.terrainData.heightmapWidth, targetTerrain.terrainData.heightmapHeight); } return default(float[,]); } public int GetCurrentTerrainWidth() { if (targetTerrain) { return targetTerrain.terrainData.heightmapWidth; } return 0; } public int GetCurrentTerrainHeight() { if (targetTerrain) { return targetTerrain.terrainData.heightmapHeight; } return 0; //test2.GetComponent<MeshRenderer>().material.mainTexture = texture; } public float[,] GenerateBrush(Texture2D texture, int size) { float[,] heightMap = new float[size,size];//creates a 2d array which will store our brush Texture2D scaledBrush = ResizeBrush(texture,size,size); // this calls a function which we will write next, and resizes the brush image //This will iterate over the entire re-scaled image and convert the pixel color into a value between 0 and 1 for (int x = 0; x < size; x++) { for(int y = 0; y < size; y++) { Color pixelValue = scaledBrush.GetPixel(x, y); heightMap[x, y] = pixelValue.grayscale / 255; } } return heightMap; } public static Texture2D ResizeBrush(Texture2D src, int width, int height, FilterMode mode = FilterMode.Trilinear) { Rect texR = new Rect(0, 0, width, height); _gpu_scale(src, width, height, mode); //Get rendered data back to a new texture Texture2D result = new Texture2D(width, height, TextureFormat.ARGB32, true); result.Resize(width, height); result.ReadPixels(texR, 0, 0, true); return result; } static void _gpu_scale(Texture2D src, int width, int height, FilterMode fmode) { //We need the source texture in VRAM because we render with it src.filterMode = fmode; src.Apply(true); //Using RTT for best quality and performance. Thanks, Unity 5 RenderTexture rtt = new RenderTexture(width, height, 32); //Set the RTT in order to render to it Graphics.SetRenderTarget(rtt); //Setup 2D matrix in range 0..1, so nobody needs to care about sized GL.LoadPixelMatrix(0, 1, 1, 0); //Then clear & draw the texture to fill the entire RTT. GL.Clear(true, true, new Color(0, 0, 0, 0)); Graphics.DrawTexture(new Rect(0, 0, 1, 1), src); } // Vorschlag von Kommentarschreiber Siedel: // Und die folgenden 2 Zeilen in der Update-Methode einfügen: // Vector3 newCor = ConvertWordCor2TerrCor(hit.point); // ModifyTerrain((int)newCor.x, (int)newCor.z); private Vector3 ConvertWordCor2TerrCor(Vector3 wordCor) { Vector3 vecRet = new Vector3(); Terrain ter = targetTerrain; Vector3 terPosition = ter.transform.position; vecRet.x = ((wordCor.x - terPosition.x) / ter.terrainData.size.x) * ter.terrainData.alphamapWidth; vecRet.z = ((wordCor.z - terPosition.z) / ter.terrainData.size.z) * ter.terrainData.alphamapHeight; return vecRet; } }
  14. Hallo zusammen Ich bin auf der Suche nach einer Möglichkeit, wie ich einen Pinsel mit transparentem Hintergrund (linke Bildhälfte: png mit Alpha) auf eine 2D Textur an verschiedene Positionen kopieren kann (rechte Bildhälfte). Also eine einfache Malfunktion. Die Umsetzung mit Ray usw. ist mir klar, so dass ich in der Lage wäre, bei gedrückter Maustaste die gewünschte Pinselposition zu ermitteln. Das Problem ist aber der eigentliche Kopiercode! Dabei muss die 2D Textur tatsächlich neu bemalt werden, also keine Lösung mit spawnen vom Pinsel-Prefab. Leider habe ich keinen Schimmer, wie man das bewerkstelligen könnte! Pseudocode: 1. Solange die Maustaste gedrückt ist 2. Kopiere den Pinsel an die Mausposition auf die 2D Textur 3. Wenn man die Transparenz (also Deckungsgrad des Pinsels) einstellen könnte, wäre natürlich super. Z.B.: Kopiere den Pinsel mit 20% Deckung. Kann mir bitte jemand zwei, drei Codezeilen liefern, wie der Kopiercode aussehen müsste! Besten Dank für eure Hilfe!
  15. Ok, danke Christoph! Ich hab's nun gecheckt und es funktioniert!
  16. Danke für deine Antwort! Ich werde zwar leider nicht schlauer daraus, da mir der Umgang mit Skripts ohne MonoBehaviour völlig unbekannt ist. Wäre es denn nicht das Beste, wenn ich das ganze Skript in ein normales Skript mit MonoBehaviour und voids umschreibe, die ich dann einfach wie gewohnt aufrufen kann?
  17. Hallo Leute Ich habe das folgende Skript (ein SudokuSolver) aus einem Tutorial abgetippt. Es ist zwar in C# geschrieben, aber nicht für Unity angepasst. Den Inhalt des Skripts verstehe ich soweit, allerdings habe ich keinen blassen Schimmer, was man da ändern muss, damit es auch in Unity zu funktioniert! Bei den ersten vier Zeilen muss wahrscheinlich überall using Unity.System.... stehen! Da es sich nicht um ein Monobehaviour-Skript handelt, lässt es sich auch nicht auf ein GameObjekt ziehen. Ich habe versucht, aus dem "namespace Sudo" ein "public class Sudo MonoBehaviour" zu machen, aber dann bocken die Zeilen "class Program" und alle "static bool". Ich habe noch die Erläuterungen von Sascha zum Thema "Statische Variablen und Funktionen" durchgelesen, hat mir aber nicht weitergeholfen. Kann mal jemand zeigen, wie man das Skript umschreiben müsste, damit es in Unity genutzt werden kann? Vielleicht muss man das ja gar nicht umschreiben, sondern einfach nur aufrufen?! Allerdings hätte ich auch hier keine Ahnung, wie man aus einem MonoBehaviour-Skript das untenstehende Script aufrufen kann und wo dieses denn hin müsste (da es sich ja an kein Gameobjekt anhängen lässt). Besten Dank für eure Hilfe! using System.Collections; using System.Collections.Generic; using System.Linq using System.Text; namespace Sudo { class Program { static bool checkZeile(int zeile, int wert, int[,] xox) { for (int i = 0; i < 9; i++) { if (xox[i, zeile] == wert) return false; } return true; } static bool checkSpalte(int spalte, int wert, int[,] xox) { for (int i = 0; i < 9; i++) { if (xox[spalte, i] == wert) return false; } return true; } static bool checkBlock(int zeile, int spalte, int wert, int[,] xox) { for (int i = 0; i < 3; i++) { if (i == spalte) continue; for (int j = 0; j < 3; j++) { if (j == zeile) continue; if (xox [spalte - (spalte % 3) + i, zeile - (zeile % 3) + j] == wert) return false; } } return true; } static bool checkMove(int zeile, int spalte, int wert, int[,] xox) { if (!checkZeile (zeile, wert, xox)) return false; if (!checkSpalte (zeile, wert, xox)) return false; if (!checkBlock (zeile, spalte, wert, xox)) return false; return true; } static int[,] BSudoku(int wert, int px, int py, int[,] field) { int[,] workerField = new int[9, 9]; System.Array.Copy (field, workerField, field.Length); //for (int i = 0; i < 9; i++) //{ // for (int j = 0; j < 9; j++) // { // workerField[i, j] = field[j, i]; // } //} workerField [px, py] = wert; for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { if (workerField [x, y] == 0) { for (int val = 1; val <= 9; val++) { if (checkMove (y, x, val, workerField)) { BSudoku (val, x, y, workerField); } } return null; } } } for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { Debug.Log (workerField[i, j]); } Debug.Log (" "); } Debug.Log ("--------"); return workerField; } static void Main(string[] args) { int[,] field = new int[9, 9]; BSudoku (0, 0, 0, field); } } }
  18. Ok! Ich werde die diversen Vorschläge ausprobieren. Danke an euch für eure Hilfestellungen!
  19. Ich glaube "EventSystem.current.currentSelectedGameObject" tut das, was ich will!
  20. Danke malzbie Die Überprüfung sollte aber auch erst nach Beendigung der Eingabe stattfinden! Ich habe das nun auf OnValue geändert. Nun möchte ich, wie von dir vorgeschlagen, eine Zahl übermitteln ( z.B. int eingabebox = 1 ...) . Wie geht denn das? Zitat: "bei OnValue.. weisst du welches Field eben gerade verändert wurde (da könntest du z.b. eine Zahl übermitteln)." Meine Idee wäre: Im Skript mittels einer Schleife herauszufinden, welche der Eingabebox "is.Focused" ist. Ist das der richtige Ansatz?
  21. Hallo zusammen Ich habe 6 InputFields nebeneinander positioniert. Der Anwender kann diese in beliebiger Reihenfolge anklicken und eine Eingabe machen. Nach jeder gemachten Eingabe möchte ich den Eingabewert kontrollieren. In "On End Edit (string)" hat jedes InputField eine Verknüpfung zu meinem Hauptskript in dem eine "void eingabetext(string s)" mir den aktuellen Eingabewert mitteilt. Das funktioniert soweit gut, allerdings weiss ich nicht, von welchem InputField der Eingabewert stammt! Genau das wäre aber wichtig zu wissen, um die Eingabe zu überprüfen! 1. Wie kann ich herausfinden, welches InputField der Anwender als letztes mit der Entertaste beendet hat oder mit Mausklick ins Leere bearbeitet hat? 2. Oder muss ich anstelle von "On End Edit (string)" besser "On Value Changed (string)" verwenden?
  22. Hallo zusammen Unter diesem Link https://news.infernalscoop.com/ahglzz habe ich ein Interview von dem Typen gelesen, der z.B. FlowScape in Unity realisiert hat. Seine Beispielprojekte finde ich visuell ziemlich beeindruckend. Das Erstaunliche ist aber, dass er solche Projekte praktisch ohne Code erstellen kann. Nach seinen Aussagen erreicht er das mit "Visual Scripting". - Ist das nun eine neue Technik, um Programme zu entwickeln? - Ist das bereits in Unity implementiert oder muss man das extra installieren? - Ist das auch für Unity 2017 verfügbar?
  23. Hallo zusammen Das folgende Script ist mit einem Button verknüpft. Wenn dieser Button gedrückt wird, wird ein Screenshot in den Projektordner gesichert. Im Editor funktioniert das einwandfrei (sowohl die Variante mit dem Datum wie auch die Variante mit fixem Filenamen). Problem: Nachdem ich Build und Run gedrückt habe, startet das Programm, aber das mit dem Screenshot funktioniert nicht mehr. Es wird kein Bild mehr gespeichert, zumindest kann ich es nirgends entdecken! Ich vermute, dass es sich um ein Pfadproblem handelt. Ich arbeite mit einem Mac OSX System, weiss aber nicht, wie man den Pfad zum Ordner, in den die Screenshots gespeichert werden können, korrekt setzen kann! Vielleicht fehlt irgend etwas im Stile von "Application.path" oder System.path". Eigentlich möchte ich, dass die Bilder in einen Ordner "Screenshots", welcher sich im Ordner "Dokumente" befindet, hineingespeichert werden! In meinem Fall: Harddisk > Benutzer > Benutzername > Dokumente > Screenshots Wie kann ich das beheben? Danke für eure Hilfe! using System.Collections; using System.Collections.Generic; using UnityEngine; public class screenshot : MonoBehaviour { public void shot () { Debug.Log ("Bild wurde gesichert!"); //var nameScreenshot = "Screenshot " + System.DateTime.Now.ToString("dd-MM-yyyy HH-mm-ss") + ".png"; //ScreenCapture.CaptureScreenshot(nameScreenshot); ScreenCapture.CaptureScreenshot("ScreenshotNEW.png");// , 1); für grössere Auflösung 1,2,3 oder 4 } }
×
×
  • Create New...