Hướng dẫn Shader trong 21w10a+/vanilla 1.17

  • Chào bạn, hãy đăng ký hoặc đăng nhập để tham gia cùng bọn mình và sử dụng được đầy đủ chức năng của diễn đàn :).

nahkd123

DEVELOPER
THÀNH VIÊN
21/1/18
580
443
450
sun
Với snapshot 21w10a, shader giờ đây có thể insert trực tiếp vào trong resource pack mà không cần cài thêm mods nhờ OpenGL 3.1.
Hướng dẫn này mình sẽ làm custom overworld skybox với vanilla shader, còn các shader khác thì tự mò trong client jar (a.k.a /.minecraft/versions/21w10a/21w10a.jar)

I. Yêu cầu trước khi làm shader
- Snapshot 21w10a (sau này sẽ là vanilla 1.17)
- Text editor (notepad, vim, emacs, vscode, etc... Có syntax coloring thì càng tốt)
- Một chút hiểu biết về OpenGL Shading Language (Hoặc có hiểu biết về common programming language syntax, VD như C++, Java, JS)
- GPU hỗ trợ OpenGL 3.1 trở lên (Intel HD Graphics support OpenGL 4.1)

II. Hệ thống vanilla shader
Vanilla shader dựa trên OpenGL 3.1 (or OpenGL Core 3.1). Vanilla shader không tích hợp với Optifine shader nên không thể dễ dàng convert từ Optifine sang vanilla (hoặc nếu convert sẽ mất nhiều thời gian).

1. Vị trí đặt shader
Toàn bộ shader được đặt tại /assets/minecraft/shaders:
29735
- core: Nơi đặt các shader chính. Ở đây custom skybox sẽ dùng mỗi thư mục core
- include: Giống như C++ "#include", nhưng trong shader phải dùng "#moj_import <abcxyz.glsl>"
- post: idk
- program: Nơi đặt các shader liên quan đến "Super Secret Settings" mà chỉ có thể enable ở 1.7. Hình như trong này có composition program

2. /shaders/core/*.json
File *.json được sử dụng khi uniform trong shader không được phiên bản mienkraft hỗ trợ:
29736
- "blend": idk
- "vertex"/"fragment": Tên shader. Nếu shader là skybox.fsh thì "fragment" sẽ là "skybox"
- "attributes": Đầu vào cho shader nếu không được phiên bản mienkraft hỗ trợ
- "samplers": Texture, nhưng mà ko rõ cách load texture từ rsp
- "uniforms": Danh sách các uniform, loại uniform, array size và failback values

3. /shaders/core/*.vsh
Vertex Shader (VSH) là shader dùng cho việc position các vertex dựa trên các thuộc tính. Dùng cái này để làm lá cây rung chuyển chẳng hạn

4. /shaders/core/*.fsh
Fragment Shader (FSH) là loại shader để hiển thị màu. VD như làm rainbow block hoặc epic skybox

III. Làm custom skybox (copy and paste edition)
B1
: Tạo resource pack (ofc)
B2: Tạo "position.json":
JSON:
{
    "blend": {
        "func": "add",
        "srcrgb": "srcalpha",
        "dstrgb": "1-srcalpha"
    },
    "vertex": "position",
    "fragment": "position",
    "attributes": [
    ],
    "samplers": [
    ],
    "uniforms": [
        { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
        { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
        { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] },
        { "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] },
        { "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] },
        { "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] },
        { "name": "ScreenSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
        { "name": "GameTime", "type": "float", "count": 1, "values": [ 0.0 ] },

        { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
        { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }
    ]
}
B3: Tạo "position.fsh"
B4: Thêm version và include fog.glsl:
Mã:
#version 150
#moj_import <fog.glsl>
- "#version 150": Phiên bản OpenGL mà shader này sử dụng
- "#moj_import <fog.glsl>": Include file "fog.glsl" (ở đây include từ file jar thay vì resource pack)

B5: Thêm các uniform cần thiết và fragment I/O:
Mã:
uniform vec4 ColorModulator;
uniform float FogStart;
uniform float FogEnd;
uniform vec4 FogColor;
uniform vec2 ScreenSize;
uniform mat4 ProjMat;
uniform mat4 ModelViewMat;
uniform float GameTime;

in float vertexDistance;
out vec4 fragColor;
- FogStart/FogEnd/FogColor: Fog thing
- ScreenSize: Kích thước màn hình game
- ProjMat: Projection matrix
- ModelViewMat: View matrix
- GameTime: Thời gian game đã chạy

B6: Thêm hàm 3d perlin noise (copy tại https://github.com/BrianSharpe/Wombat/blob/master/SimplexPerlin3D.glsl)
B7: Thêm hàm castSky:
Mã:
vec3 castSky(vec3 v) {
    // code here
}
- "vec3 v" là tham số của hàm castSky. Tham số này là hướng của player view ray lên skybox
- Hàm này phải trả về giá trị "vec3", là giá trị màu RGB dựa trên hướng của player view ray
Ở đây mình dùng hàm perlin noise ở trên để tạo ra clouds:
Mã:
    float time = GameTime * 10.0;

    v.x += time;
    float sky1 = snoise(v * 2.0) * 0.25;
    float sky2 = max(snoise(v * 10.0) * 0.15, -0.1);
    float sky3 = max(snoise(v * 50.0) * 0.03, -0.5);
    vec3 sky = vec3(max(sky1 + sky2 + sky3, 0.0));

    return sky;
B8: Thêm hàm main:
Mã:
void main() {
    vec2 pos = gl_FragCoord.xy / ScreenSize;
    pos -= vec2(0.5, 0.5);
    pos *= 2;

    vec4 cast_pos = vec4(pos, 1.0, 1.0);
    cast_pos = normalize(inverse(ProjMat) * cast_pos);
    vec3 v = normalize(cast_pos.xyz * mat3(ModelViewMat));

    if (v.y < 0) {
        fragColor = linear_fog(ColorModulator, vertexDistance, FogStart, FogEnd, FogColor);
        return;
    }

    vec4 color = linear_fog(ColorModulator, vertexDistance, FogStart, FogEnd, FogColor);
    color += vec4(castSky(v), 1.0) * 12.0 / vertexDistance;
    fragColor = color;
}
- Phần thứ nhất là để lấy relative position. Thông thường, gl_FragCoord trả về giá trị dựa trên vị trí pixel trên màn hình. Ở đây convert thành vector 2d với mỗi giá trị X và Y đi từ -1 đến 1
- Phần thứ hai là tính toán vị trí để cast ray lên skybox
- Phần thứ ba là phần check ray. Nếu ray hướng xuống thì trả về giá trị default. Nếu bỏ phần này sẽ thấy clouds ở dưới void
- Phần thứ tư trả về giá trị sau khi cast lên skybox

B9: enjoy
29737
29738

bonus: lên shadertoy xong tìm cái j ngon thì implement vào, vd như https://www.shadertoy.com/view/MlcBW7