經(jīng)實驗默怨,這種方式是目前能做到最好的方式了质和。
- 原理:
- 在點擊的地方畫出LineRender,分別計算出各個點的最大、最小X羞迷,Y坐標(biāo),可以得到一個矩形距糖。
image.png -
獲得矩形長寬較大的一個撤蟆,作為Ortho相機的OrthoSize;同時也作為Projector投影器的OrthoSize牵舵。把相機和投影器放置在正確的位置上柒啤,正好能把畫的紅線罩住。
image.png - Ortho相機拍照一張畸颅,作為投影器的貼圖担巩。(增大RenderTexture貼圖分辨率,可以獲得更好的效果)投影器向下投影没炒。Over涛癌。
-
部分代碼
image.png
using SGF.Unity.Common;
using System;
using System.Collections.Generic;
using UnityEngine;
public enum DrawMode
{
NULL,
POLYGON,
ELLIPTICAL,
}
public class TextureGenerator : MonoSingleton<TextureGenerator>
{
private float _minX;
private float _maxX;
private float _minY;
private float _maxY;
private float _middleX;
private float _middleY;
private int _textureWidth;
private int _textureHeight;
public Color LineColor = Color.red; //作為單例,提供顏色給ProjController畫lineRender
private Color _backgroundColor = new Color(1, 1, 1, 0); //白色透明
[Header("生成貼圖分辨率倍數(shù)")]
[Range(1,20)]
public int TexResolutionMult = 10;
[Header("投影器距離地面高度--要比最高的地面位置高")]
public float ProjectorHeight = 200;
public Vector3 GetProjectorPos()
{
return new Vector3(_middleX, ProjectorHeight, _middleY);
}
private void DataRelease()
{
_minX = 0;
_maxX = 0;
_minY = 0;
_maxY = 0;
_middleX = 0;
_middleY = 0;
_textureWidth = 0;
_textureHeight = 0;
}
/// <summary>
/// 根據(jù)相機拍照LineRender生成紋理圖片
/// </summary>
/// <param name="camera"></param>
/// <param name="proj"></param>
/// <param name="posList"></param>
/// <param name="closePolygon"></param>
/// <param name="type"></param>
/// <returns></returns>
public Texture2D GenerateProceduralTexture(Camera camera, Projector proj, DrawMode type = DrawMode.POLYGON)
{
//CalculateTextureWH(posList); //提前計算過了
int longSide = _textureWidth > _textureHeight ? _textureWidth : _textureHeight;
float orthoSize = longSide / 2.0f;
camera.orthographicSize = orthoSize;
proj.orthographicSize = orthoSize;
longSide *= TexResolutionMult; //乘以分辨率倍數(shù)
RenderTexture rt = null;
rt = camera.targetTexture;
if (rt == null)
{
rt = new RenderTexture(longSide, longSide, 0);
camera.targetTexture = rt;
}
else
{
rt.Release();
rt.width = longSide;
rt.height = longSide;
}
Texture2D image = new Texture2D(longSide, longSide);
// The Render Texture in RenderTexture.active is the one
// that will be read by ReadPixels.
RenderTexture.active = rt; //設(shè)置當(dāng)前活動的rendertexture為當(dāng)前相機的
// Render the camera's view.
camera.Render();
// Make a new texture and read the active Render Texture into it.
//image.ReadPixels(new Rect(0, 0, camera.targetTexture.width, camera.targetTexture.height), 0, 0);
image.ReadPixels(new Rect(0, 0, longSide, longSide), 0, 0);
image.Apply();
return image;
}
#region ===== 程序生成紋理(方案已被取代) =====
/// <summary>
/// 根據(jù)計算點生成圖片
/// </summary>
/// <param name="posList"></param>
/// <param name="closePolygon"></param>
/// <param name="type"></param>
/// <returns></returns>
//public Texture2D GenerateProceduralTexture(List<Vector3> posList, bool closePolygon = false, DrawMode type = DrawMode.POLYGON)
//{
// CalculateTextureWH(posList);
// Debug.Log(_textureWidth + ", " + _textureHeight);
// Texture2D proceduralTexture = new Texture2D(_textureWidth, _textureHeight);
// for(int w = 0;w < _textureWidth; w ++)
// {
// for(int h = 0; h < _textureHeight; h++)
// {
// Color pixel = _backgroundColor;
// //遍歷該點距離每條邊的距離,一旦有一條邊滿足條件跳出循環(huán)
// for(int i = 0;i < posList.Count;i ++)
// {
// int next = i + 1;
// if (next == posList.Count) next = 0;
// Vector3 vstart = WorldToTexture(posList[i]);
// Vector3 vend = WorldToTexture(posList[next]);
// Vector3 vcurrent = new Vector3(w, 0, h);
// if (PointInRect(vstart, vend, vcurrent, LineWidth))
// {
// if (PointToStraightlineDistance(vstart, vend, vcurrent) <= LineWidth)
// {
// pixel = LineColor;
// break;
// }
// }
// }
// proceduralTexture.SetPixel(w, h, pixel);
// }
// }
// proceduralTexture.Apply();
// return proceduralTexture;
//}
#endregion
//計算圖片長寬
public void CalculateTextureWH(List<Vector3> posList)
{
DataRelease();
for (int i = 0;i < posList.Count;i ++)
{
float curX = posList[i].x;
float curY = posList[i].z;
if(i == 0)
{
_minX = _maxY = curX;
_minY = _maxY = curY;
}
if (curX < _minX) _minX = curX;
if (curX >= _maxX) _maxX = curX;
if (curY < _minY) _minY = curY;
if (curY >= _maxY) _maxY = curY;
}
_middleX = (_minX + _maxX) / 2;
_middleY = (_minY + _maxY) / 2;
_textureWidth = (int)Math.Ceiling(_maxX - _minX);
_textureHeight = (int)Math.Ceiling(_maxY - _minY);
}
//轉(zhuǎn)換世界坐標(biāo)系到圖片坐標(biāo)系
private Vector3 WorldToTexture(Vector3 originData)
{
Vector3 transData = new Vector3(originData.x - _minX, 0, originData.z - _minY);
return transData;
}
/// <summary>
/// 點到直線的距離
/// </summary>
/// <returns>The of point to vector.</returns>
/// <param name="startPoint">Start point.</param>
/// <param name="endPoint">End point.</param>
/// <param name="point">Point.</param>
public float PointToStraightlineDistance(Vector3 lineStartPoint, Vector3 lineEndPoint, Vector3 targetPoint)
{
//需要轉(zhuǎn)到2維平面計算
Vector2 startVe2 = IgnoreYAxis(lineStartPoint);
Vector2 endVe2 = IgnoreYAxis(lineEndPoint);
float A = endVe2.y - startVe2.y;
float B = startVe2.x - endVe2.x;
float C = endVe2.x * startVe2.y - startVe2.x * endVe2.y;
float denominator = Mathf.Sqrt(A * A + B * B);
Vector2 pointVe2 = IgnoreYAxis(targetPoint);
return Mathf.Abs((A * pointVe2.x + B * pointVe2.y + C) / denominator);
}
/// <summary>
/// 只計算 起點到終點+linewidth 矩形內(nèi)的點拳话,忽略矩形外部的點
/// </summary>
/// <param name="lineStartPoint"></param>
/// <param name="lineEndPoint"></param>
/// <param name="targetPoint"></param>
/// <returns></returns>
private bool PointInRect(Vector3 lineStartPoint, Vector3 lineEndPoint, Vector3 targetPoint, float linewidth)
{
float minx,miny,maxx,maxy = 0;
if(lineStartPoint.x < lineEndPoint.x)
{
minx = lineStartPoint.x;
maxx = lineEndPoint.x;
}
else
{
minx = lineEndPoint.x;
maxx = lineStartPoint.x;
}
if (lineStartPoint.y < lineEndPoint.y)
{
miny = lineStartPoint.y;
maxy = lineEndPoint.y;
}
else
{
miny = lineEndPoint.y;
maxy = lineStartPoint.y;
}
//minx -= linewidth;
//maxx += linewidth;
//miny -= linewidth;
//maxy += linewidth;
if (targetPoint.x <= maxx && targetPoint.x >= minx)
{
if(targetPoint.y <= maxy && targetPoint.y >= miny)
{
return true;
}
}
return false;
}
/// <summary>
/// 去掉三維向量的Y軸先匪,把向量投射到xz平面。
/// </summary>
/// <param name="vector3"></param>
/// <returns></returns>
public static Vector2 IgnoreYAxis(Vector3 vector3)
{
return new Vector2(vector3.x, vector3.z);
}
}