How to use " 9-sliced" image type in non-GUI elements? - unity3d

In my game, I am using simple textures on quads. I could see Unity GUI allows us to slice the image by setting "image type" option as sliced.
I would like to do the same to my other textures I use in quads.
In simple words, I dont want the edges of my textures to be scaled when the texture itself is scaled.
Thanks.

Looks like you have to generate the mesh yourself, not so hard as it sounds. The mesh has to look like this:
Each textured mesh is defined by vertices (red dots on the picture) and (in this case) each vertex has two parameters:
A Vector3 with position. Only x and y used here, as a quad is flat (so, z = 0).
A Vector2 with the UV, that is how the material is put on the mesh. This are the texture coordinates: u and v.
To configure this mesh, I added parameters:
b - for border - how big is the border of the gameobject (in 3d units)
w, h - for width and height of the gameobject (in 3d units)
m - how big is the margin in the image (in float 0f to 0.5f)
How to do this in Unity3d:
Create an GameObject, add a MeshRenderer with the material you want and an empty MeshFilter.
Add a script that creates a mesh. Look at Unity3d docs for Mesh, first example.
Note that for unity3d you have to create this with triangles, not quads (so for each quad make two triangles).

Chanibal's solutions worked like a charm for me, but since I wasn't an expert in the matter, it wasn't trivial to me to implement this. I will let this code here in case somebody could find it useful.
using UnityEngine;
public class SlicedMesh : MonoBehaviour
{
private float _b = 0.1f;
public float Border
{
get
{
return _b;
}
set
{
_b = value;
CreateSlicedMesh();
}
}
private float _w = 1.0f;
public float Width
{
get
{
return _w;
}
set
{
_w = value;
CreateSlicedMesh();
}
}
private float _h = 1.0f;
public float Height
{
get
{
return _h;
}
set
{
_h = value;
CreateSlicedMesh();
}
}
private float _m = 0.4f;
public float Margin
{
get
{
return _m;
}
set
{
_m = value;
CreateSlicedMesh();
}
}
void Start()
{
CreateSlicedMesh();
}
void CreateSlicedMesh()
{
Mesh mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.vertices = new Vector3[] {
new Vector3(0, 0, 0), new Vector3(_b, 0, 0), new Vector3(_w-_b, 0, 0), new Vector3(_w, 0, 0),
new Vector3(0, _b, 0), new Vector3(_b, _b, 0), new Vector3(_w-_b, _b, 0), new Vector3(_w, _b, 0),
new Vector3(0, _h-_b, 0), new Vector3(_b, _h-_b, 0), new Vector3(_w-_b, _h-_b, 0), new Vector3(_w, _h-_b, 0),
new Vector3(0, _h, 0), new Vector3(_b, _h, 0), new Vector3(_w-_b, _h, 0), new Vector3(_w, _h, 0)
};
mesh.uv = new Vector2[] {
new Vector2(0, 0), new Vector2(_m, 0), new Vector2(1-_m, 0), new Vector2(1, 0),
new Vector2(0, _m), new Vector2(_m, _m), new Vector2(1-_m, _m), new Vector2(1, _m),
new Vector2(0, 1-_m), new Vector2(_m, 1-_m), new Vector2(1-_m, 1-_m), new Vector2(1, 1-_m),
new Vector2(0, 1), new Vector2(_m, 1), new Vector2(1-_m, 1), new Vector2(1, 1)
};
mesh.triangles = new int[] {
0, 4, 5,
0, 5, 1,
1, 5, 6,
1, 6, 2,
2, 6, 7,
2, 7, 3,
4, 8, 9,
4, 9, 5,
5, 9, 10,
5, 10, 6,
6, 10, 11,
6, 11, 7,
8, 12, 13,
8, 13, 9,
9, 13, 14,
9, 14, 10,
10, 14, 15,
10, 15, 11
};
}
}

