File: galaxy.py

package info (click to toggle)
python-vispy 0.15.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,868 kB
  • sloc: python: 59,799; javascript: 6,800; makefile: 69; sh: 6
file content (205 lines) | stat: -rwxr-xr-x 6,043 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/usr/bin/env python
import numpy as np
import sys

from vispy.util.transforms import perspective
from vispy.util import transforms
from vispy import gloo
from vispy import app
from vispy import io

import galaxy_specrend
from galaxy_simulation import Galaxy

VERT_SHADER = """
#version 120
uniform mat4  u_model;
uniform mat4  u_view;
uniform mat4  u_projection;

//sampler that maps [0, n] -> color according to blackbody law
uniform sampler1D u_colormap;
//index to sample the colormap at
attribute float a_color_index;

//size of the star
attribute float a_size;
//type
//type 0 - stars
//type 1 - dust
//type 2 - h2a objects
//type 3 - h2a objects
attribute float a_type;
attribute vec2  a_position;
//brightness of the star
attribute float a_brightness;

varying vec3 v_color;
void main (void)
{
    gl_Position = u_projection * u_view * u_model * vec4(a_position, 0.0,1.0);

    //find base color according to physics from our sampler
    vec3 base_color = texture1D(u_colormap, a_color_index).rgb;
    //scale it down according to brightness
    v_color = base_color * a_brightness;


    if (a_size > 2.0)
    {
        gl_PointSize = a_size;
    } else {
        gl_PointSize = 0.0;
    }

    if (a_type == 2) {
        v_color *= vec3(2, 1, 1);
    }
    else if (a_type == 3) {
        v_color = vec3(.9);
    }
}
"""

FRAG_SHADER = """
#version 120
//star texture
uniform sampler2D u_texture;
//predicted color from black body
varying vec3 v_color;

void main()
{
    //amount of intensity from the grayscale star
    float star_tex_intensity = texture2D(u_texture, gl_PointCoord).r;
    gl_FragColor = vec4(v_color * star_tex_intensity, 0.8);
}
"""

galaxy = Galaxy(10000)
galaxy.reset(13000, 4000, 0.0004, 0.90, 0.90, 0.5, 200, 300)
# coldest and hottest temperatures of out galaxy
t0, t1 = 200.0, 10000.0
# total number of discrete colors between t0 and t1
n = 1000
dt = (t1 - t0) / n

# maps [0, n) -> colors
# generate a linear interpolation of temperatures
# then map the temperatures to colors using black body
# color predictions
colors = np.zeros(n, dtype=(np.float32, 3))
for i in range(n):
    temperature = t0 + i * dt
    x, y, z = galaxy_specrend.spectrum_to_xyz(galaxy_specrend.bb_spectrum,
                                              temperature)
    r, g, b = galaxy_specrend.xyz_to_rgb(galaxy_specrend.SMPTEsystem, x, y, z)
    r = min((max(r, 0), 1))
    g = min((max(g, 0), 1))
    b = min((max(b, 0), 1))
    colors[i] = galaxy_specrend.norm_rgb(r, g, b)


# load the PNG that we use to blend the star with
# to provide a circular look to each star.
def load_galaxy_star_image():
    fname = io.load_data_file('galaxy/star-particle.png')
    raw_image = io.read_png(fname)

    return raw_image


class Canvas(app.Canvas):

    def __init__(self):
        # setup initial width, height
        app.Canvas.__init__(self, keys='interactive', size=(800, 600))

        # create a new shader program
        self.program = gloo.Program(VERT_SHADER, FRAG_SHADER,
                                    count=len(galaxy))

        # load the star texture
        self.texture = gloo.Texture2D(load_galaxy_star_image(),
                                      interpolation='linear')
        self.program['u_texture'] = self.texture

        # construct the model, view and projection matrices
        self.view = transforms.translate((0, 0, -5))
        self.program['u_view'] = self.view

        self.model = np.eye(4, dtype=np.float32)
        self.program['u_model'] = self.model

        self.program['u_colormap'] = colors

        w, h = self.size
        self.projection = perspective(45.0, w / float(h), 1.0, 1000.0)
        self.program['u_projection'] = self.projection

        # start the galaxy to some decent point in the future
        galaxy.update(100000)
        data = self.__create_galaxy_vertex_data()

        # setup the VBO once the galaxy vertex data has been setup
        # bind the VBO for the first time
        self.data_vbo = gloo.VertexBuffer(data)
        self.program.bind(self.data_vbo)

        # setup blending
        gloo.set_state(clear_color=(0.0, 0.0, 0.03, 1.0),
                       depth_test=False, blend=True,
                       blend_func=('src_alpha', 'one'))

        self._timer = app.Timer('auto', connect=self.update, start=True)

    def __create_galaxy_vertex_data(self):
        data = np.zeros(len(galaxy),
                        dtype=[('a_size', np.float32),
                               ('a_position', np.float32, 2),
                               ('a_color_index', np.float32),
                               ('a_brightness', np.float32),
                               ('a_type', np.float32)])

        # see shader for parameter explanations
        pw, ph = self.physical_size
        data['a_size'] = galaxy['size'] * max(pw / 800.0, ph / 800.0)
        data['a_position'] = galaxy['position'] / 13000.0

        data['a_color_index'] = (galaxy['temperature'] - t0) / (t1 - t0)
        data['a_brightness'] = galaxy['brightness']
        data['a_type'] = galaxy['type']

        return data

    def on_resize(self, event):
        # setup the new viewport
        gloo.set_viewport(0, 0, *event.physical_size)
        # recompute the projection matrix
        w, h = event.size
        self.projection = perspective(45.0, w / float(h),
                                      1.0, 1000.0)
        self.program['u_projection'] = self.projection

    def on_draw(self, event):
        # update the galaxy
        galaxy.update(50000)  # in years !

        # recreate the numpy array that will be sent as the VBO data
        data = self.__create_galaxy_vertex_data()
        # update the VBO
        self.data_vbo.set_data(data)
        # bind the VBO to the GL context
        self.program.bind(self.data_vbo)

        # clear the screen and render
        gloo.clear(color=True, depth=True)
        self.program.draw('points')


if __name__ == '__main__':
    c = Canvas()
    c.show()

    if sys.flags.interactive == 0:
        app.run()