Tag Archives: unity3d

Problems in using unity3d to build easy movie texture [How to Solve]

After running, the first error reported needs to be changed to – fno objc arc

New errors after compilation.

Need to

CustomVideoPlayer.mm
_lastFrameTimestamp = _curFrameTimestamp;
curTex = CMVideoSampling_SampleBuffer(&_videoSampling, _cmSampleBuffer, (int)_videoSize.width, (int)_video

Change to

_lastFrameTimestamp = _curFrameTimestamp;
size_t w, h;
w =(int)_videoSize.width;
h =(int)_videoSize.height;
curTex = CMVideoSampling_SampleBuffer(&_videoSampling, _cmSampleBuffer, &w, &h);

There will be more

CustomVideoPlayer.mm
AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];

Change to

AVPlayerStatus status = (AVPlayerStatus)[[change objectForKey:NSKeyValueChangeNewKey] integerValue];

Rigidbody.moveposition rigid body movement

using UnityEngine;

public class PlayerContrller1 : MonoBehaviour 
{
    private Transform mmTransform;
    private Rigidbody mmRigidbody;

    
    void Start ()
    {
        mmTransform=gameObject.GetComponent<Transform>();
        mmRigidbody=gameObject.GetComponent<Rigidbody>();
    }
    void Update ()
    {
        PlayerMove();
    }
    //Method

    private void PlayerMove()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 dir = new Vector3(h, 0, v);
        mmRigidbody.MovePosition(mmTransform.position + dir * 0.2f);
    }
}

Input input key settings.

Upper menu bar: edit=>Project settings=>input

Log system reconstruction of unity3d

Editor’s note

Because the log system of unity3d needs to be rewritten, it is changed to the custom mode, and the content method of log4j is used

Log of unity3d

In general, write the log entry code in unity3d

Debug.Log("hello message");

In unityeditor and unityengine, besides message, stack information is also printed. The performance is low. According to an experienced person, printing a large number of logs on the client will seriously reduce the rendering performance

Debug principle of unity3d

Principle analysis

Check the implementation of debug. Log in rider, and we can see the following

public static void Log(object message)
{
    Debug.unityLogger.Log(LogType.Log, message);
}

We can understand that the essence is to call debug. Unitylogger

public static ILogger unityLogger
{
    get
    {
        return Debug.s_Logger;
    }
}

Unitylogger actually calls debug. S_ Logger, and S is defined below_ Implementation of logger

internal static ILogger s_Logger = (ILogger) new Logger((ILogHandler) new DebugLogHandler());

The essence of debugglohandler is to call static methods, which are called according to the implementation of various platforms of unityengine

using System;
using System.Runtime.CompilerServices;
using UnityEngine.Scripting;

namespace UnityEngine
{
  internal sealed class DebugLogHandler : ILogHandler
  {
    [ThreadAndSerializationSafe]
    [GeneratedByOldBindingsGenerator]
    [MethodImpl(MethodImplOptions.InternalCall)]
    internal static extern void Internal_Log(LogType level, string msg, [Writable] Object obj);

    [ThreadAndSerializationSafe]
    [GeneratedByOldBindingsGenerator]
    [MethodImpl(MethodImplOptions.InternalCall)]
    internal static extern void Internal_LogException(Exception exception, [Writable] Object obj);

    public void LogFormat(LogType logType, Object context, string format, params object[] args)
    {
      DebugLogHandler.Internal_Log(logType, string.Format(format, args), context);
    }

    public void LogException(Exception exception, Object context)
    {
      DebugLogHandler.Internal_LogException(exception, context);
    }
  }
}

There are only two ways to achieve it

internal static extern void Internal_Log(LogType level, string msg, [Writable] Object obj);
internal static extern void Internal_LogException(Exception exception, [Writable] Object obj);

Code testing

Debug.unityLogger.Log(LogType.Log,"hello message");

Unityeditor printing

hello message
UnityEngine.Logger:Log(LogType, Object)
InitController:Start() (at Assets/Scripts/Controller/InitController.cs:14)

Conclusion: the problem of reducing stack information printing cannot be solved

UnityEngine.Application

