2024年11月

前段时间给 StarRocks 的物化视图新增了一个
特性
,那也是我第一次接触 StarRocks,因为完全不熟悉这个数据库,所以很多东西都是从头开始了解概念。

为了能顺利的新增这个特性(具体内容可以见后文),我需要把整个物化视图的流程串联一遍,于是便有了这篇文章。

在开始之前简单了解下物化视图的基本概念:

image.png

简单来说,视图和 MySQL 这类传统数据库的概念类似,也是用于解决大量消耗性能的 SQL 的,可以提前将这些数据查询好然后放在一张单独的表中,这样再查询的时候性能消耗就比较低了。

刷新条件

为了保证视图数据的实时性,还需要在数据发生变化的时候能够及时刷新视图里的数据,目前有这几个地方会触发视图刷新:
image.png

  • 手动刷新视图,使用
    REFRESH MATERIALIZED VIEW order_mv;
    语句
  • 将视图设置为 active 状态:
    ALTER MATERIALIZED VIEW order_mv ACTIVE;
  • 基表数据发生变化时触发刷新。
    • image.png
  • truncate 基表时触发刷新:
    truncate table trunc_db.t1;
  • drop partition 时触发:
    ALTER TABLE <tbl_name> DROP PARTITION(S) p0, p1 [, ...];

这里的 truncate table 和 drop partition 目前的版本还存在 bug:当基表和物化视图不在一个数据库时不会触发自动刷新,目前已经修复了。

image.png

刷新流程

image.png

如图所示,当触发一次刷新之后主要就是需要计算出需要刷新的分区。

第一次触发刷新的时候是不会带上周期(比如时间范围),然后根据过滤计算出来的周期,默认情况下只会使用第一个周期(我们可以通过
partition_refresh_number
参数来调整单次刷新的分区数量)。

然后如果还有其余的周期,会将这些周期重新触发一次刷新任务(会带上刚才剩余的周期数据),这样进行递归执行。

通过日志会看到返回的分区数据。

新增优化参数

我们在使用物化视图的时候,碰到一个场景:

CREATE TABLE IF NOT EXISTS test.par_tbl1
(
    datekey DATETIME,
    k1      INT,
    item_id STRING,
    v2      INT
)PRIMARY KEY (`datekey`,`k1`)
 PARTITION BY date_trunc('day', `datekey`);

 CREATE TABLE IF NOT EXISTS test.par_tbl2
(
    datekey DATETIME,
    k1      INT,
    item_id STRING,
    v2      INT
)PRIMARY KEY (`datekey`,`k1`)
 PARTITION BY date_trunc('day', `datekey`);

 CREATE TABLE IF NOT EXISTS test.par_tbl3
(
    datekey DATETIME,
    k1      INT,
    item_id STRING,
    v2      INT
)
 PRIMARY KEY (`datekey`,`k1`);

但我们有三张基表,其中 1 和 2 都是分区表,但是 3 是非分区表。

此时基于他们新建了一个物化视图:

CREATE
MATERIALIZED VIEW test.mv_test
REFRESH ASYNC
PARTITION BY a_time
PROPERTIES (
"excluded_trigger_tables" = "par_tbl3"
)
AS
select date_trunc("day", a.datekey) as a_time, date_trunc("day", b.datekey) as b_time,date_trunc("day", c.datekey) as c_time
from test.par_tbl1 a
         left join test.par_tbl2 b on a.datekey = b.datekey and a.k1 = b.k1
         left join test.par_tbl3 c on a.k1 = c.k1;

当我同时更新了分区表和非分区表的数据时:

UPDATE `par_tbl1` SET `v2` = 2 WHERE `datekey` = '2024-08-05 01:00:00' AND `k1` = 3;
UPDATE `par_tbl3` SET `item_id` = '3' WHERE `datekey` = '2024-10-01 01:00:00' AND `k1` = 3;

预期的结果是只有
par_tbl1
表里修改的数据会被同步到视图(
"excluded_trigger_tables" = "par_tbl3"
已经被设置为不会触发视图刷新),但实际情况是
par_tbl1