Here is another impementation of the same mesh as described above(just add Tile9Mesh script to empty GameObject and it should work
):
using UnityEngine;
namespace Util {
[ExecuteInEditMode]
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class Tile9Mesh : MonoBehaviour {
public float width = 1;
public float height = 1;
[Range(0, 0.5f)]
public float uvLeft = 0.2f;
[Range(0, 0.5f)]
public float uvRight = 0.2f;
[Range(0, 0.5f)]
public float uvTop = 0.2f;
[Range(0, 0.5f)]
public float uvBottom = 0.2f;
public float uvToWorldScaleX = 1;
public float uvToWorldScaleY = 1;
private Mesh mesh;
private Vector3[] vertices;
private Vector2[] uv;
private void Start() {
vertices = new Vector3[16];
uv = new Vector2[16];
mesh = new Mesh {
name = "Tile9Mesh"
};
FillGeometry();
FillMesh();
mesh.triangles = new[] {
0, 1, 12, 0, 12, 11,
1, 2, 13, 1, 13, 12,
2, 3, 4, 2, 4, 13,
13, 4, 5, 13, 5, 14,
14, 5, 6, 14, 6, 7,
15, 14, 7, 15, 7, 8,
10, 15, 8, 10, 8, 9,
11, 12, 15, 11, 15, 10,
12, 13, 14, 12, 14, 15
};
RecalculateMesh();
gameObject.GetComponent<MeshFilter>().mesh = mesh;
}
public void UpdateMesh() {
if (mesh != null) {
FillGeometry();
FillMesh();
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
}
private void FillGeometry() {
{
float w = width;
float h = height;
float l = uvLeft * uvToWorldScaleX;
float r = width - uvRight * uvToWorldScaleX;
float t = height - uvTop * uvToWorldScaleY;
float b = uvBottom * uvToWorldScaleY;
vertices[0] = new Vector3(0, 0, 0);
vertices[1] = new Vector3(0, b, 0);
vertices[2] = new Vector3(0, t, 0);
vertices[3] = new Vector3(0, h, 0);
vertices[4] = new Vector3(l, h, 0);
vertices[5] = new Vector3(r, h, 0);
vertices[6] = new Vector3(w, h, 0);
vertices[7] = new Vector3(w, t, 0);
vertices[8] = new Vector3(w, b, 0);
vertices[9] = new Vector3(w, 0, 0);
vertices[10] = new Vector3(r, 0, 0);
vertices[11] = new Vector3(l, 0, 0);
vertices[12] = new Vector3(l, b, 0);
vertices[13] = new Vector3(l, t, 0);
vertices[14] = new Vector3(r, t, 0);
vertices[15] = new Vector3(r, b, 0);
}
{
const float w = 1;
const float h = 1;
float l = uvLeft;
float r = 1 - uvRight;
float t = 1 - uvTop;
float b = uvBottom;
uv[0] = new Vector2(0, 0);
uv[1] = new Vector2(0, b);
uv[2] = new Vector2(0, t);
uv[3] = new Vector2(0, h);
uv[4] = new Vector2(l, h);
uv[5] = new Vector2(r, h);
uv[6] = new Vector2(w, h);
uv[7] = new Vector2(w, t);
uv[8] = new Vector2(w, b);
uv[9] = new Vector2(w, 0);
uv[10] = new Vector2(r, 0);
uv[11] = new Vector2(l, 0);
uv[12] = new Vector2(l, b);
uv[13] = new Vector2(l, t);
uv[14] = new Vector2(r, t);
uv[15] = new Vector2(r, b);
}
}
private void FillMesh() {
mesh.vertices = vertices;
mesh.uv = uv;
}
private void RecalculateMesh() {
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
#if UNITY_EDITOR
private void OnValidate() {
if (mesh != null) {
UpdateMesh();
}
}
#endif
}
}

Related

Unity: How to Create a projection such that the local coordinates match the monitor coordinates

I'm learning about mesh rendering in unity.
I followed the documentation and was able to draw a blue quad on the screen.
However I can't figure out how render thinng such that the entire monitor is used.
I think what I'm missing is setting some sort of projections for this coordinate system to match. But how can I do that? Ideally I would like to do:
x_start = 0;
x_end = W;
y_start = 0;
y_end = H;
And have this quad cover the entire screen.
Here is the code:
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class MeshRendererTest : MonoBehaviour
{
// Start is called before the first frame update
static Material mat;
float z;
float W;
float H;
Matrix4x4 projectionMatrix;
void Start(){
W = 2480.0f;
H = 2416.0f;
//projectionMatrix = Matrix4x4.Ortho(0, (int)W, (int)H, 0, -1, 100);
Shader shader = Shader.Find("Hidden/Internal-Colored");
//Shader shader2 = Shader.Find("Standard");
//Shader shader2 = Shader.Find("Unlit/UnlitAlphaWithFade");
mat = new Material(shader);
mat.hideFlags = HideFlags.HideAndDontSave;
//texMat.hideFlags = HideFlags.HideAndDontSave;
// Turn backface culling off
mat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
//texMat.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
// Turn off depth writes
mat.SetInt("_ZWrite", 0);
//texMat.SetInt("_ZWrite", 0);
z = 999.0f;
mat.SetColor("_Color", Color.blue);
mat.SetPass(0);
MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
if (meshRenderer == null){
Debug.Log("Mesh Renderer is NUll");
return;
}
//meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));
meshRenderer.sharedMaterial = mat;
MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
if (meshFilter == null){
Debug.Log("Mesh Filter is NUll");
return;
}
Mesh mesh = new Mesh();
float x_start = 0;
float x_end = x_start + 100;
float y_start = 0;
float y_end = y_start + 600;
Vector3[] vertices = new Vector3[4]
{
new Vector3(x_start, y_start, z),
new Vector3(x_end, y_start, z),
new Vector3(x_start, y_end, z),
new Vector3(x_end, y_end, z)
};
mesh.vertices = vertices;
int[] tris = new int[6]
{
// lower left triangle
0, 2, 1,
// upper right triangle
2, 3, 1
};
mesh.triangles = tris;
Vector3[] normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
meshFilter.mesh = mesh;
}
void OnRenderObject(){
TestStuff();
}
void TestStuff(){
Camera.main.ResetProjectionMatrix();
Matrix4x4 newProj = Matrix4x4.identity;
newProj = newProj * transform.localToWorldMatrix;
newProj = newProj * Camera.main.projectionMatrix;
newProj = newProj * projectionMatrix;
Camera.main.projectionMatrix = newProj;
}
}

How do I add FVectors to a TArray<FVector>?

I am trying to create a TArray Recoil Pattern for my Gun with 30 different FVector coordinates for each bullet. I went through tultorial videos and read https://docs.unrealengine.com/5.0/en-US/array-containers-in-unreal-engine/ this guide for adding to the array.I tried using Add, Emplace, Innit to no avail. I even set the size to 30 with SetNum, still didn't work i do not understand what my issue is with adding elements to the TArray. I keep getting this crash error : I keep getting this crash error
this is my GunProperties.H
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/BoxComponent.h"
#include "Camera/CameraComponent.h"
#include "GunProperties.generated.h"
#define TRACE_WEAPON ECC_GameTraceChannel1
UENUM(BlueprintType)
namespace EWeaponProjectile
{
enum ProjectileType
{
EBullet UMETA(DisplayName = "Bullet"),
ESpread UMETA(DisplayName = "Spread"),
EProjectile UMETA(DisplayName = "Projectile"),
};
}
USTRUCT()
struct FWeaponData
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditDefaultsOnly, Category = Ammo)
int32 MaxAmmo;
UPROPERTY(EditDefaultsOnly, Category = Config)
float TimeBetweenShots;
UPROPERTY(EditDefaultsOnly, Category = Ammo)
int32 ShotCost;
UPROPERTY(EditDefaultsOnly, Category = Config)
float WeaponRange;
UPROPERTY(EditDefaultsOnly, Category = Config)
float WeaponSpread;
UPROPERTY(EditDefaultsOnly, Category = Config)
float recoilResetTimeSeconds;
UPROPERTY(EditDefaultsOnly, Category = Config)
float lastTimeShotForAr;
};
UCLASS()
class PLAYERVSAI_API AGunProperties : public AActor
{
GENERATED_BODY()
public:
// Called when the game starts or when spawned
AGunProperties();
// Called every frame
UFUNCTION()
void Fire(const FVector CameraDir);
UFUNCTION()
void InstantFire(const FVector CameraDir);
virtual void BeginPlay() override;
UPROPERTY(EditDefaultsOnly, Category = Config)
FWeaponData WeaponConfig;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = Config)
TEnumAsByte<EWeaponProjectile::ProjectileType> ProjectileType;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Collision)
UBoxComponent* CollisionComp;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Config)
USkeletalMeshComponent* WeaponMesh;
/*void InterpAiming(float DeltaSeconds);
void InterpRelativeHand(float DeltaSeconds);*/
FTransform RecoilTransform;
FTransform FinalRecoilTransform;
//Handle Vector Recoil , returns New Location
protected:
FHitResult WeaponTrace(const FVector &TraceFrom, const FVector &TraceTo) const;
void HandleARShooting(UCameraComponent* Camera);
void ProcessInstantHit(const FHitResult& Impact, const FVector& Origin, const FVector& ShootDir, int32 RandomSeed, float RadicalSpread);
void ProcessInstantHitForAR(const FHitResult& Impact, const FVector& Origin);
TArray<FVector> RecoilPattern[];
};
This is my GunProperties.cpp
#include "GunProperties.h"
#include "Engine.h"
AGunProperties::AGunProperties()
{
PrimaryActorTick.bCanEverTick = false;
CollisionComp = CreateDefaultSubobject<UBoxComponent>(TEXT("CollisionComp"));
RootComponent = CollisionComp;
WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Gun Mesh"));
WeaponMesh->AttachTo(RootComponent);
}
void AGunProperties::BeginPlay()
{
Super::BeginPlay();
if (ProjectileType == EWeaponProjectile::EBullet)
{
RecoilPattern->SetNum(30);
RecoilPattern->Emplace(FVector(-0.2, 0, 0));
RecoilPattern->Emplace(FVector(-0.2, 0, 0));
RecoilPattern->Emplace(FVector(-0.2, 0, 0));
RecoilPattern->Emplace(FVector(-0.2, 0, 0));
RecoilPattern->Emplace(FVector(-0.2, 0, 0));
RecoilPattern->Emplace(FVector(-0.2, 0, 0));
RecoilPattern->Emplace(FVector(-0.3, 0, 0));
RecoilPattern->Emplace(FVector(-0.3, 0, 0));
RecoilPattern->Emplace(FVector(-0.3, 0, 0));
RecoilPattern->Emplace(FVector(-0.3, 0, 0));
RecoilPattern->Emplace(FVector(-0.3, 0, 0));
RecoilPattern->Emplace(FVector(-0.3, 0, 0));
RecoilPattern->Emplace(FVector(-0.5, 0, 0));
RecoilPattern->Emplace(FVector(-0.5, 0, 0));
RecoilPattern->Emplace(FVector(-0.5, 0, 0));
RecoilPattern->Emplace(FVector(-0.5, 0, 0));
RecoilPattern->Emplace(FVector(-0.5, 0, 0));
RecoilPattern->Emplace(FVector(-0.5, 0, 0));
RecoilPattern->Emplace(FVector(0, -0.3, 0));
RecoilPattern->Emplace(FVector(0, -0.3, 0));
RecoilPattern->Emplace(FVector(0, -0.3, 0));
RecoilPattern->Emplace(FVector(0, -0.3, 0));
RecoilPattern->Emplace(FVector(0, -0.3, 0));
RecoilPattern->Emplace(FVector(0, -0.3, 0));
RecoilPattern->Emplace(FVector(0, 0.3, 0));
RecoilPattern->Emplace(FVector(0, 0.3, 0));
RecoilPattern->Emplace(FVector(0, 0.3, 0));
RecoilPattern->Emplace(FVector(0, 0.3, 0));
RecoilPattern->Emplace(FVector(0, 0.3, 0));
RecoilPattern->Emplace(FVector(0, 0.3, 0));
}
}
void AGunProperties::Fire( FVector CameraDir)
{
if (ProjectileType == EWeaponProjectile::EBullet)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Black, TEXT("Bullet"));
//InstantFire(CameraDir);
}
if (ProjectileType == EWeaponProjectile::ESpread)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Black, TEXT("Spread"));
for (int32 i = 0; i <= WeaponConfig.WeaponSpread; i++)
{
InstantFire(CameraDir);
}
}
if (ProjectileType == EWeaponProjectile::EProjectile)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Black, TEXT("Projectile"));
}
}
void AGunProperties::InstantFire( FVector CameraDir)
{
const int32 RandomSeed = FMath::Rand();
FRandomStream WeaponRandomStream(RandomSeed);
const float CurrentSpread = WeaponConfig.WeaponSpread;
const float SpreadCone = FMath::DegreesToRadians(WeaponConfig.WeaponSpread );
const FVector StartTrace = WeaponMesh->GetSocketLocation("MF");
const FVector ShootDir = WeaponRandomStream.VRandCone(StartTrace, SpreadCone, SpreadCone);
const FVector EndTrace = StartTrace + ShootDir * WeaponConfig.WeaponRange;
const FHitResult Impact = WeaponTrace(StartTrace, EndTrace);
ProcessInstantHit(Impact, StartTrace, ShootDir, RandomSeed, CurrentSpread);
}
FHitResult AGunProperties::WeaponTrace(const FVector& TraceFrom, const FVector& TraceTo) const
{
static FName WeaponFireTag = FName(TEXT("WeaponTrace"));
FCollisionQueryParams TraceParams(WeaponFireTag, true);
TraceParams.bReturnPhysicalMaterial = true;
TraceParams.AddIgnoredActor(this);
FHitResult Hit(ForceInit);
GetWorld()->LineTraceSingleByChannel(Hit, TraceFrom, TraceTo, TRACE_WEAPON, TraceParams);
return Hit;
}
void AGunProperties::HandleARShooting(UCameraComponent* Camera)
{
if (GetWorld()->DeltaTimeSeconds - WeaponConfig.lastTimeShotForAr / WeaponConfig.TimeBetweenShots)
{
//We shoot
const FVector StartTrace = WeaponMesh->GetSocketLocation("MF");
const FVector ShootDir = FVector(StartTrace);
const FVector EndTrace = StartTrace * WeaponConfig.WeaponRange;
const FHitResult Impact = WeaponTrace(StartTrace, EndTrace);
ProcessInstantHitForAR(Impact, StartTrace);
WeaponConfig.lastTimeShotForAr = GetWorld()->DeltaTimeSeconds;
}
}
void AGunProperties::ProcessInstantHit(const FHitResult& Impact, const FVector& Origin, const FVector& ShootDir, int32 RandomSeed, float RadicalSpread)
{
const FVector EndTrace = Origin + ShootDir * WeaponConfig.WeaponRange;
const FVector EndPoint = Impact.GetActor() ? Impact.ImpactPoint : EndTrace;
DrawDebugLine(this->GetWorld(), Origin, Impact.TraceEnd, FColor::Black,false, 1000, 10.f);
}
void AGunProperties::ProcessInstantHitForAR(const FHitResult& Impact, const FVector& Origin)
{
const FVector EndTrace = Origin* WeaponConfig.WeaponRange;
const FVector EndPoint = Impact.GetActor() ? Impact.ImpactPoint : EndTrace;
DrawDebugLine(this->GetWorld(), Origin, Impact.TraceEnd, FColor::Black, false, 1000, 10.f);
}
The issues was that i did not add UPROPERTY() above the TArray. Epic does not mention this in the guide that i linked or maybe i missed it somewhere. Give the credits to the people in this post who mentioned it . https://forums.unrealengine.com/t/why-does-the-engine-crash-when-adding-to-an-array/82703/8