According to the logcallback document of unityengine. Application, we can understand the application. Logmessage received and application. Logmessage received threaded related to logcallback

public delegate void LogCallback(string condition, string stackTrace, LogType type);

Since logcallback uses the delegate delegate method, you need to specify the implementation method, which is officially recommended by unity as follows

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour {
    public string output = "";
    public string stack = "";
    void OnEnable() {
        Application.logMessageReceived += HandleLog;
    }
    void OnDisable() {
        Application.logMessageReceived -= HandleLog;
    }
    void HandleLog(string logString, string stackTrace, LogType type) {
        output = logString;
        stack = stackTrace;
    }
}

Principle analysis

Logmessage received only works on the main thread. That’s the main line of unity. And the document describes the implementation method is not thread safe. The implementation code of logmessage receivedthreaded must be thread safe and support access from outside the main thread

    public static event Application.LogCallback logMessageReceived
    {
      add
      {
        Application.s_LogCallbackHandler += value;
        Application.SetLogCallbackDefined(true);
      }
      remove
      {
        Application.s_LogCallbackHandler -= value;
      }
    }

    public static event Application.LogCallback logMessageReceivedThreaded
    {
      add
      {
        Application.s_LogCallbackHandlerThreaded += value;
        Application.SetLogCallbackDefined(true);
      }
      remove
      {
        Application.s_LogCallbackHandlerThreaded -= value;
      }
    }

According to CSharp’s annotation, calllogcallback is called by local code. In other words, the logcallbackhandler implementation of the main thread will be called first, and then the callbackhandlerthreaded implementation will be called regardless of whether the main thread is called or not

    [RequiredByNativeCode]
    private static void CallLogCallback(string logString, string stackTrace, LogType type, bool invokedOnMainThread)
    {
      if (invokedOnMainThread)
      {
        Application.LogCallback logCallbackHandler = Application.s_LogCallbackHandler;
        if (logCallbackHandler != null)
          logCallbackHandler(logString, stackTrace, type);
      }
      Application.LogCallback callbackHandlerThreaded = Application.s_LogCallbackHandlerThreaded;
      if (callbackHandlerThreaded == null)
        return;
      callbackHandlerThreaded(logString, stackTrace, type);
    }

SetLogCallbackDefined

    [GeneratedByOldBindingsGenerator]
    [MethodImpl(MethodImplOptions.InternalCall)]
    private static extern void SetLogCallbackDefined(bool defined);

Design of log system

Demand

It doesn’t affect unity

File output

Support unity debug

Support output log level

Log4Net

According to the previous Java way, log4j is easy to use. First, we decided to use it in the way of slf4j interface. Secondly, log4net is used to realize the requirements, as long as it does not affect the running of unity. The actual test did not affect the unity operation

Interface design

LoggerFactory

using log4net;

namespace Assets.Scripts.Utils.Log4Unity
{
    public class LoggerFactory
    {
        public static Log4Unity getLogger(string name)
        {
            return new Log4Unity(LogManager.GetLogger(name));
        }
    }
}

Log4unity: originally, I wanted to use logger directly, but it was occupied by unity

using System;
using System.IO;
using log4net;
using log4net.Config;
using UnityEngine;

namespace Assets.Scripts.Utils.Log4Unity
{
    public class Log4Unity
    {
        private ILog log;
        public Log4Unity(ILog log)
        {
            this.log = log;
        }

        public void debug(string message)
        {
            this.log.Debug(message);
            LogConfigurator.refresh();
        }

        public void info(string message)
        {
            this.log.Info(message);
            LogConfigurator.refresh();
        }

        public void warning(string message)
        {
            this.log.Warn(message);
            LogConfigurator.refresh();
        }

        public void error(string message)
        {
            Debug.LogError(message);
            if(!LogConfigurator.lazy_mode)
                this.log.Error(message);
            LogConfigurator.refresh();
        }

        public void exception(Exception exception)
        {
            Debug.LogException(exception);
            if(!LogConfigurator.lazy_mode)
                this.log.Warn(exception.ToString());
            LogConfigurator.refresh();
        }

