红警DIY论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
123
返回列表 发新帖
楼主: 鬼蟬

上头,还是想研究vpl

[复制链接]
发表于 2020-7-30 12:24:13 | 显示全部楼层
扒HVA Builder的源码,里面有现成的逻辑,不用试了。
发表于 2020-7-30 12:27:54 | 显示全部楼层
西城杨柳 发表于 2020-4-3 18:14
刚才逆向了一下引擎的代码,VXL相关代码似乎在0x755DB0附近。不过那里一大堆虚函数调用,静态反汇编根本 ...

HVA Builder是开源的,你研究研究。
发表于 2020-7-30 12:50:23 | 显示全部楼层
西城杨柳 发表于 2020-4-22 10:03
主要是后面一大堆虚函数调用,太难读了,看不出用的什么计算方法。

HVAbuilder里面有渲染原理,只可惜我不会PASCAL(HVAB是Pascal写的)
发表于 2020-7-30 12:57:53 | 显示全部楼层
重点代码在此:procedure UpdateVoxelList2(const Vxl : TVoxel; Var VoxelBoxes : TVoxelBoxs; Var VoxelBox_No : Integer; Const HVAOpen : Boolean; HVA : THVA; Frames : Integer);
var
   x,y,z,i: Byte;
   v: TVoxelUnpacked;
   num : integer;
   CD : TVector3f;
