Generating a DLL from a Simulink model with S-Function and using it in Unity 3D - unity3d

I'm trying to generate a DLL for a Simulink model with an S function and use that in Unity 3D. To try a simple example, I just made a model with an S-function that multiplies the input value by 2.
I've generated the DLL of this using the Embedded Coder feature. The code generated contains the essential function as follows:
void S_function_tlc_try_step(RT_MODEL_S_function_tlc_try_T *const
S_function_tlc_try_M, real_T S_function_tlc_try_U_x, real_T
*S_function_tlc_try_Y_y)
{
/* local block i/o variables */
real_T rtb_Level2MATLABSFunction1;
/* M-S-Function: '<Root>/Level-2 MATLAB S-Function1' incorporates:
* Inport: '<Root>/x'
*/
/* Multiply input by two */
rtb_Level2MATLABSFunction1 = S_function_tlc_try_U_x * 2.0;
/* Outport: '<Root>/y' */
*S_function_tlc_try_Y_y = rtb_Level2MATLABSFunction1;
/* Update absolute time for base rate */
/* The "clockTick0" counts the number of times the code of this task has
* been executed. The absolute time is the multiplication of "clockTick0"
* and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
* overflow during the application lifespan selected.
*/
S_function_tlc_try_M->Timing.t[0] =
((time_T)(++S_function_tlc_try_M->Timing.clockTick0)) *
S_function_tlc_try_M->Timing.stepSize0;
UNUSED_PARAMETER(S_function_tlc_try_M);
}
The script in Unity is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
public class Sfunctiontry : MonoBehaviour
{
public double input, output;
double constant;
[DllImport("S_function_tlc_try_win64")]
static extern void S_function_tlc_try_step(double constant, double inp, ref double outp);
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
S_function_tlc_try_step(constant, input, ref output);
Debug.Log("Multiplying by 2");
print(output);
}
}
However whenever I attach this to an object and execute, Unity crashes. It works fine when I'm using the DLL of a model without any S-function.
Is there a solution for this? Any leads would be great.
Thanks in advance.

Related

How do I set a shader setting/property at runtime using MonoBehaviour?

I have a shader that displays a mesh's vertex colors and has the ability to clip vertices that are blue. I'd like the user to be able to turn this setting on/off while using the application.
I've tried the suggestions offered here Find and change property name in a shader and here How do I discard pixels based on vertex color and turn that on or off in a MonoBehaviour?
but so far none of those have worked for me.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HoloToolkit.Unity;
using System;
public class AnchorScript : MonoBehaviour
{
private Renderer rend;
Vector3 scale;
public WorldAnchorManager worldAnchorManager;
// Start is called before the first frame update
void Start()
{
rend = gameObject.GetComponent<Renderer>();
// transform.localScale = scale;
TurnOffContext();
}
private void Update()
{
SaveScale();
TurnOffContext();
}
public void AnchorIt()
{
worldAnchorManager.AttachAnchor(this.gameObject);
this.gameObject.GetComponent<Renderer>().material.color = Color.red;
}
public void ReleaseAnchor()
{
worldAnchorManager.RemoveAnchor(this.gameObject);
this.gameObject.GetComponent<Renderer>().material.color =
Color.green;
}
public void ShowDifferences()
{
gameObject.GetComponent<Renderer>().enabled = true;
}
public void HideAugmentations()
{
gameObject.GetComponent<Renderer>().enabled = false;
}
public void TurnOffContext()
{
rend.material.SetFloat("_Toggle", 1);
Debug.Log("Toggle ");
}
public void SaveScale()
{
scale = gameObject.GetComponent<Transform>().localScale;
}
}
I expect this script to cause my mesh's blue parts to be discarded, because in my shader's fragment I have
clip(_Toggle * (0.5f - IN.vertColor.b));
Specifically the part that doesn't work is the line
rend.material.Setfloat("_Toggle", 1);
The function is being called, but it's not setting the _Toggle value to 1 as expected.
If I manually change the _Toggle setting in the inspector panel from 0 to 1, the blue parts of the mesh are discarded, which is the expected result. The script I pasted above should have the same result as manually changing the setting in the inspector panel.
I don't know why your current solution doesn't work (it looks fine to me), but i know that you can work around this whole thing using shader variants.
Inside your shader, add this line to the pragmas:
#pragma multi_compile __ DISCARD_BLUE
And then change your clip statement to this:
#ifdef DISCARD_BLUE
clip(0.5f - IN.vertColor.b);
#endif
To enable and disable this feature, just change the C# script to use rend.material.EnableKeyword("DISCARD_BLUE") and rend.material.DisableKeyword("DISCARD_BLUE") respectively. This has the added benefit that it saves a few instructions when the keyword is disabled. You can also enable/disable the keyword globally like this:
Shader.Find("Custom/VertexColor").EnableKeyword("DISCARD_BLUE");
Other than that, have you made absolutely sure that your script references the correct renderer?