        public void fatal(string message)
        {
            Debug.LogAssertion(message);
            if(!LogConfigurator.lazy_mode)
                this.log.Fatal(message);
            LogConfigurator.refresh();
        }
    }

    
}

Initialization of log4unity

Log4unity initialization, using unity’s monobehavior to complete, while printing some simple logs, check the log file location

using System.IO;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Core;
using UnityEngine;

namespace Assets.Scripts.Utils.Log4Unity
{
public class LogConfigurator : MonoBehaviour
    {
        private static readonly string config_path = "log4unity.properties";
        private static readonly ILog logger = LogManager.GetLogger("LogConfigurator");
        private static bool config_load = false;
        public static bool refresh_realtime = true;
        public static bool lazy_mode = true;

        private static FileInfo fileInfo = new FileInfo(config_path);
        
        private void Awake()
        {
            if (fileInfo.Exists)
            {
                XmlConfigurator.Configure(fileInfo);
                IAppender appender = LogManager.GetRepository().GetAppenders()[0];
                if (appender.Name.Equals("FileAppender"))
                {
                    FileAppender fileAppender = (FileAppender) appender;

                    Debug.Log("[logpath]:" + fileAppender.File);
                }
                
                
                config_load = true;
            }
            else
            {
                Debug.LogError("class Log4Unity method Awake configfile " + fileInfo.FullName + " is not existed.");
            }
        }

        private void OnEnable()
        {
            logger.Debug("method OnEnable");
            if(config_load == true)
            {
                Application.logMessageReceivedThreaded += ThreadLog;
            }
        }

        private void ThreadLog(string condition, string stackTrace, LogType type)
        {
            if (LogType.Warning.Equals(type))
            {
                logger.Warn(condition);
            }
            else if(LogType.Log.Equals(type))
            {
                logger.Info(condition);
            }
            
            // fixed:double print
            if(lazy_mode)
                if (LogType.Exception.Equals(type))
                {
                    logger.Warn(condition);
                }
                else if (LogType.Error.Equals(type))
                {
                    logger.Error(condition);
                }
                else if (LogType.Assert.Equals(type))
                {
                    logger.Fatal(condition);
                }

            refresh();
        }

        public static void refresh()
        {
            if(refresh_realtime)
                fileInfo.Refresh();
        }

        private void OnDisable()
        {
            logger.Debug("method OnDisable");
            if(config_load == true)
            {
                Application.logMessageReceivedThreaded -= ThreadLog;
            }
        }

        private void OnDestroy()
        {
            logger.Debug("method OnDestroy");
            fileInfo.Refresh();
        }
    }
}

log4unity.properties

<?xml version='1.0' encoding='UTF-8'?>
<log4net>
	<appender name="FileAppender" type="log4net.Appender.FileAppender">
		<file value="log4unity.log" />
		<appendToFile value="true" />
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%date %-5level --- [%-5thread]  %-20logger : %message%newline" />
		</layout>
	</appender>
	
	<root>
        <level value="DEBUG" />
		<appender-ref ref="FileAppender" />
    </root>
</log4net>

log4net.dll

Note: unity has two runtimes dotnet2.0 and dotnet4.6 on windows, both of which need to load the correct DLL version. In addition, the behavior of unityeditor is different in the two dotnet versions. Pay attention to the output location of the log. There is no problem after build

How to use it

public class FpsCounter : MonoBehaviour
    {
        private static readonly Log4Unity logger = LoggerFactory.getLogger("FpsCounter");
        
        ....
        
        private void Start()
        {
            logger.info("method Start");
            ....
        }

make complaints about

There are a lot of holes recently. Fill this up first

android unity Error: your hardware does not support this application,sorry!

recently, I met a problem about this, which occurred when I connected to unity3d on Android

the problem is to open the app and pop up the pop-up box below. Click OK to exit

This problem is caused by a problem with the so file in the LIBS folder

Solution one

Delete other so files, only v7a and x86

then clean it and run it

Next, I’ll post out the LIBS folder in the project: (just two red boxes are needed)

Solution two

Edit the build.gradle File, add the following code to it:

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

Code after adding:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    buildToolsVersion "28.0.0"

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }