スポンサーリンク

GLSLのフラグメントシェーダでスカラー値をサーモグラフィー的に表示

頂点に何らかの重みを割り当て、サーモグラフィー的に表示したい。三角形一枚の色はデフォルトでは各頂点の線形補間になってしまうので、フラグメントシェーダで重みを色に変換する関数を通して着色する。なおこのコードは以前作ったRust+OpenGLで三角形を表示するコードのdraw.rsを書き換えている。

draw.rs

use std::ptr::null;
use std::ffi::CString;
use std::ffi::CStr;

pub fn draw_prepare() ->(gl::types::GLuint, gl::types::GLuint){

    // 頂点の定義
    let vertices: [f32;9]=[
        0.0,  0.5, 0.0, // 上頂点
        -0.5, -0.5, 0.0, // 左下
        0.5, -0.5, 0.0, // 右下
    ];

    // スカラー値
    let scalar:[f32;3]=[
        1.0,
        0.3,
        0.0,
    ];

    let mut vertexbuffer=0;
    unsafe{
        gl::GenBuffers(1,&mut vertexbuffer);
        gl::BindBuffer(gl::ARRAY_BUFFER,vertexbuffer);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            3*3*std::mem::size_of::<gl::types::GLfloat>() as gl::types::GLsizeiptr,
            vertices.as_ptr() as *const _,
            gl::STATIC_DRAW
        );
    }
    let mut scalarbuffer=0;
    unsafe{
        gl::GenBuffers(1,&mut scalarbuffer);
        gl::BindBuffer(gl::ARRAY_BUFFER,scalarbuffer);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            3*std::mem::size_of::<gl::types::GLfloat>() as gl::types::GLsizeiptr,
            scalar.as_ptr() as *const _,
            gl::STATIC_DRAW
        );
    }

    (vertexbuffer,scalarbuffer)
}