begin
   VoxelBox_No := 0;
   if VoxelBoxes.NumSections > 0 then
      for x := 0 to VoxelBoxes.NumSections-1 do
         If VoxelBoxes.Sections[x].List > 0 then
            glDeleteLists(VoxelBoxes.Sections[x].List, 1);

   VoxelBoxes.NumSections := VXL.Header.NumSections;
   SetLength(VoxelBoxes.Sections,0);
   SetLength(VoxelBoxes.Sections,VXL.Header.NumSections);

   for i := 0 to VXL.Header.NumSections-1 do
   begin
      VoxelBoxes.Sections[i].NumBoxs := 0;
      num:=0;
      SetLength(VoxelBoxes.Sections[i].Boxs,VoxelBoxes.Sections[i].NumBoxs);
      for z:=0 to (Vxl.Section[i].Tailer.zSize-1) do
      begin
         for y:=0 to (Vxl.Section[i].Tailer.YSize-1) do
         begin
            for x:=0 to (Vxl.Section[i].Tailer.xSize-1) do
            begin
               Vxl.Section[i].GetVoxel(x,y,z,v);
               if v.Used=true then
               begin
                  inc(VoxelBox_No);
                  inc(VoxelBoxes.Sections[i].NumBoxs);
                  SetLength(VoxelBoxes.Sections[i].Boxs,VoxelBoxes.Sections[i].NumBoxs);
                  VoxelBoxes.Sections[i].Boxs[num].Section := i;
                  VoxelBoxes.Sections[i].Boxs[num].MinBounds.x := (Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/Vxl.Section[i].Tailer.xSize;
                  VoxelBoxes.Sections[i].Boxs[num].MinBounds.y := (Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/Vxl.Section[i].Tailer.ySize;
                  VoxelBoxes.Sections[i].Boxs[num].MinBounds.z := (Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/Vxl.Section[i].Tailer.zSize;

                  CD.x := Vxl.Section[i].Tailer.MaxBounds[1] + (-(Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/2);
                  CD.y := Vxl.Section[i].Tailer.MaxBounds[2] + (-(Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/2);
                  CD.z := Vxl.Section[i].Tailer.MaxBounds[3] + (-(Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/2);

                  VoxelBoxes.Sections[i].Boxs[num].MinBounds2.x := CD.x + (-(Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/2);
                  VoxelBoxes.Sections[i].Boxs[num].MinBounds2.y := CD.y + (-(Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/2);
                  VoxelBoxes.Sections[i].Boxs[num].MinBounds2.z := CD.z + (-(Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/2);

                  if HVAOpen then
                  begin
                     VoxelBoxes.Sections[i].Boxs[num].Faces[1] := True;
                     VoxelBoxes.Sections[i].Boxs[num].Faces[2] := True;
                     VoxelBoxes.Sections[i].Boxs[num].Faces[3] := True;
                     VoxelBoxes.Sections[i].Boxs[num].Faces[4] := True;
                     VoxelBoxes.Sections[i].Boxs[num].Faces[5] := True;
                     VoxelBoxes.Sections[i].Boxs[num].Faces[6] := True;

                     VoxelBoxes.Sections[i].Boxs[num].Position.X := {Vxl.Section[i].Tailer.Transform[1][4]+}X;//X {* Vxl.Section[i].Tailer.MinBounds[1]}-((Vxl.Section[i].Tailer.xSize-1) / 2){+ 80* Vxl.Section[i].Tailer.Det};
                     VoxelBoxes.Sections[i].Boxs[num].Position.Y := {Vxl.Section[i].Tailer.Transform[2][4]+}Y;//Y {* Vxl.Section[i].Tailer.MinBounds[2]}-((Vxl.Section[i].Tailer.ySize-1) / 2){+ 80* Vxl.Section[i].Tailer.Det};
                     VoxelBoxes.Sections[i].Boxs[num].Position.Z := {Vxl.Section[i].Tailer.Transform[3][4]+}Z;//Z {* Vxl.Section[i].Tailer.MinBounds[3]} {- ((Vxl.Section[i].Tailer.zSize-1) / 2) + 80* Vxl.Section[i].Tailer.Det};
{
                     if ApplyMatrix2(HVA,Vxl,AddVector(ScaleVector3f(VoxelBoxes.Sections[i].Boxs[num].Position,VoxelBoxes.Sections[i].Boxs[num].MinBounds),VoxelBoxes.Sections[i].Boxs[num].MinBounds2),i,Frames).Z < LowestZ then
                        LowestZ := ApplyMatrix2(HVA,Vxl,AddVector(ScaleVector3f(VoxelBoxes.Sections[i].Boxs[num].Position,VoxelBoxes.Sections[i].Boxs[num].MinBounds),VoxelBoxes.Sections[i].Boxs[num].MinBounds2),i,Frames).Z;
}
                  end
                  else
                  begin
                     VoxelBoxes.Sections[i].Boxs[num].Faces[1] := CheckFace(Vxl.Section[i],x,y+1,z);
                     VoxelBoxes.Sections[i].Boxs[num].Faces[2] := CheckFace(Vxl.Section[i],x,y-1,z);
                     VoxelBoxes.Sections[i].Boxs[num].Faces[3] := CheckFace(Vxl.Section[i],x,y,z+1);
                     VoxelBoxes.Sections[i].Boxs[num].Faces[4] := CheckFace(Vxl.Section[i],x,y,z-1);
                     VoxelBoxes.Sections[i].Boxs[num].Faces[5] := CheckFace(Vxl.Section[i],x-1,y,z);
                     VoxelBoxes.Sections[i].Boxs[num].Faces[6] := CheckFace(Vxl.Section[i],x+1,y,z);
                     VoxelBoxes.Sections[i].Boxs[num].Position.X := Vxl.Section[i].Tailer.Transform[1][4]+X;// - ((Vxl.Section[i].Tailer.xSize-1) / 2);
                     VoxelBoxes.Sections[i].Boxs[num].Position.Y := Vxl.Section[i].Tailer.Transform[2][4]+Y;// - ((Vxl.Section[i].Tailer.ySize-1) / 2);
                     VoxelBoxes.Sections[i].Boxs[num].Position.Z := {HighestZ+}Vxl.Section[i].Tailer.Transform[3][4]+Z;// - ((Vxl.Section[i].Tailer.zSize-1) / 2);
{
                     if AddVector(ScaleVector3f(VoxelBoxes.Sections[i].Boxs[num].Position,VoxelBoxes.Sections[i].Boxs[num].MinBounds),VoxelBoxes.Sections[i].Boxs[num].MinBounds2).Z < LowestZ then
                        LowestZ := AddVector(ScaleVector3f(VoxelBoxes.Sections[i].Boxs[num].Position,VoxelBoxes.Sections[i].Boxs[num].MinBounds),VoxelBoxes.Sections[i].Boxs[num].MinBounds2).Z;
}
                  end;

                  VoxelBoxes.Sections[i].Boxs[num].Color := v.Colour;
                  VoxelBoxes.Sections[i].Boxs[num].Normal := v.Normal;

                  Inc(num);
               end;
            end;
         end;
      end;
   end;
end;

Procedure GETMinMaxBounds(Const Vxl : TVoxel; i : Integer; Var MB,MB2 : TVector3f);
var
   CD : TVector3f;
begin
   // As far as I could understand, this is the scale.
   MB.x := (Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/Vxl.Section[i].Tailer.xSize;
   MB.y := (Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/Vxl.Section[i].Tailer.ySize;
   MB.z := (Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/Vxl.Section[i].Tailer.zSize;
{
   // This is suposed to be the half...
   CD.x := (Vxl.Section[i].Tailer.MaxBounds[1] - ((Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/2));
   CD.y := (Vxl.Section[i].Tailer.MaxBounds[2] - ((Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/2));
   CD.z := (Vxl.Section[i].Tailer.MaxBounds[3] - ((Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/2));

   // That's the offset.
   MB2.x := CD.x - ((Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/2);
   MB2.y := CD.y - ((Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/2);
   MB2.z := CD.z - ((Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/2);
}
   // That's the offset.
   MB2.x := Vxl.Section[i].Tailer.MinBounds[1]; //Vxl.Section[i].Tailer.MaxBounds[1] - ((Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1]));
   MB2.y := Vxl.Section[i].Tailer.MinBounds[2]; //Vxl.Section[i].Tailer.MaxBounds[2] - ((Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2]));
   MB2.z := Vxl.Section[i].Tailer.MinBounds[3]; //Vxl.Section[i].Tailer.MaxBounds[3] - ((Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3]));
end;

Procedure GetOffsetAndSize(Const Vxl : TVoxel; i : Integer; Var Size,Offset : TVector3f);
var
   CD : TVector3f;
begin
   Size.x := (Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/Vxl.Section[i].Tailer.xSize;
   Size.y := (Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/Vxl.Section[i].Tailer.ySize;
   Size.z := (Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/Vxl.Section[i].Tailer.zSize;

   Offset.x := Vxl.Section[i].Tailer.MaxBounds[1] + (-(Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/2);
   Offset.y := Vxl.Section[i].Tailer.MaxBounds[2] + (-(Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/2);
   Offset.z := Vxl.Section[i].Tailer.MaxBounds[3] + (-(Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/2);

   ScaleVector3f(Offset,Size);

   //Offset.x := CD.x + (-(Vxl.Section[i].Tailer.MaxBounds[1]-Vxl.Section[i].Tailer.MinBounds[1])/2);
   //Offset.y := CD.y + (-(Vxl.Section[i].Tailer.MaxBounds[2]-Vxl.Section[i].Tailer.MinBounds[2])/2);
   //Offset.z := CD.z + (-(Vxl.Section[i].Tailer.MaxBounds[3]-Vxl.Section[i].Tailer.MinBounds[3])/2);
end;

Function CleanV3fCol(Color : TVector3f) : TVector3f;
Var
   T : TVector3f;
begin
   T.X := Color.X;
   T.Y := Color.Y;
   T.Z := Color.Z;

   If T.X > 255 then
      T.X := 255;

   If T.X < 0 then
      T.X := 0;

   If T.Y > 255 then
      T.Y := 255;

   If T.Y < 0 then
      T.Y := 0;

   If T.Z > 255 then
      T.Z := 255;

   If T.Z < 0 then
      T.Z := 0;

   T.X := T.X / 255;
   T.Y := T.Y / 255;
   T.Z := T.Z / 255;

   Result := T;
end;

// Importing and adapting change remappable from OS SHP Builder.
procedure ChangeRemappable (var Palette:TPalette; Colour : TVector3f);
var
   base,x,rsub,gsub,bsub:byte;
   rmult,gmult,bmult: single;
begin
   base := 64;
   rmult := (Colour.X * 255) / 128;
   gmult := (Colour.Y * 255) / 128;
   bmult := (Colour.Z * 255) / 128;
   // Generate Remmapable colours
   if rmult <> 0 then
     rsub := 1
   else
     rsub := 0;
   if gmult <> 0 then
     gsub := 1
   else
     gsub := 0;
   if bmult <> 0 then
     bsub := 1
   else
     bsub := 0;

   for x := 16 to 31 do
   begin
      Palette[x]:= RGB(Round(((base*2)*rmult)-rsub),Round(((base*2)*gmult)-gsub),Round(((base*2)*bmult)-bsub));
      if (((x+1) div 3) <> 0) then
         base := base - 4
      else
         base := base - 3;
   end;
end;

function GetCorrectColour(Color : integer) : TVector3f;
var
   T : TVector3f;
begin
{
   if (Color > 15) and (Color < 32) then
   begin
      T.X := RemapColour.X*255 + ((Color-15)-15/2);
      T.Y := RemapColour.Y*255 + ((Color-15)-15/2);
      T.Z := RemapColour.Z*255 + ((Color-15)-15/2);

      Result := CleanV3fCol(T);
   end
   else
}
   result := TColorToTVector3f(VXLPalette[Color]);
end;

Function GetVXLColor(Color,Normal : integer) : TVector3f;
begin
   if SpectrumMode = ModeColours then
      Result := GetCorrectColour(color)
   else
      Result := CleanV3fCol(SetVector(127,127,127));
end;

Function GetVXLColorWithSelection(Vxl : TVoxel; Color,Normal,Section : integer) : TVector3f;
begin
   Result := GetVXLColor(Color,Normal);

   if (Vxl = CurrentVoxel^) and (Section = CurrentVoxelSection) and (Highlight) then
   begin
      Result.X := (Result.X *255) + 70;
      Result := CleanV3fCol(Result);
   end;
end;
发表于 2020-7-30 13:06:41 | 显示全部楼层
我把整个源码留在这里,希望会PASCAL的朋友破解一下,谢谢~

HVA BUILDER源码.rar

262.87 KB, 下载次数: 8

源码

发表于 2020-7-30 22:37:35 | 显示全部楼层
笨030504 发表于 2020-7-30 13:06
我把整个源码留在这里,希望会PASCAL的朋友破解一下,谢谢~

HVA Builder画vxl跟游戏不一样 效果也跟游戏相差很多 虽然hva builder和新版的vxlse里面法线表跟游戏是一样的
发表于 2021-11-21 18:44:54 | 显示全部楼层
k002300 发表于 2020-7-30 22:37
HVA Builder画vxl跟游戏不一样 效果也跟游戏相差很多 虽然hva builder和新版的vxlse里面法线表跟游戏是一 ...

(光速跑回来挖坟记录一下,感觉在犯罪)
游戏索引vpl中第n个色盘序列表时,其n与夹角大小不成正比,而是与“两道光照”夹角余弦值之和成正比;
游戏为了计算迅速,会在画一个模型时预先计算一个表,以拿到一个normal序号(每一个voxel的)就能直接索引对应的色盘序列表(意思就是,这个模型在当前状况下,各法线值对应各颜色序列表的情况);
在游戏程序打开很短的时间内,会生成一个用于计算光照的方向(首先是(-0.707,-0.707)即两个-1/sqrt(2) ,然后绕Y轴旋转45°得到的方向向量);
如何计算上面所说的这个表:
先用单位当前的矩阵变换光照方向,求法线表内的每一个法线与变换得到的方向的夹角余弦a,然后变换得到的方向z+1,再求一个余弦值b,然后b=b/(3-2b),a和b如果小于0则设为0,得到色盘序列表序号n=(a+b)*16,向下取整;所以上述的计算看起来,就像是有两道“光”在同时作用(z和z+1的)
暂存记录
发表于 2023-5-29 16:07:30 | 显示全部楼层
本帖最后由 Iowa3 于 2023-5-29 16:41 编辑

(我也来一铲子)
实际上不需要这么复杂。在给定颜色的情况下,245种法线值×32个朝向=7840种着色方案,但是在游戏中渲染只用了32种着色方案。考虑到这一点,如果只是要指导VPL的制作,那么可以把问题简化成:研究这32种着色方案在32个朝向下的分布。并且由于游戏的着色算法固定,甚至可以更进一步地只研究几个朝向下的着色方案分布即可制作表现效果良好的VPL。

这里再吐槽下SBWW,把光源渲染写死了根本无法通过VPL来变换光源角度,结果就是VXL一个仰角10°的光源配一个SHP仰角45°的光源,RA星有两个太阳(确信)

发表于 2023-5-29 18:03:14 | 显示全部楼层
本帖最后由 Iowa3 于 2023-5-29 20:01 编辑

对上文所指的着色方案作个补充。使用某个特殊色(色盘3号色)对法线球进行上色(vxl上色如上图),同时将3号色对应的vpl的32个渲染色用不同颜色标识(游戏内渲染为中图),以下方T-72的方向当作参考,会发现箭头所指的四个不同法线在该方向渲染的颜色其实是同一个(青涩),而球体后方的大量不同法线统一渲染为白色。

再补充一下,vpl的section很可能是按球面进行逐层扩散的,PPM上的洋人画了个示意图(下图)

再再补充一下,section确实是按球面扩散的(最底图),SBWW连个球面光照都做不好。

ball.png
render.png

render2.png


您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|Archiver|手机版|管理员邮箱|红警DIY官方论坛

GMT+8, 2023-10-4 23:50 , Processed in 0.046471 second(s), 14 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表