par_tbl2
表里所有的数据都会被刷新到物化视图中。

我们可以使用这个 SQL 查询无刷视图任务的运行状态:

SELECT * FROM information_schema.task_runs order by create_time desc;

这样就会造成资源损耗,如果这两张基表的数据非常大,本次刷新会非常耗时。

所以我们的需求是在这样的场景下也只刷新修改的数据。

因此我们在新建物化视图的时候新增了一个参数:

CREATE
MATERIALIZED VIEW test.mv_test
REFRESH ASYNC
PARTITION BY a_time
PROPERTIES (
"excluded_trigger_tables" = "par_tbl3",
"excluded_refresh_tables"="par_tbl3"
)
AS
select date_trunc("day", a.datekey) as a_time, date_trunc("day", b.datekey) as b_time,date_trunc("day", c.datekey) as c_time
from test.par_tbl1 a
         left join test.par_tbl2 b on a.datekey = b.datekey and a.k1 = b.k1
         left join test.par_tbl3 c on a.k1 = c.k1;

这样当在刷新数据的时候,会判断
excluded_refresh_tables
配置的表是否有发生数据变化,如果有的话则不能将当前计算出来的分区(1,2 两张表的全量数据)全部刷新,而是继续求一个交集,只计算基表发生变化的数据。

这样就可以避免 par_tbl1、par_tbl2 的数据全量刷新,而只刷新修改的数据。

这样的场景通常是在关联的基表中有一张字典表,通常数据量不大,所以也不需要分区的场景。

这样在创建物化视图的时候就可以使用这两个参数
excluded_trigger_tables,excluded_refresh_tables
将它排除掉了。

整体的刷新逻辑并不复杂,主要就是几个不同的刷新入口以及刷新过程中计算分区的逻辑。

参考链接:

编译构建工具DevEco Hvigor(以下简称Hvigor)是一款基于TS实现的构建任务编排工具,主要提供任务管理机制,包括任务注册编排、工程模型管理、配置管理等关键能力,提供专用于构建和测试应用的流程和可配置设置。

DevEco Studio使用构建工具Hvigor来自动执行和管理构建流程,实现应用/服务构建任务流的执行,完成HAP/APP的构建打包。

Hvigor可独立于DevEco Studio运行,这意味着,你可以在DevEco Studio内、命令行工具或是集成服务器上构建应用。无论您从命令行工具或是DevEco Studio上构建项目,构建过程的输出都将相同。

了解任务

任务是Hvigor构建过程中的执行基本单元,任务中通常包含一段编译过程处理的可执行代码;一个任务可以依赖其他多个任务。Hvigor任务调度执行时通过解析依赖关系确定任务执行时序。

UP-TO-DATE

任务标识,表示任务未实际执行。Hvigor任务增量跳过机制,在二次执行任务时检测任务输入输出条件未发生变化,则任务跳过执行提高构建效率。例如

hvigor UP-TO-DATE ::PackageApp...

Finished

任务执行完成标识,表示任务已执行完成。例如

hvigor Finished ::PackageApp... after 310 ms

注册任务

使用HvigorNode节点对象注册任务。

  1. 编辑工程下hvigorfile.ts文件。
// 导入模块
import { getNode, HvigorNode, HvigorTask } from '@ohos/hvigor';
  1. 编写任务代码。
// 获取当前hvigorNode节点对象
const node: HvigorNode = getNode(__filename);

// 注册Task
node.registerTask({
    name: 'customTask',
    run() {
        console.log('this is Task');
    }
});
  1. 执行任务。
    使用hvigor命令行工具执行任务。例如

hvigorw customTask

  1. 查看任务执行结果。
PS D:\SDAutoTestRunInfo\AppDemo\MyApplication > hvigorw customTask
this is Task
> hvigor Finished :: customTask... after 2 ms
> hvigor BUILD SUCCESSFUL in 2 s 211 ms

一、问题

假设存在这样的时钟控制模型:

CLK1、CLK2以及系统时钟的频率与相位均不一致,我们希望在clk_sel=1时,输出CLK1,反之输出CLK2,CLK_SEL可以由系统时钟驱动,也可以由组合逻辑驱动。那么在这种情况下就会出现以下的“毛刺”问题:

