KSP-Conformal-Decals/Source/ConformalDecals/ProjectionTarget.cs
drewcassidy e9c8f3dafb Big refactor to enable preview materials
• add shader variants for decal previewing
• start to add code for part icon
• refactor material properties to be serializable
todo:
• fix decal preview scale (need to call UpdateScale on detached state)
• fix texture preview in part icon
• adjust culling per-object when rendering (turns out cull and ztest values are used by unity at the render time, not by the shader itself, so they can be adjusted in material property blocks!)
2020-06-04 00:12:09 -07:00

80 lines
3.6 KiB
C#

using ConformalDecals.Util;
using UnityEngine;
using UnityEngine.Rendering;
namespace ConformalDecals {
public class ProjectionTarget {
private static readonly int _projectionMatrixID = Shader.PropertyToID("_ProjectionMatrix");
private static readonly int _decalNormalID = Shader.PropertyToID("_DecalNormal");
private static readonly int _decalTangentID = Shader.PropertyToID("_DecalTangent");
// Target object data
public readonly Transform target;
private readonly Renderer _targetRenderer;
private readonly Mesh _targetMesh;
private bool _projectionEnabled;
// property block
private readonly MaterialPropertyBlock _decalMPB;
private static readonly int normalID = Shader.PropertyToID("_BumpMap");
private static readonly int normalIDST = Shader.PropertyToID("_BumpMap_ST");
public ProjectionTarget(MeshRenderer targetRenderer, Mesh targetMesh, bool useBaseNormal) {
target = targetRenderer.transform;
_targetRenderer = targetRenderer;
_targetMesh = targetMesh;
_decalMPB = new MaterialPropertyBlock();
}
public void Project(Matrix4x4 orthoMatrix, OrientedBounds projectorBounds, Transform projector, bool useBaseNormal) {
var targetBounds = _targetRenderer.bounds;
if (projectorBounds.Intersects(targetBounds)) {
_projectionEnabled = true;
var targetMaterial = _targetRenderer.sharedMaterial;
var projectorToTargetMatrix = target.worldToLocalMatrix * projector.localToWorldMatrix;
var projectionMatrix = orthoMatrix * projectorToTargetMatrix.inverse;
var decalNormal = projectorToTargetMatrix.MultiplyVector(Vector3.back).normalized;
var decalTangent = projectorToTargetMatrix.MultiplyVector(Vector3.right).normalized;
_decalMPB.SetMatrix(_projectionMatrixID, projectionMatrix);
_decalMPB.SetVector(_decalNormalID, decalNormal);
_decalMPB.SetVector(_decalTangentID, decalTangent);
Debug.Log($"Projection enabled for {target.gameObject}");
if (useBaseNormal && targetMaterial.HasProperty(normalID)) {
var normal = targetMaterial.GetTexture(normalID);
if (normal != null) {
_decalMPB.SetTexture(normalID, targetMaterial.GetTexture(normalID));
var normalScale = targetMaterial.GetTextureScale(normalID);
var normalOffset = targetMaterial.GetTextureOffset(normalID);
_decalMPB.SetVector(normalIDST, new Vector4(normalScale.x, normalScale.y, normalOffset.x, normalOffset.y));
}
}
}
else {
_projectionEnabled = false;
Debug.Log($"Projection disabled for {target.gameObject}");
}
}
public bool Render(Material decalMaterial, MaterialPropertyBlock partMPB, Camera camera) {
if (_projectionEnabled) {
_decalMPB.SetFloat(PropertyIDs._RimFalloff, partMPB.GetFloat(PropertyIDs._RimFalloff));
_decalMPB.SetColor(PropertyIDs._RimColor, partMPB.GetColor(PropertyIDs._RimColor));
Graphics.DrawMesh(_targetMesh, target.localToWorldMatrix, decalMaterial, 0, camera, 0, _decalMPB, ShadowCastingMode.Off, true);
return true;
}
return false;
}
}
}