modulo to cycle though a compute buffer not working as expected

The Setup
In my compute-shader I have a StructuredBuffer that is storing an amount of colors. There is also an int variable storing the amount of colors in total ( _colres ). From another script a node tree is dispatched into the shader every frame. The amount of nodes changes dynamically. Because of that the points buffer containing the nodes is at a fixed size of 8192 that the amount of nodes never exceeds.
The Problem
When I'm now trying to draw the points I am storing in the points buffer, oddly enough only every third color is displayed, starting at index [0] (tested for up to 12 colors -> [0],[3],[6],[9]).
Result[pointsBuffer[id.x].xy] = colorsBuffer[id.x % _colres];
What I tried
I used the fmod() function instead but was presented with the same result. Individually targeting stored colors by hard-coding the index has worked so my guess would be that the colors buffer is not the problem. Maybe it has something to do with all the empty spaces in the pointsbuffer but I could't figure it out.
The Question(s)
Is there a fundamental problem I am overlooking?
Is there some other simple way to cycle through the indices of my colorsbuffer that works in this scenario?
Detailed Information
System:
Unity Version 2021.2.12f1 using the HDRP on MacOS Monterey 12.2.1
Compute-Shader
#pragma kernel DrawPoints
// texture
shared RWTexture2D<float4> Result;
int _texres;
int _colres;
// buffer
StructuredBuffer<float2> pointsBuffer;
StructuredBuffer<float4> colorsBuffer;
[numthreads(64,1,1)]
void DrawPoints (uint3 id : SV_DispatchThreadID)
{
if ((pointsBuffer[id.x].x * pointsBuffer[id.x].y) > 0) Result[pointsBuffer[id.x].xy] = colorsBuffer[id.x % _colres];
}
C# Setup
public differentialGrowth diffGrowth;
int texResolution = 4096;
int colorAmount = 12;
RenderTexture settingRef;
Material target;
ComputeShader shader;
RenderTexture outputTexture;
ComputeBuffer pointsBuffer;
ComputeBuffer colorsBuffer;
int pointsHandle;
void Start()
{
outputTexture = new RenderTexture(settingRef);
outputTexture.enableRandomWrite = true;
outputTexture.Create();
// INIT
pointsHandle = shader.FindKernel("DrawPoints");
shader.SetInt("_texres", texResolution);
shader.SetInt("_colres", colorAmount);
int stride = (3) * 4; // every component as a float (3) * 4 bytes per float
pointsBuffer = new ComputeBuffer(8192, stride);
stride = (4) * 4;
colorsBuffer = new ComputeBuffer(colorAmount, stride);
shader.SetTexture( pointsHandle, "Result", outputTexture );
target.SetTexture("_MainTex", outputTexture);
Color[] testColors = new Color[colorAmount];
testColors[0] = new Color(1, 0, 0, 0); //red _ yes
testColors[1] = new Color(0, 1, 0, 0); //green
testColors[2] = new Color(0, 0, 1, 0); //blue
testColors[3] = new Color(1, 1, 0, 0); //yellow _yes
testColors[4] = new Color(0, 1, 1, 0); //cyan
testColors[5] = new Color(1, 0, 1, 0); //magenta
testColors[6] = new Color(0.5f, 0, 1, 0); //mix6 _yes
testColors[7] = new Color(1, 0.5f, 1, 0); //mix7
testColors[8] = new Color(0.5f, 0, 1, 0); //mix8
testColors[9] = new Color(0.5f, 0.5f, 1, 0); //mix9 _yes
testColors[10] = new Color(0.5f, 0.5f, 1, 0); //mix10
testColors[11] = new Color(0.5f, 0.5f, 1, 0); //mix11
}
void Update()
{
pointsBuffer.SetData(diffGrowth.nodes.Points);
shader.SetBuffer(pointsHandle, "colorsBuffer", colorsBuffer);
shader.SetBuffer(pointsHandle, "pointsBuffer", pointsBuffer);
shader.Dispatch(pointsHandle, 128, 1, 1);
}
private void OnDestroy()
{
if (pointsBuffer != null) pointsBuffer.Dispose();
if (colorsBuffer != null) colorsBuffer.Dispose();
}
}