可以看到,在CLK_SEL的交界处,非常容易出现CLK_OUT时钟出现毛刺的现象,从而影响系统的正常工作。

二、解决方法

(以下方法出自B站UP:皮特派)

具体思路是:1.两个时钟互斥输出,即B4、B5两个非门作为最后的A2、A4的输入;

2.S3、S6寄存器采用下降沿驱动对sel进行同步,这样就可以在延迟一拍的情况下做到两个时钟无毛刺的输出。

分析如下:当sel为0时,ali_2初始值为0,ali_1为1,A1选通,随后在CLKA的驱动下对alo信号打两拍同步,随后S3在CLKA的下降沿对打拍同步的信号进行采样,这样在下降沿到后一个上升沿之前,由于CLKA为0,CLK-OUT始终拉低,而后CLKA为高,此时由于上个下降沿已经对ai2_2进行了同步,CLKA为1,且ai2_2为1,此时CLK_OUT输出为CLKA。
本质上是用延迟换准确性。

三、代码

根据上述的RTL,代码如下:

  1. RTL

// // =============================================================================
// File Name    : clk_gating_module.v
// Module       : clk_gating_module
// Function     : Burr free clock switching
// Type         : RTL
// Aythor       : Dongyang
// -----------------------------------------------------------------------------
// Update History :
// -----------------------------------------------------------------------------
`timescale 1 ns/1 ns
module  clk_gating_module(
        input            sys_clk    ,
        input            sys_rst_n  ,
  
        input            i_clka     ,
        input            i_clkb     ,
        input            i_clk_sel  ,
        output           o_clk_out  

);

//******************** siganl define ********************
wire         a1i_1        ;
wire         a1i_2        ;
wire         a3i_1        ;
wire         a1o          ;
wire         a3o          ;
wire         a3i_2        ;
wire         a2o          ;
wire         a4o          ;
reg          a4i_2    =  'b0;
reg          a2i_2    =  'b0;
reg  [1:0]   a1o_dly  =  'b0;
reg  [1:0]   a3o_dly  =  'b0;  

//******************** assign  *****************************
assign   a1i_1 =   ~i_clk_sel         ;
assign   a3i_1 =    i_clk_sel         ;
assign   a1i_2 =    ~a4i_2         ;
assign   a3i_2 =    ~a2i_2         ;
assign   a1o   =   a1i_1 & a1i_2 ;
assign   a3o   =   a3i_2 & a3i_1;
assign   a2o   =   i_clka & a2i_2;
assign   a4o   =   a4i_2 & i_clkb;
assign   o_clk_out = a2o | a4o   ;

//**********************always*********************************
// CLKA domain
always @(posedge i_clka) begin
    if(~sys_rst_n) begin
        a1o_dly <= 'b0;
    end
    else begin
        a1o_dly<= {a1o_dly[0],a1o};
    end
end

always @(negedge i_clka) begin
    if(~sys_rst_n) begin
        a2i_2 <= 'b0;
    end
    else  begin
        a2i_2 <= a1o_dly[1];
    end
end

//CLK B domain
always @(posedge i_clkb) begin
    if(~sys_rst_n) begin
        a3o_dly <= 'b0;
    end
    else begin
        a3o_dly<= {a3o_dly[0],a3o};
    end
end

always @(negedge i_clkb) begin
    if(~sys_rst_n) begin
        a4i_2 <= 'b0;
    end
    else  begin
        a4i_2 <= a3o_dly[1];
    end
end

endmodule
  1. TestBench

`timescale 1 ns/1 ns
module  tb_clk_gatting();

reg    clka   = 'b0;
reg    clkb   = 'b0;
reg    sys_clk = 'b0;
reg    sys_rst_n = 'b0;
reg    clk_sel  = 'b0 ;

initial begin
clka   = 'b0;
clkb   = 'b0;
sys_clk = 'b0;
sys_rst_n = 'b0;
clk_sel  = 'b0 ;
#6
clkb   = 'b1;
#100
sys_rst_n = 'b1;
#1000
clk_sel  = 1'b1;
#756
clk_sel  = 1'b1;
#1500
clk_sel  = 1'b0;
end

always  # 10   sys_clk = ~sys_clk;    //sys_clk     50M
always  # 50   clka    = ~clka   ;    // CLKA       10M
always  # 30   clkb    = ~clkb   ;     // CLKB     16.6M
clk_gating_module  U_clk_gating_module(
        .sys_clk    (sys_clk),
        .sys_rst_n  (sys_rst_n),
        .i_clka     (clka),
        .i_clkb     (clkb), 
        .i_clk_sel  (clk_sel), 
        .o_clk_out  ()

);

endmodule

四、仿真波形

前言

推荐一款集成了超过100款控件的流行 XAML 控件库,同时提供了一系列常用的 .NET 帮助类-CookPopularUI。它可以简化开发流程,让我们能够更加专注于核心业务逻辑的实现。

让我们一起学习如何使用 CookPopularUI,并详细了解其提供的丰富控件内容。

项目介绍

CookPopularUI
不仅提供了丰富的控件选择,包括但不限于数据网格、图表、导航菜单、对话框等,还特别注重于提升开发效率。通过内置的帮助类,可以轻松处理诸如数据绑定、异步操作、文件操作等常见任务,而无需从头开始编写大量代码。

另外,该控件库对多个版本的 .NET 提供了良好的支持,无论是 .NET Framework 还是 .NET Core/.NET 5+,都能确保应用的兼容性和稳定性。

项目特点

  • 丰富的控件库:CookPopularUI 包含了多种类型的控件,如数据网格、图表、导航菜单、对话框等,满足不同应用场景的需求。
  • 常用 .NET 帮助类:内置了大量 .NET 帮助类,简化了数据绑定、异步操作、文件处理等常见开发任务。
  • 高度可定制化:所有控件都支持高度自定义,您可以根据自己的需求调整样式和行为。
  • 良好的文档和示例:提供了详细的文档和丰富的示例代码,帮助您快速上手并高效开发。
  • 多版本支持:支持多个版本的 .NET,无论是 .NET Framework 还是 .NET Core/.NET 5+,都能确保兼容性和稳定性。

项目使用

1、添加Nuget包引用

<PackageReferenceInclude="CookPopularUI.WPF"Version="1.0.1-preview2" />

2、添加如下代码即可全部引用(两种方式皆可)

<Application.Resources>
    <ResourceDictionary>
          <ResourceDictionary.MergedDictionaries>
              <!--<ResourceDictionary Source="pack://application:,,,/CookPopularUI.WPF;component/Themes/DefaultPopularColor.xaml" />-->
              <!--<ResourceDictionary Source="pack://application:,,,/CookPopularUI.WPF;component/Themes/DefaultPopularControl.xaml" />-->
              <ui:PopularThemeLanguage="English"Theme="Light" />
          </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

项目控件

1、Border

2、DataGrid

3、Message

项目地址

Gitee:
https://gitee.com/CookCSharp/CookPopularUI

总结

本文展示了部分功能和内容,如有需求访问案例地址获取详细信息。希望本文能在WPF控件开发方面为各位提供有益的帮助。期待大家在评论区留言交流,分享您的宝贵经验和建议。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号
[DotNet技术匠]
社区,与其他热爱技术的同行一起交流心得,共同成长!

前言

深入理解相机视口,摸索相机视口旋转功能,背景透明或者不透明。
本篇,实现了一个左下角旋转HUD且背景透明的相机视口。


Demo

请添加图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


HUD相机的坐标

抬头HUD就是通过投影矩阵来实现,具体可参看《OSG开发笔记(二十):OSG使用HUD显示文字》

  • Hud要单独创建一个新相机
  • 注意关闭光照,不受光照影响,所以内容以同一亮度显示
  • 关闭深度测试
  • 渲染顺序设置为POST,否则可能会被场景中的其他图形所覆盖。
  • 设置参考贴为绝对型:setReferenceFrame(osg::Transform:ABSOLUTE_RF)
  • 使其不受父节点变换的影响:setMatrix(osg::Matrix::identity())
  • 投影矩阵通常会设置为屏幕尺寸大小


