шейдеры билбордов
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
class_name M2Builder
|
||||
|
||||
const WOW_M2_MATERIAL := preload("res://addons/mpq_extractor/loaders/wow_m2_material.gd")
|
||||
const MATERIAL_FORMAT_VERSION := 1
|
||||
|
||||
static var _texture_cache: Dictionary = {}
|
||||
|
||||
@@ -67,7 +68,8 @@ static func build(data: Dictionary, extracted_dir: String = "") -> Node3D:
|
||||
arrays[Mesh.ARRAY_TEX_UV2] = uvs2
|
||||
arrays[Mesh.ARRAY_INDEX] = batch_indices
|
||||
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
||||
var surface_flags := _apply_billboard_custom_data(arrays, batch, verts.size())
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays, [], {}, surface_flags)
|
||||
|
||||
var surf_idx := mesh.get_surface_count() - 1
|
||||
var mat_def: Dictionary = materials[mat_id] if mat_id >= 0 and mat_id < materials.size() else {}
|
||||
@@ -94,6 +96,8 @@ static func build(data: Dictionary, extracted_dir: String = "") -> Node3D:
|
||||
|
||||
if mesh.get_surface_count() == 0:
|
||||
return root
|
||||
mesh.set_meta("wow_m2_material_refresh_version", MATERIAL_FORMAT_VERSION)
|
||||
mesh.set_meta("wow_m2_source_path", model_path)
|
||||
|
||||
var mi := MeshInstance3D.new()
|
||||
mi.name = "Mesh"
|
||||
@@ -163,6 +167,7 @@ static func _build_material(
|
||||
combiner["vertex_shader_id"] = _m2_vertex_shader_id(texture_count, int(batch.get("shader_id", 0)))
|
||||
combiner["pixel_shader_id"] = _m2_pixel_shader_id(texture_count, int(batch.get("shader_id", 0)))
|
||||
combiner["priority_plane"] = int(batch.get("priority_plane", 0))
|
||||
combiner["billboard_enabled"] = bool(batch.get("has_billboard", false)) or int(batch.get("billboard_vertex_count", 0)) > 0
|
||||
if _is_soft_waterfall_material(model_path, blend_mode, combiner):
|
||||
combiner["effect_alpha_scale"] = 1.12
|
||||
combiner["effect_alpha_power"] = 0.92
|
||||
@@ -187,9 +192,19 @@ static func _build_material(
|
||||
mat.set_meta("wow_m2_vertex_shader_id", int(combiner.get("vertex_shader_id", 0)))
|
||||
mat.set_meta("wow_m2_pixel_shader_id", int(combiner.get("pixel_shader_id", 0)))
|
||||
mat.set_meta("wow_priority_plane", int(batch.get("priority_plane", 0)))
|
||||
mat.set_meta("wow_m2_billboard_enabled", bool(combiner.get("billboard_enabled", false)))
|
||||
mat.set_meta("wow_m2_billboard_bone_flags", int(batch.get("billboard_bone_flags", 0)))
|
||||
return mat
|
||||
|
||||
|
||||
static func _apply_billboard_custom_data(arrays: Array, batch: Dictionary, vertex_count: int) -> int:
|
||||
var billboard_data: PackedFloat32Array = batch.get("billboard_data", PackedFloat32Array())
|
||||
if billboard_data.size() != vertex_count * 4:
|
||||
return 0
|
||||
arrays[Mesh.ARRAY_CUSTOM0] = billboard_data
|
||||
return int(Mesh.ARRAY_CUSTOM_RGBA_FLOAT) << int(Mesh.ARRAY_FORMAT_CUSTOM0_SHIFT)
|
||||
|
||||
|
||||
static func _is_soft_waterfall_material(model_path: String, blend_mode: int, combiner: Dictionary) -> bool:
|
||||
if blend_mode != 2:
|
||||
return false
|
||||
|
||||
@@ -72,7 +72,8 @@ static func _build_mesh(data: Dictionary, surfaces: Array, extracted_dir: String
|
||||
arrays[Mesh.ARRAY_TEX_UV2] = uvs2
|
||||
arrays[Mesh.ARRAY_INDEX] = indices
|
||||
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
||||
var surface_flags := M2_BUILDER_SCRIPT._apply_billboard_custom_data(arrays, surface, verts.size())
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays, [], {}, surface_flags)
|
||||
var surface_index := mesh.get_surface_count() - 1
|
||||
var material_id := int(surface.get("material_id", -1))
|
||||
var texture_combo_index := int(surface.get("texture_combo_index", -1))
|
||||
|
||||
@@ -87,6 +87,7 @@ static func build(
|
||||
mat.set_shader_parameter("effect_alpha_scale", combiner.get("effect_alpha_scale", 1.0))
|
||||
mat.set_shader_parameter("effect_alpha_power", combiner.get("effect_alpha_power", 1.0))
|
||||
mat.set_shader_parameter("uv_edge_fade_strength", combiner.get("uv_edge_fade_strength", 0.0))
|
||||
mat.set_shader_parameter("billboard_enabled", bool(combiner.get("billboard_enabled", false)))
|
||||
mat.set_meta("wow_flags", material_flags)
|
||||
mat.set_meta("wow_blend_mode", blend_mode)
|
||||
mat.set_meta("wow_priority_plane", int(combiner.get("priority_plane", 0)))
|
||||
@@ -94,6 +95,7 @@ static func build(
|
||||
mat.set_meta("wow_texture2_flags", texture2_flags)
|
||||
mat.set_meta("wow_texture3_flags", texture3_flags)
|
||||
mat.set_meta("wow_texture4_flags", texture4_flags)
|
||||
mat.set_meta("wow_m2_billboard_enabled", bool(combiner.get("billboard_enabled", false)))
|
||||
return mat
|
||||
|
||||
|
||||
@@ -228,6 +230,7 @@ uniform vec2 stage3_uv_scroll = vec2(0.0);
|
||||
uniform float effect_alpha_scale = 1.0;
|
||||
uniform float effect_alpha_power = 1.0;
|
||||
uniform float uv_edge_fade_strength = 0.0;
|
||||
uniform bool billboard_enabled = false;
|
||||
|
||||
global uniform vec4 wow_ambient_color;
|
||||
global uniform vec4 wow_light_color;
|
||||
@@ -244,8 +247,58 @@ varying vec2 uv_interp;
|
||||
varying vec2 uv2_interp;
|
||||
varying float edge_fade;
|
||||
|
||||
vec3 safe_normalize(vec3 value, vec3 fallback) {
|
||||
float len = length(value);
|
||||
if (len <= 0.00001) {
|
||||
return normalize(fallback);
|
||||
}
|
||||
return value / len;
|
||||
}
|
||||
|
||||
vec3 apply_m2_billboard(vec3 vertex, vec3 normal, vec4 custom0, mat4 model_matrix, mat3 model_normal_matrix, mat4 inv_view_matrix, out vec3 billboard_world_normal) {
|
||||
billboard_world_normal = safe_normalize(model_normal_matrix * normal, normal);
|
||||
if (!billboard_enabled) {
|
||||
return vertex;
|
||||
}
|
||||
|
||||
int mode = int(custom0.w + 0.5);
|
||||
if (mode <= 0) {
|
||||
return vertex;
|
||||
}
|
||||
|
||||
vec3 pivot = custom0.xyz;
|
||||
vec3 offset = vertex - pivot;
|
||||
vec3 camera_right = safe_normalize(inv_view_matrix[0].xyz, vec3(1.0, 0.0, 0.0));
|
||||
vec3 camera_up = safe_normalize(inv_view_matrix[1].xyz, vec3(0.0, 1.0, 0.0));
|
||||
vec3 camera_back = safe_normalize(inv_view_matrix[2].xyz, vec3(0.0, 0.0, 1.0));
|
||||
vec3 world_x = camera_right;
|
||||
vec3 world_y = camera_up;
|
||||
vec3 world_z = camera_back;
|
||||
|
||||
if (mode == 2) {
|
||||
world_x = safe_normalize((model_matrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz, camera_right);
|
||||
world_y = safe_normalize(camera_up - world_x * dot(camera_up, world_x), (model_matrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz);
|
||||
world_z = safe_normalize(cross(world_x, world_y), camera_back);
|
||||
} else if (mode == 3) {
|
||||
world_z = safe_normalize((model_matrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz, camera_back);
|
||||
world_x = safe_normalize(camera_right - world_z * dot(camera_right, world_z), (model_matrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz);
|
||||
world_y = safe_normalize(cross(world_z, world_x), camera_up);
|
||||
} else if (mode == 4) {
|
||||
world_y = safe_normalize((model_matrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz, camera_up);
|
||||
world_x = safe_normalize(cross(world_y, camera_back), (model_matrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz);
|
||||
world_z = safe_normalize(cross(world_x, world_y), camera_back);
|
||||
}
|
||||
|
||||
vec3 world_pivot = (model_matrix * vec4(pivot, 1.0)).xyz;
|
||||
vec3 billboard_world_pos = world_pivot + world_x * offset.x + world_y * offset.y + world_z * offset.z;
|
||||
billboard_world_normal = world_z;
|
||||
return (inverse(model_matrix) * vec4(billboard_world_pos, 1.0)).xyz;
|
||||
}
|
||||
|
||||
void vertex() {
|
||||
world_normal = normalize(MODEL_NORMAL_MATRIX * NORMAL);
|
||||
vec3 billboard_normal;
|
||||
VERTEX = apply_m2_billboard(VERTEX, NORMAL, CUSTOM0, MODEL_MATRIX, MODEL_NORMAL_MATRIX, INV_VIEW_MATRIX, billboard_normal);
|
||||
world_normal = billboard_normal;
|
||||
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||
view_pos = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||
uv_interp = UV;
|
||||
|
||||
Reference in New Issue
Block a user