[C#] Raycasting de Sphere sans l'API d'Unity

Cette section est destinée aux scripts partagés par la communauté. Chaque post est destiné à un script. Suivez bien les recommandations.
Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

[C#] Raycasting de Sphere sans l'API d'Unity

Message par ZJP » 12 Fév 2017 03:39

Bonjour,

Pour mon IA , il me fallait - vu le nombre de tests à faire- une fonction (100% Math "Classique" :mrgreen: ) de RayCast pouvant être utilisée dans des threads (voir même dans une DLL Native en C++), le tout a partir de données "brutes".

Ce code apporte une solution a ce problème.


-NOM DU SCRIPT : testINTERSECT

-AUTEUR(S): ZJP aidé par Google. :
https://www.google.fr/search?q=intercep ... EQ_AUIBygC
http://paulbourke.net/geometry/circlesphere/
http://stackoverflow.com/search?q=ray%20sphere
http://stackoverflow.com/questions/6533 ... tersection
https://en.wikipedia.org/wiki/Line%E2%8 ... tersection
etc etc... Honnêtement, ce ne fut pas si facile. :mrgreen:

-DESCRIPTION : Fonction qui permet de tester si un rayon (ligne) entre en collision avec une sphère de détection. Le tout, sans utiliser l'API d'Unity et/ou les fonctions de Vector3..
Edit du 22/09/17 : Ajout de la localisation du point d'impact

-UTILISATION :
Pour tester la fonction.
a) Créer une scène avec 3 GOs (2 Cubes pour délimiter le rayon de Raycast, 1 Sphere cible. Pas besoin de Collider vu que le but est de se passer de PhysX justement. Edit du 22/09/17 : Ajoutez un GO pour marquer le point d'impact
b) Placer le script sur un Go quelconque. Ex la Camera
c) Activer l'affichage des Gizmos
d) Après lancement du projet, bouger dans la scène l'un des 3 GOs. Le rayon du Raycast passera au rouge si détection.

-SCRIPT :

Code : Tout sélectionner


using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class testINTERSECT : MonoBehaviour {

	public Transform deb;   // Cube
	public Transform fin;   // Cube
	public Transform cible; // Sphere
	public Transform contact;
	private float rayonC = 0.0f;
	private Color GizCol = Color.green;
	
	private Vector3 tempo = new Vector3(0,0,0);

	void Start () {
		rayonC = cible.localScale.y / 2.0f;
		/*
		// test sqrt ***********************
		UnityEngine.Debug.Log("Precision methode UNITY = " + Mathf.Sqrt(123456.0f));
		UnityEngine.Debug.Log("Precision methode .NET = "  + (float)Math.Sqrt(123456.0f));
		int f = 2000000;
		int z = 0;
		float c = 0.0f;
		var s1 = Stopwatch.StartNew();
		for (z = 0; z < f; z++){
			c = Mathf.Sqrt(z + 1);
		}
		s1.Stop();
		//
		var s2 = Stopwatch.StartNew();
		for (z = 0; z < f; z++){
			c = (float)Math.Sqrt(z + 1);
		}
		s2.Stop();
		UnityEngine.Debug.Log("Timing methode UNITY = " + (double)(s1.Elapsed.TotalMilliseconds));
		UnityEngine.Debug.Log("Timing methode .NET = "  + (double)(s2.Elapsed.TotalMilliseconds)); // 2,5 fois plus rapide !!!!!!!!!!!
		*/
	}

	void LateUpdate () {
		bool Bam = SphereIntersect(deb.position.x, deb.position.y, deb.position.z , fin.position.x, fin.position.y, fin.position.z , cible.position.x, cible.position.y, cible.position.z , rayonC);
		GizCol = Bam ? Color.red : Color.green;
	}

	public bool SphereIntersect( float x1, float y1, float z1, float x2, float y2, float z2, float xC, float yC, float zC, float r )
	{
		float a = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1);
		//Debug.Log("Distance entre les cubes = " + Mathf.Sqrt(a)); // Pour info !!!
		//Debug.Log("Distance sans SQRT - plus rapide- entre les cubes = " + a); // Pour info !!!
		//if (a > far * far || a < near * near) return false; // Pas la bonne distance. Comparaison sans SQRT !!!
		float b = 2.0f * ((x2 - x1) * (x1 - xC) + (y2 - y1) * (y1 - yC) + (z2 - z1) * (z1 - zC));
		float c = (x1 - xC) * (x1 - xC) + (y1 - yC) * (y1 - yC) + (z1 - zC) * (z1 - zC) - r * r;
		float d = b * b - (4.0f * a * c);

		if (d < 0.01f) return false;
		else
		{ 
			// Contact perpendiculaire au centre de la sphere
			//float mu = -b / ( 2 * a);

			// Contact fin du raycast
			//float mu = (-b + (float)Math.Sqrt((b * b) - 4 * a * c )) / (2 * a);

			// Contact depart du raycast
			float mu = (-b - (float)Math.Sqrt((b * b) - 4 * a * c )) / (2 * a);
			tempo.x = x1 + mu * (x2 - x1);
			tempo.y = y1 + mu * (y2 - y1);
			tempo.z = z1 + mu * (z2 - z1);
			contact.transform.position = tempo;
			return true;
		}
	}

	public void OnDrawGizmos() 
	{
		if(fin == null || deb == null) return;
		Gizmos.color = GizCol;
		Gizmos.DrawLine(deb.position, fin.position);
	}
	
}
PS : si vous cherchez un SQRT plus performant .
Pièces jointes
Intercept.7z
(21.38 Kio) Téléchargé 201 fois
Dernière édition par ZJP le 31 Oct 2017 21:19, édité 7 fois.