相机(Camera)

相机(osg::Camera)和视口(Viewport)是两个核心概念,对于理解OSG中的三维场景渲染至关重要。
相机在OSG中用于模拟真实世界中的摄影机,它负责捕捉和渲染三维场景。相机类(osg::Camera)继承自osg::Transform和osg::CullSetting类,用来管理OSG中的模型——视图矩阵。相机的管理主要是通过各种变换实现的,这些变换包括:

  • 视点变换:设置视点的方向和位置。默认情况下,视点定位为坐标原点,指向Y正方向。可以通过调整视点的位置和参考点的位置来改变相机的观察方向和角度。
  • 投影变换:由于显示器只能用二维图像显示三维物体,因此要靠投影来降低维数。投影变换的目的是定义一个视景体,使视景体外多余的部分被裁减掉,最终进入图像的只是视景体内的有关部分。OSG支持两种投影方式:透视投影(Perspective Projection)和正视投影(Orthographic Projection)。透视投影能够模拟人眼的视觉效果,使远处的物体看起来更小,而正视投影则保持物体的大小不变,不受距离影响。
  • 视口变换:将视景体内投影的物体显示在二维的视口平面上。即将经过几何变换、投影变换和裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形,称为视口。


视口(ViewPort)

具体来说,视口变换涉及以下几个参数:

  • 屏幕左下角的坐标:定义了视口在屏幕上的左下角位置。
  • 屏幕宽度和高度:定义了视口的宽度和高度,即相机捕捉的场景在屏幕上显示的区域大小。
    在OSG中,可以通过调用相机的setViewport方法来设置视口。例如:
pCamera->setViewport(new osg::Viewport(0, 0, width, height));

这行代码创建了一个新的视口,并将其设置为相机的当前视口。其中,0和0是屏幕左下角的坐标,width和height是视口的宽度和高度。


相机与视口的关系

相机和视口在OSG中紧密相连,共同决定了三维场景的渲染效果。相机负责捕捉和渲染场景,而视口则定义了相机捕捉的场景在屏幕上的显示位置和大小。通过调整相机的各种变换和设置视口的大小和位置,可以实现丰富的三维视觉效果和交互体验。


设置相机观察函数

void setViewMatrixAsLookAt(const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up);
  • eye:表示相机的位置。这是一个三维向量,指定了相机在世界坐标系中的位置。
  • center:表示相机观察的中心点。这也是一个三维向量,指定了相机应该对准的物体或场景的中心位置。
  • up:表示哪个方向是正方向。这同样是一个三维向量,通常用于指定相机的上方方向(例如,通常设置为 (0,0,1) 表示Y轴正方向为上方)。
    设置相机位置和方向:通过指定 eye、center 和 up 三个参数,你可以精确地控制相机的位置和姿态。eye 和 center 之间的向量表示相机的观察方向,而 up 向量则用于确定相机的上方方向。
    关闭漫游器:在使用 setViewMatrixAsLookAt 函数之前,通常需要关闭相机的漫游器(Camera Manipulator)。这是因为漫游器会自动更新相机的观察矩阵,从而覆盖你通过 setViewMatrixAsLookAt 设置的参数。可以通过调用 viewer->setCameraManipulator(NULL) 来关闭漫游器。
    坐标系:OSG 使用右手坐标系,其中 X 轴向右,Y 轴向上,Z 轴向前。因此,在设置 eye、center 和 up 参数时,需要确保它们符合右手坐标系的规则。
    视图矩阵:setViewMatrixAsLookAt 函数实际上是通过设置相机的视图矩阵来实现相机位置和姿态的调整。视图矩阵是一个 4x4 的矩阵,用于将相机坐标系中的点转换到世界坐标系中。
    setViewMatrixAsLookAt 是一个强大的函数,它允许你以直观的方式设置相机的位置和姿态。通过合理地使用这个函数,你可以创建出各种复杂而逼真的三维场景和视觉效果。


Demo关键源码


创建Hud相机

    // 步骤一:创建HUD摄像机
