4.29 How to render a textured sphere with Axis, Eye, and Light Positioner in OpenGL?
As you know, in OpenGL, you can easily map a texture to a solid sphere by using gluSphere and gluQuadricTexture APIs in OpenGL GLU library.
In this example, we have used the following classes.
AxisPositioner
EyePositioner
LightPositioner
OpenGLTexturedSphere
The following TexturedSphereWithAxisEyeLightPositioner is a simple example to render and rotate a textured sphere by
dynamically changing an axis position, an eye position, and light position respectively.
In this example, we have used Venus map 'ven0aaa2.jpg' Caltech/JPL/USGS in JPL NASA SOLAR SYSTEM SIMULATOR .
We have also used the following Lunar Orbiter's 'Lunar_LO_UVVISv2_Hybrid_Mosaic_Global_1024.jpg' in Astrogeology Science Center.
Furthermore, we have used the following Voyager Galileo IO 'jup1vss2.jpg' in the page
JPL NASA SOLAR SYSTEM SIMULATOR
/*
* TexturedSphereWithAxisEyeLightPositioner.cpp
* Copyright (c) 2017 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*/
//2017/11/23
//W have used the following venus image file 'ven0aaa2.jpg' create by Caltech/JPL/USGS:
//
// https://maps.jpl.nasa.gov/venus.html
#include <sol/Stdio.h>
#include <sol/Vector3.h>
#include <sol/LabeledTrackBar.h>
#include <sol/AxisPositioner.h>
#include <sol/EyePositioner.h>
#include <sol/LightPositioner.h>
#include <sol/FileDialog.h>
#include <sol/opengl/OpenGLMainView.h>
#include <sol/opengl/OpenGLView.h>
#include <sol/opengl/OpenGLGC.h>
#include <sol/opengl/OpenGLLight.h>
#include <sol/opengl/OpenGLMaterial.h>
#include <sol/opengl/Vertex3.h>
#include <sol/opengl/OpenGLLight.h>
#include <sol/opengl/OpenGLMaterial.h>
#include <sol/opengl/OpenGLTexturedSphere.h>
#include "Resource.h"
namespace SOL {
class MainView :public OpenGLMainView {
private:
///////////////////////////////////////////////////////////
//Inner class starts
class SimpleView: public OpenGLView {
private:
SmartPtr<OpenGLGC> gc;
SmartPtr<OpenGLTexturedSphere> texture;
float angle;
Vertex3 axis;
Vector3 veye;
Vector3 vlight;
public:
virtual void display()
{
if (gc && texture) {
gc->loadIdentity();
gc->clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gc->loadIdentity();
gc->clearColor(0.0, 0.0, 0.0, 1.0);
gc->enable(GL_LIGHTING);
gc->enable(GL_DEPTH_TEST);
gc->color(1.0f, 1.0f, 1.0f);
gc->lookAt(veye.x, veye.y, veye.z, 0.0, 0.0, 0.0, 0.0, 6.0, 0.0);
gc->translate(0.0f, 0.0f, 0.0f);
gc->rotate(angle, axis.x, axis.y, axis.z);
OpenGLLight light(GL_LIGHT0);
light.position(vlight.x, vlight.y, vlight.z, 0.0f);
GLfloat white[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat blue[] = {0.0f, 0.0f, 1.0f, 1.0f};
GLfloat shininess[] = {100.0};
OpenGLMaterial material(GL_FRONT);
material.diffuse(blue);
material.specular(white);
material.shininess(shininess);
texture -> draw(gc);
}
}
virtual void resize(int w, int h)
{
if (w == 0 || h == 0) {
return;
}
if (gc) {
const float r = (float) w / (float) h;
gc -> matrixMode(GL_PROJECTION);
gc -> loadIdentity();
gc -> frustum(r, -r, -1.0, 1.0, 2.0, 30.0);
gc -> matrixMode(GL_MODELVIEW);
gc -> loadIdentity() ;
}
}
void createTexture(const char* filename)
{
try {
texture = NULL;
texture = new OpenGLTexturedSphere(filename, 2.5f, 40, 40);
} catch (Exception& ex) {
caught(ex);
}
}
virtual void initialize()
{
gc = new OpenGLGC();
gc -> enable(GL_DEPTH_TEST);
gc -> enable(GL_TEXTURE_2D);
try {
//https://maps.jpl.nasa.gov/venus.html
const char* filename = "./images/ven0aaa2.jpg";
//const char* filename = "./images/Lunar_Clementine_UVVIS_750nm_Global_Mosaic_1024.jpg";
MainView* parent= (MainView*)getParent();
parent->openFile(filename);
} catch (Exception& ex) {
caught(ex);
}
}
public:
SimpleView(View* parent, const char* name, Args& args)
:OpenGLView(parent, name, args),
angle(120.0f)
{
}
~SimpleView()
{
}
void setAngle(int value)
{
angle =value;
postRenderRequest();
}
void setAxisPosition(int x, int y, int z)
{
axis.x = (float)x;
axis.y = (float)y;
axis.z = (float)z;
postRenderRequest();
}
void setEyePosition(int x, int y, int z)
{
veye.x = (float)x;
veye.y = (float)y;
veye.z= (float)z;
postRenderRequest();
}
void setLightPosition(int x, int y, int z)
{
vlight.x = (float)x;
vlight.y = (float)y;
vlight.z = (float)z;
postRenderRequest();
}
};
//Inner class ends.
///////////////////////////////////////////////////////////
private:
SmartPtr<SimpleView> view;
SmartPtr<LabeledTrackBar> rotator;
SmartPtr<AxisPositioner> axisPositioner;
SmartPtr<EyePositioner> eyePositioner;
SmartPtr<LightPositioner> lightPositioner;
FileDialog filedlg;
long size(Event& event)
{
int w, h;
event.getSize(w, h);
if (view && rotator && eyePositioner && lightPositioner) {
int posw = eyePositioner->getDefaultWidth();
int posh = eyePositioner->getDefaultHeight();
int rth = rotator->getDefaultHeight();
view -> reshape(0, 0, w-posw-4, h);
view -> postResizeRequest(w-posw-4, h);
rotator->reshape(w-posw-2, 2, posw, rth);
int posy = rth + 4;
axisPositioner->reshape(w-posw-2, posy, posw, posh);
eyePositioner->reshape(w-posw-2, posy+posh+2, posw, posh);
lightPositioner->reshape(w-posw-2,posy+(posh+2)*2, posw, posh);
}
return 1L;
}
virtual void angleChanged(Action& action)
{
if (view && rotator) {
int angle = rotator->getPosition();
view -> setAngle(angle);
}
}
virtual long axisPositionChanged(Event& event)
{
if (view && axisPositioner) {
view -> setAxisPosition(axisPositioner->getX(),
axisPositioner->getY(),
axisPositioner->getZ());
}
return 0;
}
virtual long eyePositionChanged(Event& event)
{
if (view && eyePositioner) {
view -> setEyePosition(eyePositioner->getX(),
eyePositioner->getY(),
eyePositioner->getZ());
}
return 0;
}
virtual long lightPositionChanged(Event& event)
{
if (view && lightPositioner) {
view -> setLightPosition(lightPositioner->getX(),
lightPositioner->getY(),
lightPositioner->getZ());
}
return 0;
}
public:
MainView(Application& applet, const char* name, Args& args)
:OpenGLMainView(applet, name, args.set(XmNstyle, WS_CLIPCHILDREN|WS_CLIPSIBLINGS))
{
Args ar;
view = new SimpleView(this, "", ar);
ar.reset();
ar.set(XmNminimum, -180);
ar.set(XmNmaximum, 180);
ar.set(XmNheight, 60);
ar.set(XmNposition, 127);
ar.set(XmNlabelString, "Rotator");
rotator = new LabeledTrackBar(this, "", ar);
rotator->addCallback(XmNtrackBarScrollCallback, this,
(Callback)&MainView::angleChanged, NULL);
ar.reset();
ar.set(XmNminimum, -100);
ar.set(XmNmaximum, 100);
ar.set(XmNlabelString, "AxisPositioner [-100, 100]");
axisPositioner = new AxisPositioner(this, "", ar);
int axisX = -10;// 7;
int axisY = -50; //-68;
int axisZ = 80; //85;
axisPositioner->setThumbPosition(axisX, axisY, axisZ);
view ->setAxisPosition(axisX, axisY, axisZ);
ar.reset();
ar.set(XmNminimum, -200);
ar.set(XmNmaximum, 200);
ar.set(XmNlabelString, "EyePositioner [-200, 200]");
eyePositioner = new EyePositioner(this, "", ar);
int eyeX = 0;
int eyeY = 6;
int eyeZ = 2;
eyePositioner->setThumbPosition(eyeX, eyeY, eyeZ);
view -> setEyePosition(eyeX, eyeY, eyeZ);
ar.reset();
ar.set(XmNminimum, -200);
ar.set(XmNmaximum, 200);
ar.set(XmNlabelString, "LightPositioner [-200, 200]");
lightPositioner = new LightPositioner(this, "", ar);
int lightX = 21;
int lightY = -10;
int lightZ = 2;
lightPositioner->setThumbPosition(lightX, lightY, lightZ);
view -> setLightPosition(lightX, lightY, lightZ);
addEventHandler(axisPositioner->getPositionChangedMessage(), this,
(Handler)&MainView::axisPositionChanged, NULL);
addEventHandler(eyePositioner->getPositionChangedMessage(), this,
(Handler)&MainView::eyePositionChanged, NULL);
addEventHandler(lightPositioner->getPositionChangedMessage(), this,
(Handler)&MainView::lightPositionChanged, NULL);
view -> postRenderRequest();
ar.reset();
ar.set(XmNfilter, FileDialog::getImageFilesFilter());
filedlg.create(this, "OpenFile", ar);
}
~MainView()
{
}
void openFile(const char* filename)
{
try {
view -> createTexture(filename);
view -> postRenderRequest();
ModuleFileName module;
const char* appName = module.getAppName();
const char* name = filename;
const char* slash = strrchr(filename, '\\');
if (slash) {
name = ++slash;
}
char title[MAX_PATH];
sprintf_s(title, CountOf(title), "%s - %s", name, appName);
setText(title);
} catch (Exception& ex) {
caught(ex);
}
}
virtual void open(Action& action)
{
Args ar;
char dir[MAX_PATH] = { 0 };
if (restoreFileFolder(dir, CountOf(dir))) {
ar.set(XmNdirectory, dir);
filedlg.setValues(ar);
}
try {
if(filedlg.open()) {
const char* filename = filedlg.getFileName();
saveFileFolder(filename);
openFile(filename);
}
} catch (Exception& ex) {
caught(ex);
}
}
};
}
//
void Main(int argc, char** argv)
{
try {
const char* name = appName(argv[0]);
Application applet(name, argc, argv);
Args args;
args.set(XmNwidth, 840);
args.set(XmNheight, 490);
MainView view(applet, name, args);
view.realize();
applet.run();
} catch (Exception& ex) {
caught(ex);
}
}
Last modified: 24 Nov. 2017
Copyright (c) 2017 Antillia.com ALL RIGHTS RESERVED.