Skip to content

Commit b1e15fe

Browse files
birhburhnot-fl3
authored andcommitted
Added custom material example for metal and documented load_material
1 parent d0b5866 commit b1e15fe

File tree

2 files changed

+186
-7
lines changed

2 files changed

+186
-7
lines changed

examples/custom_material.rs

Lines changed: 127 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,54 @@ void main() {
2626
gl_FragColor = test_color * texture2D(Texture, uv);
2727
}"#;
2828

29+
pub const METAL: &str = r#"
30+
#include <metal_stdlib>
31+
using namespace metal;
32+
33+
struct Vertex
34+
{
35+
float3 position [[attribute(0)]];
36+
float2 texcoord [[attribute(1)]];
37+
float4 color0 [[attribute(2)]];
38+
};
39+
40+
struct RasterizerData
41+
{
42+
float4 position [[position]];
43+
float4 color [[user(locn0)]];
44+
float2 uv [[user(locn1)]];
45+
};
46+
47+
// Uniforms should have Model, Projection, _Time in exact order for shader to work,
48+
// because they are laying in a single buffer
49+
struct Uniforms
50+
{
51+
float4x4 Model;
52+
float4x4 Projection;
53+
float4 _Time;
54+
55+
float4 test_color;
56+
};
57+
58+
vertex RasterizerData vertexShader(Vertex v [[stage_in]],
59+
constant Uniforms& u [[buffer(0)]])
60+
{
61+
RasterizerData out;
62+
63+
out.position = u.Projection * u.Model * float4(v.position, 1);
64+
out.uv = v.texcoord;
65+
66+
return out;
67+
}
68+
69+
fragment float4 fragmentShader(RasterizerData in [[stage_in]],
70+
constant Uniforms& u [[buffer(0)]],
71+
texture2d<float> Texture [[texture(0)]],
72+
sampler TextureSmplr [[sampler(0)]])
73+
{
74+
return u.test_color * Texture.sample(TextureSmplr, in.uv);
75+
}"#;
76+
2977
const FRAGMENT_WITH_ARRAY: &str = r#"#version 100
3078
varying lowp vec2 uv;
3179
@@ -36,7 +84,70 @@ void main() {
3684
gl_FragColor = test_color[5] * texture2D(Texture, uv);
3785
}"#;
3886

