3
$\begingroup$

The folowing code produces 2 graphicses:

  • LEFT ONE (denoted slika1): camera view and an object (octahedron)
  • RIGHT ONE (denoted slika2): rendered image of an object, given the coresponding view options

The center of view (denoted ViewC) (ABSOLUTE COORDINATES) is controled vith the first row of sliders. The next three sliders control the displacement of camera from the center of view (denoted by ΔT).

In the code, the position of camera is denoted by T.

Clear["Global`*"];
\[Epsilon]=.000001;

(*
-TčjiKota je: {krak1, vrh, krak2}
-obr je obroba
-FaktZamikaKot: premakne napis v smeri navzven kota za ta faktor*VelNap
*)
PlotajKot3D[TčjiKota_,Rkota_,Bnot_,Bobr_,DebObr_,Npodkotov_,NapTex_,VelNap_,FaktZamikaKot_]:=(
    (*
    SetOptions[MaTeX,"Preamble"->{
    "\\usepackage{color,bm}",
    "\\definecolor{Bobr}{rgb}"<>ToString[Bobr[[;; 3]]]
    }];
    *)
    VektKota1=TčjiKota[[1]]-TčjiKota[[2]];
    VektKota2=TčjiKota[[3]]-TčjiKota[[2]];
    kot=VectorAngle[VektKota1,VektKota2];
    RMjikota=Table[RotationMatrix[\[Theta]kota,{VektKota1,VektKota2}],{\[Theta]kota,0,kot,kot/Npodkotov}];
    LokKota=(TčjiKota[[2]]+Rkota # . Normalize[VektKota1])&/@RMjikota;
    
    DaljiceLoka=Partition[LokKota,2,1];
    TrikotnikiKota={
        DaljiceLoka[[;;,1]],
        Table[TčjiKota[[2]],Npodkotov],
        DaljiceLoka[[;;,2]]
    }\[Transpose];
        
    Show[
        Graphics3D[{RGBColor[Bnot],EdgeForm[],Polygon@#}]&/@TrikotnikiKota,
        Graphics3D[{RGBColor[Bobr],Thickness->DebObr,Line@LokKota}](*,
        
        Graphics3D[Text[
            MaTeX["\\color{Bobr}"<>NapTex,
            FontSize->VelNap],
            TčjiKota[[2]]+(Rkota-FaktZamikaKot VelNap) Normalize[Normalize@VektKota1+Normalize@VektKota2]
        ]]*)
        
    ]
);

oktaeder=Graphics3D[{
    RGBColor@{0,1,1,.5},EdgeForm[],
    Polygon[{
    {{1,0,0},{0,1,0},{0,0,1}},
    {{-1,0,0},{0,1,0},{0,0,1}},
    {{1,0,0},{0,-1,0},{0,0,1}},
    {{-1,0,0},{0,-1,0},{0,0,1}},
    {{1,0,0},{0,1,0},{0,0,-1}},
    {{-1,0,0},{0,1,0},{0,0,-1}},
    {{1,0,0},{0,-1,0},{0,0,-1}},
    {{-1,0,0},{0,-1,0},{0,0,-1}}
    }]
}];

res={resx,resy}=Round[{1920,1080}/2.7];




GEkrana[ViewC_,T_,d_,a_,\[CurlyPhi]_]:=(
\[CapitalDelta]T={x,y,z}=T-ViewC;  (*relativni T, glede na ViewCenter*)
xy=Sqrt[x^2+y^2];(*POZOR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*)
b=resy/resx a;
S=ViewC+(Norm[\[CapitalDelta]T]-d)Normalize@\[CapitalDelta]T;


\[CapitalDelta]x1=(b z x)/(2Norm[\[CapitalDelta]T]xy);
\[CapitalDelta]y1=(b z y)/(2Norm[\[CapitalDelta]T]xy);
\[CapitalDelta]z1=(b xy)/(2Norm[\[CapitalDelta]T]);
\[CapitalDelta]x2=(a y)/(2xy);
\[CapitalDelta]y2=(a x)/(2xy);
O1=S+{\[CapitalDelta]x1,\[CapitalDelta]y1,-\[CapitalDelta]z1}+{\[CapitalDelta]x2,-\[CapitalDelta]y2,0};
O2=S+{\[CapitalDelta]x1,\[CapitalDelta]y1,-\[CapitalDelta]z1}-{\[CapitalDelta]x2,-\[CapitalDelta]y2,0};
O3=S-{\[CapitalDelta]x1,\[CapitalDelta]y1,-\[CapitalDelta]z1}-{\[CapitalDelta]x2,-\[CapitalDelta]y2,0};
O4=S-{\[CapitalDelta]x1,\[CapitalDelta]y1,-\[CapitalDelta]z1}+{\[CapitalDelta]x2,-\[CapitalDelta]y2,0};


rot=RotationMatrix[\[CurlyPhi],\[CapitalDelta]T];
O1=S+rot . (O1-S);
O2=S+rot . (O2-S);
O3=S+rot . (O3-S);
O4=S+rot . (O4-S);
Oji={O1,O2,O3,O4};

rViewSfere=Max[Norm[# - ViewC] & /@ {T, O1}];
ViewSfera=Sphere[ViewC, rViewSfere];

(*zdej pa še dobimo žarke na drug stran ViewSfere*)
TO1=O1-T;
lžarkov=2 rViewSfere Cos@VectorAngle[-\[CapitalDelta]T,TO1];
žarki={T,T+lžarkov Normalize[#-T]}&/@Oji;

PiramidaŽarkov=Polygon[{
    žarki[[;;,2]],
    RotateRight@žarki[[;;,2]],
    žarki[[;;,1]]
}\[Transpose]];

(*
    Graphics3D[Text["1",O1]],
    Graphics3D[Text["2",O2]],
    Graphics3D[Text["3",O3]],
    Graphics3D[Text["4",O4]],
*)










slika1=Show[
    Graphics3D[Point@ViewC],
    Graphics3D[{Green,Point[T]}],
    Graphics3D[Point[S]],
    Graphics3D[{White,Line[{T,ViewC}]}],
    Graphics3D[{Yellow,Line@žarki}],
    Graphics3D[{RGBColor@{1,1,0,.5},EdgeForm[{RGBColor@{1,1,0,.9},[email protected]}],Polygon@Oji}],
    Graphics3D[{[email protected],ViewSfera}],
    Graphics3D[{RGBColor@{1,1,0,.06},EdgeForm[],PiramidaŽarkov}],
    Graphics3D[{
        RGBColor[{1,0,0}],Arrowheads[.008],
        ViewVIzh=Mean@{O3,O4}; RViewV=.8; ViewV=RViewV Normalize[O4-O1];
        Arrow[Tube[{{0,0,0},ViewV}+Threaded[ViewVIzh,2], .012]]
    }],
    PlotajKot3D[
        {\[CapitalDelta]T,{0,0,0},-\[CapitalDelta]T+\[Epsilon] ViewV}+Threaded[ViewVIzh,2],
        RViewV,RGBColor@{1,0,0,.1},RGBColor@{0,0,0,0},.01,30,"",15,0],
    oktaeder,
    
    Boxed->False,Background->Black,Lighting->"Neutral",
    
    ViewPoint->{0, -2, .5},ViewVertical->{0, 0, 1},
    SphericalRegion->ViewSfera,
    ImageSize->{resy,resy}
];







slika2=Show[
    oktaeder,
    Boxed->False,Background->Black,Lighting->"Neutral",
    
    ViewPoint->T, ViewVector -> {Scaled@T, ViewC},
    ViewAngle->ArcTan[b/(2 d)],ViewVertical->ViewV,
    ImageSize->res
];

{slika1,slika2}
);












Manipulate[
GEkrana[ViewC,ViewC+r{Cos[\[Beta]]Cos[\[Alpha]],Cos[\[Beta]]Sin[\[Alpha]],Sin[\[Beta]]},d,2 d Tan[ViewA],\[CurlyPhi]],

Style["ViewCenter in absolute coordinates",15,Bold],
    {{ViewC,{0,0,0}},{-1,-1,-1},{1,1,1}},
Delimiter,
Style["\[CapitalDelta]Viewpoint",15,Bold],
    {{\[Alpha],.6},0,2\[Pi]},
    {{\[Beta],.2},-\[Pi]/2+\[Epsilon],\[Pi]/2-\[Epsilon]},
    {{r,5},\[Epsilon],10},
Delimiter,
Style["ViewAngle",15,Bold],
    {{d,2},\[Epsilon],10},
    {{ViewA,15°},\[Epsilon],\[Pi]/2-\[Epsilon]},
Delimiter,
Style["ViewVertical je poljuben 
\[RightVector]  iz rdeče polravnine",15,Bold],
    {{\[CurlyPhi],0},0,2\[Pi]},

ControlPlacement->Left
]

For slika2, I first tried the option ViewCenter -> Scaled@ViewC. The result was wrong. Then I read this post: Am I missing the point of ViewCenter?. The answer in it advised ViewVector -> {Scaled@T, ViewC}. In my case this gives more accurate result, but it is still wrong.

For example: if I leave the ViewC at the oreign {0,0,0} and delete ViewVector -> {Scaled@T, ViewC} from the code, using the same parameters, I get different result, without ViewVector -> {Scaled@T, ViewC}, then with it. This is shown on the nex image. enter image description here

Also you see on the left image, that the bottom vertex should be on the image. But if you look on the right image, the bottom vertex is not on the image. enter image description here

How to fix it?

$\endgroup$

1 Answer 1

3
$\begingroup$

Okay, I later tried it also with SphericalRegion and that seems to be working at least in this case (can't be 100% sure if it always works), so I'll not close the question just jet.

To be exact, instead of ViewVector -> {Scaled@T, ViewC}, I used SphericalRegion -> Sphere[ViewC, Norm@\[CapitalDelta]T/Sqrt[((2 d)/Min@{a, b})^2 + 1]]

enter image description here.

This follows from similar triangles, where a and b are sides of the camera rectangle at distance d from the camera.
enter image description here

EDIT

Below is a more usefull version of the code. You can use the function Camera, where the arguments are:

  • grafikaMo: 3D thing you want to display
  • resMo: resolution of the image
  • ViewCMo: point in $\mathbb{R}^{3}$, that camera aims (in the center of image)
  • ViewPPolarneMo: polar coorinates $\{\alpha,\beta,r\}$ of a vector from ViewCMo to the camera. To use cartesian coords, just delete first 2 lines from the deffinition and use \[CapitalDelta]TMo and \[CapitalDelta]T instead of ViewPPolarneMo and ViewPPolarne.
  • ViewAMo: angle between central axis of camera and the right plane of cameras view.
  • ZasukMo: tilt angle of camera around central axis of camera
Remove["Global`*"];
Camera[grafikaMo_,resMo_,ViewCMo_,ViewPPolarneMo_,ViewAMo_,ZasukMo_]:=Module[{
grafika=grafikaMo,res=resMo,ViewC=ViewCMo,ViewPPolarne=ViewPPolarneMo,ViewA=ViewAMo,Zasuk=ZasukMo,
\[Alpha],\[Beta],r,\[CapitalDelta]T,T,x,y,z,xy,a,b
(*za d=1*)
},
    {\[Alpha],\[Beta],r}=ViewPPolarne;
    \[CapitalDelta]T={x,y,z}=r{Cos[\[Beta]]Cos[\[Alpha]],Cos[\[Beta]]Sin[\[Alpha]],Sin[\[Beta]]};
    T=ViewC+\[CapitalDelta]T;
    xy=Sqrt[x^2+y^2];
    a=2 Tan[ViewA];   
    b=res[[2]]/res[[1]] a;
    
    Show[
        grafika, Boxed->False,Background->RGBColor[{0,0,0}],Lighting->"Neutral",
        
        ViewPoint->T,
        SphericalRegion->Sphere[ViewC,Norm@\[CapitalDelta]T/Sqrt[(2/Min@{a,b})^2+1]],
        ViewAngle->ArcTan[b/2],
        ViewVertical->-(b/Norm@\[CapitalDelta]T) RotationMatrix[Zasuk,\[CapitalDelta]T] . {(z x)/xy,(z y)/xy,-xy},
        ImageSize->res
    ]
];

And also an interactive example:

oktaeder=Graphics3D[{
    RGBColor@{0,1,1,.5},EdgeForm[],
    Polygon[{
    {{1,0,0},{0,1,0},{0,0,1}},
    {{-1,0,0},{0,1,0},{0,0,1}},
    {{1,0,0},{0,-1,0},{0,0,1}},
    {{-1,0,0},{0,-1,0},{0,0,1}},
    {{1,0,0},{0,1,0},{0,0,-1}},
    {{-1,0,0},{0,1,0},{0,0,-1}},
    {{1,0,0},{0,-1,0},{0,0,-1}},
    {{-1,0,0},{0,-1,0},{0,0,-1}}
    }]
}];

resolucija=Round[{1920,1080}/2.7];



\[Epsilon]=.0001;
Manipulate[
Camera[oktaeder,resolucija,ViewC,{\[Alpha],\[Beta],r},ViewA,\[CurlyPhi]],

Style["ViewCenter v absolutnih koordinatah",15,Bold],
    {{ViewC,{0,0,0}},{-1,-1,-1},{1,1,1}},
Delimiter,
Style["\[CapitalDelta]Viewpoint",15,Bold],
    {{\[Alpha],.6},0,2\[Pi]},
    {{\[Beta],.2},-\[Pi]/2+\[Epsilon],\[Pi]/2-\[Epsilon]},
    {{r,5},\[Epsilon],10},
Delimiter,
Style["ViewAngle",15,Bold],
    {{ViewA,15°},\[Epsilon],\[Pi]/2-\[Epsilon]},
Delimiter,
Style["ViewVertical je poljuben 
\[RightVector]  iz rdeče polravnine",15,Bold],
    {{\[CurlyPhi],0},0,2\[Pi]},

ControlPlacement->Left
]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.