1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Various material implementations
18 intrude import depth_core
21 # Simple material with static colors used for debugging or display abstract objects
25 # Get the default blueish material
31 # Ambient color, always visible
32 var ambient_color
: Array[Float]
34 # Diffuse color when covered by a light source
35 var diffuse_color
: Array[Float]
37 # Specular color affecting reflections
38 var specular_color
: Array[Float]
40 redef fun draw
(actor
, model
)
42 var program
= app
.versatile_program
48 program
.translation
.uniform
(actor
.center
.x
, -actor
.center
.y
, actor
.center
.z
, 0.0)
49 program
.scale
.uniform actor
.scale
50 program
.rotation
.uniform
new Matrix.rotation
(actor
.rotation
, 0.0, 1.0, 0.0)
53 program
.coord
.array_enabled
= true
54 program
.coord
.array
(mesh
.vertices
, 3)
56 program
.normal
.array_enabled
= true
57 program
.normal
.array
(mesh
.normals
, 3)
60 program
.use_map_ambient
.uniform
false
61 program
.use_map_diffuse
.uniform
false
62 program
.use_map_specular
.uniform
false
63 program
.tex_coord
.array_enabled
= false
66 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
69 program
.camera
.uniform
(app
.world_camera
.position
.x
, app
.world_camera
.position
.y
, app
.world_camera
.position
.z
)
71 # Colors from the material
72 program
.ambient_color
.uniform
(ambient_color
[0], ambient_color
[1], ambient_color
[2], ambient_color
[3]*actor
.alpha
)
73 program
.diffuse_color
.uniform
(diffuse_color
[0], diffuse_color
[1], diffuse_color
[2], diffuse_color
[3]*actor
.alpha
)
74 program
.specular_color
.uniform
(specular_color
[0], specular_color
[1], specular_color
[2], specular_color
[3]*actor
.alpha
)
77 if mesh
.indices
.is_empty
then
78 glDrawArrays
(gl_TRIANGLES
, 0, mesh
.vertices
.length
/3)
80 glDrawElements
(gl_TRIANGLES
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
85 # Material with potential `diffuse_texture` and `specular_texture`
86 class TexturedMaterial
89 # Texture applied to the ambient_color
90 var ambient_texture
: nullable Texture = null is writable
92 # Texture applied to the diffuse color
93 var diffuse_texture
: nullable Texture = null is writable
95 # Texture applied to the specular color
96 var specular_texture
: nullable Texture = null is writable
98 redef fun draw
(actor
, model
)
100 var mesh
= model
.mesh
102 var program
= app
.versatile_program
105 var need_tex_coord
= false
107 var texture
= ambient_texture
108 if texture
!= null then
109 glActiveTexture gl_TEXTURE0
110 glBindTexture
(gl_TEXTURE_2D
, texture
.gl_texture
)
111 program
.use_map_ambient
.uniform
true
112 program
.map_ambient
.uniform
0
113 need_tex_coord
= true
115 program
.use_map_ambient
.uniform
false
118 texture
= diffuse_texture
119 if texture
!= null then
120 glActiveTexture gl_TEXTURE1
121 glBindTexture
(gl_TEXTURE_2D
, texture
.gl_texture
)
122 program
.use_map_diffuse
.uniform
true
123 program
.map_diffuse
.uniform
1
124 need_tex_coord
= true
126 program
.use_map_diffuse
.uniform
false
129 texture
= specular_texture
130 if texture
!= null then
131 glActiveTexture gl_TEXTURE2
132 glBindTexture
(gl_TEXTURE_2D
, texture
.gl_texture
)
133 program
.use_map_specular
.uniform
true
134 program
.map_specular
.uniform
2
135 need_tex_coord
= true
137 program
.use_map_specular
.uniform
false
140 program
.translation
.uniform
(actor
.center
.x
, -actor
.center
.y
, actor
.center
.z
, 0.0)
141 program
.scale
.uniform actor
.scale
143 program
.tex_coord
.array_enabled
= need_tex_coord
144 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
146 program
.coord
.array_enabled
= true
147 program
.coord
.array
(mesh
.vertices
, 3)
148 program
.rotation
.uniform
new Matrix.rotation
(actor
.rotation
, 0.0, 1.0, 0.0)
150 program
.ambient_color
.uniform
(ambient_color
[0], ambient_color
[1], ambient_color
[2], ambient_color
[3]*actor
.alpha
)
151 program
.diffuse_color
.uniform
(diffuse_color
[0], diffuse_color
[1], diffuse_color
[2], diffuse_color
[3]*actor
.alpha
)
152 program
.specular_color
.uniform
(specular_color
[0], specular_color
[1], specular_color
[2], specular_color
[3]*actor
.alpha
)
154 program
.normal
.array_enabled
= true
155 program
.normal
.array
(mesh
.normals
, 3)
157 program
.light_center
.uniform
(app
.light
.position
.x
, app
.light
.position
.y
, app
.light
.position
.z
)
158 program
.camera
.uniform
(app
.world_camera
.position
.x
, app
.world_camera
.position
.y
, app
.world_camera
.position
.z
)
160 if mesh
.indices
.is_empty
then
161 glDrawArrays
(gl_TRIANGLES
, 0, mesh
.vertices
.length
/3)
163 glDrawElements
(gl_TRIANGLES
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
168 # Simple material using the normals of the surface as color
170 # Each axis composing the normals are translated to color values.
171 # This material is useful for debugging normals or display models in a colorful way.
172 class NormalsMaterial
175 redef fun draw
(actor
, model
)
177 var program
= app
.normals_program
179 program
.mvp
.uniform app
.world_camera
.mvp_matrix
181 var mesh
= model
.mesh
183 # TODO apply normal map
185 program
.translation
.uniform
(actor
.center
.x
, -actor
.center
.y
, actor
.center
.z
, 0.0)
186 program
.scale
.uniform actor
.scale
188 program
.tex_coord
.array_enabled
= true
189 program
.tex_coord
.array
(mesh
.texture_coords
, 2)
191 program
.coord
.array_enabled
= true
192 program
.coord
.array
(mesh
.vertices
, 3)
193 program
.rotation
.uniform
new Matrix.rotation
(actor
.rotation
, 0.0, 1.0, 0.0)
195 program
.normal
.array_enabled
= true
196 program
.normal
.array
(mesh
.normals
, 3)
198 if mesh
.indices
.is_empty
then
199 glDrawArrays
(gl_TRIANGLES
, 0, mesh
.vertices
.length
/3)
201 glDrawElements
(gl_TRIANGLES
, mesh
.indices
.length
, gl_UNSIGNED_SHORT
, mesh
.indices_c
.native_array
)
206 # Graphic program to display 3D models with Lamber diffuse lighting
208 super GamnitProgramFromSource
210 redef var vertex_shader_source
= """
211 // Vertex coordinates
212 attribute vec4 coord;
214 // Vertex translation
215 attribute vec4 translation;
218 attribute float scale;
220 // Vertex coordinates on textures
221 attribute vec2 tex_coord;
224 attribute vec3 normal;
226 // Model view projection matrix
229 uniform mat4 rotation;
232 uniform vec3 light_center;
234 // Coordinates of the camera
237 // Output for the fragment shader
238 varying vec2 v_tex_coord;
239 varying vec3 v_normal;
240 varying vec4 v_light_center;
241 varying vec4 v_camera;
245 // Pass varyings to the fragment shader
246 v_tex_coord = vec2(tex_coord.x, 1.0 - tex_coord.y);
247 v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
249 gl_Position = (vec4(coord.xyz * scale, 1.0) * rotation + translation) * mvp;
251 // TODO compute v_light_center and v_camera on the CPU side and pass as uniforms
252 v_light_center = vec4(light_center, 0.0) * mvp;
253 v_camera = vec4(camera, 0.0) * mvp;
255 """ @ glsl_vertex_shader
257 redef var fragment_shader_source
= """
258 precision mediump float;
260 // Input from the vertex shader
261 varying vec2 v_tex_coord;
262 varying vec3 v_normal;
263 varying vec4 v_light_center;
264 varying vec4 v_camera;
267 uniform vec4 ambient_color;
268 uniform vec4 diffuse_color;
269 uniform vec4 specular_color;
272 uniform bool use_map_ambient;
273 uniform sampler2D map_ambient;
276 uniform bool use_map_diffuse;
277 uniform sampler2D map_diffuse;
280 uniform bool use_map_specular;
281 uniform sampler2D map_specular;
284 uniform bool use_map_bump;
285 uniform sampler2D map_bump;
288 uniform bool use_map_normal;
289 uniform sampler2D map_normal;
294 vec3 light_dir = normalize(v_light_center.xyz);
295 float lambert = max(dot(light_dir, v_normal), 0.0);
298 gl_FragColor = ambient_color + texture2D(map_ambient, v_tex_coord);
300 gl_FragColor = ambient_color;
303 gl_FragColor += lambert * diffuse_color * texture2D(map_diffuse, v_tex_coord);
305 gl_FragColor += lambert * diffuse_color;
307 """ @ glsl_fragment_shader
309 # Vertices coordinates
310 var coord
= attributes
["coord"].as(AttributeVec4) is lazy
312 # Should this program use the texture `map_ambient`?
313 var use_map_ambient
= uniforms
["use_map_ambient"].as(UniformBool) is lazy
315 # Ambient texture unit
316 var map_ambient
= uniforms
["map_ambient"].as(UniformSampler2D) is lazy
318 # Should this program use the texture `map_diffuse`?
319 var use_map_diffuse
= uniforms
["use_map_diffuse"].as(UniformBool) is lazy
321 # Diffuser texture unit
322 var map_diffuse
= uniforms
["map_diffuse"].as(UniformSampler2D) is lazy
324 # Should this program use the texture `map_specular`?
325 var use_map_specular
= uniforms
["use_map_specular"].as(UniformBool) is lazy
327 # Specularity texture unit
328 var map_specular
= uniforms
["map_specular"].as(UniformSampler2D) is lazy
331 var normal
= attributes
["normal"].as(AttributeVec3) is lazy
333 # Coordinates on the textures, per vertex
334 var tex_coord
= attributes
["tex_coord"].as(AttributeVec2) is lazy
337 var ambient_color
= uniforms
["ambient_color"].as(UniformVec4) is lazy
340 var diffuse_color
= uniforms
["diffuse_color"].as(UniformVec4) is lazy
343 var specular_color
= uniforms
["specular_color"].as(UniformVec4) is lazy
345 # Center position of the light
346 var light_center
= uniforms
["light_center"].as(UniformVec3) is lazy
349 var camera
= uniforms
["camera"].as(UniformVec3) is lazy
351 # Translation applied to each vertex
352 var translation
= attributes
["translation"].as(AttributeVec4) is lazy
355 var rotation
= uniforms
["rotation"].as(UniformMat4) is lazy
358 var scale
= attributes
["scale"].as(AttributeFloat) is lazy
360 # Model view projection matrix
361 var mvp
= uniforms
["mvp"].as(UniformMat4) is lazy
364 # Program to color objects from their normal vectors
368 redef var fragment_shader_source
= """
369 precision mediump float;
371 // Input from the vertex shader
372 varying vec3 v_normal;
376 gl_FragColor = vec4(v_normal*0.5 + 0.5, 1.0);
378 """ @ glsl_fragment_shader
382 private var versatile_program
= new LambertProgram is lazy
384 private var normals_program
= new NormalProgram is lazy