Unity3D: Setting AudioSource volume dynamically using AnimationCurve

Newcomer to Unity here. For this project, I am reading in an outside AnimationCurve, and attempting to use it to adjust the volume of my GameObject every frame in the Update function. I have found documentation on how to access the volume of my AudioSource GameObject component (this is working), but I can't figure out how to use my evaluated curve to update the volume.
Screencap with imported AnimationCurve and evaluated values
My cs script is included below. Sorry if it's a bit opaque. This is for a neuroscience experiment, so I need to carefully control the animation curves. It reads in times and values (stored in currentCurveData) used to add keyframes to the new AnimationCurve (curveThisTrl) in the SetAnimationFrames() function.
The key part is in Update(). The initial tone.volume is correct, so I know it's reading that property from the GameObject. I can also see the correct curve values coming through in the Debug Log every frame, so I know the curve evaluation is working. It's just not changing the volume property of the GameObject as I want it to.
Hopefully this is enough information to spot a problem, but if not I can try to provide a test AnimationCurve for reproducibility. Thanks in advance for any help.
public class AnimationControl : MonoBehaviour {
private DataController dataControllerRef;
private CurveDataSingleTrial currentCurveData;
private float initTime;
public AnimationCurve curveThisTrl;
AudioSource tone;
void Awake()
{
initTime = Time.time;
}
// Use this for initialization
void Start ()
{
// Get references to key objects in scene
dataControllerRef = FindObjectOfType<DataController>(); // Has values from JSON
tone = GetComponent<AudioSource>();
Debug.Log(tone.volume);
// query the DataController for the current curve data
currentCurveData = dataControllerRef.GetCurrentCurveData();
SetAnimationFrames();
}
void SetAnimationFrames()
{
int numKeyFrames = currentCurveData.keyframeTimes.Length;
for (int c = 0; c < numKeyFrames; c++)
{
curveThisTrl.AddKey(currentCurveData.keyframeTimes[c], currentCurveData.keyframeVals[c]);
}
}
// Update is called once per frame
void Update ()
{
float currTime = Time.time - initTime;
tone.volume = curveThisTrl.Evaluate(currTime);
Debug.Log(tone.volume);
}
}

How to play audioclips in unity from script?

So I am trying to get the sing method to play one of the audioclips I created up top. I know I need an audioSource, I just have no clue how it fits in with the audioClips. I don't currently have an audiosoure assigned to the object that this script is assigned to, so that might impact things. Thanks for your help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Piano : MonoBehaviour {
private List<AudioClip> notes = new List<AudioClip>();
public string voice;
public AudioClip ash1, a1, b1, csh1, c1, dsh1, d1, e1, f1, fsh1, g1, gsh1;
// Use this for initialization
void Start () {
//octave1
notes.Add(a1); notes.Add(b1); notes.Add(ash1); notes.Add(c1); notes.Add(csh1);notes.Add(d1); notes.Add(dsh1);
notes.Add(e1); notes.Add(f1); notes.Add(g1); notes.Add(gsh1);
WarmUp(voice);
}
//consider adding countertenor, true alto (i am using mezzo soprano), and baritone.
void WarmUp(string vp)
{
//high and low end of voice parts
// 30 = c4 for example
int high;
int low;
ArrayList range = new ArrayList();
//c4 to c6
if (vp == "Soprano")
{
high = 0; //this is just a range to make the code shorter
low = 7;
for(int i = low; i < high; i++)
{
range.Add(notes[i]);
}
Sing(range);
}
}
/**
* #Param: range. the arraylist of range of notes.
* shift the pitch UP one half step if the up arrow key is pressed
* shift the pitch down one half step if the down arrow key is pressed
* shift the pitch up a third (4 half steps) if the left arrow key is pressed
* shift the pitch up a fifth (7 half steps) if the right arrow key is pressed
*/
void Sing(ArrayList range)
{
//how to play one of the audioclips in range here
}
// Update is called once per frame
void Update () {
}
}
If you attach an AudioSource component to the GameObject, then you could set an AudioSource variable to that component and then call the setter function clip(AudioClip x) to set the clip the source should play. At that point, you could just call Play() and wait for the length of the audio clip.
Code shouldn't be too difficult to figure out but if you have any more questions, don't hesitate to ask. Good luck!
Attach a AudioSource component to your GameObject.
In Sing:
yourAudioSource.clip = (AudioClip)range[Random.Range(0, range.Count)];
yourAudioSource.Play()
You might also consider changing ArrayList range to List<AudioClip> range or similar to avoid the cast
Take a variable of AudioSource _aSource and AudioClip _aClip and assign the audio source game object to the _aSource and clip to the _aClip on the inspector and where want to play the sound just write _aSource.PlayOneShot(a_Clip) that it.

