Add launch clamp fallback for older versions of OpenGL

Add a fallback method for the launch clamp module that does not require GPU instancing, for users with older computers. This method is currently very slow when calculating several launch clamps in a single frame in the editor, but fine in the flight scene
pull/822/head
Andrew Cassidy 4 years ago
parent 85ab757271
commit 2c16fab42e
No known key found for this signature in database
GPG Key ID: 963017B38FD477A1

@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Restock
{
public class ModuleRestockLaunchClamp : LaunchClamp
{
private Material _girderMaterial;
private Matrix4x4[] _girderMatrices;
private Mesh _girderMesh;
private int _girderSegments;
[KSPField] public int maxSegments = 100;
[KSPField] public Transform towerAnchor;
[KSPField] public Transform towerGirder;
@ -20,6 +16,28 @@ namespace Restock
[KSPField] public string trf_towerGirder_name = "";
[KSPField] public string trf_towerYoke_name = "";
[KSPField] public Mesh girderMesh;
private Material _girderMaterial;
private Matrix4x4[] _girderMatrices;
//used by non-instanced fallback girder implementation
[KSPField] public bool instancingEnabled = true;
[KSPField] public Mesh girderSegmentMesh;
private List<Vector3> _girderVerts;
private List<Vector2> _girderUVs;
private List<Vector3> _girderNormals;
private List<Vector4> _girderTangents;
private List<Color32> _girderColors;
private List<int> _girderTris;
private bool _girderHasTangents = false;
private bool _girderHasColors = false;
private int _girderVertCount;
private int _girderTriCount;
private int _girderSegments;
public override void OnLoad(ConfigNode node)
{
towerPivot = part.FindModelTransform(trf_towerPivot_name);
@ -28,6 +46,15 @@ namespace Restock
towerGirder = part.FindModelTransform(trf_towerGirder_name);
towerStretch = part.FindModelTransform(trf_towerStretch_name);
if (!SystemInfo.supportsInstancing)
{
this.LogWarning("You are using a computer which does not support instancing, " +
"falling back to a slower launch clamp implementation");
instancingEnabled = false;
girderMesh = towerGirder.GetComponent<MeshFilter>().mesh;
girderSegmentMesh = Instantiate<Mesh>(girderMesh);
}
base.OnLoad(node);
}
@ -35,50 +62,135 @@ namespace Restock
{
base.OnStart(state);
var girderRenderer = towerGirder.GetComponent<MeshRenderer>();
_girderMaterial = girderRenderer.material;
_girderMesh = towerGirder.GetComponent<MeshFilter>().mesh;
girderMesh = towerGirder.GetComponent<MeshFilter>().mesh;
girderRenderer.enabled = false; // we'll render manually from now on
if (instancingEnabled)
{
var girderRenderer = towerGirder.GetComponent<MeshRenderer>();
girderRenderer.enabled = false; // we'll render manually from now on
_girderSegments = 0;
_girderMatrices = new Matrix4x4[maxSegments];
_girderMatrices = new Matrix4x4[maxSegments];
_girderMaterial.enableInstancing = true;
if (!_girderMaterial.enableInstancing)
_girderMaterial = girderRenderer.material;
_girderMaterial.enableInstancing = true;
}
else
{
this.LogError("Could not enable instancing! Aborting");
_girderSegments = -1;
this.Log("Instancing is disabled, setting up fallback");
_girderVertCount = girderSegmentMesh.vertexCount;
_girderTriCount = girderSegmentMesh.triangles.Length;
_girderVerts = new List<Vector3>(girderSegmentMesh.vertices);
_girderUVs = new List<Vector2>(girderSegmentMesh.uv);
_girderNormals = new List<Vector3>(girderSegmentMesh.normals);
if (girderSegmentMesh.tangents.Length > 0)
{
_girderHasTangents = true;
_girderTangents = new List<Vector4>(girderSegmentMesh.tangents);
}
if (girderSegmentMesh.colors32.Length > 0)
{
_girderHasColors = true;
_girderColors = new List<Color32>(girderSegmentMesh.colors32);
}
_girderTris = new List<int>(girderSegmentMesh.triangles);
_girderSegments = 1;
}
}
public void LateUpdate()
{
if (_girderSegments < 0) return;
var height = HighLogic.LoadedSceneIsEditor ? towerStretch.position.y : this.height;
var initialHeight = this.initialHeight;
towerAnchor.position = towerStretch.position - towerStretch.up * height;
var vec1 = Vector3.down;
var vec2 = towerAnchor.localPosition - towerYoke.localPosition;
towerYoke.localRotation = Quaternion.FromToRotation(vec1, vec2);
_girderSegments = Mathf.CeilToInt(height / this.initialHeight);
_girderSegments = Math.Min(_girderSegments, maxSegments);
_girderSegments = Math.Max(_girderSegments, 0);
var girderSegments = Mathf.CeilToInt(height / initialHeight);
girderSegments = Math.Min(girderSegments, maxSegments);
girderSegments = Math.Max(girderSegments, 0);
if (instancingEnabled)
{
UpdateGirder(girderSegments);
}
else
{
UpdateGirderFallback(girderSegments);
}
}
private void UpdateGirder(int girderSegments)
{
var matrix = towerGirder.localToWorldMatrix;
var offset = Matrix4x4.Translate(towerGirder.TransformVector(Vector3.down * initialHeight));
for (var i = 0; i < _girderSegments; i++)
for (var i = 0; i < girderSegments; i++)
{
_girderMatrices[i] = matrix;
matrix = offset * matrix;
}
Graphics.DrawMeshInstanced(_girderMesh, 0, _girderMaterial, _girderMatrices, _girderSegments, part.mpb);
Graphics.DrawMeshInstanced(girderMesh, 0, _girderMaterial, _girderMatrices, girderSegments, part.mpb);
}
private void UpdateGirderFallback(int newGirderSegments)
{
if (newGirderSegments == _girderSegments) return;
if (newGirderSegments > _girderSegments)
{
for (int i = _girderSegments; i < newGirderSegments; i++)
{
var offset = Vector3.down * base.initialHeight * i;
var indexOffset = _girderVertCount * i;
for (int v = 0; v < _girderVertCount; v++)
{
_girderVerts.Add(girderSegmentMesh.vertices[v] + offset);
}
_girderNormals.AddRange(girderSegmentMesh.normals);
_girderUVs.AddRange(girderSegmentMesh.uv);
if (_girderHasTangents) _girderTangents.AddRange(girderSegmentMesh.tangents);
if (_girderHasColors) _girderColors.AddRange(girderSegmentMesh.colors32);
for (int t = 0; t < _girderTriCount; t++)
{
_girderTris.Add(girderSegmentMesh.triangles[t] + indexOffset);
}
}
}
else if (newGirderSegments < _girderSegments)
{
var startIndex = newGirderSegments * _girderVertCount;
var count = (_girderSegments - newGirderSegments) * _girderVertCount;
_girderVerts.RemoveRange(startIndex, count);
_girderNormals.RemoveRange(startIndex, count);
_girderUVs.RemoveRange(startIndex, count);
if (_girderHasTangents) _girderTangents.RemoveRange(startIndex, count);
if (_girderHasColors) _girderColors.RemoveRange(startIndex, count);
_girderTris.RemoveRange(newGirderSegments * _girderTriCount, (_girderSegments - newGirderSegments) * _girderTriCount);
}
girderMesh.Clear();
girderMesh.SetVertices(_girderVerts);
girderMesh.SetNormals(_girderNormals);
girderMesh.SetUVs(0, _girderUVs);
if (_girderHasTangents) girderMesh.SetTangents(_girderTangents);
if (_girderHasColors) girderMesh.SetColors(_girderColors);
girderMesh.SetTriangles(_girderTris, 0);
girderMesh.RecalculateBounds();
_girderSegments = newGirderSegments;
}
}
}
Loading…
Cancel
Save