39-
#[macroquad::main("Shaders")]
87+
pub const METAL_WITH_ARRAY: &str = r#"#include <metal_stdlib>
88+
using namespace metal;
89+
90+
struct Vertex
91+
{
92+
float3 position [[attribute(0)]];
93+
float2 texcoord [[attribute(1)]];
94+
float4 color0 [[attribute(2)]];
95+
};
96+
97+
struct RasterizerData
98+
{
99+
float4 position [[position]];
100+
float4 color [[user(locn0)]];
101+
float2 uv [[user(locn1)]];
102+
};
103+
104+
// Uniforms should have Model, Projection, _Time for material shaders to work
105+
struct Uniforms
106+
{
107+
float4x4 Model;
108+
float4x4 Projection;
109+
float4 _Time;
110+
111+
float4 test_color[10];
112+
};
113+
114+
vertex RasterizerData vertexShader(Vertex v [[stage_in]],
115+
constant Uniforms& u [[buffer(0)]])
116+
{
117+
RasterizerData out;
118+
119+
out.position = u.Projection * u.Model * float4(v.position, 1);
120+
out.uv = v.texcoord;
121+
122+
return out;
123+
}
124+
125+
fragment float4 fragmentShader(RasterizerData in [[stage_in]],
126+
constant Uniforms& u [[buffer(0)]],
127+
texture2d<float> Texture [[texture(0)]],
128+
sampler TextureSmplr [[sampler(0)]])
129+
{
130+
return u.test_color[5] * Texture.sample(TextureSmplr, in.uv);
131+
}"#;
132+
133+
fn window_conf() -> Conf {
134+
let metal = std::env::args().nth(1).as_deref() == Some("metal");
135+
let apple_gfx_api = if metal {
136+
conf::AppleGfxApi::Metal
137+
} else {
138+
conf::AppleGfxApi::OpenGl
139+
};
140+
Conf {
141+
window_title: "Shaders".to_owned(),
142+
platform: conf::Platform {
143+
apple_gfx_api,
144+
..Default::default()
145+
},
146+
..Default::default()
147+
}
148+
}
149+
150+
#[macroquad::main(window_conf)]
40151
async fn main() {
41152
let pipeline_params = PipelineParams {
42153
color_blend: Some(BlendState::new(
@@ -47,10 +158,14 @@ async fn main() {
47158
..Default::default()
48159
};
49160

161+
let ctx = unsafe { get_internal_gl().quad_context };
50162
let mat = load_material(
51-
ShaderSource::Glsl {
52-
vertex: VERTEX,
53-
fragment: FRAGMENT,
163+
match ctx.info().backend {
164+
Backend::OpenGl => ShaderSource::Glsl {
165+
vertex: VERTEX,
166+
fragment: FRAGMENT,
167+
},
168+
Backend::Metal => ShaderSource::Msl { program: METAL },
54169
},
55170
MaterialParams {
56171
uniforms: vec![UniformDesc::new("test_color", UniformType::Float4)],
@@ -61,9 +176,14 @@ async fn main() {
61176
.unwrap();
62177

63178
let mat_with_array = load_material(
64-
ShaderSource::Glsl {
65-
vertex: VERTEX,
66-
fragment: FRAGMENT_WITH_ARRAY,
179+
match ctx.info().backend {
180+
Backend::OpenGl => ShaderSource::Glsl {
181+
vertex: VERTEX,
182+
fragment: FRAGMENT_WITH_ARRAY,
183+
},
184+
Backend::Metal => ShaderSource::Msl {
185+
program: METAL_WITH_ARRAY,
186+
},
67187
},
68188
MaterialParams {
69189
uniforms: vec![UniformDesc::array(

src/material.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,65 @@ pub struct MaterialParams {
6060
pub textures: Vec<String>,
6161
}
6262

63+
/// Creates custom material
64+
///
65+
/// For OpenGL and Metal examples check examples/custom_material.rs.
66+
///
67+
/// # Default variables for OpenGL backend:
68+
/// ## Attributes (order doesn't matter, any could be skipped):
69+
/// ```glsl
70+
/// attribute vec3 position;
71+
/// attribute vec4 color0;
72+
/// attribute vec2 texcoord;
73+
/// ```
74+
/// ## Uniforms (order doesn't matter, any could be skipped):
75+
/// ```glsl
76+
/// uniform mat4 Model;
77+
/// uniform mat4 Projection;
78+
/// uniform float4 _Time;
79+
/// ```
80+
/// ## Textures (order doesn't matter, any could be skipped):
81+
/// ```glsl
82+
/// uniform sampler2D Texture;
83+
/// uniform sampler2D _ScreenTexture; // check examples/screen_texture.rs to see how it works
84+
/// ```
85+
///
86+
/// # Default variables for Metal backend:
87+
/// ## Attributes (order doesn't matter, any could be skipped, should have exact index in attribute()):
88+
/// ```msl
89+
/// struct Vertex
90+
/// {
91+
/// float3 position [[attribute(0)]];
92+
/// float2 texcoord [[attribute(1)]];
93+
/// float4 color0 [[attribute(2)]];
94+
/// };
95+
/// ```
96+
/// ## Uniforms (**order matters, all fields before needed one should present**):
97+
/// **All uniforms are in the same buffer, so order matters also for custom additional uniforms**
98+
/// ```msl
99+
/// struct Uniforms
100+
/// {
101+
/// float4x4 Model;
102+
/// float4x4 Projection;
103+
/// float4 _Time;
104+
/// ...
105+
/// additional uniforms
106+
/// };
107+
/// // same for vertexShader
108+
/// // Only buffer(0) is correct here
109+
/// fragment float4 fragmentShader(..., constant Uniforms& u [[buffer(0)]], ...) {...}
110+
/// ```
111+
/// ## Textures (order doesn't matter, any could be skipped, should have exact indices in `texture()` and `sampler()`):
112+
/// ```msl
113+
/// // same for vertexShader
114+
/// fragment float4 fragmentShader(...,
115+
/// texture2d<float> Texture [[texture(0)]],
116+
/// sampler TextureSmplr [[sampler(0)]],
117+
/// _ScreenTexture is not working for metal for now
118+
/// ...
119+
/// ) {...}
120+
/// ```
121+
///
63122
pub fn load_material(
64123
shader: crate::ShaderSource,
65124
params: MaterialParams,

0 commit comments

Comments
 (0)