How to pan/scale the contents inside a GUI area?

I want to have a zoom effect inside an area in a EditorWindow, something like a zoomable scrollview.
The following snippet deals only with the panning effect but it exemplifies the issue I'm having when the contents inside the zoomable area and the clipping rect can't be handled independently of each other through hSliderValue1 (clipping) and hSliderValue2 (panning).
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ZoomTestWindow : EditorWindow
{
private static float kEditorWindowTabHeight = 20;
private static Matrix4x4 _prevGuiMatrix;
public static float hSliderValue1 = 0;
public static float hSliderValue2 = 0;
Rect[] wr = new Rect[]{
new Rect(0, 0, 100, 100),
new Rect(50, 50, 100, 100),
new Rect(100, 100, 100, 100)
};
[MenuItem("Window/Zoom Test #%w")]
private static void Init()
{
ZoomTestWindow window = EditorWindow.GetWindow<ZoomTestWindow>("Zoom Test", true, new System.Type[] {
typeof(UnityEditor.SceneView),
typeof(EditorWindow).Assembly.GetType("UnityEditor.SceneHierarchyWindow")});
window.Show();
EditorWindow.FocusWindowIfItsOpen<ZoomTestWindow>();
}
public static Rect BeginZoomArea()
{
GUI.EndGroup(); //End the group that Unity began so we're not bound by the EditorWindow
GUI.BeginGroup(new Rect(hSliderValue1, 0, 200, 200));
_prevGuiMatrix = GUI.matrix;
GUI.matrix = Matrix4x4.TRS(new Vector2(hSliderValue2, 0), Quaternion.identity, Vector3.one);;
return new Rect();
}
public static void EndZoomArea()
{
GUI.matrix = _prevGuiMatrix;
GUI.EndGroup();
GUI.BeginGroup(new Rect(0.0f, kEditorWindowTabHeight, Screen.width, Screen.height - (kEditorWindowTabHeight + 3)));
}
public void OnGUI()
{
BeginZoomArea();
BeginWindows();
wr[0] = GUI.Window(0, wr[0], DrawWindow, "hello");
wr[1] = GUI.Window(1, wr[1], DrawWindow, "world");
wr[2] = GUI.Window(2, wr[2], DrawWindow, "!");
EndWindows();
EndZoomArea();
hSliderValue1 = GUI.HorizontalSlider(new Rect(200, 5, 100, 30), hSliderValue1, 0, 100);
hSliderValue2 = GUI.HorizontalSlider(new Rect(200, 25, 100, 30), hSliderValue2, 0, 100);
}
void DrawWindow(int id)
{
GUI.Button(new Rect(0, 30, 100, 50), "Wee!");
GUI.DragWindow();
}
}
Is there a way to do this, maybe by using a scroll view?
Embed the group controlled by hSliderValue1 inside a new group.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ZoomMoveTestWindow: EditorWindow
{
private static float kEditorWindowTabHeight = 20;
private static Matrix4x4 _prevGuiMatrix;
public static float hSliderValue1 = 0;
public static float hSliderValue2 = 0;
Rect[] wr = new Rect[]{
new Rect(0, 0, 100, 100),
new Rect(50, 50, 100, 100),
new Rect(100, 100, 100, 100)
};
[MenuItem("Window/Zoom Test #%w")]
private static void Init()
{
ZoomMoveTestWindow window = EditorWindow.GetWindow<ZoomMoveTestWindow>("Zoom Test", true, new System.Type[] {
typeof(UnityEditor.SceneView),
typeof(EditorWindow).Assembly.GetType("UnityEditor.SceneHierarchyWindow")});
window.Show();
EditorWindow.FocusWindowIfItsOpen<ZoomMoveTestWindow>();
}
public static Rect BeginZoomArea(Rect rect)
{
GUI.BeginGroup(rect);
GUI.BeginGroup(new Rect(hSliderValue1, 0, 200, 200));
_prevGuiMatrix = GUI.matrix;
GUI.matrix = Matrix4x4.TRS(new Vector2(hSliderValue2, 0), Quaternion.identity, Vector3.one);
return new Rect();
}
public static void EndZoomArea()
{
GUI.EndGroup();
GUI.matrix = _prevGuiMatrix;
GUI.EndGroup();
GUI.BeginGroup(new Rect(0.0f, kEditorWindowTabHeight, Screen.width, Screen.height - (kEditorWindowTabHeight + 3)));
}
public void OnGUI()
{
GUI.EndGroup(); //End the group that Unity began so we're not bound by the EditorWindow
BeginZoomArea(new Rect(10,10, 200, 200));
BeginWindows();
wr[0] = GUI.Window(0, wr[0], DrawWindow, "hello");
wr[1] = GUI.Window(1, wr[1], DrawWindow, "world");
wr[2] = GUI.Window(2, wr[2], DrawWindow, "!");
EndWindows();
EndZoomArea();
hSliderValue1 = GUI.HorizontalSlider(new Rect(250, 5, 100, 30), hSliderValue1, 0, 100);
hSliderValue2 = GUI.HorizontalSlider(new Rect(250, 35, 100, 30), hSliderValue2, 0, 100);
}
void DrawWindow(int id)
{
GUI.Button(new Rect(0, 30, 100, 50), "Wee!");
GUI.DragWindow();
}
}
It works but I don't know why. Because the interaction of GUI.matrix and BeginGroup(rect) is unknown.
PS: This post may help you.