// osg::ref_ptr<osg::Camera> pCamera = new osg::Camera;
osg::ref_ptr<HudRotateCamera> pCamera = new HudRotateCamera;
pCamera->setMasterCamera(_pViewer->getCamera());
// 步骤二:设置投影矩阵
// pCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1280, 0, 800));
// 步骤三:设置视图矩阵,同时确保不被场景中其他图形位置变换影响, 使用绝对帧引用
pCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
pCamera->setViewMatrix(osg::Matrix::identity());
// 步骤四:清除深度缓存
pCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
// 步骤五:设置POST渲染顺序(最后渲染)
// pCamera->setRenderOrder(osg::Camera::PRE_RENDER); // 渲染不显示
// pCamera->setRenderOrder(osg::Camera::NESTED_RENDER);
pCamera->setRenderOrder(osg::Camera::POST_RENDER);
// 步骤六:设置为不接收事件,始终得不到焦点
pCamera->setAllowEventFocus(false);

// osg::ref_ptr<osg::Geode> pGeode = new osg::Geode();
// pGeode = new osg::Geode();
osg::ref_ptr<osg::StateSet> pStateSet = pGeode->getOrCreateStateSet();
// 步骤七:关闭光照
pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
// 步骤九:关闭深度测试
pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);

// pGeode->addDrawable(pGeometry.get());

pCamera->addChild(pGeode.get());

pGroup->addChild(pCamera.get());


HudRotateCamera.h

#ifndef HUDROTATECAMERA_H
#define HUDROTATECAMERA_H

#include "osg/Camera"
#include "osg/CopyOp"

class HudRotateCamera : public osg::Camera
{
public:
HudRotateCamera();

HudRotateCamera(const HudRotateCamera& copy, const osg::CopyOp &copyOp = osg::CopyOp::SHALLOW_COPY);

META_Node(osg, HudRotateCamera);

public:
void setMasterCamera(Camera* camera);

public:
virtual void traverse(osg::NodeVisitor& nodeVisitor);

protected:
virtual ~HudRotateCamera();

protected:
osg::observer_ptr<Camera> _pMasterCamera; // 新增了相机,主要是用来获取举证的
};

#endif // HUDROTATECAMERA_H


HudRotateCamera.cpp

#include "HudRotateCamera.h"

HudRotateCamera::HudRotateCamera(): Camera()
{

}

HudRotateCamera::HudRotateCamera(const HudRotateCamera & copy, const osg::CopyOp & copyOp)
: Camera(copy, copyOp),
_pMasterCamera(copy._pMasterCamera)
{

}

HudRotateCamera::~HudRotateCamera()
{

}

void HudRotateCamera::setMasterCamera(osg::Camera *camera)
{
_pMasterCamera = camera;
}

void HudRotateCamera::traverse(osg::NodeVisitor &nodeVisitor)
{
double fovy, aspectRatio, vNear, vFar;
_pMasterCamera->getProjectionMatrixAsPerspective(fovy, aspectRatio, vNear, vFar);

// 设置投影矩阵,使缩放不起效果, 改为正投影,正投影不会随相机的拉近拉远而放大、缩小,这样就没有缩放效果,
// 放大缩小是根据左右,上下距离,越大就物体越小,越小就物体越大
this->setProjectionMatrixAsOrtho(-50 * aspectRatio,
50 * aspectRatio,
-50,
50,
vNear,
vFar);
// 让坐标轴模型位于窗体左下角
osg::Vec3 vec3(-40, -40, 0);
if (_pMasterCamera.valid())
{
// 改变视图矩阵, 让移动位置固定
osg::Matrix matrix = _pMasterCamera->getViewMatrix();

// 让移动固定, 即始终位于窗体右下角,否则鼠标左键按住模型可以拖动或按空格键时模型会动
matrix.setTrans(vec3);
this->setViewMatrix(matrix);
}
osg::Camera::traverse(nodeVisitor);
}


工程模板v1.35.0

在这里插入图片描述


入坑


入坑一:没有按照预期的方式全屏显示在正中间


问题

想一直显示在中间,且能旋转,移动中心,但是实际效果如下,方格100x100,间距1.0,测试:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


