Création d'univers 3D avec HTML et CSS par Keith Clark
L'année dernière, j'ai créé une démo montrant comment CSS 3D transforme pourraient être utilisés pour créer des environnements 3D. La démo a été une vitrine technique de ce qui pourrait être réalisé avec CSS au moment, mais je voulais voir jusqu'où je pouvais pousser les choses, si au cours des derniers mois que je travaille sur une nouvelle version avec des modèles plus complexes, l'éclairage réaliste , les ombres et la détection de collision. Ce document post comment je l'ai fait et les techniques que j'ai utilisé.
Création d'objets 3D
Dans les moteurs 3D d'aujourd'hui une géométrie des objets est stockée comme un ensemble de points (ou de sommets) ayant chacun un x. propriété y et z qui définit sa position dans l'espace 3D. Un rectangle par exemple serait défini par quatre sommets, un pour chaque coin. Chaque coin peut être manipulé individuellement permettant le rectangle d'être tiré dans des formes différentes en déplaçant ses sommets le long de l'axe x, y et z. Le moteur 3D utilisera ces données de sommet et un peu de mathématiques intelligent pour rendre des objets 3D sur votre écran 2D.
Avec CSS transforme cette option est activée la tête. Nous ne pouvons pas définir des formes arbitraires en utilisant un ensemble de points, nous sommes coincés avec des éléments HTML qui sont toujours rectangulaires et ont deux propriétés dimensions telles que le dessus. la gauche. largeur et hauteur de déterminer leur position et leur taille. À bien des égards ce qui rend le traitement avec 3D plus facile, car il n'y a pas de mathématiques complexes à traiter - il suffit d'appliquer une CSS transformée pour faire pivoter un élément autour d'un axe et vous avez terminé!
Création d'objets de rectangles semble limiter au début, mais vous pouvez faire une quantité surprenante avec eux, surtout quand vous commencez à jouer avec les chaînes PNG alpha. Dans l'image ci-dessous, vous pouvez voir le haut du corps et des objets de roue semble arrondi en dépit d'être composée de rectangles.
L'exemple suivant montre dans la pratique - jetez un oeil à l'onglet « JS »:
Tambour d'huile 3D construite en utilisant rectangulaire
L'éclairage était le plus grand défi dans ce projet. Je ne vais pas mentir, les maths me presque cassé, mais il en valait la peine parce que l'éclairage apporte un incroyable sens de la profondeur et de l'atmosphère d'un environnement autrement plat et sans vie.
Comme je l'ai mentionné plus tôt, un objet dans votre moteur 3D moyen est défini par une série de sommets. Pour calculer l'éclairage de ces sommets sont utilisés pour calculer une « normale » qui peut être utilisé pour déterminer la quantité de lumière frappera le point central d'une surface. Cela pose un problème lors de la création d'objets 3D avec des éléments HTML, car ces données de sommet n'existe pas. Donc, le premier défi était d'écrire un ensemble de fonctions pour calculer les quatre sommets (un pour chaque coin) pour un élément qui a été transformé avec CSS afin que l'éclairage pourrait être calculé. Une fois que cela a été compris que j'ai commencé à expérimenter différentes façons d'objets légers. Dans ma première expérience, je multiple background-image s pour simuler la lumière frappant une surface en combinant un gradient linéaire avec une image. L'effet utilise un gradient qui commence et se termine avec la même valeur de rgba, produisant un bloc solide de couleur. Faire varier la valeur du canal alpha permet à l'image sous-jacente de purge à travers le bloc de couleur créant l'illusion d'ombrage.
Pour atteindre le deuxième plus sombre effet dans l'image ci-dessus j'applique les styles suivants à un élément:
Tambour d'huile 3D ombragée plat
Cette technique est appelée ombrage comme plat. Il est une méthode efficace d'ombrage, mais il ne résulte en surface ayant le même détail. Par exemple, si je crée un mur 3D étendu dans la distance, il serait ombrée identique sur toute sa longueur. Je voulais quelque chose qui semblait plus réaliste.
Un second coup de couteau à l'éclairage
Pour simuler l'éclairage réel, les surfaces doivent assombrir comme ils vont au-delà de la portée d'une source lumineuse, et si plusieurs feux ont frappé la même surface il se doit l'ombre en conséquence.
Pour une surface plane l'ombre, je ne devais calculer la lumière atteignant le point central, mais maintenant je dois goûter à la lumière en différents points de la surface afin que je puisse déterminer comment chaque lumière ou sombre point devrait être. Le calcul nécessaire pour créer ces données d'éclairage est identique à celui utilisé pour l'ombrage plat.
La solution était d'utiliser un
La règle de style de fond pour appliquer une carte texture légère et à une surface ressemble à ceci:
Qui produit la surface éclairée finale:
casting Shadows
S'établir sur toile pour l'éclairage fait des ombres possible. La logique derrière l'ombre de coulée se révèle être assez facile. surfaces de commande en fonction de leur proximité d'une source de lumière m'a permis non seulement de produire une carte de lumière pour une surface, mais aussi déterminer si une surface précédente avait déjà été frappé par le rayon courant de la lumière. Si elle avait, je pouvais mettre le pixel carte de lumière pertinente pour être dans l'ombre. Cette technique permet une image à la fois utilisée pour l'éclairage et les ombres.
collisions
La détection de collision utilise une carte de hauteur - haut vers le bas l'image du niveau qui utilise la couleur pour représenter la hauteur des objets qui s'y trouvent. Le blanc représente le le plus profond et noir position possible le joueur peut atteindre. Comme le joueur se déplace autour du niveau je convertir leur position en coordonnées 2D et de les utiliser pour vérifier la couleur sur la carte de hauteur. Si la couleur est plus léger que les joueurs dernière position du joueur tombe, si elle est légèrement plus foncée que le joueur peut intensifier ou sauter sur un objet. Si la couleur est beaucoup plus sombre que le joueur arrive à un arrêt - j'utiliser ce pour les murs et les clôtures. À l'heure actuelle, cette image est tirée par la main, mais je vais être à la recherche dans la création de façon dynamique.
Et après?
Eh bien, un jeu serait une prochaine étape naturelle pour ce projet - il serait intéressant de voir comment ces techniques sont évolutives. À court terme, j'ai commencé à travailler sur un prototype CSS3 pour les excellentes renderer Three.js qui utilise ces mêmes techniques pour rendre la géométrie et les lumières créées par un vrai moteur 3D.
Jamais pensé à utiliser l'approche traditionnelle collisionneur FPS (ellipsoïde contre les essais d'avion) pour une collision? Si vous testez contre les solides convexes / cellules, vous pouvez exclure toute collision possible tant qu'il ne touche aucun des plans donnés formés par le solide convexe. L'éclairage est vraiment bonne.
D'une certaine manière, l'événement de détection mousemove ne semble pas fonctionner bien sur ma version de Safari. Considéré comme l'aide d'un contrôleur de glisser comme ce que je l'ai fait pour mes démos de fps? Mon contrôleur de glisser fonctionne aussi bien sur mobile, car j'utilise Hammer.js api. Cependant, avoir quelque chose sur mobile n'est pas facile en termes de limites de performance / fonctionnalités / mémoire. Les meilleures utilisations est une Cubic VR et une géométrie 3D, ou une géométrie simple 3d dans une seule pièce.
Très impressionnant, Keith! Continuez le travail impressionnant.
Grande expérience! Sur la dernière version stable de Chrome encore (version 24.0.1312.56) sur Linux, votre démo est entièrement fonctionnelle mais les modèles sont écrêtage tout en se déplaçant.
Beau travail dans tous les cas, très intéressant!
Malheureusement, Chrome ne souffre de problèmes de découpage. J'ai documenté cela, ainsi que des problèmes dans d'autres navigateurs dans un billet de blog précédent