pub fn prepare_vertex_shader()->gl::types::GLuint{
    let mut VertexShaderID = 0;

    // 頂点シェーダプログラム
    let vertex_shader_source = "\
#version 460 core

layout (location = 0) in vec3 aPos;

// layout (location = 1) in vec3 incolor;
layout (location = 1) in float scalar; // out vec4 vertexColor; out float fragscalar; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0);
// vertexColor = vec4(incolor, 1.0); fragscalar = scalar; }
"; let c_src = CString::new(vertex_shader_source).unwrap(); let mut Result:gl::types::GLint = 0; let mut InfoLogLength:i32 = 0; let mut info_log; unsafe{ VertexShaderID = gl::CreateShader(gl::VERTEX_SHADER); gl::ShaderSource( VertexShaderID, 1, &c_src.as_ptr(), std::ptr::null() ); gl::CompileShader(VertexShaderID); // シェーダのチェック gl::GetShaderiv(VertexShaderID,gl::COMPILE_STATUS,&mut Result); gl::GetShaderiv(VertexShaderID,gl::INFO_LOG_LENGTH,&mut InfoLogLength); if InfoLogLength > 0 { info_log = vec![0u8; InfoLogLength as usize]; if Result == gl::FALSE as i32 { gl::GetShaderInfoLog( VertexShaderID, InfoLogLength, std::ptr::null_mut(), info_log.as_mut_ptr() as *mut gl::types::GLchar ); if let Ok(msg) = CStr::from_ptr(info_log.as_ptr() as *const i8).to_str() { println!("Vertex Shader Error :\n {}\n", msg); } } } } VertexShaderID }

pub fn prepare_fragment_shader()->gl::types::GLuint{
    let mut FragmentShaderID=0;

    let fragment_shader_source = "\
#version 460 core

out vec4 FragColor;

// in vec4 vertexColor;
in float fragscalar;


// スカラーをサーモグラフィーのRGBに変換
vec3 scalarToThermalColor(float scalar)
{
    // 0.0〜1.0の範囲に制限
    scalar = clamp(scalar, 0.0, 1.0);

    // サーモグラフィーカラーの計算
    vec3 color;
    if (scalar < 0.25) {
        color = vec3(0.0, 4.0 * scalar, 1.0);               // 青 → シアン
    } else if (scalar < 0.5) {
        color = vec3(0.0, 1.0, 1.0 - 4.0 * (scalar - 0.25)); // シアン → 緑
    } else if (scalar < 0.75) {
        color = vec3(4.0 * (scalar - 0.5), 1.0, 0.0);       // 緑 → 黄
    } else {
        color = vec3(1.0, 1.0 - 4.0 * (scalar - 0.75), 0.0); // 黄 → 赤
    }

    return color;
}


void main()
{
   // FragColor = vertexColor;
   FragColor = vec4(scalarToThermalColor(fragscalar), 1.0);  // 出力
}
";
    let c_str = CString::new(fragment_shader_source).unwrap();
    let mut Result:gl::types::GLint=0;
    let mut InfoLogLength:i32=0;
    let mut info_log;
    unsafe {
        FragmentShaderID = gl::CreateShader(gl::FRAGMENT_SHADER);
        gl::ShaderSource(
            FragmentShaderID,
            1,
            &c_str.as_ptr(), null()
        );
        gl::CompileShader(FragmentShaderID);

        // フラグメントシェーダ
        gl::GetShaderiv(FragmentShaderID, gl::COMPILE_STATUS, &mut Result);
        gl::GetShaderiv(FragmentShaderID, gl::INFO_LOG_LENGTH, &mut InfoLogLength);
        if InfoLogLength > 0 {
            if Result == gl::FALSE as i32 {
                info_log = vec![0u8; InfoLogLength as usize];
                gl::GetShaderInfoLog(
                    FragmentShaderID,
                    InfoLogLength,
                    std::ptr::null_mut(),
                    info_log.as_mut_ptr() as *mut gl::types::GLchar
                );
                if let Ok(msg) = CStr::from_ptr(info_log.as_ptr() as *const i8).to_str() {
                    println!("Fragment Shader Error :\n{}\n", msg);
                }
            }
        }
    }

    FragmentShaderID

}

pub fn link_program(VertexShaderID:gl::types::GLuint,FragmentShaderID:gl::types::GLuint)->gl::types::GLuint{
    let mut Result:gl::types::GLint = gl::FALSE as i32;
    let mut InfoLogLength:i32=0;
    let mut ProgramID:gl::types::GLuint=0;

    println!("Linking program");

    unsafe{
        ProgramID = gl::CreateProgram();

        gl::AttachShader(ProgramID,VertexShaderID);
        gl::AttachShader(ProgramID,FragmentShaderID);
        gl::LinkProgram(ProgramID);

        gl::GetProgramiv(ProgramID,gl::LINK_STATUS,&mut Result);
        gl::GetProgramiv(ProgramID,gl::INFO_LOG_LENGTH,&mut InfoLogLength);

        if InfoLogLength > 0 {
            let mut ProgramErrorMessage = vec![0u8; InfoLogLength as usize];

            gl::GetProgramInfoLog(
                ProgramID,
                InfoLogLength,
                std::ptr::null_mut(),
                ProgramErrorMessage.as_mut_ptr() as *mut gl::types::GLchar
            );

            if let Ok(msg) = CStr::from_ptr(ProgramErrorMessage.as_ptr() as *const i8).to_str() {
                println!("Program Link Error:\n{}\n",msg);
            }
        }
    }

    ProgramID

}


pub fn draw_triangle(programid:gl::types::GLuint,vertexbuffer: gl::types::GLuint,scalarbuffer:gl::types::GLuint){

    unsafe {
        gl::UseProgram(programid);
    }

    let proj_mat:[f32;16]=[
        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,
    ];

    let model_mat:[f32;16]=[
        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,
    ];

    let proj;
    let model;
    unsafe {
        let proj_location_name = CString::new("projectionMatrix").unwrap();
        let model_location_name = CString::new("modelViewMatrix").unwrap();
        proj = gl::GetUniformLocation(programid,proj_location_name.as_ptr());
        model = gl::GetUniformLocation(programid,model_location_name.as_ptr());

        gl::UniformMatrix4fv(proj,1,gl::FALSE,proj_mat.as_ptr());
        gl::UniformMatrix4fv(model,1,gl::FALSE,model_mat.as_ptr());
    }
    /*
        // デバッグ
        println!("proj location: {}",proj);
        println!("model location: {}",model);
    */

    unsafe{
        gl::EnableVertexAttribArray(0);
        gl::BindBuffer(gl::ARRAY_BUFFER,vertexbuffer);
        gl::VertexAttribPointer(
            0,
            3,
            gl::FLOAT,
            gl::FALSE,
            0,
            null()
        );
    }

    unsafe{
        gl::EnableVertexAttribArray(1);
        gl::BindBuffer(gl::ARRAY_BUFFER,scalarbuffer);
        gl::VertexAttribPointer(
            1,
            1, // 一次元配列
            gl::FLOAT,
            gl::FALSE,
            0,
            null()
        );
    }

    unsafe {
        gl::DrawArrays(gl::TRIANGLES, 0,3);

        let err_check = gl::GetError();
        if err_check != gl::NO_ERROR {
            println!("ERROR::: {}\n", err_check);
        }

        gl::DisableVertexAttribArray(0);
        gl::DisableVertexAttribArray(1);
    }

    unsafe {
        gl::UseProgram(0);
    }

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: