400 lines
14 KiB
C#
400 lines
14 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class Environment : MonoBehaviour
|
|
{
|
|
public int sizeX = 100;
|
|
public int sizeY = 100;
|
|
public int sizeZ = 100;
|
|
public float voxelSize = 0.1f;
|
|
// public bool visualizeWater = true;
|
|
public bool visualizeLigth = true;
|
|
public int visualizeEveryNVoxel = 100;
|
|
public GameObject shape;
|
|
public GameObject ball;
|
|
// Voxel[,,] voxelSpace;
|
|
byte[,,] voxelSpace;
|
|
|
|
private Bounds bounds;
|
|
public Material material;
|
|
|
|
public bool rotateTowardsLight = false;
|
|
public bool sendShadowToLSystem = true;
|
|
public bool cutBranchesWithMaxShadow = false;
|
|
|
|
|
|
private ComputeBuffer meshPropertiesBuffer;
|
|
private ComputeBuffer argsBuffer;
|
|
|
|
|
|
List<List<Matrix4x4>> transformListJ;
|
|
|
|
// Start is called before the first frame update
|
|
public void Reset()
|
|
{
|
|
Start();
|
|
}
|
|
void Start()
|
|
{
|
|
voxelSpace = new byte[sizeX, sizeY, sizeZ];
|
|
for(int i = 0; i < sizeX; i++)
|
|
{
|
|
for(int k = 0; k < sizeZ; k++)
|
|
{
|
|
for(int j = sizeY-1; j >= 0; j--)
|
|
{
|
|
voxelSpace[i,j,k] = (byte)1;
|
|
if(i == 0 || i == sizeX-1 || k == 0 || k == sizeZ -1)
|
|
{
|
|
voxelSpace[i,j,k] = (byte)255;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
List<Matrix4x4> transformList = new List<Matrix4x4>();
|
|
transformListJ = new List<List<Matrix4x4>>();
|
|
for(int i = 0; i < sizeX; i++)
|
|
{
|
|
for(int k = 0; k < sizeZ; k++)
|
|
{
|
|
for(int j = sizeY-1; j >= 0; j--)
|
|
{
|
|
if(visualizeLigth &&
|
|
(i%visualizeEveryNVoxel == 0 && j%visualizeEveryNVoxel == 0 && k%visualizeEveryNVoxel == 0 ))
|
|
{
|
|
Vector3 position = gameObject.GetComponent<Transform>().position;
|
|
Matrix4x4 matrixLigth = new Matrix4x4();
|
|
|
|
//Take the origin position, and apply the offsets
|
|
position.x += i*voxelSize;
|
|
position.y += j*voxelSize;
|
|
position.z += k*voxelSize;
|
|
|
|
//Create a matrix for the position created from this iteration of the loop
|
|
|
|
//Set the position/rotation/scale for this matrix
|
|
if(voxelSpace[i,j,k] != null)
|
|
{
|
|
matrixLigth.SetTRS(position, Quaternion.Euler(Vector3.zero),new Vector3(voxelSpace[i,j,k]*voxelSize*visualizeEveryNVoxel/255.0f, voxelSpace[i,j,k]*voxelSize*visualizeEveryNVoxel/255.0f, voxelSpace[i,j,k]*voxelSize*visualizeEveryNVoxel/255.0f));
|
|
}
|
|
else
|
|
{
|
|
matrixLigth.SetTRS(position, Quaternion.Euler(Vector3.zero), new Vector3(0,0,0));
|
|
}
|
|
transformList.Add(matrixLigth);
|
|
}
|
|
if(transformList.Count > 1020)
|
|
{
|
|
transformListJ.Add(transformList);
|
|
transformList = new List<Matrix4x4>();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(transformList.Count > 0)
|
|
{
|
|
transformListJ.Add(transformList);
|
|
transformList = new List<Matrix4x4>();
|
|
}
|
|
|
|
// Debug.Log("G_first_frame_end");
|
|
}
|
|
|
|
// Update is called once per frame
|
|
int frame = 0;
|
|
void Update()
|
|
{
|
|
if(frame > 60)
|
|
{
|
|
for(int i = 0;i<transformListJ.Count;i++)
|
|
{
|
|
Graphics.DrawMeshInstanced(shape.GetComponent<MeshFilter>().mesh, 0, shape.GetComponent<MeshRenderer>().material, transformListJ[i], null, UnityEngine.Rendering.ShadowCastingMode.Off, false);
|
|
}
|
|
}
|
|
if(frame%300 == 0)
|
|
{
|
|
int mxx = 0;
|
|
Vector3 pos = new Vector3(0,0,0);
|
|
for(int j = sizeY-1; j >= 0; j--)
|
|
{
|
|
for(int i = 0; i < sizeX; i++)
|
|
{
|
|
for(int k = 0; k < sizeZ; k++)
|
|
{
|
|
if(voxelSpace[i,j,k] > mxx)
|
|
{
|
|
mxx = voxelSpace[i,j,k];
|
|
pos = new Vector3(i, j, k);
|
|
// Debug.Log("mxPos = "+mxx+" "+pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ball.GetComponent<Transform>().position = pos*voxelSize+gameObject.GetComponent<Transform>().position;
|
|
ball.name = "shadow max = "+mxx;
|
|
// Debug.Log("mxShadow = "+mxx);
|
|
|
|
}
|
|
|
|
frame += 1;
|
|
// Debug.Log("frame"+frame);
|
|
}
|
|
public void addShadowPoint(Vector3 position, sbyte strength) // negative value to remove
|
|
{
|
|
Vector3 voxelPosition = positionInVoxel(position);
|
|
Debug.Log(voxelPosition+" adding "+strength);
|
|
if(inVoxelSpace((int)voxelPosition.x,(int)voxelPosition.y,(int)voxelPosition.z))
|
|
{
|
|
voxelSpace[(int)voxelPosition.x,(int)voxelPosition.y,(int)voxelPosition.z] += (byte)strength;
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("not in vexel space: "+voxelPosition+" - error adding");
|
|
}
|
|
|
|
}
|
|
public void removeShadow(Vector3 position, sbyte strength) // negative value to remove
|
|
{
|
|
addShadow(position, (sbyte)-strength);
|
|
}
|
|
public void addShadow(Vector3 position, sbyte strength) // negative value to remove
|
|
{
|
|
// 6.2 / 0.1 = 62.0
|
|
Vector3 voxelPosition = positionInVoxel(position);
|
|
for(int j = (int)voxelPosition.y; j >= 0; j--)
|
|
{
|
|
if(voxelPosition.y - j > 250)
|
|
{
|
|
break;
|
|
}
|
|
int rotj = (int)(voxelPosition.y - j)*1;
|
|
for(int i = (int)voxelPosition.x-rotj; i <= (int)voxelPosition.x+rotj; i++)
|
|
{
|
|
for(int k = (int)voxelPosition.z-rotj; k <= (int)voxelPosition.z+rotj; k++)
|
|
{
|
|
|
|
if(inVoxelSpace(i, j, k)&&
|
|
(i%visualizeEveryNVoxel == 0 && j%visualizeEveryNVoxel == 0 && k%visualizeEveryNVoxel == 0 ))
|
|
{
|
|
float secondaryStrength = 1.0f*strength;
|
|
secondaryStrength = secondaryStrength/((Mathf.Abs(k-(int)voxelPosition.z)+1+Mathf.Abs(i-(int)voxelPosition.x))/8.0f);
|
|
// Debug.Log("j "+j+" i "+(i-voxelPosition.x)+" s "+(sbyte)secondaryStrength);
|
|
// voxelSpace[i,j,k].addShadow((sbyte)secondaryStrength);
|
|
// if(secondaryStrength<3)
|
|
// {
|
|
// return;
|
|
// }
|
|
if(voxelSpace[i,j,k] == null)
|
|
{
|
|
voxelSpace[i,j,k] = 0;
|
|
}
|
|
if(secondaryStrength > 0)
|
|
{
|
|
if(voxelSpace[i,j,k] >= 255-(byte)secondaryStrength)
|
|
{
|
|
voxelSpace[i,j,k] = 255;
|
|
}
|
|
else
|
|
{
|
|
voxelSpace[i,j,k] += (byte)secondaryStrength;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(voxelSpace[i,j,k] > (byte)secondaryStrength)
|
|
{
|
|
voxelSpace[i,j,k] -= (byte)(-1*secondaryStrength);
|
|
}
|
|
else
|
|
{
|
|
voxelSpace[i,j,k] = 1;
|
|
}
|
|
}
|
|
|
|
if( (i%visualizeEveryNVoxel == 0 && j%visualizeEveryNVoxel == 0 && k%visualizeEveryNVoxel == 0 ) && visualizeLigth)
|
|
{
|
|
Vector3 positionBox = gameObject.GetComponent<Transform>().position;
|
|
Matrix4x4 matrixLigth = new Matrix4x4();
|
|
|
|
//Take the origin position, and apply the offsets
|
|
positionBox.x += i*voxelSize;
|
|
positionBox.y += j*voxelSize;
|
|
positionBox.z += k*voxelSize;
|
|
|
|
//Create a matrix for the position created from this iteration of the loop
|
|
|
|
//Set the position/rotation/scale for this matrix
|
|
matrixLigth.SetTRS(positionBox, Quaternion.Euler(Vector3.zero), new Vector3(voxelSpace[i,j,k]*voxelSize*visualizeEveryNVoxel/255.0f, voxelSpace[i,j,k]*voxelSize*visualizeEveryNVoxel/255.0f, voxelSpace[i,j,k]*voxelSize*visualizeEveryNVoxel/255.0f));
|
|
int l = (i*sizeZ*sizeY/(visualizeEveryNVoxel*visualizeEveryNVoxel*visualizeEveryNVoxel) + k*sizeY/(visualizeEveryNVoxel*visualizeEveryNVoxel) + j/visualizeEveryNVoxel);
|
|
transformListJ[l / 1021][l % 1021] = matrixLigth;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public void addShadowLine(Vector3 positionStart, Vector3 positionEnd, sbyte strength) // negative value to remove
|
|
{
|
|
int linePoints = (int)((Mathf.Abs(positionEnd.x - positionStart.x) + Mathf.Abs(positionEnd.z - positionStart.z))/(voxelSize));
|
|
if (linePoints < 3)
|
|
{
|
|
linePoints = 3;
|
|
}
|
|
Vector3 stepChange = new Vector3(
|
|
(positionEnd.x - positionStart.x)/linePoints,
|
|
(positionEnd.y - positionStart.y)/linePoints,
|
|
(positionEnd.z - positionStart.z)/linePoints);
|
|
Vector3 positionNow = positionStart;
|
|
sbyte newStrength = (sbyte)(2*(strength/linePoints));
|
|
if(newStrength == 0)
|
|
{
|
|
if(strength>0)
|
|
{
|
|
if(strength > 0.4f)
|
|
newStrength = (sbyte)1;
|
|
}
|
|
if(strength<0)
|
|
{
|
|
newStrength = (sbyte)-1;
|
|
}
|
|
}
|
|
for(int i = 0;i<linePoints;i++)
|
|
{
|
|
addShadow(positionNow, newStrength);
|
|
positionNow += stepChange;
|
|
}
|
|
}
|
|
bool inVoxelSpace(int a, int b, int c)
|
|
{
|
|
return (a<sizeX&&a>=0&&b<sizeY&&b>=0&&c<sizeZ&&c>=0);
|
|
}
|
|
public Vector3 positionInVoxel(Vector3 positionInWorld)
|
|
{
|
|
Vector3 voxelPosition = new Vector3(0.0f,0.0f,0.0f);
|
|
positionInWorld -= gameObject.GetComponent<Transform>().position;
|
|
voxelPosition.x = (int)(0.5f + (positionInWorld.x / voxelSize));
|
|
voxelPosition.y = (int)(0.5f + (positionInWorld.y / voxelSize));
|
|
voxelPosition.z = (int)(0.5f + (positionInWorld.z / voxelSize));
|
|
return voxelPosition;
|
|
}
|
|
|
|
public Vector3 positionInWorld(Vector3 positionInVoxel)
|
|
{
|
|
return positionInVoxel*voxelSize+gameObject.GetComponent<Transform>().position;
|
|
}
|
|
public void groundShape()
|
|
{
|
|
|
|
for(int i = 0; i < sizeX; i++)
|
|
{
|
|
for(int k = 0; k < sizeZ; k++)
|
|
{
|
|
for(int j = sizeY-1; j >= 0; j--)
|
|
{
|
|
|
|
Collider[] hitColliders = Physics.OverlapSphere(new Vector3(i*voxelSize, j*voxelSize, k*voxelSize), voxelSize/2.0f);
|
|
foreach (var hitCollider in hitColliders)
|
|
{
|
|
addShadow(new Vector3(i*voxelSize, j*voxelSize, k*voxelSize), 100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public byte shadowStrength(Vector3 pos)
|
|
{
|
|
Vector3 shadowPosition = positionInVoxel(pos);//pos - gameObject.GetComponent<Transform>().position;
|
|
if(inVoxelSpace((int)((shadowPosition.x)),(int)((shadowPosition.y)),(int)((shadowPosition.z))))
|
|
{
|
|
byte mx = voxelSpace[0+(int)((shadowPosition.x)),(int)((shadowPosition.y)),0+(int)((shadowPosition.z))];
|
|
// if(mx >10)
|
|
// {
|
|
// Debug.Log("#shadowPosA " + (int)((shadowPosition.x))+" "+(int)((shadowPosition.y))+" "+(int)((shadowPosition.z))+" = "+voxelSpace[(int)((shadowPosition.x)),(int)((shadowPosition.y)),(int)((shadowPosition.z))]+" ("+mx+") ");
|
|
//// Instantiate(ball, positionInWorld(shadowPosition), Quaternion.Euler(0,0,0));
|
|
// }
|
|
return mx;
|
|
}
|
|
return 255;
|
|
}
|
|
public bool isShadow(Vector3 pos)
|
|
{
|
|
if(shadowStrength(pos) > 10)
|
|
{
|
|
// Debug.Log("#shadow");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Voxel
|
|
{
|
|
public byte shadow = 0; // 0 - 1
|
|
// public int x = 0;
|
|
// public int y = 0;
|
|
// public int z = 0;
|
|
// public float voxelSize = 0.1f;
|
|
// public Matrix4x4 matrixWater = new Matrix4x4();
|
|
// public Matrix4x4 matrixLigth = new Matrix4x4();
|
|
|
|
// public void updateWater()
|
|
// {
|
|
// if(y > 0)
|
|
// {
|
|
// if(water > waterAbsortion)
|
|
// {
|
|
// if(waterTransmission < (water - waterAbsortion))
|
|
// {
|
|
// waterChange = -1.0f * waterTransmission;
|
|
// }
|
|
// else
|
|
// {
|
|
// waterChange = -1.0f * (water - waterAbsortion);
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// public void applyChanges(float change)
|
|
// {
|
|
// water += waterChange+change;
|
|
// waterChange = 0.0f;
|
|
//// shape.GetComponent<Transform>().localScale = new Vector3(water*0.5f*voxelSize, water*0.5f*voxelSize, water*0.5f*voxelSize);
|
|
//
|
|
//
|
|
// }
|
|
public void addShadow(sbyte strength)
|
|
{
|
|
if(strength > 0)
|
|
{
|
|
if(shadow >= 255-strength)
|
|
{
|
|
shadow = 255;
|
|
}
|
|
else
|
|
{
|
|
shadow += (byte)strength;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(shadow > strength)
|
|
{
|
|
shadow -= (byte)(-1*strength);
|
|
}
|
|
else
|
|
{
|
|
shadow = 0;
|
|
}
|
|
}
|
|
// }
|
|
}
|
|
}
|