Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief définition d'une scène 

5""" 

6import math 

7from .image_synthese_base import Pixel, Vecteur, Rayon, Couleur 

8 

9 

10class Scene: 

11 """ 

12 définit une scène, les axes x,y sont ceux de l'écran, 

13 z-1 est la distance à l'écran du point (x,y,z) 

14 """ 

15 

16 def __init__(self, repere, alpha, x, y): 

17 """définit la position de l'oeil, l'angle d'ouverture, 

18 et la taille de l'écran""" 

19 self.repere = repere 

20 self.alpha = float(alpha) 

21 self.dim = (int(x), int(y)) 

22 

23 def ajoute_source(self, source): 

24 """ajoute une source ponctuelle de lumière""" 

25 if not hasattr(self, "sources"): 

26 self.sources = [] 

27 self.sources.append(source) 

28 

29 def ajoute_objet(self, objet): 

30 """ajoute un objet à la scène""" 

31 if not hasattr(self, "objets"): 

32 self.objets = [] 

33 self.objets.append(objet) 

34 

35 def __str__(self): 

36 """affichage""" 

37 s = "scene ----------------------------\n" 

38 s += "repere : " + str(self.repere) + "\n" 

39 s += "angle d'ouverture : " + str(self.alpha) + "\n" 

40 s += "dimension de l'ecran : " + str(self.dim) + "\n" 

41 if hasattr(self, "sources"): 

42 for a in self.sources: 

43 s += " " + str(a) + "\n" 

44 if hasattr(self, "objets"): 

45 for a in self.objets: 

46 s += " " + str(a) + "\n" 

47 return s 

48 

49 def intersection(self, rayon): 

50 """calcule le point d'intersection entre un rayon et le plus proche des objets, 

51 retourne l'objet et le point d'intersection""" 

52 if not hasattr(self, "objets"): 

53 return None, None 

54 p = rayon.origine 

55 sp, so = None, None 

56 for o in self.objets: 

57 i = o.intersection(rayon) 

58 if i is None: 

59 continue 

60 if rayon.direction.scalaire(i - p) <= 0: 

61 continue 

62 if i == rayon.origine: 

63 continue 

64 if sp is None: 

65 sp = i 

66 so = o 

67 else: 

68 v = i - p 

69 d = sp - p 

70 if v.norme2() < d.norme2(): 

71 sp = i 

72 so = o 

73 return so, sp 

74 

75 def sources_atteintes(self, p): 

76 """retourne la liste des sources atteintes depuis une position p de l'espace, 

77 vérifie qu'aucun objet ne fait obstacle""" 

78 res = [] 

79 for s in self.sources: 

80 r = Rayon(s.origine, p - s.origine, Pixel(0, 0), s.couleur) 

81 _, i = self.intersection(r) 

82 if i is None: 

83 continue 

84 if (i - p).norme2() < 1e-10: # possible problème d'arrondi 

85 res.append(s) 

86 continue 

87 return res 

88 

89 def construit_rayon(self, pixel): 

90 """construit le rayon correspondant au pixel pixel""" 

91 x = (pixel.x - self.dim[0] / 2) * \ 

92 math.tan(self.alpha / 2) / min(self.dim) 

93 y = (pixel.y - self.dim[1] / 2) * \ 

94 math.tan(self.alpha / 2) / min(self.dim) 

95 v = Vecteur(x, y, 1) 

96 r = Rayon(self.repere.origine, self.repere.coordonnees(v), 

97 pixel, Couleur(1, 1, 1)) 

98 return r 

99 

100 def modele_illumination(self, rayon, p, obj, source): 

101 """calcule la couleur pour un rayon donné, un point p, un objet obj, 

102 et une source de lumière source""" 

103 n = obj.normale(p, rayon) 

104 cos = n.cosinus(source.origine - p) 

105 cl = obj.couleur_point(p) * cos 

106 cl = cl.produit_terme(rayon.couleur) 

107 return cl 

108 

109 def couleur_fond(self): 

110 """retourne la couleur du fond""" 

111 return Couleur(0, 0, 0) 

112 

113 def rayon_couleur(self, rayon, ref=True): 

114 """retourne la couleur d'un rayon connaissant les objets, 

115 cette fonction doit être surchargée pour chaque modèle d'illumination, 

116 si ref == True, on tient compte des rayons réfractés et réfléchis""" 

117 

118 list_rayon = [rayon] 

119 c = Couleur(0, 0, 0) 

120 b = False 

121 while len(list_rayon) > 0: 

122 r = list_rayon.pop() 

123 o, p = self.intersection(r) 

124 

125 if p is None: 

126 continue 

127 

128 if ref: 

129 t = o.rayon_refracte(r, p) 

130 if t is not None: 

131 list_rayon.append(t) 

132 t = o.rayon_reflechi(r, p) 

133 if t is not None: 

134 list_rayon.append(t) 

135 

136 sources = self.sources_atteintes(p) 

137 if len(sources) == 0: 

138 return Couleur(0, 0, 0) 

139 for s in sources: 

140 cl = self.modele_illumination(r, p, o, s) 

141 c += cl 

142 b = True 

143 

144 if not b: 

145 c = self.couleur_fond() 

146 else: 

147 c.borne() 

148 return c 

149 

150 def construit_image(self, screen, pygame, fLOG): 

151 """construit l'image de synthèse où screen est un objet du module pygame""" 

152 count = 0 

153 nbpixel = int(self.dim[0] * self.dim[1] / 100) 

154 for y in range(0, self.dim[1]): 

155 for x in range(0, self.dim[0]): 

156 p = Pixel(x, y) 

157 r = self.construit_rayon(p) 

158 c = self.rayon_couleur(r, True) 

159 q = (p.x, self.dim[1] - p.y - 1) 

160 d = (int(c.x * 255), int(c.y * 255), int(c.z * 255)) 

161 pygame.draw.line(screen, d, q, q) 

162 count += 1 

163 if count % 150 == 0: 

164 pygame.display.flip() 

165 if count % nbpixel == 0: 

166 fLOG("avancement ", count // nbpixel, "%") 

167 pygame.display.flip()