En esta oportunidad te presentamos un tutorial donde te mostraremos cómo crear generar rig y animar tus personajes desde cero, de una forma rápida, sencilla y divertida. Con Mixamo, Character Generator podremos crear personajes bípedos muy complejos.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios web y más.

Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!
FPS Game

Aprende a crear tu propio vídeo juego en primera persona FPS (First Person Shooter). con Unity3D.

Suscribete a nuestro canal de Youtube

Siguenos en nuestro canal de Youtube Síguenos en nuestro canal de Youtube dedicado a Tecnología, MarketPlace de Proyectos Tecnológicos, Cursos Online y Tutoriales de Desarrollo de Videojuegos. Ofrecemos consultoría en Desarrollo de Software, Marketing Online, Servicios de TI, Hosting Web, dominios web entre otros.

Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!
https://www.youtube.com/watch?v=sHGjMkVF4nk

En esta oportunidad te presentamos tutorial de como crear un juego en 3D de shooter space con Unity. Esperamos les sea de provecho.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Síguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

En esta oportunidad te presentamos tutorial de cómo publicar una aplicación en la Google Play Store con Unity. Esperamos les sea de provecho.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Síguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

En esta oportunidad te presentamos tutorial de cómo crear una funcionalidad de cargar y guardar partida de un juego al estilo RPG de shooter con Unity. Esperamos les sea de provecho.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Síguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

Realizar portales dimensionales en realidad aumentada ya es una realidad. En esta oportunidad te presentamos una muestra del potencial y alcance que puede implementar el motor de realidad aumentada ARCore en Unity.

Asset Implementados:

https://assetstore.unity.com/packages…

https://assetstore.unity.com/packages…

https://assetstore.unity.com/packages…

Links de referencia:

https://unity3d.com/es

https://developers.google.com/ar/

https://developers.google.com/ar/deve…l

Clase ARController:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GoogleARCore;

#if UNITY_EDITOR
//using input = GoogleARCore.InstantPreviewInput;
#endif
public class ARController : MonoBehaviour
{
    //Listamos la lista de planos que ARCore detecta en el frame actual
    private List m_newDetectedPlanes = new List();
    public GameObject GridPrefab;
    public GameObject Portal;
    public GameObject ARCamera;


    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        Screen.sleepTimeout = SleepTimeout.NeverSleep;
        //Verifica ARCore session status
        if(Session.Status != SessionStatus.Tracking)
        {
            return;
        }

        //La siguiente funcion llenará m_newDetectedPlanes con los planos que ARCore detecte en el frame actual
        Session.GetTrackables(m_newDetectedPlanes, TrackableQueryFilter.New);

        //Instanciamos un Grid por cada DetectedPlane en m_newDetectedPlanes
        for(int i=0; i < m_newDetectedPlanes.Count; i++)
        {
            GameObject grid = Instantiate(GridPrefab, Vector3.zero, Quaternion.identity, transform);
            //Ésta función seteará la posición del Grid y modificará los vertices del mesh adjunto
            grid.GetComponent().Initialize(m_newDetectedPlanes[i]);
        }

        //Verifica si el usuario ha tocado la pantalla
        Touch touch;
        if(Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began)
        {
            return;
        }

        //Verificamos is el usuario tocó algun plano detectado
        TrackableHit hit;
        if(Frame.Raycast(touch.position.x,touch.position.y, TrackableHitFlags.PlaneWithinPolygon, out hit))
        {
            //Ahora ubicamos el portal arriba de los planos detectados cuando los tocamos

            //Habilitamos el portal
            Portal.SetActive(true);

            //Creamos una nueva ancla
            Anchor anchor = hit.Trackable.CreateAnchor(hit.Pose);

            //Seteamos la posición del portal a la misma de la posición de toque
            Portal.transform.position = hit.Pose.position;
            Portal.transform.rotation = hit.Pose.rotation;

            //Ubicamos el portal enfrente de la camara
            Vector3 cameraPosition = ARCamera.transform.position;

            //El portal sólo rotará en el eje Y
            cameraPosition.y = hit.Pose.position.y;

            //Rotamos el portal enfrente de la camara
            Portal.transform.LookAt(cameraPosition, Portal.transform.up);

            //ARCore se mantendrá analizando el entorno del mundo real y actualizando las anclas mientras necesitemos añadir nuestro portal a las anclas
            Portal.transform.parent = anchor.transform;
        }
    }
}