尝试

将面方格缩小为10x10,线放小,测试:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

缩小正交投影:
在这里插入图片描述
在这里插入图片描述

可能跟相机查看位置有关,新增相机位置和方向等信息:
在这里插入图片描述

没什么影响:
在这里插入图片描述

这里可能理解有问题,我们需要区域投影到视口,那么一个是投影的区域三维区域的大小,一个是投影到桌面2D他的大小,这里其实类似于HUD,通过HUD的方式,添加了几行代码设置投影矩阵:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

经过测试,可以跳过相机调整视口、中心改变后也会移动,所以他一种在其位置区域。
然后回到前面,发现也可以,再次摸索,发现如下特点:
在这里插入图片描述

所以此时,纵横都是10,所以窗口大小要是符合1:1(10:10=1:1)的比例,改为400,400测试,还是一样:
在这里插入图片描述

但是调整为800x800就好了:
在这里插入图片描述

放最大也不会截取少了:
在这里插入图片描述

所以这个有点搞不明白了,总之是解决了,且投影矩阵和正交矩阵都可以解决,测试投影矩阵和正交举证都收视口大小影响,但是影响具体不知,就好像800x800是最小一样(其他的没测了,只测了400x400、600x600不行,看比例800x800是最小正好满窗口了)。
在这里插入图片描述

又怀疑投过去的区域小了,将区域放大,其位置反倒缩小,所以跟理解不一样:

  • 一种是理解直接投射过去,投射过去区域变大所以变大(不是的);
  • 一种是投射过去区域不变,那么区域变大视图区域可见空间范围变大(实际是这样,但是视口对屏幕的大小未变);
    综合以上,又测试了加大视口,也正常,所以怀疑有可能是qt和osg结合的时候这个地方设置了一个最小值,而可能吧,欢迎探讨,这里深究暂时也没结果,且解决了,所以不继续深究了。


解决

修改相机视口大小为最小800x800。
在这里插入图片描述


后续补充

后续查看做的这个qtosg兼容类,做的时候,自己设置的800x800,就是这个原因了:
在这里插入图片描述


入坑二:相机视口区域不透明


问题

当作最前面的文本hud,是可以透明,但是这里进行调整之后,无法透明。
在这里插入图片描述


尝试

修改了语句,可以透明了部分,但是没了。
在这里插入图片描述

在这里插入图片描述


解决

相机是一个投影矩阵,没有透明,但是文字hud为什么透明呢?。


入坑三:内置几何体关闭光照后纯白色


问题

关闭光照后,几何体白色
在这里插入图片描述


原理

光照关闭要设置颜色,不想设置颜色,就单独给体开放关照。


解决

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


入坑四:文本看不到


问题

文本看不到,旋转后发现是太大了。
在这里插入图片描述

位置较大。


尝试

测试下是把整个坐标区域的展示范围扩大,那么实际看起来就是缩小。


解决

在这里插入图片描述

在这里插入图片描述


入坑五:hud旋转中心不对


问题

Hud旋转中心不对
在这里插入图片描述

这时旋转中心还不对,可能需要调整旋转中心
在这里插入图片描述


原理

开始去修改矩阵,发现都不对,其实中间点一直是0,0,0,其就是中心,那么我们设置文本的显示点不是从0,0开始即可。
下面将四边形的角点改为0,0,0来标识,然后修改文本的中心点:
在这里插入图片描述


解决

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


入坑六:hud旋转反向了


问题

旋转是反的,然后光照也反了,变换矩阵有问题
在这里插入图片描述


原理

数据几何变换算来算去很费劲,直接测试的结论:
在这里插入图片描述

代码写反了,让上下反向了,应该是-50~50


解决

在这里插入图片描述

在这里插入图片描述

还剩下光照问题,这个不好咋弄了,反正是关闭光照,或者是自己手动添加光源,用系统的可能有点问题。
在这里插入图片描述

在这里插入图片描述

这个暂时没解决,实际使用就是用一个,可以从长度单独给这个相机设置一个光源,这里因为需求本身不需要投影,不做测试了。