Unity Random is detroying all objects

I'm trying to make the system work so that when a game starts and for each wall, it will either be in the game or not, randomly. Somehow, when I run it, it either keeps or destroys all the walls. How do I fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallGen : MonoBehaviour{
public GameObject wallObject;
System.Random rnd = new System.Random();
// Use this for initialization
void Start () {
generate();
}
void generate()
{
int number = rnd.Next(1, 5);
if (number == 2)
{
OnDestroy();
}
}
private void OnDestroy(){
Destroy(wallObject);
}
// Update is called once per frame
void Update () {
}
}
Every time you do new System.Random() it is initialised using the clock. Now as the Start function is called at the same time, you get the same value for all the gameobjects. You should keep a single Random instance for all gameobjects and keep using Next on the same instance.
Or the easy solution
just Use Random.Range (1,5) instead of rnd.Next(1, 5);
As a side note, don't use the function name OnDestroy, as it is one of the MonoBehaviour functions in Unity and is called automatically when the attached gameobject is destroyed.

Capture image on every frame in unity 3d

I'm working upon an algorithm that is based on Hand gesture recognition. This algorithm i found and run on Winform with c# scripts. The same technique i need to use in my game to perform hand gesture detection through webcam. I tried to use the algorithm in my game scripts but unable to capture any image using the algorithm. Below is the code that i'm currently working upon. I'm using aForge.net framework to implement the idea of motion detection. The bitmap image always returns null. However using the same algorithm in winform it captures image on every frame changed. I know there is a technique of using PhotoCapture in unity but i'm not sure how do i use it at runtime on every frame. Every guidance is appreciated. Thanks!
OpenCamera.cs
using AForge.GestureRecognition;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using UnityEngine;
using System.Drawing.Design;
using UnityEngine.VR.WSA.WebCam;
using System.Linq;
using System;
public class OpenCamera : MonoBehaviour {
// statistics length
private const int statLength = 15;
Bitmap image;
PhotoCapture photoCaptureObject = null;
Texture2D targetTexture = null;
// current statistics index
private int statIndex = 0;
// ready statistics values
private int statReady = 0;
// statistics array
private int[] statCount = new int[statLength];
private GesturesRecognizerFromVideo gesturesRecognizer = new GesturesRecognizerFromVideo();
private Gesture gesture = new Gesture();
private int gestureShowTime = 0;
// Use this for initialization
void Start()
{
WebCamTexture webcamTexture = new WebCamTexture();
Renderer renderer = GetComponent<Renderer>();
renderer.material.mainTexture = webcamTexture;
webcamTexture.Play();
}
// Update is called once per frame
void Update ()
{
gesturesRecognizer.ProcessFrame(ref image);
// check if we need to draw gesture information on top of image
if (gestureShowTime > 0)
{
if ((gesture.LeftHand == HandPosition.NotRaised) || (gesture.RightHand != HandPosition.NotRaised))
{
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image);
string text = string.Format("Left = " + gesture.LeftHand + "\nRight = " + gesture.RightHand);
System.Drawing.Font drawFont = new System.Drawing.Font("Courier", 13, System.Drawing.FontStyle.Bold);
SolidBrush drawBrush = new SolidBrush(System.Drawing.Color.Blue);
g.DrawString(text, drawFont, drawBrush, new PointF(0, 5));
drawFont.Dispose();
drawBrush.Dispose();
g.Dispose();
}
gestureShowTime--;
}
}
}
As mentioned in the comments (which I am not able to reply to at the moment) those libraries always heavely depend on system.drawing libraries, which are kind of windows only.
What you could try is downloading the drawing library dll (or copying from your system folder) into your unity project (it's managed code, so it'll run on every exportable platform) to keep teh references. Then you could capture a texture2d every frame (rendertextures or so) and draw those pixels into a bitmap which is fed to the library.
Note that copying thousands of pixels every frame is really really heavy. you'd have to convert the UnityEngine.Color to System.Drawing.Color...
This is the easies solution that might work. But definitly not a good final one.