Clase GridVisualizer:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GoogleARCore;
public class GridVisualizer : MonoBehaviour
{
    private static int s_PlaneCount = 0;
    private readonly Color[] k_PlaneColors = new Color[]
    {
        new Color(1.0f, 1.0f, 1.0f),
        new Color(0.956f, 0.262f, 0.211f),
        new Color(0.913f, 0.117f, 0.388f),
        new Color(0.611f, 0.152f, 0.654f),
        new Color(0.403f, 0.227f, 0.717f),
        new Color(0.247f, 0.317f, 0.709f),
        new Color(0.129f, 0.588f, 0.952f),
        new Color(0.011f, 0.662f, 0.956f),
        new Color(0f, 0.737f, 0.831f),
        new Color(0f, 0.588f, 0.533f),
        new Color(0.298f, 0.686f, 0.313f),
        new Color(0.545f, 0.764f, 0.290f),
        new Color(0.803f, 0.862f, 0.223f),
        new Color(1.0f, 0.921f, 0.231f),
        new Color(1.0f, 0.756f, 0.027f)
    };

    private DetectedPlane m_DetectedPlane;

    // Keep previous frame's mesh polygon to avoid mesh update every frame.
    private List m_PreviousFrameMeshVertices = new List();
    private List m_MeshVertices = new List();
    private Vector3 m_PlaneCenter = new Vector3();

    private List m_MeshColors = new List();

    private List m_MeshIndices = new List();

    private Mesh m_Mesh;

    private MeshRenderer m_MeshRenderer;

    ///
    /// The Unity Awake() method.
    /// 
    public void Awake()
    {
        m_Mesh = GetComponent().mesh;
        m_MeshRenderer = GetComponent();
    }

    ///
    /// The Unity Update() method.
    /// 
    public void Update()
    {
        if (m_DetectedPlane == null)
        {
            return;
        }
        else if (m_DetectedPlane.SubsumedBy != null)
        {
            Destroy(gameObject);
            return;
        }
        else if (m_DetectedPlane.TrackingState != TrackingState.Tracking)
        {
                m_MeshRenderer.enabled = false;
                return;
        }

        m_MeshRenderer.enabled = true;

        _UpdateMeshIfNeeded();
    }

    ///
    /// Initializes the DetectedPlaneVisualizer with a DetectedPlane.
    /// 
    ///The plane to vizualize.
    public void Initialize(DetectedPlane plane)
    {
        m_DetectedPlane = plane;
        m_MeshRenderer.material.SetColor("_GridColor", k_PlaneColors[s_PlaneCount++ % k_PlaneColors.Length]);
        m_MeshRenderer.material.SetFloat("_UvRotation", Random.Range(0.0f, 360.0f));

        Update();
    }