How to add to scene own gameobject on unity

I create my own cube. I use below code to do it
void Start () {
MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();
Mesh mesh = new Mesh ();
meshFilter.mesh = mesh;
mesh.vertices = new Vector3[]{
// face 1 (xy plane, z=0)
new Vector3(0,0,0),
new Vector3(1,0,0),
new Vector3(1,1,0),
new Vector3(0,1,0),
// face 2 (zy plane, x=1)
new Vector3(1,0,0),
new Vector3(1,0,1),
new Vector3(1,1,1),
new Vector3(1,1,0),
// face 3 (xy plane, z=1)
new Vector3(1,0,1),
new Vector3(0,0,1),
new Vector3(0,1,1),
new Vector3(1,1,1),
// face 4 (zy plane, x=0)
new Vector3(0,0,1),
new Vector3(0,0,0),
new Vector3(0,1,0),
new Vector3(0,1,1),
// face 5 (zx plane, y=1)
new Vector3(0,1,0),
new Vector3(1,1,0),
new Vector3(1,1,1),
new Vector3(0,1,1),
// face 6 (zx plane, y=0)
new Vector3(0,0,0),
new Vector3(0,0,1),
new Vector3(1,0,1),
new Vector3(1,0,0),
};
int faces = 6; // here a face = 2 triangles
List<int> triangles = new List<int>();
List<Vector2> uvs = new List<Vector2>();
for (int i = 0; i < faces; i++) {
int triangleOffset = i*4;
triangles.Add(0+triangleOffset);
triangles.Add(2+triangleOffset);
triangles.Add(1+triangleOffset);
triangles.Add(0+triangleOffset);
triangles.Add(3+triangleOffset);
triangles.Add(2+triangleOffset);
// same uvs for all faces
uvs.Add(new Vector2(0,0));
uvs.Add(new Vector2(1,0));
uvs.Add(new Vector2(1,1));
uvs.Add(new Vector2(0,1));
}
mesh.triangles = triangles.ToArray();
mesh.uv = uvs.ToArray();
GetComponent<Renderer>().material = new Material(Shader.Find("Diffuse"));
mesh.RecalculateNormals();
mesh.RecalculateBounds ();
mesh.Optimize();
I want to add this object many times at runtime. I create a prefab by click right button on editor. I drag gameobject to it. I create a member variable public Gameobject prefab. I drag prefab to member variable on inspector.
I want to add 2 cube on my scene. I use below code but it doesn't work for me. It adds many objects.
I use below code clone and add object
prefab = gameObject;
// for (int i = 0; i < 3; i++) {
gO = Instantiate (prefab, new Vector3 (0 * 1.8F - 8.2f, 0, 0), Quaternion.identity) as GameObject;
// }
How can I create a prefab from my own gameobject? How can I add it to scene at runtime properly?
EDIT
If I create unity shape from editor, and I drag it to prefab, I can add many object on C# code. But I can't do same work for my own cube.
So in the end you have 2 Scripts:
public class CubeFactory : MonoBehaviour
{
public GameObject PrefabToCreate;
// Use this for initialization
void Start () {
var cube = Instantiate(PrefabToCreate, new Vector3(0 * 1.8F - 8.2f, 0, 0), Quaternion.identity) as GameObject;
}
// Update is called once per frame
void Update () {
}
}
and
public class Cube : MonoBehaviour
{
private void Start()
{
MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();
Mesh mesh = new Mesh();
meshFilter.mesh = mesh;
mesh.vertices = new Vector3[]
{
// face 1 (xy plane, z=0)
new Vector3(0, 0, 0),
new Vector3(1, 0, 0),
new Vector3(1, 1, 0),
new Vector3(0, 1, 0),
// face 2 (zy plane, x=1)
new Vector3(1, 0, 0),
new Vector3(1, 0, 1),
new Vector3(1, 1, 1),
new Vector3(1, 1, 0),
// face 3 (xy plane, z=1)
new Vector3(1, 0, 1),
new Vector3(0, 0, 1),
new Vector3(0, 1, 1),
new Vector3(1, 1, 1),
// face 4 (zy plane, x=0)
new Vector3(0, 0, 1),
new Vector3(0, 0, 0),
new Vector3(0, 1, 0),
new Vector3(0, 1, 1),
// face 5 (zx plane, y=1)
new Vector3(0, 1, 0),
new Vector3(1, 1, 0),
new Vector3(1, 1, 1),
new Vector3(0, 1, 1),
// face 6 (zx plane, y=0)
new Vector3(0, 0, 0),
new Vector3(0, 0, 1),
new Vector3(1, 0, 1),
new Vector3(1, 0, 0),
};
int faces = 6; // here a face = 2 triangles
List<int> triangles = new List<int>();
List<Vector2> uvs = new List<Vector2>();
for (int i = 0; i < faces; i++)
{
int triangleOffset = i*4;
triangles.Add(0 + triangleOffset);
triangles.Add(2 + triangleOffset);
triangles.Add(1 + triangleOffset);
triangles.Add(0 + triangleOffset);
triangles.Add(3 + triangleOffset);
triangles.Add(2 + triangleOffset);
// same uvs for all faces
uvs.Add(new Vector2(0, 0));
uvs.Add(new Vector2(1, 0));
uvs.Add(new Vector2(1, 1));
uvs.Add(new Vector2(0, 1));
}
mesh.triangles = triangles.ToArray();
mesh.uv = uvs.ToArray();
GetComponent<Renderer>().material = new Material(Shader.Find("Diffuse"));
mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.Optimize();
}
}
in your Scene you have your Camera and a GameObject with the CubeFactory on it.
Before you have to make a Prefab. Wich contains a GameObject with the "Cube.cs" Script on it.
Add the prefab as "PrefabToCreate" to your Cubefactory in the inspector.