fix(render): honor terrain base-only face flags
Docs Deploy / Build and Deploy MkDocs (push) Successful in 33s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 33s
This commit is contained in:
7 files changed
+95
-22
No files matched your search
@@ -114,7 +114,8 @@ void main() {
|
|||||||
0.0,
|
0.0,
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
vec3 base_rgb = 2.0 * base.rgb * detail.rgb;
|
bool terrain_base_only = (mode & 16) != 0;
|
||||||
|
vec3 base_rgb = terrain_base_only ? base.rgb : 2.0 * base.rgb * detail.rgb;
|
||||||
vec3 overlay_rgb = 2.0 * overlay.rgb * overlay_detail_sample.rgb;
|
vec3 overlay_rgb = 2.0 * overlay.rgb * overlay_detail_sample.rgb;
|
||||||
vec3 base_lit_rgb = base_rgb * in_base_diffuse + in_base_specular;
|
vec3 base_lit_rgb = base_rgb * in_base_diffuse + in_base_specular;
|
||||||
vec3 overlay_lit_rgb = overlay_rgb * in_overlay_diffuse + in_overlay_specular;
|
vec3 overlay_lit_rgb = overlay_rgb * in_overlay_diffuse + in_overlay_specular;
|
||||||
|
|||||||
Binary file not shown.
@@ -865,6 +865,7 @@ fn append_node_fallback_batch(
|
|||||||
lightmap_index: batch.lightmap_index,
|
lightmap_index: batch.lightmap_index,
|
||||||
batch_flags: batch.batch_flags,
|
batch_flags: batch.batch_flags,
|
||||||
pipeline_state: world_pipeline_state(),
|
pipeline_state: world_pipeline_state(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1205,20 +1206,23 @@ fn static_terrain_draw_ranges(
|
|||||||
let mut ranges = Vec::new();
|
let mut ranges = Vec::new();
|
||||||
let mut start_face = 0usize;
|
let mut start_face = 0usize;
|
||||||
while start_face < lod0.len() {
|
while start_face < lod0.len() {
|
||||||
let material_index = terrain
|
let first_face = terrain
|
||||||
.faces
|
.faces
|
||||||
.get(lod0[start_face].face_index)
|
.get(lod0[start_face].face_index)
|
||||||
.ok_or(VulkanAssetMeshError::IndexOutOfRange)?
|
.ok_or(VulkanAssetMeshError::IndexOutOfRange)?;
|
||||||
.material_tag;
|
let material_index = first_face.material_tag;
|
||||||
|
let terrain_base_only = first_face.flags.0 & 0x400 == 0;
|
||||||
let mut end_face = start_face + 1;
|
let mut end_face = start_face + 1;
|
||||||
while end_face < lod0.len()
|
while end_face < lod0.len() {
|
||||||
&& terrain
|
let next_face = terrain
|
||||||
.faces
|
.faces
|
||||||
.get(lod0[end_face].face_index)
|
.get(lod0[end_face].face_index)
|
||||||
.ok_or(VulkanAssetMeshError::IndexOutOfRange)?
|
.ok_or(VulkanAssetMeshError::IndexOutOfRange)?;
|
||||||
.material_tag
|
if next_face.material_tag != material_index
|
||||||
== material_index
|
|| (next_face.flags.0 & 0x400 == 0) != terrain_base_only
|
||||||
{
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
end_face += 1;
|
end_face += 1;
|
||||||
}
|
}
|
||||||
ranges.push(VulkanStaticDrawRange {
|
ranges.push(VulkanStaticDrawRange {
|
||||||
@@ -1234,6 +1238,7 @@ fn static_terrain_draw_ranges(
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: world_pipeline_state(),
|
pipeline_state: world_pipeline_state(),
|
||||||
|
terrain_base_only,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
});
|
});
|
||||||
start_face = end_face;
|
start_face = end_face;
|
||||||
@@ -1279,6 +1284,7 @@ fn static_model_indices_and_ranges(
|
|||||||
lightmap_index: batch.lightmap_index,
|
lightmap_index: batch.lightmap_index,
|
||||||
batch_flags: batch.batch_flags,
|
batch_flags: batch.batch_flags,
|
||||||
pipeline_state: world_pipeline_state(),
|
pipeline_state: world_pipeline_state(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1481,6 +1487,7 @@ mod tests {
|
|||||||
lightmap_index: 0,
|
lightmap_index: 0,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: world_pipeline_state(),
|
pipeline_state: world_pipeline_state(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
@@ -2002,6 +2009,7 @@ mod tests {
|
|||||||
lightmap_index: 0,
|
lightmap_index: 0,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: world_pipeline_state(),
|
pipeline_state: world_pipeline_state(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference:
|
alpha_test_reference:
|
||||||
VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
},
|
},
|
||||||
@@ -2012,6 +2020,7 @@ mod tests {
|
|||||||
lightmap_index: 0,
|
lightmap_index: 0,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: world_pipeline_state(),
|
pipeline_state: world_pipeline_state(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference:
|
alpha_test_reference:
|
||||||
VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
},
|
},
|
||||||
@@ -2168,8 +2177,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn terrain_face_with_tag(material_tag: u16, vertices: [u16; 3]) -> TerrainFace28 {
|
fn terrain_face_with_tag(material_tag: u16, vertices: [u16; 3]) -> TerrainFace28 {
|
||||||
|
terrain_face_with_tag_and_flags(material_tag, 0, vertices)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn terrain_face_with_tag_and_flags(
|
||||||
|
material_tag: u16,
|
||||||
|
flags: u32,
|
||||||
|
vertices: [u16; 3],
|
||||||
|
) -> TerrainFace28 {
|
||||||
TerrainFace28 {
|
TerrainFace28 {
|
||||||
flags: FullSurfaceMask(0),
|
flags: FullSurfaceMask(flags),
|
||||||
material_tag,
|
material_tag,
|
||||||
aux_tag: 0,
|
aux_tag: 0,
|
||||||
vertices,
|
vertices,
|
||||||
@@ -2201,7 +2218,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn terrain_ranges_preserve_face_order_and_packed_material_tags() {
|
fn terrain_ranges_merge_only_contiguous_equal_material_and_surface_mode() {
|
||||||
let mut terrain = LandMeshDocument {
|
let mut terrain = LandMeshDocument {
|
||||||
streams: Vec::new(),
|
streams: Vec::new(),
|
||||||
nodes_raw: Vec::new(),
|
nodes_raw: Vec::new(),
|
||||||
@@ -2216,27 +2233,35 @@ mod tests {
|
|||||||
aux14: Vec::new(),
|
aux14: Vec::new(),
|
||||||
aux18: Vec::new(),
|
aux18: Vec::new(),
|
||||||
faces: vec![
|
faces: vec![
|
||||||
terrain_face_with_tag(0xff01, [0, 1, 2]),
|
terrain_face_with_tag_and_flags(0xff00, 0x400, [0, 1, 2]),
|
||||||
terrain_face_with_tag(0xff01, [0, 1, 2]),
|
terrain_face_with_tag_and_flags(0xff00, 0x400, [0, 1, 2]),
|
||||||
|
terrain_face_with_tag_and_flags(0xff00, 0, [0, 1, 2]),
|
||||||
terrain_face_with_tag(0x0102, [0, 1, 2]),
|
terrain_face_with_tag(0x0102, [0, 1, 2]),
|
||||||
terrain_face_with_tag(0xff01, [0, 1, 2]),
|
terrain_face_with_tag_and_flags(0xff00, 0x400, [0, 1, 2]),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
set_terrain_lod_slots(&mut terrain, &[[0, u16::MAX]], &[[0, 4]]);
|
set_terrain_lod_slots(&mut terrain, &[[0, u16::MAX]], &[[0, 5]]);
|
||||||
|
|
||||||
let lod0 = static_terrain_lod0_assignments(&terrain).expect("terrain LOD0");
|
let lod0 = static_terrain_lod0_assignments(&terrain).expect("terrain LOD0");
|
||||||
let ranges = static_terrain_draw_ranges(&terrain, &lod0).expect("representable terrain");
|
let ranges = static_terrain_draw_ranges(&terrain, &lod0).expect("representable terrain");
|
||||||
|
|
||||||
assert_eq!(ranges.len(), 3);
|
assert_eq!(ranges.len(), 4);
|
||||||
assert_eq!(ranges[0].first_index, 0);
|
assert_eq!(ranges[0].first_index, 0);
|
||||||
assert_eq!(ranges[0].index_count, 6);
|
assert_eq!(ranges[0].index_count, 6);
|
||||||
assert_eq!(ranges[0].material_index, 0xff01);
|
assert_eq!(ranges[0].material_index, 0xff00);
|
||||||
|
assert!(!ranges[0].terrain_base_only);
|
||||||
assert_eq!(ranges[1].first_index, 6);
|
assert_eq!(ranges[1].first_index, 6);
|
||||||
assert_eq!(ranges[1].index_count, 3);
|
assert_eq!(ranges[1].index_count, 3);
|
||||||
assert_eq!(ranges[1].material_index, 0x0102);
|
assert_eq!(ranges[1].material_index, 0xff00);
|
||||||
|
assert!(ranges[1].terrain_base_only);
|
||||||
assert_eq!(ranges[2].first_index, 9);
|
assert_eq!(ranges[2].first_index, 9);
|
||||||
assert_eq!(ranges[2].index_count, 3);
|
assert_eq!(ranges[2].index_count, 3);
|
||||||
assert_eq!(ranges[2].material_index, 0xff01);
|
assert_eq!(ranges[2].material_index, 0x0102);
|
||||||
|
assert!(ranges[2].terrain_base_only);
|
||||||
|
assert_eq!(ranges[3].first_index, 12);
|
||||||
|
assert_eq!(ranges[3].index_count, 3);
|
||||||
|
assert_eq!(ranges[3].material_index, 0xff00);
|
||||||
|
assert!(!ranges[3].terrain_base_only);
|
||||||
assert!(ranges.iter().all(|range| {
|
assert!(ranges.iter().all(|range| {
|
||||||
range.alpha_test_reference == VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE
|
range.alpha_test_reference == VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1902,18 +1902,23 @@ impl VulkanSmokeRenderer {
|
|||||||
60,
|
60,
|
||||||
&material_uv_transforms,
|
&material_uv_transforms,
|
||||||
);
|
);
|
||||||
let unlit = self.material_unlit.get(texture_index).ok_or(
|
let material_mode = self.material_unlit.get(texture_index).ok_or(
|
||||||
VulkanSmokeRendererError::InvariantViolation {
|
VulkanSmokeRendererError::InvariantViolation {
|
||||||
context: "static material unlit flag",
|
context: "static material unlit flag",
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let unlit = [unlit.to_ne_bytes()];
|
let material_mode = if range.terrain_base_only {
|
||||||
|
((*material_mode).round() as i32 | 16) as f32
|
||||||
|
} else {
|
||||||
|
*material_mode
|
||||||
|
};
|
||||||
|
let material_mode = [material_mode.to_ne_bytes()];
|
||||||
device.device().cmd_push_constants(
|
device.device().cmd_push_constants(
|
||||||
command_buffer,
|
command_buffer,
|
||||||
resources.pipeline_layout,
|
resources.pipeline_layout,
|
||||||
vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
|
vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
|
||||||
124,
|
124,
|
||||||
&unlit.concat(),
|
&material_mode.concat(),
|
||||||
);
|
);
|
||||||
device.device().cmd_draw_indexed(
|
device.device().cmd_draw_indexed(
|
||||||
command_buffer,
|
command_buffer,
|
||||||
@@ -2577,6 +2582,7 @@ mod tests {
|
|||||||
lightmap_index: 4,
|
lightmap_index: 4,
|
||||||
batch_flags: 0x108,
|
batch_flags: 0x108,
|
||||||
pipeline_state: base_state,
|
pipeline_state: base_state,
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 17,
|
alpha_test_reference: 17,
|
||||||
},
|
},
|
||||||
VulkanStaticDrawRange {
|
VulkanStaticDrawRange {
|
||||||
@@ -2586,6 +2592,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -2769,6 +2776,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@@ -2792,6 +2800,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
super::super::VulkanStaticDrawRange {
|
super::super::VulkanStaticDrawRange {
|
||||||
@@ -2801,6 +2810,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
super::super::VulkanStaticDrawRange {
|
super::super::VulkanStaticDrawRange {
|
||||||
@@ -2810,6 +2820,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -2833,6 +2844,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
pipeline_state: fparkan_render::LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@@ -2861,6 +2873,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|||||||
@@ -422,6 +422,8 @@ pub struct VulkanStaticDrawRange {
|
|||||||
/// Bits `0x100` and `0x008` opt a range into that queue independently of
|
/// Bits `0x100` and `0x008` opt a range into that queue independently of
|
||||||
/// the material blend category.
|
/// the material blend category.
|
||||||
pub batch_flags: u16,
|
pub batch_flags: u16,
|
||||||
|
/// Terrain ranges that use the native lit base-only path (face flag 0x400 clear).
|
||||||
|
pub terrain_base_only: bool,
|
||||||
/// Backend-neutral fixed-function state for this source range.
|
/// Backend-neutral fixed-function state for this source range.
|
||||||
pub pipeline_state: LegacyPipelineState,
|
pub pipeline_state: LegacyPipelineState,
|
||||||
/// Alpha-test reference in legacy 0..=255 units; dynamic material data.
|
/// Alpha-test reference in legacy 0..=255 units; dynamic material data.
|
||||||
@@ -754,6 +756,7 @@ impl VulkanStaticMesh {
|
|||||||
material_index: 0,
|
material_index: 0,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
|
terrain_base_only: false,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
}],
|
}],
|
||||||
@@ -989,6 +992,7 @@ mod static_mesh_tests {
|
|||||||
material_index: 0,
|
material_index: 0,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
|
terrain_base_only: false,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
}],
|
}],
|
||||||
@@ -1019,6 +1023,7 @@ mod static_mesh_tests {
|
|||||||
material_index: 7,
|
material_index: 7,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
|
terrain_base_only: false,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
@@ -1028,6 +1033,7 @@ mod static_mesh_tests {
|
|||||||
material_index: 2,
|
material_index: 2,
|
||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
|
terrain_base_only: false,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1944,6 +1944,7 @@ fn append_environment_range(
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags: 0,
|
batch_flags: 0,
|
||||||
pipeline_state,
|
pipeline_state,
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
});
|
});
|
||||||
Ok(EnvironmentGpuRange {
|
Ok(EnvironmentGpuRange {
|
||||||
@@ -6347,6 +6348,7 @@ mod tests {
|
|||||||
LegacyBlendMode::Opaque,
|
LegacyBlendMode::Opaque,
|
||||||
LegacyDepthMode::TestReadOnly,
|
LegacyDepthMode::TestReadOnly,
|
||||||
),
|
),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
};
|
};
|
||||||
let mut mesh = VulkanStaticMesh {
|
let mut mesh = VulkanStaticMesh {
|
||||||
@@ -6405,6 +6407,7 @@ mod tests {
|
|||||||
lightmap_index: u8::MAX,
|
lightmap_index: u8::MAX,
|
||||||
batch_flags,
|
batch_flags,
|
||||||
pipeline_state: world_pipeline_state(blend, LegacyDepthMode::TestReadOnly),
|
pipeline_state: world_pipeline_state(blend, LegacyDepthMode::TestReadOnly),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: 0,
|
alpha_test_reference: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -7645,6 +7648,7 @@ mod tests {
|
|||||||
lightmap_index: 0,
|
lightmap_index: 0,
|
||||||
batch_flags,
|
batch_flags,
|
||||||
pipeline_state: LegacyPipelineState::default(),
|
pipeline_state: LegacyPipelineState::default(),
|
||||||
|
terrain_base_only: false,
|
||||||
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
alpha_test_reference: VulkanStaticDrawRange::NATIVE_DEFAULT_ALPHA_TEST_REFERENCE,
|
||||||
};
|
};
|
||||||
let mesh = VulkanStaticMesh {
|
let mesh = VulkanStaticMesh {
|
||||||
|
|||||||
@@ -430,6 +430,30 @@ full 00000040 -> compact 2000
|
|||||||
full 00200000 -> compact 8000
|
full 00200000 -> compact 8000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Бит `0x400` в маске грани рельефа управляет detail-текстурой. В `Terrain.dll`
|
||||||
|
метод `CShade` по смещению `+0x10` таблицы `0x10065108` ведёт к `0x10028A50`:
|
||||||
|
он читает `flags` по смещению `+0x3C` и проверяет бит в `0x10029191`. Ветка для
|
||||||
|
очищенного бита обнуляет указатель detail-текстуры в `0x10029427`. Затем
|
||||||
|
`Ngi32` применяет режим 1 или 7: для RGB stage 0 умножает текстуру на diffuse-
|
||||||
|
цвет, а stage 1 отключён. Alpha режима 1 берётся из texture, режима 7 — из
|
||||||
|
diffuse; на проверенных непрозрачных полосах основания это различие не меняет
|
||||||
|
цвет фрагмента. Текущий код сохраняет выбор в каждой полосе отрисовки рельефа:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let terrain_base_only = first_face.flags.0 & 0x400 == 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
Фрагментный шейдер пропускает умножение на detail-текстуру:
|
||||||
|
|
||||||
|
```glsl
|
||||||
|
bool terrain_base_only = (mode & 16) != 0;
|
||||||
|
vec3 base_rgb = terrain_base_only ? base.rgb : 2.0 * base.rgb * detail.rgb;
|
||||||
|
```
|
||||||
|
|
||||||
|
В исходных картах бит установлен у всех 275 882 граней рельефа. У полос
|
||||||
|
основания, которые создаются процедурно при загрузке миссии, бит очищен;
|
||||||
|
именно поэтому им нужен этот вариант без detail-текстуры.
|
||||||
|
|
||||||
Для шестибитного material-поля используются full-биты `0x100`, `0x8000`,
|
Для шестибитного material-поля используются full-биты `0x100`, `0x8000`,
|
||||||
`0x10000`, `0x40000`, `0x80000` и `0x80`; они переходят соответственно в
|
`0x10000`, `0x40000`, `0x80000` и `0x80`; они переходят соответственно в
|
||||||
compact-биты `1`, `2`, `4`, `8`, `0x10`, `0x20`.
|
compact-биты `1`, `2`, `4`, `8`, `0x10`, `0x20`.
|
||||||
|
|||||||
Reference in new issue
Block a user