    ///
    /// Update mesh with a list of Vector3 and plane's center position.
    /// 
    private void _UpdateMeshIfNeeded()
    {
        m_DetectedPlane.GetBoundaryPolygon(m_MeshVertices);

        if (_AreVerticesListsEqual(m_PreviousFrameMeshVertices, m_MeshVertices))
        {
            return;
        }

        m_PreviousFrameMeshVertices.Clear();
        m_PreviousFrameMeshVertices.AddRange(m_MeshVertices);

        m_PlaneCenter = m_DetectedPlane.CenterPose.position;

        Vector3 planeNormal = m_DetectedPlane.CenterPose.rotation * Vector3.up;

        m_MeshRenderer.material.SetVector("_PlaneNormal", planeNormal);

        int planePolygonCount = m_MeshVertices.Count;

        // The following code converts a polygon to a mesh with two polygons, inner
        // polygon renders with 100% opacity and fade out to outter polygon with opacity 0%, as shown below.
        // The indices shown in the diagram are used in comments below.
        // _______________     0_______________1
        // |             |      |4___________5|
        // |             |      | |         | |
        // |             | =>   | |         | |
        // |             |      | |         | |
        // |             |      |7-----------6|
        // ---------------     3---------------2
        m_MeshColors.Clear();

        // Fill transparent color to vertices 0 to 3.
        for (int i = 0; i < planePolygonCount; ++i)
        {
            m_MeshColors.Add(Color.clear);
        }

        // Feather distance 0.2 meters.
        const float featherLength = 0.2f;

        // Feather scale over the distance between plane center and vertices.
        const float featherScale = 0.2f;

        // Add vertex 4 to 7.
        for (int i = 0; i < planePolygonCount; ++i)
        {
            Vector3 v = m_MeshVertices[i];

            // Vector from plane center to current point
            Vector3 d = v - m_PlaneCenter;

            float scale = 1.0f - Mathf.Min(featherLength / d.magnitude, featherScale);
            m_MeshVertices.Add((scale * d) + m_PlaneCenter);

            m_MeshColors.Add(Color.white);
        }

        m_MeshIndices.Clear();
        int firstOuterVertex = 0;
        int firstInnerVertex = planePolygonCount;

        // Generate triangle (4, 5, 6) and (4, 6, 7).
        for (int i = 0; i < planePolygonCount - 2; ++i)
        {
            m_MeshIndices.Add(firstInnerVertex);
            m_MeshIndices.Add(firstInnerVertex + i + 1);
            m_MeshIndices.Add(firstInnerVertex + i + 2);
        }

        // Generate triangle (0, 1, 4), (4, 1, 5), (5, 1, 2), (5, 2, 6), (6, 2, 3), (6, 3, 7)
        // (7, 3, 0), (7, 0, 4)
        for (int i = 0; i < planePolygonCount; ++i)
        {
            int outerVertex1 = firstOuterVertex + i;
            int outerVertex2 = firstOuterVertex + ((i + 1) % planePolygonCount);
            int innerVertex1 = firstInnerVertex + i;
            int innerVertex2 = firstInnerVertex + ((i + 1) % planePolygonCount);

            m_MeshIndices.Add(outerVertex1);
            m_MeshIndices.Add(outerVertex2);
            m_MeshIndices.Add(innerVertex1);

            m_MeshIndices.Add(innerVertex1);
            m_MeshIndices.Add(outerVertex2);
            m_MeshIndices.Add(innerVertex2);
        }

        m_Mesh.Clear();
        m_Mesh.SetVertices(m_MeshVertices);
        m_Mesh.SetTriangles(m_MeshIndices, 0);
        m_Mesh.SetColors(m_MeshColors);
    }

    private bool _AreVerticesListsEqual(List firstList, List secondList)
    {
        if (firstList.Count != secondList.Count)
        {
            return false;
        }

        for (int i = 0; i < firstList.Count; i++)
        {
            if (firstList[i] != secondList[i])
            {
                return false;
            }
        }

        return true;
    }
}

Clase PortalManager:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class PortalManager : MonoBehaviour
{
    public GameObject MainCamera;
    public GameObject Sponza;
    public GameObject Scenario;
    public GameObject Zombie;
    public GameObject SPIDER;


    private Material[] SponzaMaterials;
    private Material[] ScenarioMaterials;
    private Material[] ZombieMaterials;
    private Material[] SpiderMaterials;

    private Vector3 camPositionInPortalSpace;

    // Start is called before the first frame update
    void Start()
    {
        SponzaMaterials = Sponza.GetComponent().sharedMaterials;
        ScenarioMaterials = Scenario.GetComponent().sharedMaterials;
        ZombieMaterials = Zombie.GetComponent().sharedMaterials;
        SpiderMaterials = SPIDER.GetComponent().sharedMaterials;

    }

    // Update is called once per frame
    void OnTriggerStay(Collider collider)
    {
        Debug.Log("camPositionInPortalSpace: "+camPositionInPortalSpace.z);
        Debug.Log("MainCamera.transform.position: "+MainCamera.transform.position);

        if(MainCamera.transform.position.z < 0.5f)
        {
            //Deshabilita la plantilla de prueba
            for(int i=0; i < SponzaMaterials.Length; ++i)
            {
                SponzaMaterials[i].SetInt("_StencilComp", 0);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }

            for(int i=0; i < ScenarioMaterials.Length; ++i)
            {
                ScenarioMaterials[i].SetInt("_StencilComp", 0);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }
            for(int i=0; i < ZombieMaterials.Length; ++i)
            {
                ZombieMaterials[i].SetInt("_StencilComp", 0);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }
            for(int i=0; i < SpiderMaterials.Length; ++i)
            {
                SpiderMaterials[i].SetInt("_StencilComp", 0);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }
            
        }
        else
        {
            //Habilita la plantilla de prueba
            for(int i=0; i < SponzaMaterials.Length; ++i)
            {
                SponzaMaterials[i].SetInt("_StencilComp", 3);
            }

            for(int i=0; i < ScenarioMaterials.Length; ++i)
            {
                ScenarioMaterials[i].SetInt("_StencilComp", 3);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }
            for(int i=0; i < ZombieMaterials.Length; ++i)
            {
                ZombieMaterials[i].SetInt("_StencilComp", 3);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }
            for(int i=0; i < SpiderMaterials.Length; ++i)
            {
                SpiderMaterials[i].SetInt("_StencilComp", 3);
                Debug.Log("else camera position: "+MainCamera.transform.position.z);
            }
        } 
    }

}