Avatar de l’utilisateur
F@B
Messages : 1844
Inscription : 01 Août 2013 10:41
Contact :

Re: [C#] Raycasting de Sphere sans l'API d'Unity

Message par F@B » 12 Fév 2017 13:27

Super ZJP ! :super: :super:

merci
ʕ·͡ᴥ·ʔ ==> Mon Portfolio <== ʕ·͡ᴥ·ʔ

Merci de lire et de prendre en considération la Nétiquette des Forums avant de poster un sujet !

Avatar de l’utilisateur
E3DStef
Administrateur
Administrateur
Messages : 1646
Inscription : 14 Juil 2013 18:30
Localisation : https://www.carte-des-membres.com/fr/Unity3D-France/

Re: [C#] Raycasting de Sphere sans l'API d'Unity

Message par E3DStef » 12 Fév 2017 15:18

Super intéressant ! Bravo et merci ZJP.

Par contre désolé je n'ai pas saisi pourquoi c'est mieux que d'utiliser la détection d'unity ?

Problématique de charge CPU de calculs ?

+
Stef
Le Savoir n'est Précieux que s'il est Partagé

Si besoin urgent de me contacter, faites moi un mail sur : franceunity3d@gmail.com

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [C#] Raycasting de Sphere sans l'API d'Unity

Message par ZJP » 12 Fév 2017 15:56

F@B a écrit :..merci
A ton service ;-)
E3DStef a écrit :Super intéressant ! Bravo et merci ZJP.
Merci.
E3DStef a écrit :..pourquoi c'est mieux que d'utiliser la détection d'unity ?
Tu ne peux pas utiliser l'API d'Unity pour le multi-thread. En tout cas pas facilement et sans risque. De plus, j'étais à la recherche de formules plus classiques pouvant être utilisées même hors Unity .
E3DStef a écrit :Problématique de charge CPU de calculs ?
Multi-thread possible + pas de limite sur le nombre ni la portée des Raycasts?. Oui, incontestablement

Pour mon projet je traite les entités en 3 groupes.
a) Ceux dans le champs de vision du joueur.
b) Ceux proches du joueur mais pas vus par lui.
c) Ceux éloignés du joueur.
Dans les cas a) je suis sur du 100% PhysX. Dans b) un mélange PhysX + Math classique. Dans c), 100% Math classique.
Dernière édition par ZJP le 22 Sep 2017 17:57, édité 2 fois.

Avatar de l’utilisateur
E3DStef
Administrateur
Administrateur
Messages : 1646
Inscription : 14 Juil 2013 18:30
Localisation : https://www.carte-des-membres.com/fr/Unity3D-France/

Re: [C#] Raycasting de Sphere sans l'API d'Unity

Message par E3DStef » 12 Fév 2017 15:59

Ok ok intéressant tout cela...

:pleur4: pourquoi je n'ai qu'une vie pour apprendre tout cela :pleur4:

Je suivrai ton pblm avec intérêt !

A+ et bon dimanche...

Stef
Le Savoir n'est Précieux que s'il est Partagé

Si besoin urgent de me contacter, faites moi un mail sur : franceunity3d@gmail.com

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [C#] Raycasting de Sphere sans l'API d'Unity

Message par ZJP » 22 Sep 2017 19:26

Mise à jour avec un ajout de la localisation du point d'impact. ;-)

Répondre

Revenir vers « Scripts »