--User changes

-Allow for saving EXR as full 31-bit float per component per pixel.
 -Allow for saving the output from the final render dialog as a different image format without starting the rendering process over.

--Code changes:
 -Make StripsRender() handle memsetting the final output image so calling code no longer has to.
 -Make FinalRenderEmberController<T>::SaveCurrentRender() return the path that the image was actually saved to.
This commit is contained in:
Person
2019-11-29 23:52:17 -08:00
parent 59605f10a8
commit 35d4eb3464
12 changed files with 352 additions and 64 deletions

View File

@ -263,12 +263,12 @@ static void Rgba32ToRgba16(v4F* rgba, glm::uint16* rgb, size_t width, size_t hei
}
/// <summary>
/// Convert an RGBA 32-bit float buffer to an EXR RGBA 32-bit float buffer.
/// Convert an RGBA 32-bit float buffer to an EXR RGBA 16-bit float buffer.
/// The two buffers can point to the same memory location if needed.
/// Note that this squares the values coming in, for some reason EXR expects that.
/// </summary>
/// <param name="rgba">The RGBA 32-bit float buffer</param>
/// <param name="rgb">The EXR RGBA 32-bit float buffer</param>
/// <param name="ilmfRgba">The EXR RGBA 16-bit float buffer</param>
/// <param name="width">The width of the image in pixels</param>
/// <param name="height">The height of the image in pixels</param>
/// <param name="doAlpha">True to use alpha transparency, false to assign the max alpha value to make each pixel fully visible</param>
@ -283,6 +283,30 @@ static void Rgba32ToRgbaExr(v4F* rgba, Rgba* ilmfRgba, size_t width, size_t heig
}
}
/// <summary>
/// Convert an RGBA 32-bit float buffer to an EXR RGBA 32-bit float buffer.
/// The two buffers can point to the same memory location if needed.
/// Note that this squares the values coming in, for some reason EXR expects that.
/// </summary>
/// <param name="rgba">The RGBA 32-bit float buffer</param>
/// <param name="r">The EXR red 32-bit float buffer</param>
/// <param name="g">The EXR green 32-bit float buffer</param>
/// <param name="b">The EXR blue 32-bit float buffer</param>
/// <param name="a">The EXR alpha 32-bit float buffer</param>
/// <param name="width">The width of the image in pixels</param>
/// <param name="height">The height of the image in pixels</param>
/// <param name="doAlpha">True to use alpha transparency, false to assign the max alpha value to make each pixel fully visible</param>
static void Rgba32ToRgba32Exr(v4F* rgba, float* r, float* g, float* b, float* a, size_t width, size_t height, bool doAlpha)
{
for (size_t i = 0; i < (width * height); i++)
{
r[i] = Clamp<float>(Sqr(rgba[i].r), 0.0f, 1.0f);
g[i] = Clamp<float>(Sqr(rgba[i].g), 0.0f, 1.0f);
b[i] = Clamp<float>(Sqr(rgba[i].b), 0.0f, 1.0f);
a[i] = doAlpha ? Clamp<float>(rgba[i].a * 1.0f, 0.0f, 1.0f) : 1.0f;
}
}
/// <summary>
/// Make a filename for a single render. This is used in EmberRender.
/// </summary>
@ -599,6 +623,7 @@ static bool StripsRender(RendererBase* renderer, Ember<T>& ember, vector<v4F>& f
vector<QTIsaac<ISAAC_SIZE, ISAAC_INT>> randVec;
ember.m_Quality *= strips;
ember.m_FinalRasH = size_t(ceil(floatStripH));
Memset(finalImage);
if (strips > 1)
randVec = renderer->RandVec();
@ -654,7 +679,6 @@ static bool StripsRender(RendererBase* renderer, Ember<T>& ember, vector<v4F>& f
if (success)
allStripsFinished(ember);
Memset(finalImage);
return success;
}

View File

@ -67,11 +67,15 @@
#include <OpenEXR/ImfRgbaFile.h>
#include <OpenEXR/ImfStringAttribute.h>
#include <OpenEXR/half.h>
#define ENUM_DYLD_BOOL
#include <mach-o/dyld.h>
#include <OpenEXR/ImfChannelList.h>
#include <OpenEXR/ImfOutputFile.h>
#define ENUM_DYLD_BOOL
#include <mach-o/dyld.h>
#else
#include <ImfRgbaFile.h>
#include <ImfStringAttribute.h>
#include <ImfChannelList.h>
#include <ImfOutputFile.h>
#include <half.h>
#endif

View File

@ -364,9 +364,9 @@ static bool WriteBmp(const char* filename, byte* image, size_t width, size_t hei
}
/// <summary>
/// Write an EXR file.
/// This is used for extreme color precision because it uses
/// floats for each color channel.
/// Write an EXR file which will use the 16 bit half float format for each pixel channel.
/// This is used for high color precision because it uses
/// HALFS for each color channel.
/// </summary>
/// <param name="filename">The full path and name of the file</param>
/// <param name="image">Pointer to the image data to write</param>
@ -378,7 +378,7 @@ static bool WriteBmp(const char* filename, byte* image, size_t width, size_t hei
/// <param name="url">Url of the author</param>
/// <param name="nick">Nickname of the author</param>
/// <returns>True if success, else false</returns>
static bool WriteExr(const char* filename, Rgba* image, size_t width, size_t height, bool enableComments, const EmberImageComments& comments, const string& id, const string& url, const string& nick)
static bool WriteExr16(const char* filename, Rgba* image, size_t width, size_t height, bool enableComments, const EmberImageComments& comments, const string& id, const string& url, const string& nick)
{
try
{
@ -419,3 +419,89 @@ static bool WriteExr(const char* filename, Rgba* image, size_t width, size_t hei
return false;
}
}
/// <summary>
/// Write an EXR file which will use the 32 bit half float format for each pixel channel.
/// This is used for extreme color precision because it uses
/// floats for each color channel.
/// </summary>
/// <param name="filename">The full path and name of the file</param>
/// <param name="r">Pointer to the red image data to write</param>
/// <param name="g">Pointer to the green image data to write</param>
/// <param name="b">Pointer to the blue image data to write</param>
/// <param name="a">Pointer to the alpha image data to write</param>
/// <param name="width">Width of the image in pixels</param>
/// <param name="height">Height of the image in pixels</param>
/// <param name="enableComments">True to embed comments, else false</param>
/// <param name="comments">The comment string to embed</param>
/// <param name="id">Id of the author</param>
/// <param name="url">Url of the author</param>
/// <param name="nick">Nickname of the author</param>
/// <returns>True if success, else false</returns>
static bool WriteExr32(const char* filename, float* r, float* g, float* b, float* a, size_t width, size_t height, bool enableComments, const EmberImageComments& comments, const string& id, const string& url, const string& nick)
{
try
{
int iw = int(width);
int ih = int(height);
std::unique_ptr<OutputFile> file;
try
{
rlg l(fileCs);
Header header(iw, ih);
header.channels().insert("R", Channel(PixelType::FLOAT));
header.channels().insert("G", Channel(PixelType::FLOAT));
header.channels().insert("B", Channel(PixelType::FLOAT));
header.channels().insert("A", Channel(PixelType::FLOAT));
file = std::make_unique<OutputFile>(filename, header);
}
catch (std::exception)
{
return false;
}
if (enableComments)
{
auto& header = const_cast<Imf::Header&>(file->header());
header.insert("ember_version", StringAttribute(EmberVersion()));
header.insert("ember_nickname", StringAttribute(nick));
header.insert("ember_url", StringAttribute(url));
header.insert("ember_id", StringAttribute(id));
header.insert("ember_error_rate", StringAttribute(comments.m_Badvals));
header.insert("ember_samples", StringAttribute(comments.m_NumIters));
header.insert("ember_time", StringAttribute(comments.m_Runtime));
header.insert("ember_genome", StringAttribute(comments.m_Genome));
}
FrameBuffer frameBuffer;
frameBuffer.insert("R",
Slice(PixelType::FLOAT,
(char*)r,
sizeof(*r) * 1,
sizeof(*r) * width));
frameBuffer.insert("G",
Slice(PixelType::FLOAT,
(char*)g,
sizeof(*g) * 1,
sizeof(*g) * width));
frameBuffer.insert("B",
Slice(PixelType::FLOAT,
(char*)b,
sizeof(*b) * 1,
sizeof(*b) * width));
frameBuffer.insert("A",
Slice(PixelType::FLOAT,
(char*)a,
sizeof(*a) * 1,
sizeof(*a) * width));
file->setFrameBuffer(frameBuffer);
file->writePixels(ih);
return true;
}
catch (std::exception e)
{
cout << e.what() << endl;
return false;
}
}