SponzaShader:

// (c) 2018 Guidev
// This code is licensed under MIT license (see LICENSE.txt for details)

Shader "Unlit/SponzaShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		[Enum(CompareFunction)] _StencilComp("Stencil Comp", int) = 3
		[Enum(CompareFunction)] _StencilComp("Stencil Comp", int) = 0
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			Stencil{
				Ref 1
				Comp [_StencilComp]
				//Comp Always
			}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float4 normal: NORMAL;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float3 normal: TEXCOORD1;
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.normal = normalize(mul(v.normal, unity_WorldToObject));
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float3 normal = normalize(i.normal);
				float3 lightDir = normalize(float3(0.0, 10.0, 10.0));
				float l = max(dot(lightDir, normal), 0.0);
				float4 texCol = tex2D(_MainTex, i.uv);
				fixed4 col = texCol * l + texCol * 0.4f;
				return col;
			}
			ENDCG
		}
	}
}

Portal Shader:

// (c) 2018 Guidev
// This code is licensed under MIT license (see LICENSE.txt for details)

Shader "Unlit/Portal"
{
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float4 normal: NORMAL;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float3 normal: TEXCOORD1;
				float4 vertex : SV_POSITION;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.normal = normalize(mul(v.normal, unity_WorldToObject));
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float3 normal = normalize(i.normal);
				float3 lightDir = normalize(float3(0.0, 10.0, 10.0));
				float l = max(dot(lightDir, normal), 0.0);
				return fixed4(l, l, l, 1.0f) + fixed4(0.3, 0.3, 0.3, 1.0);
			}
			ENDCG
		}
	}
}

PortalPlane Shader:

// (c) 2018 Guidev
// This code is licensed under MIT license (see LICENSE.txt for details)

Shader "Unlit/PortalPlane"
{
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100
		Zwrite Off
		ColorMask 0

		Pass
		{
			Stencil{
				Ref 1
				Comp always
				Pass replace
			}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				return fixed4(0.0, 0.0, 0.0, 0.0);
			}
			ENDCG
		}
	}
}

Imágenes de configuración de los objetos dentro del proyecto HelloAR.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Síguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

En este breve tutorial les mostraremos como descargar e instalar vuforia engine en Unity para implementar realidad aumentada en sus videojuegos.

A continuación les colocamos los enlaces de documentación oficial y descarga de los elementos necesarios para la configuración.

https://unity3d.com/es/partners/vuforia

https://library.vuforia.com/articles/Training/getting-started-with-vuforia-in-unity.html

https://developer.vuforia.com/downloads/sdk

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Síguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

Te presentamos en esta oportunidad un breve tutorial donde mostramos cómo instalar y configurar tus proyectos en los cuales quieras implementar realidad aumentada con el Core de realidad aumentada de Google.

ARCore es una excelente opción que puedes integrar fácilmente con el motor de videojuegos Unity y diseñar videojuegos y proyectos en este ámbito muy estables y que sorprenderán a más de uno en este segmento.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios web y más.

Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

En esta oportunidad te presentamos una revisión del último asset de shooter en primera persona FPS presentado por Unity hasta la fecha. Cuenta con altas prestaciones gráficas y al ser multijugador presenta una excelente opción para implementarlo en tus vídeojuegos, preferiblemente enfocado a consolas de última generación.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios web y más.

Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!